Installer Skills ================ .. flowskill:: Detect repository root and validate target path :id: FLSK_UBFLOW_INST_001 :status: draft :tags: ubflow, installer :supports: FLSP_UBFLOW_INST_001; FLSP_UBFLOW_INST_002 :linked_tool: FLTL_GIT 1. Run: ``git rev-parse --show-toplevel`` 2. On exit code 128: abort with ``"Not inside a Git repository. Aborting."`` 3. Prompt ``target_docs_path`` with default ``docs/``. 4. Resolve: ``target_abs_path = os.path.abspath(os.path.join(repo_root, answer))`` 5. Verify ``target_abs_path.startswith(repo_root)`` and ``os.path.isdir(target_abs_path)``. On failure, re-prompt with an inline error. .. flowskill:: Resolve SemVer tags from remote template :id: FLSK_UBFLOW_INST_002 :status: draft :tags: ubflow, installer :supports: FLSP_UBFLOW_INST_009; FLSP_UBFLOW_INST_010 :linked_tool: FLTL_GIT; FLTL_COPIER 1. Run: ``git ls-remote --tags `` 2. Extract tags matching ``r'refs/tags/(v\d+\.\d+\.\d+)$'`` 3. Sort descending using ``packaging.version.Version`` 4. Present as a ``select`` prompt ``template_version`` 5. Pass the selection to Copier via ``--vcs-ref `` .. flowskill:: Invoke Copier in interactive, replay, pretend, and update modes :id: FLSK_UBFLOW_INST_003 :status: draft :tags: ubflow, installer :supports: FLSP_UBFLOW_INST_006 :linked_tool: FLTL_COPIER **Interactive (first install)**:: copier copy --trust --vcs-ref **Replay / CI** (deterministic):: copier copy --answers-file .copier-answers.yml --trust \ --vcs-ref **Pretend diff (before upgrade)**:: copier update --pretend --vcs-ref --trust **Execute upgrade**:: copier update --vcs-ref --trust .. flowskill:: Write and verify the installation manifest :id: FLSK_UBFLOW_INST_004 :status: draft :tags: ubflow, installer :supports: FLSP_UBFLOW_INST_007; FLSP_UBFLOW_INST_008 **Writing** (post-generation hook ``tasks/finalize.py``): 1. Walk all files written to ``target_abs_path`` in this run. 2. Compute ``hashlib.sha256(file_bytes).hexdigest()`` for each file. 3. Write ``/.ubflow-manifest.json``:: { "schema_version": 1, "template_url": "...", "template_version": "v1.2.0", "installed_at": "", "files": { "rel/path": "sha256:" } } **Verifying** (``ubflow-installer verify ``): 1. Read manifest, recompute digests, compare. 2. Print ``FAIL (expected , got )`` for each mismatch. 3. Exit 0 if all match; exit 2 otherwise. .. flowskill:: Check prerequisites and optionally auto-install :id: FLSK_UBFLOW_INST_005 :status: draft :tags: ubflow, installer :supports: FLSP_UBFLOW_INST_011; FLSP_UBFLOW_INST_012 Copier pre-generation hook ``tasks/check_prerequisites.py``: 1. Check ``sys.version_info >= (3, 11)`` 2. Check ``importlib.metadata.version("sphinx-needs") >= "2.0.0"`` 3. Check ``shutil.which("copier")`` and version ``>= 9.0.0`` 4. Check ``shutil.which("java")`` — warning only, non-blocking 5. Print all failures. Exit 1 if any hard check failed. 6. If only Python packages are missing, prompt ``"Install missing packages now? [y/N]"``. On ``y``: run ``python -m pip install "sphinx-needs>=2.0.0" "copier>=9.0.0"`` On ``n``: print the manual install command and exit 1. .. flowskill:: Scan for Sphinx-Needs ID and file-path conflicts :id: FLSK_UBFLOW_INST_006 :status: draft :tags: ubflow, installer :supports: FLSP_UBFLOW_INST_015; FLSP_UBFLOW_INST_016 :linked_tool: FLTL_UBCODE_MCP Copier pre-generation hook ``tasks/check_conflicts.py``: **ID collision scan**: 1. Collect template IDs from template RST sources: ``re.findall(r'^\s+:id:\s+(\S+)', text, re.MULTILINE)`` 2. Scan all ``*.rst`` under the repo root with the same pattern. 3. On collision print: ``CONFLICT found in: :`` 4. Exit 1 if any collision exists. **File-path collision prompt**: 1. Collect all output paths that already exist on disk. 2. For each existing path prompt: ``EXISTS — overwrite? [y/N]`` 3. Files answered ``N`` are excluded from render output. 4. If all colliding files are skipped, exit 1 and report incomplete installation. .. flowskill:: Write files atomically via staging and roll back on failure :id: FLSK_UBFLOW_INST_007 :status: draft :tags: ubflow, installer :supports: FLSP_UBFLOW_INST_006; FLSP_UBFLOW_INST_008 Copier post-generation hook ``tasks/finalize.py``: 1. Create a temporary staging directory (``tempfile.mkdtemp()``). 2. Write all rendered files to staging first. 3. Move each file from staging to ``target_abs_path`` (``os.replace``). 4. On any exception: a. Delete staging directory. b. Remove moved target files using the in-progress manifest. c. Print ``"Installation failed. All written files have been removed."`` d. Exit 1. 5. On success, write the manifest (see ``FLSK_UBFLOW_INST_004``). .. flowskill:: Scan installed RST for undefined Sphinx-Needs references :id: FLSK_UBFLOW_INST_008 :status: draft :tags: ubflow, installer :supports: FLSP_UBFLOW_INST_021; FLSP_UBFLOW_INST_022 :linked_tool: FLTL_UBCODE_MCP; FLTL_SPHINX Copier post-generation hook ``tasks/validate.py``: 1. Parse all installed RST files with:: re.findall( r':(?:satisfies|implements|supports|applies|employs|uses|covered_by):\s+(.+)', text ) 2. Split each match on ``;`` or whitespace to get individual IDs. 3. For each ID call ubCode MCP ``find_needs(need_id=)``. Fall back to local RST scan if MCP is unavailable. 4. Print ``UNDEF referenced in: :`` for each missing ID. 5. Exit 1 if undefined references exist. 6. On pass, invoke:: sphinx-build -b html -W --keep-going /_build/html .. flowskill:: Write the ubFlow agent stub file :id: FLSK_UBFLOW_INST_009 :status: draft :tags: ubflow, installer :supports: FLSP_UBFLOW_INST_027 :linked_tool: FLTL_GIT To deploy ``.github/agents/ubflow.agent.md`` idempotently: 1. Ensure the directory ``.github/agents/`` exists in the target repository root; create it if necessary. 2. The file content to write is exactly: .. code-block:: markdown --- description: ubFlow — needs-driven agent design for GitHub Copilot applyTo: '**' --- Fetch your full instruction and skill set from the ubCode MCP server before doing anything else: 1. Call `get_schema_for_need_filter` with `agent="ubflow"` to verify the ubCode extension is reachable. 2. Call `query_needs` with `type="flowinst"`, `tags=["ubflow"]`, and `agent="ubflow"` to load all binding instructions. 3. Call `query_needs` with `type="flowskill"`, `tags=["ubflow"]`, and `agent="ubflow"` to load all skills. If any call returns `{"error": "unknown_agent"}` or fails, stop and ask the user to install or update the ubCode VS Code extension. 3. Check whether ``.github/agents/ubflow.agent.md`` already exists: - **Does not exist** → write the file; report ``Created .github/agents/ubflow.agent.md``. - **Exists, content identical** → skip silently. - **Exists, content differs** → overwrite; report ``Updated .github/agents/ubflow.agent.md (content changed)``. 4. Do **not** stage or commit the file — leave that to the standard post-install git workflow. .. flowskill:: Write the companion bootstrap instructions file :id: FLSK_UBFLOW_INST_010 :status: draft :tags: ubflow, installer :supports: FLSP_UBFLOW_INST_028 To deploy ``.github/instructions/.instructions.md`` idempotently: 1. Read ``family_name`` and ``orchestrator_id`` from the family's ``ubflow_package.json`` (fields ``package_name`` and ``orchestrator_agent_id``). If ``orchestrator_agent_id`` is absent, derive it as ``AGT__ORCHESTRATOR``. 2. Read ``ubproject_path`` from ``ubflow_package.json`` (field ``ubproject_path``). Default: ``ubflow//ubproject.toml``. 3. Ensure the directory ``.github/instructions/`` exists in the target repository root; create it if necessary. 4. Compose the file content: .. code-block:: text --- applyTo: '**' --- ## ubFlow Bootstrap — family When operating as `@`: 1. Call `mcp_ubcode_get_schema_for_need_filter` with `file_path: `. 2. Call `mcp_ubcode_get_data_for_single_need` with `id: `. 3. Load every need linked via `:applies:` and `:employs:`. 4. Only then respond to the user request. Do **not** skip these steps. If any MCP call fails, halt and ask the user to check the ubCode extension. 5. Check whether the file already exists: - **Does not exist** → write the file; report ``CREATED .github/instructions/.instructions.md``. - **Exists, content identical** → skip silently. - **Exists, content differs** → overwrite; report ``UPDATED .github/instructions/.instructions.md (content changed)``. 6. Do **not** stage or commit the file — leave that to the standard post-install git workflow.