@gluecharm-lab/easyspecs-cli 0.0.28 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,13 +5,13 @@ Headless **EasySpecs** command-line tool: same orchestration ideas as the **Easy
5
5
  ## The three factory-level commands
6
6
 
7
7
  1. **`easyspecs-cli analysis` — create new context**
8
- Runs the full **Generate Context** factory end to end (synthesis until stable, coverage, remediation, reporting, link mapping, index assembly). Use this when you need a fresh or full rebuild of **`.gluecharm/context`** from the repo. **`--force-new-context-analysis`** overrides skip-when-already-analyzed behavior when **`easyspecs.factory.cloudContextAnalyzed`** would otherwise short-circuit the run. On a **successful** factory exit, the CLI **always** copies **`.gluecharm/context`** from the analysis worktree into **`<repoRoot>`** unless you pass **`--no-promote`** (no **`--promote`** needed); stderr **`[pipeline:analysis] promoted …`**. This step does **not** use **`easyspecs.analysis.promoteContextToWorkspace`** — that setting still applies to **`run synthesis`** and **`update context`**. After **`analysis`**, run **`easyspecs-cli upload context`** or **`upload republish`** when you want context on EasySpecs (**`auth login`** + **`config set-project-id`**). If **`git worktree add`** fails because a temp analysis checkout folder was removed but Git still lists it, the CLI runs **`git worktree prune`** in your repository and retries **`git worktree add`** once (same behaviour wherever the CLI creates that temp worktree).
8
+ Runs the full **Generate Context** factory end to end (synthesis until stable, coverage, remediation, reporting, link mapping, index assembly). Use this when you need a fresh or full rebuild of **`.gluecharm/context`** from the repo. **`--force-new-context-analysis`** overrides skip-when-already-analyzed behavior when **`easyspecs.factory.cloudContextAnalyzed`** would otherwise short-circuit the run. **`--no-worktree`** (alias **`--noworktree`**) runs the factory on the repository checkout itself instead of a detached temp git worktree (**SRS-71**). On a **successful** factory exit, the CLI **always** copies **`.gluecharm/context`** from the analysis checkout into **`<repoRoot>`** unless you pass **`--no-promote`** or the checkout is already the repo root (no **`--promote`** needed); stderr **`[pipeline:analysis] promoted …`** or a skip line when in-place. This step does **not** use **`easyspecs.analysis.promoteContextToWorkspace`** — that setting still applies to **`run synthesis`** and **`update context`**. After **`analysis`**, run **`easyspecs-cli upload context`** or **`upload republish`** when you want context on EasySpecs (**`auth login`** + **`config set-project-id`**). If **`git worktree add`** fails because a temp analysis checkout folder was removed but Git still lists it, the CLI runs **`git worktree prune`** in your repository and retries **`git worktree add`** once (same behaviour wherever the CLI creates that temp worktree).
9
9
 
10
10
  2. **`easyspecs-cli update context` — update context from code churn**
11
- Incremental refresh from a **git delta** since the stored baseline (**`easyspecs.factory.updateContext.lastRunAt`**) or, when that is absent, inferred from workspace context mtimes: materialises **`changes-since-date.md`**, runs **scoped** remediation when commits and touched paths warrant it, then optional promotion. Use **`upload context`** afterward when you need cloud sync. Use this day to day after **`analysis`** when the codebase moved but specs did not restart from zero.
11
+ Incremental refresh from a **git delta** since the stored baseline (**`easyspecs.factory.updateContext.lastRunAt`**) or, when that is absent, inferred from workspace context mtimes: materialises **`changes-since-date.md`**, runs **scoped** remediation when commits and touched paths warrant it, then optional promotion. **`--no-worktree`** / **`--noworktree`** uses **`<repoRoot>`** as the analysis checkout (**SRS-71**). Use **`upload context`** afterward when you need cloud sync. Use this day to day after **`analysis`** when the codebase moved but specs did not restart from zero.
12
12
 
13
13
  3. **`easyspecs-cli context drift <referencePath>` — analyze drift against specs**
14
- **`referencePath`** is a **file or directory** of truth documents (requirements, specs, PRD, architecture notes — whatever your team treats as ground truth relative to repo root). The CLI compares **repository / analysis worktree** context against that reference (OpenCode-assisted), writes **`drift-<label>-<date>.md`** under **`.gluecharm/context/drift/`**, and can update the reference index markdown. **`--label <slug>`** names the report file; **`--index <path>`** overrides which root markdown anchors the comparison; **`--dry-run`** validates references only (**no worktree, agent, or writes**).
14
+ **`referencePath`** is a **file or directory** of truth documents (requirements, specs, PRD, architecture notes — whatever your team treats as ground truth relative to repo root). The CLI compares **repository / analysis checkout** context against that reference (OpenCode-assisted), writes **`drift-<label>-<date>.md`** under **`.gluecharm/context/drift/`**, and can update the reference index markdown. **`--label <slug>`** names the report file; **`--index <path>`** overrides which root markdown anchors the comparison; **`--dry-run`** validates references only (**no worktree, agent, or writes**). **`--no-worktree`** / **`--noworktree`** uses **`<repoRoot>`** as the checkout and cannot be combined with **`--root worktree`** or **`--worktree <path>`** (**SRS-71**).
15
15
 
16
16
  **Supporting commands (not substitutes for those three goals):** **`auth`** and **`config`** wire API access and **`easyspecs.easyspecsProjectId`**; **`download context`** / **`upload context`** / **`upload republish`** move artefacts between disk and EasySpecs; **`doctor`** checks readiness and redacted merged settings; **`diagnose`** and **`context link-graph`** are deterministic gates and link maintenance; **`run synthesis`** and **`run synthesis resume-*`** run single stages or catch-up without the full factory; **`ace *`** manages optional learnings under **`.gluecharm/context/learnings`**.
17
17
 
@@ -219,7 +219,7 @@ These appear **before** the subcommand (everything after the first non-flag toke
219
219
  | ---- | ------ |
220
220
  | `--cwd <dir>` | Repository root for git resolution and paths (default: current working directory). |
221
221
  | `--ci` | Non-interactive mode; affects merged settings (e.g. Factory outer-iteration default). **`EASYSPECS_CI` is not read** — use this flag. |
222
- | `--json` | On supported exits, one JSON summary line on stdout. On **non-zero** exits, the line includes **`exitCode`** (number) and **`exitMeaning`** (one-line classification) alongside any command-specific fields. **`analysis`** validation failures also include **`factoryFailures`** (per failed factory phase), **`failurePhase`**, and **`validationExitId`**. |
222
+ | `--json` | On supported exits, one JSON summary line on stdout. On **non-zero** exits, the line includes **`exitCode`** (number) and **`exitMeaning`** (one-line classification) alongside any command-specific fields. Factory / pipeline failures include **`factoryFailures`** (per failed phase), **`failurePhase`**, and **`validationExitId`** (legacy alias of **`failureExitId`**). See [error-code.md](./error-code.md) — OS exit **`5`** is **not** used (**SRS-70**). |
223
223
  | `--verbose` | Extra stderr logging where implemented. |
224
224
  | `--api-base-url <url>` | System Manager API origin for this process (overrides `easyspecs.apiBaseUrl`). |
225
225
  | `--session-path <file>` | Session JSON path for **this process only** (overrides **`easyspecs.cliSessionPath`**); does not rewrite **`config.json`** unless you use **`auth login`** tail **`--session-path`** as documented under **Auth**. |
@@ -258,15 +258,15 @@ Every command the CLI accepts, with command-specific tokens. Global flags above
258
258
  | `run synthesis` | — | Context artefact pipeline pass; **`requireOpenCode`** applies. **`--promote` / `--no-promote`** affect promotion after success. |
259
259
  | `run synthesis resume-missing` | **`--worktree <path>`** (optional) | Parallel missing-artefact remediation pool on an existing checkout (from **`--worktree`** or last snapshot). **`requireOpenCode`**. |
260
260
  | `run synthesis resume-synthesis` | **`--worktree <path>`** (optional) | Same implementation as **`resume-missing`** (alias command path). |
261
- | `analysis` | **`--force-new-context-analysis`** (optional; tail only). **`--upload`** / **`--skip-upload`** → usage exit; **`--synthesis-only`** → ignored + stderr deprecation (**SRS-60**). | Full **Generate Context** factory — **create new context** trajectory. CLI **does not** run backend upload inside **`analysis`**; use **`upload context`** / **`upload republish`** afterward. **Promotion** after success is **automatic** unless **`--no-promote`** (independent of **`easyspecs.analysis.promoteContextToWorkspace`**). If **`easyspecs.factory.cloudContextAnalyzed`** is **`true`** and **`--force-new-context-analysis`** is absent, exits **0** early with **`analysisSkipped`**. Stale temp-worktree registration: **`git worktree prune`** then one retry of **`git worktree add`**. |
262
- | `update context` | | **Update context** trajectory: git window after baseline → worktree → **`changes-since-date.md`** → optional remediation → **`--promote` / `--no-promote`** → **`easyspecs.factory.updateContext.lastRunAt`**. Run **`upload context`** separately for cloud sync. Seed context should exist on **HEAD** in the checkout (the factory may copy from workspace when the worktree lacks context). |
261
+ | `analysis` | **`--force-new-context-analysis`** (optional; tail only). **`--no-worktree`** / **`--noworktree`** (**SRS-71**). **`--upload`** / **`--skip-upload`** → usage exit; **`--synthesis-only`** → ignored + stderr deprecation (**SRS-60**). | Full **Generate Context** factory — **create new context** trajectory. CLI **does not** run backend upload inside **`analysis`**; use **`upload context`** / **`upload republish`** afterward. **Promotion** after success is **automatic** unless **`--no-promote`** or checkout is already **`<repoRoot>`** (independent of **`easyspecs.analysis.promoteContextToWorkspace`**). If **`easyspecs.factory.cloudContextAnalyzed`** is **`true`** and **`--force-new-context-analysis`** is absent, exits **0** early with **`analysisSkipped`**. Stale temp-worktree registration: **`git worktree prune`** then one retry of **`git worktree add`**. |
262
+ | `update context` | **`--no-worktree`** / **`--noworktree`** (**SRS-71**). | **Update context** trajectory: git window after baseline → analysis checkout → **`changes-since-date.md`** → optional remediation → **`--promote` / `--no-promote`** → **`easyspecs.factory.updateContext.lastRunAt`**. Run **`upload context`** separately for cloud sync. Seed context should exist on **HEAD** in the checkout (the factory may copy from workspace when the detached worktree lacks context; skipped when **`--no-worktree`**). |
263
263
  | `diagnose reference-coverage` | **`--root workspace`** \| **`--root worktree`**, optional **`--worktree <path>`** | Reference coverage gate; optional percent limit via **`easyspecs.diagnose.zeroReference.maxPercentNonReferenced`**. |
264
264
  | `diagnose coordination-duplicates` | same | Duplicate/orphan reporting; **`easyspecs.diagnose.coordinationDuplicates.strict`**. |
265
265
  | `diagnose coverage-report` | same | Writes coverage execution report path. |
266
266
  | `diagnose missing-artefacts` | same | Lists missing artefacts from workspace state (JSON on stdout in human mode). |
267
267
  | `diagnose zero-reference` | **`--worktree <path>`** (optional; no **`--root`** branch) | Zero-reference remediation pool (**OpenCode**). After a successful pool run, applies context markdown navigation links under the analysis checkout context directory (fails the command if that step reports broken links). |
268
268
  | `context link-graph` | **`--root workspace`** \| **`--root worktree`**, optional **`--worktree <path>`** | Refreshes EasySpecs navigation marker blocks in **`.gluecharm/context/**/*.md`** from coordination JSON only (no agents). **`--json`** may include **`contextDir`**, **`error`**, **`brokenLinks`**. |
269
- | `context drift <referencePath>` | **`--label <slug>`**, **`--index <path>`**, **`--dry-run`**; **`--root` / `--worktree`** tail tokens are accepted and ignored for current routing | **Analyze drift against specs** trajectory: **`referencePath`** = file or directory of reference docs. Uses analysis worktree + OpenCode drift agent → **`.gluecharm/context/drift/drift-<slug>-<date>.md`** and reference index maintenance; global **`--promote` / `--no-promote`** apply when not **`--dry-run`**. Success stdout: drift report path. |
269
+ | `context drift <referencePath>` | **`--label <slug>`**, **`--index <path>`**, **`--dry-run`**, **`--no-worktree`** / **`--noworktree`** (**SRS-71**; not with **`--root worktree`** / **`--worktree`**). Optional **`--root` / `--worktree`** for other routing. | **Analyze drift against specs** trajectory: **`referencePath`** = file or directory of reference docs. Uses analysis checkout + OpenCode drift agent → **`.gluecharm/context/drift/drift-<slug>-<date>.md`** and reference index maintenance; global **`--promote` / `--no-promote`** apply when not **`--dry-run`**. Success stdout: drift report path. |
270
270
  | `download context` | **`--force`**, **`--replace-from-cloud`** (optional; any order after **`download context`**) | Requires **`auth login`** session + **`easyspecs.easyspecsProjectId`**. Resolves linked context documents from **`GET /api/content/application/:id`**, batch-fetches content, writes UTF-8 files under **`<repo>/.gluecharm/context`**. Default skips existing paths; **`--force`** overwrites; **`--replace-from-cloud`** wipes local context files first (preserves root **`easyspecs-upload-target.json`**). **`--json`**: **`downloaded`**, **`skipped`**, **`failed`**, **`localRemoved`**. Non-zero exit if **`failed` > 0`. Full narrative under **Download context (pull from EasySpecs)** above. |
271
271
  | `upload context` | — | Requires auth session + **`easyspecs.easyspecsProjectId`**. Context dir: **`<repo>/.gluecharm/context`**. Optional cloud status GET per **`easyspecs.upload.fetchContextAnalyzedInCloud`**. |
272
272
  | `upload republish` | — | Same auth + project id; context dir from **`easyspecs.upload.contextDirectory`** or analysis worktree snapshot. Same optional cloud status behaviour as **`upload context`**. |
package/commands.md CHANGED
@@ -24,21 +24,21 @@ Quick usage:
24
24
  easyspecs-cli help
25
25
  ```
26
26
 
27
- ### Factory validation reporting (**SRS-57**)
27
+ ### Factory failure reporting (**SRS-57** / **SRS-70**)
28
28
 
29
- When `**easyspecs-cli analysis`** exits with **validation** (`**5`**), human stderr prints a short banner and **one bullet per failed factory phase** (readable label, `**validationExitId`** `**5.1`–`5.9**`, normative `**title**`, optional `**detail**`). `**--json**` adds:
29
+ When `**easyspecs-cli analysis`** exits **non-zero** with factory failures, human stderr prints a short banner and **one bullet per failed factory phase** (readable label, `**failureExitId**`, normative `**title**`, optional `**detail**`). **OS exit `5` is never used** — each phase maps to a dedicated code (**50–58** for post-readiness pipeline rows, **84–87** for **`diagnose_readiness`** readiness gates per **SRS-72**), **59** when multiple distinct phases fail in one run, or **49** when unattributed. `**--json**` adds:
30
30
 
31
31
 
32
32
  | JSON key | Meaning |
33
33
  | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
34
- | `**factoryFailures**` | Array of `**{ factory, phase, exitCode, failureExitId, title, validationExitId? (when exit 5), detail?, validationSubcode? }**` — `**failureExitId**` is the canonical `**major.minor**` id (SRS-58); see `[error-code.md](./error-code.md)`. |
34
+ | `**factoryFailures**` | Array of `**{ factory, phase, exitCode, failureExitId, title, validationExitId?, detail?, validationSubcode? }**` — `**failureExitId**` is the canonical `**major.minor**` id (**SRS-58**); `**major**` matches **`process.exit`** (**SRS-70**). See `[error-code.md](./error-code.md)`. |
35
35
  | `**failurePhase**` | Last failed phase in macro order (alias for scripts). |
36
- | `**validationExitId**` | Matching `**5.x**` for `**failurePhase**`. |
36
+ | `**validationExitId**` | Legacy alias: same string as `**failureExitId**` when present. |
37
37
  | `**exitMeaning**` | First failure `**title**`, or that title plus “and *N* other pipeline phases failed”. |
38
- | `**error**` | Orchestrator message; if several phases failed, a short appendix lists extra `**validationExitId`**s (see `[factoryValidationFailures.ts](../../src/factory/factoryValidationFailures.ts)`). |
38
+ | `**error**` | Orchestrator message; if several phases failed, a short appendix lists extra `**failureExitId`**s (see `[factoryValidationFailures.ts](../../src/factory/factoryValidationFailures.ts)`). |
39
39
 
40
40
 
41
- `**validationExitId``phase` map:** `**5.1`** `create_analysis_worktree`, `**5.2**` `materialize_opencode_agents`, `**5.3**` `synthesis_convergence`, `**5.4**` `reference_coverage`, `**5.5**` `zero_reference_remediation_convergence`, `**5.6**` `reference_coverage_execution_report`, `**5.7**` `link_mapping_pipeline`, `**5.8**` `assemble_application_context_index`, `**5.9**` `backend_context_sync`, `**5.0**` unknown / unattributed. Normative `**title**` strings and readable labels: `[.gluecharm/docs/srs/srs-57.md](../../.gluecharm/docs/srs/srs-57.md)`.
41
+ **PhaseOS exit (generate_context):** **84–87** **`diagnose_readiness`** only when a **readiness gate** fails (**SRS-72** — install, credentials, model, mandatory **`opencode.json`**); **50** `create_analysis_worktree`, **51** `materialize_opencode_agents`, **52** `synthesis_convergence`, **53** `reference_coverage`, **54** `zero_reference_remediation_convergence`, **55** `reference_coverage_execution_report`, **56** `link_mapping_pipeline`, **57** `assemble_application_context_index`, **58** `backend_context_sync`, **49** unknown / unattributed. Full table: `[error-code.md](./error-code.md)`.
42
42
 
43
43
  **Optional `validationSubcode` (v1):** `**R5_MACRO_PING_PONG`** when synthesis `**detail**` notes **R5** unstable convergence; `**COVERAGE_PERCENT_THRESHOLD`** when reference-coverage `**detail**` matches the strict percent gate pattern.
44
44
 
@@ -53,7 +53,7 @@ These flags may appear **before** the subcommand. Parsing and command registrati
53
53
  | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
54
54
  | `--cwd <dir>` | Repository root for git resolution and file paths (default: current working directory). |
55
55
  | `--ci` | Non-interactive mode; feeds into merged settings (e.g. Factory outer-iteration default when unlimited). `**EASYSPECS_CI` is not read** — use this flag in CI. |
56
- | `--json` | On supported exits, prints one JSON summary line on stdout; suppresses some human-oriented stderr unless `--verbose`. On `**analysis`** validation (**exit code 5**), the JSON line includes `**factoryFailures`** (**SRS-57** — one object per `**failed`** factory phase) plus `**failurePhase**`, `**validationExitId**`, composed `**error**`, and `**exitMeaning**` tailored to the first failure. |
56
+ | `--json` | On supported exits, prints one JSON summary line on stdout; suppresses some human-oriented stderr unless `--verbose`. On `**analysis**` factory failure, the JSON line includes `**factoryFailures`** (**SRS-57** — one object per `**failed`** factory phase) plus `**failurePhase**`, `**validationExitId**`, composed `**error**`, and `**exitMeaning**` tailored to the first failure. **Exit codes:** **[SRS-70](../../.gluecharm/docs/srs/srs-70.md)** — OS **5** is not used; see `[error-code.md](./error-code.md)`. |
57
57
  | `--verbose` | Extra stderr logging where implemented. |
58
58
  | `--api-base-url <url>` | System Manager API origin for this process (overrides `easyspecs.apiBaseUrl` in config). |
59
59
  | `--environment production` | `--environment staging` | Alias: `**--env**`. Overrides `easyspecs.deploymentEnvironment` for built-in URL selection when no explicit URL is set. |
@@ -178,15 +178,15 @@ Each row lists **command-specific CLI tokens**, then **what configuration applie
178
178
  | `auth status` | — | Reads session file. |
179
179
  | `run synthesis` | — | Single SRS-9 context pass (same as extension **Run Analysis**). `**requireOpenCode`** → executable + credentials unless skip flag. Uses `**merged.pipelineOpenCode**` from `**config.json**`. `**--promote` / `--no-promote**` controls promotion after success. |
180
180
  | `run synthesis resume-missing`, `run synthesis resume-synthesis` | Optional `**--worktree <path>**` | Same implementation: resolves checkout via `--worktree` or stored snapshot (`[resolveAdHocCheckoutRoot](../../src/cli/main.ts)`). OpenCode + `**merged.pipelineOpenCode**`. |
181
- | `analysis` | Optional tail: `**--force-new-context-analysis**`. **`--upload`** → usage exit. **`--synthesis-only`**: accepted as a **hidden** Commander option (legacy scripts); **ignored** with one stderr **`[deprecated]`** line (**SRS-60**). | **SRS-32** full **Factory** loop: synthesis convergence (until no missing artefacts), coverage, zero-ref, report, **link mapping**, index assembly; **Phase 7** backend sync is skipped in CLI (**`skipBackendSync`**). **On success:** always promotes **`.gluecharm/context`** from the analysis worktree into **`<repoRoot>`** unless **`--no-promote`** (stderr **`[pipeline:analysis]`**); **`easyspecs.analysis.promoteContextToWorkspace`** does **not** apply to this step. Push context with **`upload context`** / **`upload republish`** after analysis if you need cloud sync. Factory timing from `**merged.factory`** + `**--ci**` defaults. Debug: `**easyspecs.factory.debug**`. OpenCode options from `**merged.pipelineOpenCode**`. **SRS-46:** if `**easyspecs.factory.cloudContextAnalyzed`** is `**true**` and `**--force-new-context-analysis**` is absent, exits **0** without running the Factory (`**analysisSkipped**`, …). **SRS-59:** stale worktree registration recovery — see **§ Analysis git checkout** below. |
182
- | `update context` | (no subcommand flags; **SRS-60** removed `**--upload**`) | **SRS-55:** incremental context refresh — baseline → git delta → worktree → `**changes-since-date.md`** → optional remediation → **`--promote` / `--no-promote**` (global) → persist `**lastRunAt**`. Run **`upload context`** separately if you need cloud sync. |
181
+ | `analysis` | Optional tail: `**--force-new-context-analysis**`, `**--no-worktree**` / `**--noworktree**` (**SRS-71**: use **`<repoRoot>`** as the analysis checkout; no detached temp worktree). **`--upload`** → usage exit. **`--synthesis-only`**: accepted as a **hidden** Commander option (legacy scripts); **ignored** with one stderr **`[deprecated]`** line (**SRS-60**). | **SRS-32** full **Factory** loop: synthesis convergence (until no missing artefacts), coverage, zero-ref, report, **link mapping**, index assembly; **Phase 7** backend sync is skipped in CLI (**`skipBackendSync`**). **On success:** always promotes **`.gluecharm/context`** from the analysis worktree into **`<repoRoot>`** unless **`--no-promote`** or the checkout is already the repo root (stderr **`[pipeline:analysis]`**); **`easyspecs.analysis.promoteContextToWorkspace`** does **not** apply to this step. Push context with **`upload context`** / **`upload republish`** after analysis if you need cloud sync. Factory timing from `**merged.factory`** + `**--ci**` defaults. Debug: `**easyspecs.factory.debug**`. OpenCode options from `**merged.pipelineOpenCode**`. **SRS-46:** if `**easyspecs.factory.cloudContextAnalyzed`** is `**true**` and `**--force-new-context-analysis**` is absent, exits **0** without running the Factory (`**analysisSkipped**`, …). **SRS-59:** stale worktree registration recovery — see **§ Analysis git checkout** below. |
182
+ | `update context` | Optional `**--no-worktree**` / `**--noworktree**` (**SRS-71**). **SRS-60** removed `**--upload**`. | **SRS-55:** incremental context refresh — baseline → git delta → analysis checkout → `**changes-since-date.md`** → optional remediation → **`--promote` / `--no-promote**` (global) → persist `**lastRunAt**`. With **`--no-worktree`**, the checkout is **`<repoRoot>`** (no temp worktree; seed/promote steps that would copy repo → same repo are skipped). Run **`upload context`** separately if you need cloud sync. |
183
183
  | `diagnose reference-coverage` | `**--root workspace**` | `**--root worktree**`, optional `**--worktree <path>**` | Gate when `**easyspecs.diagnose.zeroReference.maxPercentNonReferenced**` is a finite number (not `**null**`): failure when metric exceeds it. |
184
184
  | `diagnose coordination-duplicates` | Same `**--root**` / `**--worktree**` | `**easyspecs.diagnose.coordinationDuplicates.strict**`: when `**true**` (default), duplicate/orphan issues fail the exit code. |
185
185
  | `diagnose coverage-report` | Same `**--root**` / `**--worktree**` | Uses repo/worktree paths only; no extra env in `main.ts`. |
186
186
  | `diagnose missing-artefacts` | Same `**--root**` / `**--worktree**` | Reads artefact snapshot from workspace state; no OpenCode. |
187
187
  | `diagnose zero-reference` | Optional `**--worktree <path>**` (no `--root` branch in this handler) | `**requireOpenCode**`; `**merged.pipelineOpenCode**` for pool concurrency/argv/timeout. Checkout from `**--worktree**` or snapshot (`[resolveAdHocCheckoutRoot](../../src/cli/main.ts)`). On full success, runs **SRS-51** markdown link graph on `**<checkout>/.gluecharm/context`** before exit (**non-zero** if link validation fails). |
188
- | `context link-graph` | `**--root workspace`** | `**--root worktree**`, optional `**--worktree <path>**` | **SRS-51:** deterministic navigation sections in context markdown under `**<root>/.gluecharm/context`**. No OpenCode. `**--json**`: `**ok**`, `**contextDir**`, `**error**`, `**brokenLinks**`. Exit `**validation**` on broken relative links inside EasySpecs nav regions. |
189
- | `context drift <referencePath>` | `**--label <slug>**`, `**--index <path>**`, `**--dry-run**`. Optional `**--root**` / `**--worktree**` tail tokens are accepted and ignored for v1 routing. | **SRS-56:** analysis worktree → OpenCode drift agent → `**.gluecharm/context/drift/drift-<slug>-<date>.md`** + reference index patch → global `**--promote` / `--no-promote**`. Success stdout: drift report path. |
188
+ | `context link-graph` | `**--root workspace`** | `**--root worktree**`, optional `**--worktree <path>**` | **SRS-51:** deterministic navigation sections in context markdown under `**<root>/.gluecharm/context`**. No OpenCode. `**--json**`: `**ok**`, `**contextDir**`, `**error**`, `**brokenLinks**`. Exit **78** on broken relative links inside EasySpecs nav regions (**SRS-70**). |
189
+ | `context drift <referencePath>` | `**--label <slug>**`, `**--index <path>**`, `**--dry-run**`, `**--no-worktree**` / `**--noworktree**` (**SRS-71**; mutually exclusive with **`--root worktree`** / **`--worktree <path>`**). Optional `**--root**` / `**--worktree**` tail tokens are accepted for other routing. | **SRS-56:** analysis checkout → OpenCode drift agent → `**.gluecharm/context/drift/drift-<slug>-<date>.md`** + reference index patch → global `**--promote` / `--no-promote**`. Success stdout: drift report path. With **`--no-worktree`**, the checkout is **`<repoRoot>`** (no temp worktree). **`--json`** may include **`analysisInPlace: true`** when that mode ran. |
190
190
  | `download context` | Optional `**--force**`, `**--replace-from-cloud**` | **SRS-49:** requires `**auth`** session. `**GET /api/content/application/:id**` → `**srs_discovery**` ids → `**POST /api/batch/content/srs_discovery/get**` → writes files under `**<repoRoot>/.gluecharm/context**`. `**--force**` overwrites existing paths; `**--replace-from-cloud**` deletes local context files first (preserves root `**easyspecs-upload-target.json**`). `**--json**` stdout: `**downloaded**`, `**skipped**`, `**failed**`, `**localRemoved**`. Exit `**upload**` when any row fails. |
191
191
  | `upload context` | — | Requires `**auth**` session. Context dir: `**<repoRoot>/.gluecharm/context**`. Project id: `**easyspecs.easyspecsProjectId**` in `**config.json**` only. **SRS-46:** on full success, optional cloud status GET (see `**fetchContextAnalyzedInCloud`**); `**--json**` may add `**contextAnalyzedInCloud**` / `**contextAnalyzedInCloudAt**`; updates `**easyspecs.factory.cloudContext***` when fetch is enabled (legacy `**easyspecs.analysis.cloudContext***`). |
192
192
  | `upload republish` | — | Same auth + upload pipeline; context dir from `**easyspecs.upload.contextDirectory**` if non-empty and valid, else analysis worktree `**…/.gluecharm/context**` from snapshot, else error. Same project id rule as `**upload context**`. Same **SRS-46** JSON + cache behaviour as `**upload context`**. |
@@ -197,7 +197,7 @@ Each row lists **command-specific CLI tokens**, then **what configuration applie
197
197
 
198
198
  ### Analysis git checkout (**SRS-59**)
199
199
 
200
- The Factory creates a **detached** analysis checkout under `**$TMPDIR/easyspecs-analysis/easyspecs-NNN`** (`[worktreeManager.ts](../../src/analysis/worktreeManager.ts)`). If the OS removes that folder (or it is deleted) **without** `**git worktree remove`**, Git may still list the path and `**git worktree add**` fails with *missing but already registered worktree*. **SRS-59:** `**easyspecs-cli*`* detects that failure class, runs `**git worktree prune**` with `**cwd**` = the repository root (from `**--cwd**` / current directory), then retries `**git worktree add**` **once** at the same allocated path (`[gitWorktreeStaleRecovery.ts](../../src/analysis/gitWorktreeStaleRecovery.ts)`). Stderr may include `**[worktree] git worktree prune — cleared stale registration for <folder> (<absolute path>)`** before the retry. Manual troubleshooting: `[.gluecharm/docs/srs/USER-MANUAL-SRS-59.md](../../.gluecharm/docs/srs/USER-MANUAL-SRS-59.md)`.
200
+ The Factory normally creates a **detached** analysis checkout under `**$TMPDIR/easyspecs-analysis/easyspecs-NNN`** (`[worktreeManager.ts](../../src/analysis/worktreeManager.ts)`). **`--no-worktree`** / **`--noworktree`** on **`analysis`**, **`update context`**, or **`context drift`** skips that step and uses **`<repoRoot>`** (resolved **`--cwd`**) as the checkout instead (**SRS-71**). If the OS removes that folder (or it is deleted) **without** `**git worktree remove`**, Git may still list the path and `**git worktree add**` fails with *missing but already registered worktree*. **SRS-59:** `**easyspecs-cli*`* detects that failure class, runs `**git worktree prune**` with `**cwd**` = the repository root (from `**--cwd**` / current directory), then retries `**git worktree add**` **once** at the same allocated path (`[gitWorktreeStaleRecovery.ts](../../src/analysis/gitWorktreeStaleRecovery.ts)`). Stderr may include `**[worktree] git worktree prune — cleared stale registration for <folder> (<absolute path>)`** before the retry. Manual troubleshooting: `[.gluecharm/docs/srs/USER-MANUAL-SRS-59.md](../../.gluecharm/docs/srs/USER-MANUAL-SRS-59.md)`.
201
201
 
202
202
  ---
203
203
 
@@ -207,5 +207,5 @@ The Factory creates a **detached** analysis checkout under `**$TMPDIR/easyspecs-
207
207
  - `**download context**` / `**upload context**` / `**upload republish**` require a prior `**auth login**` session (`**--email**` / `**--password**`, or `**--ci**` with `**easyspecs.auth.ciLogin**` in `**config.json**`).
208
208
  - Unknown commands print help and exit with a usage error.
209
209
  - Git subprocesses may set `**GIT_TERMINAL_PROMPT=0**` on the child environment (`[runCoveragePipeline](../../src/pipelines/coverage/coveragePipeline.ts)`).
210
- - Any command path that **creates** the analysis git worktree (`**analysis`**, `**run synthesis**`, `**update context**`, `**context drift**` without `**--dry-run**`, etc.) benefits from **SRS-59** stale-registration recovery in `**createAnalysisWorktree`**, not only `**analysis**`.
210
+ - Any command path that **creates** the analysis git worktree (`**analysis`**, **`run synthesis**`, **`update context**`, **`context drift**` without `**--dry-run**` or **`--no-worktree**`, etc.) benefits from **SRS-59** stale-registration recovery in `**createAnalysisWorktree`**, not only `**analysis**`.
211
211