@dotdotgod/cli 0.1.35 → 0.1.40

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
@@ -2,41 +2,45 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@dotdotgod/cli.svg)](https://www.npmjs.com/package/@dotdotgod/cli) [![GitHub](https://img.shields.io/badge/GitHub-dotdotgod%2Fdotdotgod--kit-181717?logo=github)](https://github.com/dotdotgod/dotdotgod-kit/tree/main/packages/cli) [![License: Elastic 2.0](https://img.shields.io/badge/License-Elastic%202.0-blue.svg)](../../LICENSE)
4
4
 
5
- > **Change a file, know what else must be checked.**
5
+ Command-line tools for dotdotgod project memory.
6
+
7
+ Use this package when you want to initialize a docs-first project scaffold, validate project-memory docs, build a local graph/cache, load bounded context snapshots, expand project references, or ask what should be checked after a file changes.
8
+
9
+ ## Start Here
10
+
11
+ Run one command without installing globally:
6
12
 
7
13
  ```bash
8
- $ dotdotgod graph impact . --changed packages/cli/src/core.mjs --compact
14
+ npx @dotdotgod/cli validate .
9
15
  ```
10
16
 
11
- ```text
12
- docs:
13
- - docs/spec/REFERENCE_EXPANSION.md (91; incoming:implemented_by, semantic_similarity)
14
- - docs/test/REFERENCE_EXPANSION.md (65.3; verified_by, semantic_similarity)
15
- - docs/spec/LOAD_PROJECT.md (35.8; related_doc, semantic_similarity)
16
-
17
- tests:
18
- - packages/cli/test/core.test.mjs (78.6; semantic_similarity, incoming:semantic_similarity, verified_by)
19
- - packages/cli/test/e2e.test.mjs (51.4; verified_by)
17
+ Install only if you want a persistent `dotdotgod` command:
20
18
 
21
- files:
22
- - packages/cli/src/core.mjs (100; changed-file)
23
- - packages/pi/extensions/plan-mode/index.ts (45; implemented_by, semantic_similarity)
19
+ ```bash
20
+ npm install -g @dotdotgod/cli
24
21
  ```
25
22
 
26
- `graph impact` ranks the specs, tests, architecture notes, config docs, and source files most likely to matter for a change. `--compact` keeps a short text summary, `--yml`/`--yaml` returns a compact structured agent-facing summary, and `--json` returns machine-readable detail. It uses the project-memory graph built from Markdown links, README routes, headings, traceability blocks, package metadata, memory areas, and deterministic routing hints.
23
+ Common first commands:
27
24
 
28
- Command-line tools for dotdotgod project memory. The CLI turns explicit, maintained project links into a local graph/cache: README routes, Markdown links, traceability blocks, memory areas, package metadata, commands, tests, and deterministic routing hints. That maintained graph powers `graph impact`, while the initialized docs surface keeps agent load context high signal.
25
+ ```bash
26
+ dotdotgod init .
27
+ dotdotgod validate .
28
+ dotdotgod load-snapshot .
29
+ dotdotgod graph impact . --changed <path> --compact
30
+ ```
29
31
 
30
- ## Why Use It?
32
+ ## What It Does
31
33
 
32
- - Initialize `AGENTS.md`, thin agent entrypoints, docs indexes, active-plan space, archive map, and local cache ignores with `dotdotgod init`.
33
- - Replace ad-hoc docs checks with `dotdotgod validate`.
34
- - Keep generated Markdown traceability links synchronized with `dotdotgod traceability links`.
35
- - Build `.dotdotgod/` as a local ignored cache of file fingerprints and compact graph shards derived from maintained project links.
36
- - Use `load-snapshot` as a bounded first-pass map for high-quality agent loading.
37
- - Resolve explicit `[[...]]` references or high-signal fuzzy references before broad text search.
38
- - Query safe review scope for a changed file with grouped, bounded impact reports.
39
- - Inspect or initialize project config with `dotdotgod config` and `dotdotgod config init`.
34
+ - `init` creates `AGENTS.md`, thin agent entrypoints, docs indexes, active-plan space, archive map, and local cache ignores.
35
+ - `validate` checks the dotdotgod docs/project-memory structure, local links, traceability blocks, config validity, and optional index freshness.
36
+ - `index` builds `.dotdotgod/manifest.json` and compact graph shards from maintained project files.
37
+ - `load-snapshot` returns a bounded first-pass project map for AI agents.
38
+ - `resolve` and `expand` map explicit or high-signal prompt references to project files.
39
+ - `graph impact` ranks likely related specs, tests, docs, commands, and source files for a changed path.
40
+ - `traceability links` checks or repairs generated Markdown traceability-link sections.
41
+ - `plan validate` validates active plan artifacts and simplified Plan Generator checkpoints before execution.
42
+ - `plan stage create` creates an internal `.dotdotgod-plan/NN_STAGE_NAME.md` checkpoint for a simplified Plan Generator stage.
43
+ - `trello sync` plans or writes Trello linked-doc metadata from configured docs paths.
40
44
 
41
45
  ## Commands
42
46
 
@@ -56,60 +60,83 @@ dotdotgod expand . "Update [[PLAN_MODE]] and [[HOOKS]]"
56
60
  dotdotgod expand . "PLAN_MODE 수정하자" --fuzzy
57
61
  dotdotgod traceability links . --check
58
62
  dotdotgod traceability links . --write
63
+ dotdotgod plan validate docs/plan/<task-slug>/README.md
64
+ dotdotgod plan validate docs/plan/<task-slug>/README.md --stage 04
65
+ dotdotgod plan stage create 02 docs/plan/<task-slug>/README.md
59
66
  dotdotgod graph impact . --changed <path>
60
67
  dotdotgod graph impact . --changed <path> --compact
61
68
  dotdotgod graph impact . --changed <path> --yml
62
69
  dotdotgod graph communities .
63
70
  ```
64
71
 
65
- `--help`, `-h`, and `help` print usage to stdout. Command-specific help is available with `dotdotgod <command> --help`, including nested commands such as `dotdotgod graph impact --help`, `dotdotgod config init --help`, and `dotdotgod traceability links --help`.
72
+ `--help`, `-h`, and `help` print usage to stdout. Command-specific help is available with `dotdotgod <command> --help`, including nested commands such as `dotdotgod graph impact --help`, `dotdotgod config init --help`, `dotdotgod plan stage create --help`, and `dotdotgod traceability links --help`.
66
73
 
67
- ## Validation and Verification Boundaries
74
+ ## Which Command Should I Use?
68
75
 
69
- | Command | Responsibility |
76
+ | Need | Command |
70
77
  | --- | --- |
71
- | `dotdotgod validate <root>` | Checks dotdotgod docs/project-memory structure, local links, traceability blocks, generated traceability-link drift, config validity, and optional index freshness. |
72
- | `dotdotgod traceability links <root> --check` | Runs only the generated traceability-link and compact JSON drift check. |
73
- | `dotdotgod traceability links <root> --write` | Repairs generated traceability-link sections and rewrites canonical `json dotdotgod` blocks as compact JSON. |
74
- | `pnpm run verify` | Runs the repository-level quality gate: generated-resource checks, package verify contracts, tests, typecheck, and docs validation where each package defines it. |
78
+ | Add the dotdotgod scaffold to a repository | `dotdotgod init .` |
79
+ | Check docs, links, config, traceability, and optional index freshness | `dotdotgod validate . --check-index` |
80
+ | Refresh the local graph/cache | `dotdotgod index .` |
81
+ | Give an agent a bounded project map | `dotdotgod load-snapshot .` |
82
+ | Resolve `[[...]]` references from a prompt | `dotdotgod expand . "Update [[PLAN_MODE]]"` |
83
+ | Repair generated traceability-link sections | `dotdotgod traceability links . --write` |
84
+ | Validate an active plan before execution | `dotdotgod plan validate docs/plan/<task>/README.md` |
85
+ | Create an internal Plan Generator stage checkpoint | `dotdotgod plan stage create 03 docs/plan/<task>/README.md` |
86
+ | See what else to inspect after a change | `dotdotgod graph impact . --changed <path> --compact` |
87
+ | Preview Trello linked-doc updates | `dotdotgod trello sync . --dry-run` |
88
+
89
+ ## Changed-File Impact
75
90
 
76
- Most users start with `validate`. Use `traceability links --write` only when generated traceability output needs repair, and use `verify` before release-style handoff.
91
+ ```bash
92
+ $ dotdotgod graph impact . --changed packages/cli/src/core.mjs --compact
93
+ ```
77
94
 
78
- ## Graph, Cache, and Impact
95
+ ```text
96
+ docs:
97
+ - docs/spec/REFERENCE_EXPANSION.md (91; incoming:implemented_by, semantic_similarity)
98
+ - docs/test/REFERENCE_EXPANSION.md (65.3; verified_by, semantic_similarity)
79
99
 
80
- The cache uses `.dotdotgod/manifest.json` plus graph shards under `.dotdotgod/graph/`. `status` is read-only. `load-snapshot`, `resolve`, `expand`, and `graph` commands lazily refresh missing or stale cache data before returning agent-facing output.
100
+ files:
101
+ - packages/cli/src/core.mjs (100; changed-file)
102
+ - packages/pi/extensions/plan-mode/index.ts (45; implemented_by, semantic_similarity)
103
+ ```
81
104
 
82
- `graph impact` requires `--changed <path>` so ranking has a seed file. Raw JSON is useful for diagnostics; `--compact` returns a smaller text summary; `--yml`/`--yaml` returns structured compact groups for agents. Related nodes include scores, reasons, and retrieval metadata, and output stays bounded with omitted counts.
105
+ `graph impact` needs `--changed <path>` so ranking has a seed file. Use `--compact` for short text, `--yml` or `--yaml` for compact structured agent-facing output, and `--json` for machine-readable detail.
83
106
 
84
- `graph communities` runs Leiden community detection through `leiden-ts` with a deterministic fallback for tiny or invalid graphs.
107
+ The graph is built from maintained project files: Markdown links, README routes, headings, traceability blocks, package metadata, memory areas, imports, exports, commands, tests, and deterministic routing hints.
85
108
 
86
- ## Reference Expansion
109
+ ## Validation and Verification Boundaries
87
110
 
88
- `resolve` maps one project-memory reference such as `PLAN_MODE` or `docs/spec/PLAN_MODE.md` to ranked graph candidates. `expand` scans prompt text for `[[refs]]`, resolves each target, and can include compact impact context with `--with-impact`.
111
+ | Command | Responsibility |
112
+ | --- | --- |
113
+ | `dotdotgod validate <root>` | Checks dotdotgod docs/project-memory structure, local links, traceability blocks, generated traceability-link drift, config validity, and optional index freshness. |
114
+ | `dotdotgod traceability links <root> --check` | Runs only the generated traceability-link and compact JSON drift check. |
115
+ | `dotdotgod traceability links <root> --write` | Repairs generated traceability-link sections and rewrites canonical `json dotdotgod` blocks as compact JSON. |
116
+ | `dotdotgod plan validate <plan-readme>` | Checks active-plan structure, required Markdown sections, decision/assumption blockers, atomic-task verification, and simplified Plan Generator checkpoints when present. |
117
+ | `pnpm run verify` | Runs this repository's quality gate: generated-resource checks, package verify contracts, tests, typecheck, and docs validation where each package defines it. |
89
118
 
90
- Use `expand --fuzzy` for high-signal natural prompt references such as uppercase identifiers, path-like mentions, quoted phrases, and strong indexed aliases. Fuzzy low-signal terms use built-in defaults and can be adjusted in `dotdotgod.config.json` with `referenceExpansion.fuzzy.lowSignal.add` and `remove`. Archive bodies are excluded by default unless `--include-archive` is passed.
119
+ Most users start with `validate`. Use `traceability links --write` only when generated traceability output needs repair, and use `verify` before release-style handoff in this repository.
91
120
 
92
121
  ## Memory, Specs, and Config
93
122
 
94
- The default docs scaffold gives files explicit project-memory meaning:
95
-
96
- - `docs/spec/**`: stable shared/fresh product truth and, by default, the traceability-enforced behavior-spec path.
97
- - `docs/arch/**`: stable shared/fresh architecture rationale.
98
- - `docs/test/**`: stable shared/fresh verification knowledge.
99
- - `docs/plan/**`: local fresh active-task intent.
100
- - `docs/archive/README.md`: local stale archive map included by default.
101
- - `docs/archive/**`: local stale archive bodies excluded by default.
123
+ The default scaffold gives docs explicit roles:
102
124
 
103
- Those roles are configurable but separate. Use `memory.areas` to customize memory classification and retrieval priority. Use `traceability.required` / `traceability.exclude` to customize which markdown paths must end with `json dotdotgod` traceability blocks. Use `validation.markdown`, `impactRanking`, and `referenceExpansion` to tune size budgets, impact scoring, and fuzzy prompt matching.
125
+ - `docs/spec/**`: product behavior and requirements. This path is traceability-enforced by default.
126
+ - `docs/arch/**`: architecture rationale, boundaries, conventions, and decisions.
127
+ - `docs/test/**`: verification strategy, regression coverage, fixtures, and commands.
128
+ - `docs/plan/**`: local active-task intent.
129
+ - `docs/archive/README.md`: local archive map included by default.
130
+ - `docs/archive/**`: local archive bodies excluded by default unless targeted.
104
131
 
105
- See the [root README](../../README.md), [GitHub repository](https://github.com/dotdotgod/dotdotgod-kit), [`docs/concept/CONTEXT_CURATION.md`](../../docs/concept/CONTEXT_CURATION.md), [`docs/concept/CONTEXT_MECHANICS.md`](../../docs/concept/CONTEXT_MECHANICS.md), [`docs/spec/MEMORY_AREA_CONFIG.md`](../../docs/spec/MEMORY_AREA_CONFIG.md), and [`docs/spec/TRACEABILITY_CONFIG.md`](../../docs/spec/TRACEABILITY_CONFIG.md) for the deeper model.
132
+ Use `memory.areas` to customize memory classification and retrieval priority. Use `traceability.required` and `traceability.exclude` to customize which Markdown paths need `json dotdotgod` traceability blocks. Use `validation.markdown`, `impactRanking`, and `referenceExpansion` to tune size budgets, impact scoring, and fuzzy prompt matching.
106
133
 
107
134
  ## Indexing Scope
108
135
 
109
- `dotdotgod index` is gitignore-aware by default. It uses `git ls-files --cached --others --exclude-standard` when possible, then filters to supported text, source, script, config, web, and infrastructure files. In non-git contexts it falls back to a conservative directory walk.
136
+ `dotdotgod index` is gitignore-aware by default. It uses `git ls-files --cached --others --exclude-standard` when possible, then filters to supported text, source, script, config, web, and infrastructure files.
110
137
 
111
138
  Default exclusions include dependency, generated, cache, and secret-like paths such as `.git/`, `.dotdotgod/`, `node_modules/`, `dist/`, `build/`, `coverage/`, `.next/`, `target/`, `vendor/`, `.venv/`, and `.env`. Example env templates such as `.env.example` remain indexable.
112
139
 
113
- ## Compared with Graphify-Style Reports
140
+ ## Learn More
114
141
 
115
- The CLI is not designed to make agents read a giant graph report. The full graph stays local; agent-facing output is bounded. The strength is explicit project-maintained links before extraction: docs areas, README indexes, traceability blocks, package metadata, commands, tests, and memory policy tell agents which files are behavior truth, architecture rationale, verification, current intent, or historical memory before they read source.
142
+ See the [root README](../../README.md), [GitHub repository](https://github.com/dotdotgod/dotdotgod-kit), [Context curation](../../docs/concept/CONTEXT_CURATION.md), [Context mechanics](../../docs/concept/CONTEXT_MECHANICS.md), [Memory area config](../../docs/spec/MEMORY_AREA_CONFIG.md), and [Traceability config](../../docs/spec/TRACEABILITY_CONFIG.md).
package/bin/dotdotgod.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
2
  import { runCli } from '../src/core.mjs';
3
3
 
4
- runCli();
4
+ await runCli();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotdotgod/cli",
3
- "version": "0.1.35",
3
+ "version": "0.1.40",
4
4
  "description": "CLI for dotdotgod validation, project memory snapshots, and graph indexing.",
5
5
  "type": "module",
6
6
  "license": "Elastic-2.0",
package/src/cli/usage.mjs CHANGED
@@ -34,12 +34,43 @@ Create dotdotgod.config.json with the built-in default memory, traceability, val
34
34
  case 'load-snapshot':
35
35
  return `Usage:
36
36
  dotdotgod load-snapshot <root> [--json]`;
37
+ case 'plan':
38
+ return `Usage:
39
+ dotdotgod plan validate docs/plan/<task-slug>/README.md [--stage stage] [--json]
40
+ dotdotgod plan stage create <stage> [docs/plan/<task-slug>/README.md] [--json]`;
41
+ case 'plan validate':
42
+ return `Usage:
43
+ dotdotgod plan validate docs/plan/<task-slug>/README.md [--stage stage] [--json]
44
+
45
+ Validates an active plan artifact before execution. Supports simplified Plan Generator stages and optional .dotdotgod-plan/NN_STAGE_NAME.md workspaces. Use --stage with a stage name or numeric prefix such as 04 or 05 to validate only that stage.`;
46
+ case 'plan stage':
47
+ return `Usage:
48
+ dotdotgod plan stage create <stage> [docs/plan/<task-slug>/README.md] [--json]`;
49
+ case 'plan stage create':
50
+ return `Usage:
51
+ dotdotgod plan stage create <stage> [docs/plan/<task-slug>/README.md] [--json]
52
+
53
+ Creates the matching .dotdotgod-plan/NN_STAGE_NAME.md internal stage checkpoint for a simplified Plan Generator stage. <stage> accepts a numeric prefix such as 02 or a canonical stage name such as 02-context-load. If the plan path is omitted, exactly one active docs/plan/<task-slug>/README.md candidate must exist.`;
37
54
  case 'resolve':
38
55
  return `Usage:
39
56
  dotdotgod resolve <root> <ref> [--max-results n] [--include-archive] [--json]`;
40
57
  case 'expand':
41
58
  return `Usage:
42
59
  dotdotgod expand <root> <prompt> [--max-results n] [--include-archive] [--with-impact] [--fuzzy] [--json]`;
60
+ case 'trello':
61
+ return `Usage:
62
+ dotdotgod trello sync <root> [--dry-run]`;
63
+ case 'trello sync':
64
+ return `Usage:
65
+ dotdotgod trello sync <root> [--dry-run]
66
+
67
+ Options:
68
+ --dry-run Preview planned Trello updates without calling Trello APIs.
69
+
70
+ Write mode:
71
+ Omit --dry-run only in the trusted GitHub Actions default-branch push workflow.
72
+ Requires TRELLO_API_KEY and TRELLO_TOKEN in the trusted workflow environment.
73
+ Local/manual and pull request usage should run --dry-run.`;
43
74
  case 'traceability':
44
75
  return `Usage:
45
76
  dotdotgod traceability links <root> [--check|--write] [--json]`;
@@ -75,6 +106,9 @@ Ranks nodes related to a changed file. <root> is the project root; --changed is
75
106
  dotdotgod resolve <root> <ref> [--max-results n] [--include-archive] [--json]
76
107
  dotdotgod expand <root> <prompt> [--max-results n] [--include-archive] [--with-impact] [--fuzzy] [--json]
77
108
  dotdotgod traceability links <root> [--check|--write] [--json]
109
+ dotdotgod plan validate docs/plan/<task-slug>/README.md [--stage stage] [--json]
110
+ dotdotgod plan stage create <stage> [docs/plan/<task-slug>/README.md] [--json]
111
+ dotdotgod trello sync <root> [--dry-run]
78
112
  dotdotgod graph impact <root> --changed <path> [--compact|--json|--yml|--yaml]
79
113
  dotdotgod graph communities <root> [--json]`;
80
114
  }
@@ -120,7 +154,11 @@ export function printVersion() {
120
154
  export function helpCommandFromArgs(args) {
121
155
  const nonHelp = args.filter((arg) => !isHelpToken(arg));
122
156
  if (nonHelp[0] === 'graph' && nonHelp[1]) return `graph ${nonHelp[1]}`;
157
+ if (nonHelp[0] === 'trello' && nonHelp[1]) return `trello ${nonHelp[1]}`;
123
158
  if (nonHelp[0] === 'traceability' && nonHelp[1]) return `traceability ${nonHelp[1]}`;
159
+ if (nonHelp[0] === 'plan' && nonHelp[1] === 'stage' && nonHelp[2] === 'create') return 'plan stage create';
160
+ if (nonHelp[0] === 'plan' && nonHelp[1] === 'stage') return 'plan stage';
161
+ if (nonHelp[0] === 'plan' && nonHelp[1]) return `plan ${nonHelp[1]}`;
124
162
  if (nonHelp[0] === 'config' && nonHelp[1] === 'init') return 'config init';
125
163
  return nonHelp[0] ?? 'root';
126
164
  }
@@ -0,0 +1,85 @@
1
+ import { existsSync, statSync, writeFileSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import { usage } from '../cli/usage.mjs';
4
+ import { defaultDotdotgodConfigText, memoryConfigSummary, readMemoryConfig } from '../memory/config.mjs';
5
+
6
+ function parseConfigOptions(argv, allowForce = false, usageKey = 'config') {
7
+ const options = { root: '.', json: false, force: false };
8
+ let rootSet = false;
9
+ for (let i = 0; i < argv.length; i += 1) {
10
+ const arg = argv[i];
11
+ if (arg === '--json') options.json = true;
12
+ else if (allowForce && arg === '--force') options.force = true;
13
+ else if (!arg.startsWith('-') && !rootSet) {
14
+ options.root = arg;
15
+ rootSet = true;
16
+ } else if (!arg.startsWith('-')) usage(`Unexpected argument: ${arg}`, usageKey);
17
+ else usage(`Unknown option: ${arg}`, usageKey);
18
+ }
19
+ options.root = resolve(options.root);
20
+ return options;
21
+ }
22
+
23
+ function configSourcePath(root, source) {
24
+ return source && source !== 'default' ? join(root, source) : null;
25
+ }
26
+
27
+ function configInitError(options, code, message, path = null) {
28
+ const payload = { ok: false, command: 'config init', root: options.root, path, created: false, overwritten: false, error: { code, message } };
29
+ if (options.json) {
30
+ console.log(JSON.stringify(payload, null, 2));
31
+ process.exit(2);
32
+ }
33
+ console.error(message);
34
+ process.exit(2);
35
+ }
36
+
37
+ function formatConfigOutput(payload) {
38
+ const errors = payload.errors ?? [];
39
+ const lines = [`dotdotgod config: ${payload.source}${errors.length > 0 ? ' (invalid; using defaults)' : ''}`];
40
+ lines.push(`- path: ${payload.path ?? 'none'}`);
41
+ lines.push(`- memory areas: ${payload.config.areas.length}`);
42
+ lines.push(`- traceability required: ${(payload.config.traceability.required ?? []).join(', ') || 'none'}`);
43
+ lines.push(`- traceability exclude: ${(payload.config.traceability.exclude ?? []).join(', ') || 'none'}`);
44
+ lines.push(`- validation markdown: maxLines=${payload.config.validation.markdown.maxLines}, maxChars=${payload.config.validation.markdown.maxChars}`);
45
+ lines.push(`- validation markdown exclude: ${(payload.config.validation.markdown.exclude ?? []).join(', ') || 'none'}`);
46
+ lines.push(`- impact ranking preset: ${payload.config.impactRanking.preset}`);
47
+ lines.push(`- trello sync paths: ${(payload.config.integrations?.trello?.syncPaths ?? []).join(', ') || 'none'}`);
48
+ const lowSignal = payload.config.referenceExpansion?.fuzzy?.lowSignal ?? { terms: [], add: [], remove: [] };
49
+ lines.push(`- fuzzy low-signal terms: ${(lowSignal.terms ?? []).join(', ') || 'none'} (add: ${(lowSignal.add ?? []).join(', ') || 'none'}; remove: ${(lowSignal.remove ?? []).join(', ') || 'none'})`);
50
+ if (errors.length > 0) {
51
+ lines.push('- errors:');
52
+ for (const error of errors) lines.push(` - ${error.code} ${error.file}: ${error.message}`);
53
+ }
54
+ return lines.join('\n');
55
+ }
56
+
57
+ export function runConfig(argv) {
58
+ const isInit = argv[0] === 'init';
59
+ const options = parseConfigOptions(isInit ? argv.slice(1) : argv, isInit, isInit ? 'config init' : 'config');
60
+ if (isInit) {
61
+ if (!existsSync(options.root)) configInitError(options, 'ROOT_NOT_FOUND', `Project root not found: ${options.root}`);
62
+ try {
63
+ if (!statSync(options.root).isDirectory()) configInitError(options, 'ROOT_NOT_DIRECTORY', `Project root is not a directory: ${options.root}`);
64
+ } catch {
65
+ configInitError(options, 'ROOT_NOT_FOUND', `Project root not found: ${options.root}`);
66
+ }
67
+ const target = join(options.root, 'dotdotgod.config.json');
68
+ const rcPath = join(options.root, '.dotdotgodrc.json');
69
+ if (existsSync(rcPath)) configInitError(options, 'CONFIG_RC_EXISTS', `.dotdotgodrc.json already exists; remove or migrate it before initializing dotdotgod.config.json.`, rcPath);
70
+ const existed = existsSync(target);
71
+ if (existed && !options.force) configInitError(options, 'CONFIG_EXISTS', `dotdotgod.config.json already exists. Re-run with --force to overwrite it.`, target);
72
+ writeFileSync(target, defaultDotdotgodConfigText());
73
+ const payload = { ok: true, command: 'config init', root: options.root, path: target, created: !existed, overwritten: existed };
74
+ if (options.json) console.log(JSON.stringify(payload, null, 2));
75
+ else console.log(`dotdotgod config init: ${existed ? 'overwrote' : 'created'} ${target}`);
76
+ return;
77
+ }
78
+
79
+ const config = readMemoryConfig(options.root);
80
+ const errors = config.errors ?? [];
81
+ const payload = { ok: errors.length === 0, command: 'config', root: options.root, source: config.source ?? 'default', path: configSourcePath(options.root, config.source), config: memoryConfigSummary(config), errors };
82
+ if (options.json) console.log(JSON.stringify(payload, null, 2));
83
+ else console.log(formatConfigOutput(payload));
84
+ if (errors.length > 0) process.exit(1);
85
+ }
@@ -0,0 +1,66 @@
1
+ import { commandUsage, parseCommon, usage } from '../cli/usage.mjs';
2
+ import { buildCommunities } from '../graph/communities.mjs';
3
+ import { graphSummary, readFreshIndex } from '../index/cache.mjs';
4
+ import { buildCompactImpactReport, buildImpactReport } from '../impact/report.mjs';
5
+ import { formatCompactImpactOutput, formatYmlGraphImpactError, formatYmlImpactOutput } from '../impact/format.mjs';
6
+
7
+ export function parseGraphOptions(argv) {
8
+ const filtered = [];
9
+ let changed;
10
+ let compact = false;
11
+ let yml = false;
12
+ for (let i = 0; i < argv.length; i += 1) {
13
+ if (argv[i] === '--changed') {
14
+ const next = argv[i + 1];
15
+ if (next && !next.startsWith('-')) {
16
+ changed = next;
17
+ i += 1;
18
+ }
19
+ } else if (argv[i] === '--compact') compact = true;
20
+ else if (argv[i] === '--yml' || argv[i] === '--yaml') yml = true;
21
+ else filtered.push(argv[i]);
22
+ }
23
+ const options = parseCommon(filtered);
24
+ options.changed = changed;
25
+ options.compact = compact;
26
+ options.yml = yml;
27
+ return options;
28
+ }
29
+
30
+ export function runGraph(argv) {
31
+ const sub = argv[0];
32
+ const isImpact = sub === 'impact';
33
+ if (!['impact', 'communities'].includes(sub)) usage(sub ? `Unknown graph command: ${sub}` : 'Missing graph command.', 'graph');
34
+ const options = parseGraphOptions(argv.slice(1));
35
+ if (isImpact && [options.json, options.compact, options.yml].filter(Boolean).length > 1) {
36
+ const message = 'Choose only one graph impact output mode: --compact, --json, or --yml/--yaml.';
37
+ if (options.json) console.log(JSON.stringify({ ok: false, command: 'graph impact', compact: options.compact || undefined, yml: options.yml || undefined, root: options.root, error: { code: 'OUTPUT_MODE_CONFLICT', message }, usage: commandUsage('graph impact') }, null, 2));
38
+ else if (options.yml) console.log(formatYmlGraphImpactError(options, message, 'OUTPUT_MODE_CONFLICT'));
39
+ else usage(message, 'graph impact');
40
+ process.exit(2);
41
+ }
42
+ if (isImpact && !options.changed) {
43
+ const message = 'Missing required option: --changed <path>. Run `dotdotgod graph impact <root> --changed <path>`.';
44
+ if (options.json) {
45
+ console.log(JSON.stringify({ ok: false, command: 'graph impact', compact: options.compact || undefined, root: options.root, error: { code: 'MISSING_CHANGED', message }, usage: commandUsage('graph impact') }, null, 2));
46
+ process.exit(2);
47
+ }
48
+ if (options.yml) {
49
+ console.log(formatYmlGraphImpactError(options, message, 'MISSING_CHANGED'));
50
+ process.exit(2);
51
+ }
52
+ usage(message, 'graph impact');
53
+ }
54
+ const { status, index, metadata } = readFreshIndex(options.root);
55
+ const rawImpact = isImpact ? buildImpactReport(index, options.changed) : undefined;
56
+ const impact = isImpact && (options.compact || options.yml) ? buildCompactImpactReport(rawImpact) : rawImpact;
57
+ const payload = isImpact
58
+ ? { ok: status.ok, command: 'graph impact', compact: options.compact || undefined, root: options.root, status, metadata, changed: options.changed, related: impact.related, impact }
59
+ : { ok: status.ok, command: 'graph communities', root: options.root, status, metadata, graph: graphSummary(index), communities: buildCommunities(index) };
60
+ const refreshNote = metadata.cacheRefreshed ? ', refreshed' : '';
61
+ if (options.json) console.log(JSON.stringify(payload, null, 2));
62
+ else if (isImpact && options.yml) console.log(formatYmlImpactOutput(payload, impact));
63
+ else if (isImpact && options.compact) console.log(formatCompactImpactOutput(payload, impact));
64
+ else if (isImpact) console.log(`graph impact: ${payload.related.length} related node(s), ${impact.omittedRelated ?? 0} omitted (${status.status}${refreshNote} index)`);
65
+ else console.log(`graph communities: ${payload.communities.communities.length}/${payload.communities.total} shown, ${payload.communities.omitted} omitted (${status.status}${refreshNote} index)`);
66
+ }
@@ -0,0 +1,40 @@
1
+ import { parseCommon } from '../cli/usage.mjs';
2
+ import { buildCommunities } from '../graph/communities.mjs';
3
+ import { memoryConfigSummary, readMemoryConfig } from '../memory/config.mjs';
4
+ import { buildMemoryAreas, detectCommandGuidance } from '../load-snapshot/summary.mjs';
5
+ import { graphSummary, readFreshIndex } from '../index/cache.mjs';
6
+
7
+ export function runLoadSnapshot(argv) {
8
+ const options = parseCommon(argv);
9
+ const { status, index, metadata } = readFreshIndex(options.root);
10
+ const summary = graphSummary(index);
11
+ const communities = buildCommunities(index, { communities: 5, items: 5 });
12
+ const memoryAreas = buildMemoryAreas(index, { items: 4 });
13
+ const memoryConfig = index.memoryConfig ?? memoryConfigSummary(readMemoryConfig(options.root));
14
+ const memoryPolicy = {
15
+ source: memoryConfig.source ?? 'default',
16
+ sharedAreas: (memoryConfig.areas ?? []).filter((area) => area.scope === 'shared').map((area) => area.id),
17
+ localAreas: (memoryConfig.areas ?? []).filter((area) => area.scope === 'local').map((area) => area.id),
18
+ freshAreas: (memoryConfig.areas ?? []).filter((area) => area.freshness === 'fresh').map((area) => area.id),
19
+ staleAreas: (memoryConfig.areas ?? []).filter((area) => area.freshness === 'stale').map((area) => area.id),
20
+ };
21
+ const bounds = { communities: 5, communityItems: 5, memoryAreaItems: 4, fullGraphIncluded: false, archiveBodiesIncluded: status.archiveBodiesIncluded, archiveMapIncluded: true };
22
+ const quality = {
23
+ indexedFiles: status.indexedFiles,
24
+ currentFiles: status.currentFiles,
25
+ shownCommunities: communities.communities.length,
26
+ totalCommunities: communities.total,
27
+ omittedCommunities: communities.omitted,
28
+ omittedCommunityItems: communities.communities.reduce((sum, community) => sum + (community.omitted ?? 0), 0),
29
+ memoryAreas: memoryAreas.total,
30
+ omittedMemoryAreaItems: memoryAreas.areas.reduce((sum, area) => sum + (area.omitted ?? 0), 0),
31
+ graphNodes: summary.nodes,
32
+ graphEdges: summary.edges,
33
+ };
34
+ const commandGuidance = detectCommandGuidance(options.root);
35
+ let payload = { root: options.root, cache: status, metadata, graph: summary, memoryConfig, memoryPolicy, memoryAreas, communities, bounds, quality, commandGuidance };
36
+ const serialized = JSON.stringify(payload);
37
+ payload = { ...payload, quality: { ...quality, snapshotBytes: Buffer.byteLength(serialized), approxSnapshotTokens: Math.ceil(serialized.length / 4) } };
38
+ if (options.json) console.log(JSON.stringify(payload, null, 2));
39
+ else console.log(`dotdotgod load snapshot\n- cache: ${status.status}${metadata.cacheRefreshed ? ' (refreshed)' : ''}\n- indexed files: ${status.indexedFiles}\n- current files: ${status.currentFiles}\n- archive bodies included: ${status.archiveBodiesIncluded ? 'yes' : 'no'}\n- graph: ${summary.nodes} nodes, ${summary.edges} edges\n- memory areas: ${memoryAreas.areas.length}/${memoryAreas.total} shown\n- communities: ${communities.communities.length}/${communities.total} shown, ${communities.omitted} omitted`);
40
+ }
@@ -0,0 +1,63 @@
1
+ export const PLAN_STAGE_DIRECTORIES = [
2
+ '01-intake',
3
+ '02-context-load',
4
+ '03-discovery',
5
+ '04-plan',
6
+ ];
7
+
8
+ export const PLAN_INTERNAL_WORKSPACE = '.dotdotgod-plan';
9
+
10
+ export const PLAN_INTERNAL_STAGE_DIRECTORIES = [
11
+ ...PLAN_STAGE_DIRECTORIES,
12
+ '05-workstream-handoff',
13
+ ];
14
+
15
+ export const PLAN_REQUIRED_HEADERS = {
16
+ '01-intake': ['Request Summary', 'Goal', 'Scope', 'Non-goals', 'Constraints', 'Assumptions'],
17
+ '02-context-load': ['Memory Reads', 'Impact Candidates', 'Related Files'],
18
+ '03-discovery': ['Findings', 'Risks', 'Open Questions'],
19
+ '04-plan': ['Milestones', 'Atomic Tasks', 'Validation Plan', 'Resume Point'],
20
+ '05-workstream-handoff': ['Workstream Handoff', 'Todo Contract'],
21
+ };
22
+
23
+ export const PLAN_CONSTRUCTION_CHECKLISTS = {
24
+ '01-intake': ['Requirements', 'Constraints', 'Failure paths', 'Data shape', 'Verification', 'Integration impact'],
25
+ '02-context-load': ['Memory reads', 'Impact candidates', 'Related files', 'Boundary risk'],
26
+ '03-discovery': ['Findings', 'Risks', 'Open questions', 'Extension points'],
27
+ '04-plan': ['Milestones', 'Atomic tasks', 'Validation plan', 'Resume point'],
28
+ '05-workstream-handoff': ['Handoffs', 'Do-not rules', 'Focused verification', 'Chat-independent context'],
29
+ };
30
+
31
+ export const PLAN_BLOCKER_LABELS = new Map([
32
+ ['missing-plan', 'Plan file does not exist'],
33
+ ['invalid-plan-path', 'Plan file must be docs/plan/<task-slug>/README.md'],
34
+ ['invalid-task-slug', 'Plan task directory must be kebab-case'],
35
+ ['empty-plan', 'Plan README is empty'],
36
+ ['missing-stage', 'Missing required stage directory'],
37
+ ['missing-internal-stage', 'Missing internal stage file'],
38
+ ['missing-stage-readme', 'Missing stage README.md'],
39
+ ['invalid-markdown-name', 'Invalid Markdown file name'],
40
+ ['missing-section', 'Missing required section'],
41
+ ['empty-section', 'Required section has no content'],
42
+ ['placeholder-section', 'Required section only contains placeholder content'],
43
+ ['pending-workstream', 'Required workstream is pending'],
44
+ ['unresolved-discussion', 'Discussion Queue has unresolved items'],
45
+ ['unresolved-assumption', 'Assumptions contain unresolved items'],
46
+ ['missing-atomic-acceptance', 'Atomic Tasks must define acceptance criteria'],
47
+ ['missing-atomic-verification', 'Atomic Tasks must define verification'],
48
+ ['missing-construction-checklist', 'Missing construction checklist'],
49
+ ['missing-checklist-item', 'Missing construction checklist item'],
50
+ ['malformed-checklist-item', 'Malformed construction checklist item'],
51
+ ['open-checklist-item', 'Construction checklist item is open'],
52
+ ['placeholder-checklist-item', 'Construction checklist item only contains placeholder content'],
53
+ ]);
54
+
55
+ export function buildPlanValidationNextStagePrompt(planPath, stage, stagePath) {
56
+ return [
57
+ `Continue Plan Mode stage advancement for ${planPath}.`,
58
+ `Current stage: ${stage}.`,
59
+ `Make ${planPath} satisfy the current stage's durable README requirements first. Use ${stagePath} only as an optional checkpoint/workflow note for this stage; do not make numbered checkpoint creation the goal and do not create later checkpoint files yet.`,
60
+ stage === '05-workstream-handoff' ? 'For this stage, ensure the durable README or split UPPER_SNAKE_CASE workstream plan files expose numbered `Plan:` sections so Pi can extract todos during execution. For small plans, explicitly state that no split is needed.' : undefined,
61
+ `After completing this stage, stop and rerun \`dotdotgod plan validate ${planPath} --stage ${stage} --json\`.`,
62
+ ].filter(Boolean).join('\n\n');
63
+ }