godpowers 2.2.1 → 2.3.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/CHANGELOG.md +65 -7
- package/INSPIRATION.md +4 -2
- package/README.md +35 -22
- package/RELEASE.md +44 -23
- package/SKILL.md +2 -2
- package/agents/god-auditor.md +1 -1
- package/agents/god-debugger.md +44 -8
- package/agents/god-deps-auditor.md +11 -0
- package/agents/god-executor.md +50 -5
- package/agents/god-greenfieldifier.md +1 -1
- package/agents/god-orchestrator.md +2 -2
- package/agents/god-planner.md +14 -0
- package/agents/god-pm.md +1 -1
- package/agents/god-quality-reviewer.md +23 -1
- package/agents/god-reconciler.md +1 -1
- package/agents/god-roadmapper.md +1 -1
- package/agents/god-spec-reviewer.md +16 -0
- package/agents/god-stack-selector.md +4 -0
- package/agents/god-updater.md +1 -1
- package/bin/install.js +9 -3
- package/fixtures/dogfood/{half-migrated-gsd → half-migrated-planning}/manifest.json +2 -2
- package/lib/README.md +9 -2
- package/lib/agent-cache.js +25 -3
- package/lib/atomic-write.js +85 -0
- package/lib/checkpoint.js +2 -1
- package/lib/code-intelligence.js +161 -0
- package/lib/context-writer.js +1 -1
- package/lib/dashboard.js +54 -20
- package/lib/executor-repair.js +65 -0
- package/lib/extensions.js +6 -13
- package/lib/feature-awareness.js +2 -2
- package/lib/fs-async.js +2 -1
- package/lib/host-capabilities.js +4 -0
- package/lib/install-profiles.js +155 -0
- package/lib/installer-args.js +12 -0
- package/lib/installer-core.js +43 -8
- package/lib/linkage.js +2 -1
- package/lib/package-identity.js +38 -0
- package/lib/package-legitimacy.js +158 -0
- package/lib/planning-systems.js +16 -13
- package/lib/quick-proof.js +5 -2
- package/lib/repo-surface-sync.js +1 -1
- package/lib/requirements.js +2 -1
- package/lib/reverse-sync.js +2 -1
- package/lib/route-quality-sync.js +2 -0
- package/lib/source-grounding.js +177 -0
- package/lib/source-sync.js +6 -5
- package/lib/state.js +2 -1
- package/package.json +2 -2
- package/references/HAVE-NOTS.md +1 -1
- package/references/orchestration/MODE-DETECTION.md +2 -2
- package/references/shared/ORCHESTRATORS.md +3 -3
- package/routing/god-design.yaml +1 -1
- package/routing/god-extension-scaffold.yaml +25 -0
- package/routing/god-migrate.yaml +3 -3
- package/routing/god-stack.yaml +1 -1
- package/routing/recipes/add-feature-mid-arc-pause.yaml +6 -0
- package/routing/recipes/brownfield-onboarding.yaml +5 -2
- package/routing/recipes/extension-authoring.yaml +32 -0
- package/routing/recipes/greenfield-fast.yaml +3 -0
- package/routing/recipes/production-broken.yaml +4 -0
- package/routing/recipes/release-maintenance.yaml +3 -0
- package/routing/recipes/returning-after-break.yaml +3 -0
- package/routing/recipes/weekly-health-check.yaml +2 -0
- package/schema/state.v1.json +1 -1
- package/skills/god-build.md +17 -3
- package/skills/god-discuss.md +10 -5
- package/skills/god-doctor.md +9 -3
- package/skills/god-dogfood.md +2 -2
- package/skills/god-extension-scaffold.md +66 -0
- package/skills/god-init.md +6 -6
- package/skills/god-migrate.md +10 -10
- package/skills/god-sync.md +2 -2
- package/skills/god-update-deps.md +4 -2
- package/skills/god-version.md +2 -2
- package/skills/god.md +8 -11
- package/templates/IMPORTED-CONTEXT.md +1 -1
- package/templates/INITIAL-FINDINGS.md +2 -2
- /package/fixtures/dogfood/{half-migrated-gsd → half-migrated-planning}/.planning/PROJECT.md +0 -0
- /package/fixtures/dogfood/{half-migrated-gsd → half-migrated-planning}/.planning/REQUIREMENTS.md +0 -0
- /package/fixtures/dogfood/{half-migrated-gsd → half-migrated-planning}/.planning/ROADMAP.md +0 -0
|
@@ -63,6 +63,26 @@ Your job: would you ship this code in production?
|
|
|
63
63
|
- Flag missing or inaccurate annotations: the deliverable ledger derives
|
|
64
64
|
requirement status from them, so a gap here understates delivered work
|
|
65
65
|
|
|
66
|
+
### 8. Comment Quality and Style Fidelity
|
|
67
|
+
- Required traceability comments such as `// Implements: P-...` remain present
|
|
68
|
+
and accurate.
|
|
69
|
+
- Comments explain non-obvious why, constraints, hazards, or tradeoffs. Flag
|
|
70
|
+
comments that narrate obvious code, duplicate names, go stale, or use generic
|
|
71
|
+
AI-assistant prose.
|
|
72
|
+
- Avoid decorative section banners or chatty explanation unless the surrounding
|
|
73
|
+
codebase already uses that convention.
|
|
74
|
+
- If `CODEDNA.md` exists, compare naming, comment voice, extraction threshold,
|
|
75
|
+
error style, test style, and common idioms against the profile.
|
|
76
|
+
- Absence of `CODEDNA.md` is not a failure. When no profile exists, judge style
|
|
77
|
+
against nearby code and repository conventions.
|
|
78
|
+
|
|
79
|
+
### 9. Optional Code Intelligence
|
|
80
|
+
- When `ast-grep`, `sg`, or LSP tools are available, use them to support
|
|
81
|
+
maintainability review for structural matches, impacted references, or
|
|
82
|
+
diagnostics that plain grep can miss.
|
|
83
|
+
- Absence of these tools is not a failure. Treat them as extra evidence when
|
|
84
|
+
present.
|
|
85
|
+
|
|
66
86
|
## Output
|
|
67
87
|
|
|
68
88
|
Return verdict to orchestrator:
|
|
@@ -78,6 +98,8 @@ Return verdict to orchestrator:
|
|
|
78
98
|
- [PASS/FAIL] Maintainability: [evidence]
|
|
79
99
|
- [PASS/FAIL] Simplicity and surgicality: [evidence]
|
|
80
100
|
- [PASS/FAIL] Requirement traceability: [evidence]
|
|
101
|
+
- [PASS/FAIL] Comment quality and style fidelity: [evidence]
|
|
102
|
+
- [PASS/FAIL] Optional code intelligence: [evidence or not applicable]
|
|
81
103
|
|
|
82
104
|
### Verdict: PASS / FAIL
|
|
83
105
|
|
|
@@ -86,7 +108,7 @@ Return verdict to orchestrator:
|
|
|
86
108
|
|
|
87
109
|
## Pass Criteria
|
|
88
110
|
|
|
89
|
-
ALL
|
|
111
|
+
ALL nine dimensions must PASS. Any FAIL blocks the commit.
|
|
90
112
|
|
|
91
113
|
If FAIL: orchestrator returns the slice to god-executor.
|
|
92
114
|
If PASS: orchestrator commits the slice atomically.
|
package/agents/god-reconciler.md
CHANGED
|
@@ -144,7 +144,7 @@ For each artifact below, check (in parallel where possible):
|
|
|
144
144
|
- If imported planning systems have low confidence or conflicts: recommend
|
|
145
145
|
`god-greenfieldifier`.
|
|
146
146
|
|
|
147
|
-
#### SOURCE SYSTEM SYNC-BACK (
|
|
147
|
+
#### SOURCE SYSTEM SYNC-BACK (legacy planning, BMAD, Superpowers)
|
|
148
148
|
- Did migrated source-system summaries need managed sync-back?
|
|
149
149
|
- Verdict: not-applicable / fresh / needs-sync-back / blocked-by-conflict
|
|
150
150
|
- If conflicts exist: recommend greenfieldifier review before writes.
|
package/agents/god-roadmapper.md
CHANGED
|
@@ -36,7 +36,7 @@ If `.godpowers/prep/INITIAL-FINDINGS.md` exists, read it first for repo risks,
|
|
|
36
36
|
existing tests, docs, CI, deploy, and suggested sequencing implications.
|
|
37
37
|
|
|
38
38
|
If `.godpowers/prep/IMPORTED-CONTEXT.md` exists, read its delivery signals
|
|
39
|
-
before sequencing work. Use imported
|
|
39
|
+
before sequencing work. Use imported legacy planning, Superpowers, BMAD, or similar
|
|
40
40
|
stories and plans as hypothesis-level input only. Convert imported terminology
|
|
41
41
|
into Godpowers vocabulary. Do not preserve imported methodology terminology in
|
|
42
42
|
Godpowers artifacts unless the user explicitly asked for it.
|
|
@@ -57,6 +57,20 @@ Answer each with EVIDENCE from the code:
|
|
|
57
57
|
- A planned requirement id with no annotation is a finding, because the
|
|
58
58
|
deliverable ledger derives requirement status from those annotations.
|
|
59
59
|
|
|
60
|
+
7. **Did the implementation honor source grounding and package legitimacy?**
|
|
61
|
+
- Did every existing file or symbol cited by the slice plan exist before
|
|
62
|
+
execution?
|
|
63
|
+
- Did new files appear only under the plan's new artifacts or expected file
|
|
64
|
+
list?
|
|
65
|
+
- If the slice added a dependency, is there package legitimacy evidence or
|
|
66
|
+
an explicit accepted-risk note?
|
|
67
|
+
|
|
68
|
+
8. **Did available code intelligence support the review?**
|
|
69
|
+
- If `ast-grep`, `sg`, or LSP tools are available, use them to verify
|
|
70
|
+
impacted references, structural matches, or diagnostics for the touched
|
|
71
|
+
language when relevant.
|
|
72
|
+
- If unavailable or irrelevant, do not fail the slice for absence alone.
|
|
73
|
+
|
|
60
74
|
## Output
|
|
61
75
|
|
|
62
76
|
Return verdict to orchestrator:
|
|
@@ -83,6 +97,8 @@ Return verdict to orchestrator:
|
|
|
83
97
|
- Every touched file has request-trace evidence
|
|
84
98
|
- No speculative flexibility or unrelated cleanup entered the diff
|
|
85
99
|
- Every planned requirement id carries its `// Implements: P-...` annotation
|
|
100
|
+
- Source-grounding failures are resolved or explicitly accepted
|
|
101
|
+
- New dependencies have legitimacy evidence or accepted-risk notes
|
|
86
102
|
|
|
87
103
|
If FAIL: orchestrator returns the slice to god-executor with the failures.
|
|
88
104
|
If PASS: orchestrator spawns god-quality-reviewer next.
|
|
@@ -65,6 +65,9 @@ Rules:
|
|
|
65
65
|
3. For each category:
|
|
66
66
|
- List 2-3 viable candidates
|
|
67
67
|
- Score on: fit-for-requirements, maturity, ecosystem health, team familiarity, total cost
|
|
68
|
+
- For package-backed choices, run or request the package legitimacy gate:
|
|
69
|
+
registry existence, package age, repository signal, maintainer signal,
|
|
70
|
+
typo-squat risk, and known vulnerability status where available
|
|
68
71
|
- Document the **flip point**: condition under which you'd reverse this choice
|
|
69
72
|
- Document the **lock-in cost**: how hard is it to switch (Low/Medium/High)
|
|
70
73
|
4. Verify pairing compatibility (e.g., chosen ORM works with chosen DB)
|
|
@@ -103,6 +106,7 @@ Stack DECISION FAILS if:
|
|
|
103
106
|
- High lock-in choice with likely flip point in <6 months
|
|
104
107
|
- Pairing incompatibility (chosen ORM doesn't support chosen DB, etc.)
|
|
105
108
|
- "Best practice" rationale without specific rationale tied to ARCH
|
|
109
|
+
- Package-backed choice without legitimacy evidence or an accepted-risk note
|
|
106
110
|
|
|
107
111
|
## Pause Conditions
|
|
108
112
|
|
package/agents/god-updater.md
CHANGED
|
@@ -174,7 +174,7 @@ After feature work, every artifact that was impacted needs to reflect reality.
|
|
|
174
174
|
|
|
175
175
|
### Source-system sync-back
|
|
176
176
|
- Call `lib/source-sync.run(projectRoot)` when `.godpowers/state.json`
|
|
177
|
-
declares
|
|
177
|
+
declares legacy planning, BMAD, Superpowers, or other source-system records.
|
|
178
178
|
- Write only managed Godpowers summary sections back to source systems.
|
|
179
179
|
- Preserve user-authored source-system content outside managed sections.
|
|
180
180
|
- If source-system confidence is low or conflicts are present, recommend
|
package/bin/install.js
CHANGED
|
@@ -17,8 +17,10 @@ const {
|
|
|
17
17
|
uninstallForRuntime,
|
|
18
18
|
countInstalledSurface
|
|
19
19
|
} = require('../lib/installer-core');
|
|
20
|
+
const { describeProfiles } = require('../lib/install-profiles');
|
|
21
|
+
const identity = require('../lib/package-identity');
|
|
20
22
|
|
|
21
|
-
const VERSION =
|
|
23
|
+
const VERSION = identity.PACKAGE_VERSION;
|
|
22
24
|
|
|
23
25
|
const BANNER = `
|
|
24
26
|
GODPOWERS v${VERSION}
|
|
@@ -80,6 +82,8 @@ function showHelp() {
|
|
|
80
82
|
log(' --codebuddy Install for CodeBuddy');
|
|
81
83
|
log(' --pi Install for Pi');
|
|
82
84
|
log(' --all Install for all 15 runtimes');
|
|
85
|
+
log(' --profile=<name> Install profile: core, builder, maintainer, suite, or full');
|
|
86
|
+
log(' --minimal Alias for --profile=core');
|
|
83
87
|
log(' -u, --uninstall Uninstall Godpowers');
|
|
84
88
|
log(' -h, --help Show this help message');
|
|
85
89
|
log('');
|
|
@@ -92,6 +96,7 @@ function showHelp() {
|
|
|
92
96
|
log(' npx godpowers dogfood');
|
|
93
97
|
log(' npx godpowers extension-scaffold --name=@godpowers/my-pack --output=.');
|
|
94
98
|
log(' npx godpowers --claude --global');
|
|
99
|
+
log(' npx godpowers --claude --global --profile=core');
|
|
95
100
|
log(' npx godpowers --all');
|
|
96
101
|
log(' npx godpowers --codex --cursor');
|
|
97
102
|
}
|
|
@@ -243,10 +248,11 @@ function runInstall(opts, srcDir) {
|
|
|
243
248
|
process.exit(1);
|
|
244
249
|
}
|
|
245
250
|
|
|
246
|
-
const surface = countInstalledSurface(srcDir);
|
|
251
|
+
const surface = countInstalledSurface(srcDir, opts);
|
|
247
252
|
log('');
|
|
248
253
|
log(`\x1b[32mDone!\x1b[0m Installed Godpowers v${VERSION} for ${installed} runtime(s).`);
|
|
249
254
|
log('');
|
|
255
|
+
log(`\x1b[36mProfile:\x1b[0m ${describeProfiles(opts.profile)}`);
|
|
250
256
|
log(`\x1b[36mInstalled:\x1b[0m`);
|
|
251
257
|
log(` ${surface.skills} slash commands (try: /god-mode, /god-next, /god-status, /god-progress)`);
|
|
252
258
|
log(` ${surface.agents} specialist agents`);
|
|
@@ -258,7 +264,7 @@ function runInstall(opts, srcDir) {
|
|
|
258
264
|
log(` Or: \x1b[36m/god-next\x1b[0m to see what to run next`);
|
|
259
265
|
log(` Or: \x1b[36m/god-init\x1b[0m to start a new project`);
|
|
260
266
|
log('');
|
|
261
|
-
log(`\x1b[36mDocs:\x1b[0m
|
|
267
|
+
log(`\x1b[36mDocs:\x1b[0m ${identity.HOMEPAGE_URL}`);
|
|
262
268
|
log('');
|
|
263
269
|
}
|
|
264
270
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "Half migrated
|
|
2
|
+
"name": "Half migrated planning project",
|
|
3
3
|
"kind": "planning-migration",
|
|
4
4
|
"actions": [
|
|
5
5
|
"import-planning-context",
|
|
6
6
|
"sync-back"
|
|
7
7
|
],
|
|
8
8
|
"expectedSystems": [
|
|
9
|
-
"
|
|
9
|
+
"legacy-planning"
|
|
10
10
|
],
|
|
11
11
|
"expectedFiles": [
|
|
12
12
|
".godpowers/prep/IMPORTED-CONTEXT.md",
|
package/lib/README.md
CHANGED
|
@@ -13,7 +13,8 @@ package-level integrations.
|
|
|
13
13
|
| `intent.js` | Read and validate `intent.yaml` from project roots or `.godpowers/`. |
|
|
14
14
|
| `checkpoint.js` | Create and inspect resumable checkpoint artifacts. |
|
|
15
15
|
| `feature-awareness.js` | Detect and refresh existing-project awareness after runtime upgrades. |
|
|
16
|
-
| `
|
|
16
|
+
| `code-intelligence.js` | Detect optional `ast-grep`, `sg`, and LSP tooling for structural search, rewrite, and diagnostics guidance. |
|
|
17
|
+
| `host-capabilities.js` | Detect host guarantees for shell, git, npm, agent spawning, optional code intelligence, extension authoring, and suite dry-runs. |
|
|
17
18
|
| `repo-doc-sync.js` | Detect and refresh mechanical repository documentation surfaces. |
|
|
18
19
|
| `repo-surface-sync.js` | Detect structural drift across commands, routes, packages, agents, workflows, recipes, extensions, and release policy. |
|
|
19
20
|
| `route-quality-sync.js` | Detect symbolic route spawns, unresolved agent targets, and unapproved contextual route exits. |
|
|
@@ -22,6 +23,7 @@ package-level integrations.
|
|
|
22
23
|
| `dogfood-runner.js` | Run deterministic messy-repo scenarios against migration, host, extension, and suite release behavior. |
|
|
23
24
|
| `budget.js` | Read and enforce configured budget controls. |
|
|
24
25
|
| `cost-tracker.js` | Track token and cost estimates from event streams. |
|
|
26
|
+
| `atomic-write.js` | Write load-bearing files through temp-file validation and atomic rename. |
|
|
25
27
|
| `fs-async.js` | Promise-based file read/write helpers for non-blocking runtime paths. |
|
|
26
28
|
|
|
27
29
|
## Events and observability
|
|
@@ -45,6 +47,7 @@ package-level integrations.
|
|
|
45
47
|
| `agent-cache.js` | Cache agent metadata for faster routing. |
|
|
46
48
|
| `agent-validator.js` | Validate agent frontmatter and contracts. |
|
|
47
49
|
| `agent-refs.js` | Validate workflow agent references and scan skill/agent prose for phantom references. |
|
|
50
|
+
| `executor-repair.js` | Classify executor repair decisions as retry, decompose, prune, or escalate. |
|
|
48
51
|
| `skill-surface.js` | Derive slash-command metadata from the individual `skills/` files. |
|
|
49
52
|
|
|
50
53
|
## Artifact quality
|
|
@@ -63,7 +66,7 @@ package-level integrations.
|
|
|
63
66
|
|--------|---------|
|
|
64
67
|
| `context-writer.js` | Produce tool-specific context files. |
|
|
65
68
|
| `context-budget.js` | Keep generated context within budget. |
|
|
66
|
-
| `planning-systems.js` | Detect and import
|
|
69
|
+
| `planning-systems.js` | Detect and import legacy planning, BMAD, and Superpowers planning context. |
|
|
67
70
|
| `source-sync.js` | Write managed Godpowers progress back to source-system companion files. |
|
|
68
71
|
| `design-detector.js` | Detect design-system conventions. |
|
|
69
72
|
| `design-spec.js` | Normalize design specifications. |
|
|
@@ -74,6 +77,7 @@ package-level integrations.
|
|
|
74
77
|
| `impeccable-bridge.js` | Bridge runtime checks into impeccable quality workflows. |
|
|
75
78
|
| `extensions.js` | Load and validate extension packs. |
|
|
76
79
|
| `extension-authoring.js` | Scaffold publishable extension packs with manifest, package, README, skill, agent, and workflow files. |
|
|
80
|
+
| `package-legitimacy.js` | Assess third-party package metadata for existence, typo risk, recency, and repository signals. |
|
|
77
81
|
| `pillars.js` | Manage the Pillars project-context layer (`AGENTS.md` plus routed `agents/*.md`). |
|
|
78
82
|
|
|
79
83
|
## Repository and graph helpers
|
|
@@ -81,6 +85,7 @@ package-level integrations.
|
|
|
81
85
|
| Module | Purpose |
|
|
82
86
|
|--------|---------|
|
|
83
87
|
| `code-scanner.js` | Scan source trees for routing and quality evidence. |
|
|
88
|
+
| `source-grounding.js` | Check that build plans cite existing files and symbols before execution starts. |
|
|
84
89
|
| `cross-artifact-impact.js` | Detect relationships between changed artifacts. |
|
|
85
90
|
| `cross-repo-linkage.js` | Track suite-level repository relationships. |
|
|
86
91
|
| `drift-detector.js` | Detect context drift between artifacts and implementation. |
|
|
@@ -98,7 +103,9 @@ package-level integrations.
|
|
|
98
103
|
| `installer-core.js` | Install and uninstall the Godpowers surface for each runtime. |
|
|
99
104
|
| `installer-files.js` | File-copy helpers shared by the installer and its tests. |
|
|
100
105
|
| `installer-args.js` | Parse `bin/install.js` arguments and subcommands. |
|
|
106
|
+
| `install-profiles.js` | Select smaller role-specific slash-command install surfaces. |
|
|
101
107
|
| `installer-runtimes.js` | Map supported runtimes to their config directories. |
|
|
108
|
+
| `package-identity.js` | Centralize package name, version, repository, docs, and command identity. |
|
|
102
109
|
| `automation-providers.js` | Detect and configure host-native automation providers. |
|
|
103
110
|
| `dashboard.js` | Compute the next-step action brief and host guarantee line. |
|
|
104
111
|
| `quick-proof.js` | Render the shipped proof fixture for `godpowers quick-proof`. |
|
package/lib/agent-cache.js
CHANGED
|
@@ -134,9 +134,29 @@ function clear(projectRoot, opts = {}) {
|
|
|
134
134
|
const now = Date.now();
|
|
135
135
|
for (const shard of fs.readdirSync(dir)) {
|
|
136
136
|
const shardPath = path.join(dir, shard);
|
|
137
|
-
|
|
137
|
+
const shardStat = fs.lstatSync(shardPath);
|
|
138
|
+
if (shardStat.isSymbolicLink()) {
|
|
139
|
+
if (opts.all) {
|
|
140
|
+
fs.unlinkSync(shardPath);
|
|
141
|
+
removed++;
|
|
142
|
+
} else {
|
|
143
|
+
kept++;
|
|
144
|
+
}
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (!shardStat.isDirectory()) continue;
|
|
138
148
|
for (const fname of fs.readdirSync(shardPath)) {
|
|
139
149
|
const fpath = path.join(shardPath, fname);
|
|
150
|
+
const fileStat = fs.lstatSync(fpath);
|
|
151
|
+
if (fileStat.isSymbolicLink()) {
|
|
152
|
+
if (opts.all) { fs.unlinkSync(fpath); removed++; }
|
|
153
|
+
else { kept++; }
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (!fileStat.isFile()) {
|
|
157
|
+
kept++;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
140
160
|
let entry;
|
|
141
161
|
try { entry = JSON.parse(fs.readFileSync(fpath, 'utf8')); }
|
|
142
162
|
catch (e) {
|
|
@@ -173,10 +193,12 @@ function stats(projectRoot) {
|
|
|
173
193
|
let oldestTs = null;
|
|
174
194
|
for (const shard of fs.readdirSync(dir)) {
|
|
175
195
|
const shardPath = path.join(dir, shard);
|
|
176
|
-
|
|
196
|
+
const shardStat = fs.lstatSync(shardPath);
|
|
197
|
+
if (shardStat.isSymbolicLink() || !shardStat.isDirectory()) continue;
|
|
177
198
|
for (const fname of fs.readdirSync(shardPath)) {
|
|
178
199
|
const fpath = path.join(shardPath, fname);
|
|
179
|
-
const stat = fs.
|
|
200
|
+
const stat = fs.lstatSync(fpath);
|
|
201
|
+
if (stat.isSymbolicLink() || !stat.isFile()) continue;
|
|
180
202
|
totalBytes += stat.size;
|
|
181
203
|
count += 1;
|
|
182
204
|
try {
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const fsp = require('fs/promises');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
function tempPathFor(filePath) {
|
|
6
|
+
const dir = path.dirname(filePath);
|
|
7
|
+
const base = path.basename(filePath);
|
|
8
|
+
return path.join(dir, `.${base}.${process.pid}.${Date.now()}.tmp`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function validateContent(content, validate) {
|
|
12
|
+
if (typeof validate === 'function') validate(content);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function writeFileAtomic(filePath, content, opts = {}) {
|
|
16
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
17
|
+
const tmp = tempPathFor(filePath);
|
|
18
|
+
try {
|
|
19
|
+
fs.writeFileSync(tmp, content);
|
|
20
|
+
validateContent(content, opts.validateContent);
|
|
21
|
+
if (typeof opts.validateFile === 'function') opts.validateFile(tmp);
|
|
22
|
+
fs.renameSync(tmp, filePath);
|
|
23
|
+
return filePath;
|
|
24
|
+
} catch (error) {
|
|
25
|
+
try {
|
|
26
|
+
fs.rmSync(tmp, { force: true });
|
|
27
|
+
} catch (_) {
|
|
28
|
+
// Best-effort cleanup. The original file is still untouched.
|
|
29
|
+
}
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function writeFileAtomicAsync(filePath, content, opts = {}) {
|
|
35
|
+
await fsp.mkdir(path.dirname(filePath), { recursive: true });
|
|
36
|
+
const tmp = tempPathFor(filePath);
|
|
37
|
+
try {
|
|
38
|
+
await fsp.writeFile(tmp, content);
|
|
39
|
+
validateContent(content, opts.validateContent);
|
|
40
|
+
if (typeof opts.validateFile === 'function') await opts.validateFile(tmp);
|
|
41
|
+
await fsp.rename(tmp, filePath);
|
|
42
|
+
return filePath;
|
|
43
|
+
} catch (error) {
|
|
44
|
+
try {
|
|
45
|
+
await fsp.rm(tmp, { force: true });
|
|
46
|
+
} catch (_) {
|
|
47
|
+
// Best-effort cleanup. The original file is still untouched.
|
|
48
|
+
}
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function jsonContent(value) {
|
|
54
|
+
return JSON.stringify(value, null, 2) + '\n';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function writeJsonAtomic(filePath, value, opts = {}) {
|
|
58
|
+
const content = jsonContent(value);
|
|
59
|
+
return writeFileAtomic(filePath, content, {
|
|
60
|
+
...opts,
|
|
61
|
+
validateContent: text => {
|
|
62
|
+
JSON.parse(text);
|
|
63
|
+
validateContent(text, opts.validateContent);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function writeJsonAtomicAsync(filePath, value, opts = {}) {
|
|
69
|
+
const content = jsonContent(value);
|
|
70
|
+
return writeFileAtomicAsync(filePath, content, {
|
|
71
|
+
...opts,
|
|
72
|
+
validateContent: text => {
|
|
73
|
+
JSON.parse(text);
|
|
74
|
+
validateContent(text, opts.validateContent);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = {
|
|
80
|
+
tempPathFor,
|
|
81
|
+
writeFileAtomic,
|
|
82
|
+
writeFileAtomicAsync,
|
|
83
|
+
writeJsonAtomic,
|
|
84
|
+
writeJsonAtomicAsync
|
|
85
|
+
};
|
package/lib/checkpoint.js
CHANGED
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
const fs = require('fs');
|
|
50
50
|
const path = require('path');
|
|
51
51
|
const crypto = require('crypto');
|
|
52
|
+
const atomic = require('./atomic-write');
|
|
52
53
|
|
|
53
54
|
const MAX_ACTIONS = 20;
|
|
54
55
|
const MAX_FACTS = 10;
|
|
@@ -224,7 +225,7 @@ function write(projectRoot, state) {
|
|
|
224
225
|
''
|
|
225
226
|
].filter(line => line !== null).join('\n');
|
|
226
227
|
|
|
227
|
-
|
|
228
|
+
atomic.writeFileAtomic(file, fm + body);
|
|
228
229
|
return file;
|
|
229
230
|
}
|
|
230
231
|
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional code intelligence capability detection.
|
|
3
|
+
*
|
|
4
|
+
* These tools sharpen refactors and reviews when present, but Godpowers must
|
|
5
|
+
* keep working through grep-backed workflows when they are absent.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const cp = require('child_process');
|
|
9
|
+
|
|
10
|
+
const AST_GREP_CANDIDATES = [
|
|
11
|
+
{ id: 'ast-grep', command: 'ast-grep', args: ['--version'], match: /ast-grep/i },
|
|
12
|
+
{ id: 'sg', command: 'sg', args: ['--version'], match: /\b(ast-grep|sg\s+\d)/i }
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const LSP_CANDIDATES = [
|
|
16
|
+
{ id: 'omo-lsp', command: 'omo-lsp', args: ['--version'], languages: ['multi'] },
|
|
17
|
+
{ id: 'typescript-language-server', command: 'typescript-language-server', args: ['--version'], languages: ['javascript', 'typescript'] },
|
|
18
|
+
{ id: 'vscode-json-language-server', command: 'vscode-json-language-server', args: ['--version'], languages: ['json'] },
|
|
19
|
+
{ id: 'yaml-language-server', command: 'yaml-language-server', args: ['--version'], languages: ['yaml'] },
|
|
20
|
+
{ id: 'pyright-langserver', command: 'pyright-langserver', args: ['--version'], languages: ['python'] },
|
|
21
|
+
{ id: 'pylsp', command: 'pylsp', args: ['--version'], languages: ['python'] },
|
|
22
|
+
{ id: 'gopls', command: 'gopls', args: ['version'], languages: ['go'] },
|
|
23
|
+
{ id: 'rust-analyzer', command: 'rust-analyzer', args: ['--version'], languages: ['rust'] },
|
|
24
|
+
{ id: 'clangd', command: 'clangd', args: ['--version'], languages: ['c', 'cpp'] },
|
|
25
|
+
{ id: 'jdtls', command: 'jdtls', args: ['--version'], languages: ['java'] },
|
|
26
|
+
{ id: 'ruby-lsp', command: 'ruby-lsp', args: ['--version'], languages: ['ruby'] },
|
|
27
|
+
{ id: 'solargraph', command: 'solargraph', args: ['--version'], languages: ['ruby'] },
|
|
28
|
+
{ id: 'terraform-ls', command: 'terraform-ls', args: ['version'], languages: ['terraform'] }
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
function firstLine(value) {
|
|
32
|
+
if (!value) return null;
|
|
33
|
+
const text = String(value).trim();
|
|
34
|
+
if (!text) return null;
|
|
35
|
+
return text.split(/\r?\n/)[0] || 'installed';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function commandVersion(command, args, opts = {}) {
|
|
39
|
+
try {
|
|
40
|
+
const out = cp.execFileSync(command, args, {
|
|
41
|
+
cwd: opts.cwd || process.cwd(),
|
|
42
|
+
encoding: 'utf8',
|
|
43
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
44
|
+
timeout: opts.timeout || 800
|
|
45
|
+
});
|
|
46
|
+
return firstLine(out) || 'installed';
|
|
47
|
+
} catch (err) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function checkCandidate(candidate, opts) {
|
|
53
|
+
const version = firstLine(opts.commandVersion(candidate.command, candidate.args, {
|
|
54
|
+
cwd: opts.cwd,
|
|
55
|
+
timeout: opts.timeout
|
|
56
|
+
}));
|
|
57
|
+
if (!version) return null;
|
|
58
|
+
if (candidate.match && !candidate.match.test(version)) return null;
|
|
59
|
+
return {
|
|
60
|
+
id: candidate.id,
|
|
61
|
+
command: candidate.command,
|
|
62
|
+
version,
|
|
63
|
+
languages: candidate.languages || []
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function detectFirst(candidates, opts) {
|
|
68
|
+
for (const candidate of candidates) {
|
|
69
|
+
const found = checkCandidate(candidate, opts);
|
|
70
|
+
if (found) return found;
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function detectAll(candidates, opts) {
|
|
76
|
+
const found = [];
|
|
77
|
+
const limit = opts.maxTools || 5;
|
|
78
|
+
for (const candidate of candidates) {
|
|
79
|
+
const result = checkCandidate(candidate, opts);
|
|
80
|
+
if (result) found.push(result);
|
|
81
|
+
if (found.length >= limit) break;
|
|
82
|
+
}
|
|
83
|
+
return found;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function detect(projectRoot, opts = {}) {
|
|
87
|
+
const root = projectRoot || process.cwd();
|
|
88
|
+
const probe = opts.commandVersion || commandVersion;
|
|
89
|
+
const probeOpts = {
|
|
90
|
+
cwd: root,
|
|
91
|
+
commandVersion: probe,
|
|
92
|
+
timeout: opts.timeout || 800,
|
|
93
|
+
maxTools: opts.maxTools || 5
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const astGrep = detectFirst(opts.astGrepCandidates || AST_GREP_CANDIDATES, probeOpts);
|
|
97
|
+
const lspTools = detectAll(opts.lspCandidates || LSP_CANDIDATES, probeOpts);
|
|
98
|
+
const gaps = [];
|
|
99
|
+
if (!astGrep) gaps.push('ast-grep not detected');
|
|
100
|
+
if (lspTools.length === 0) gaps.push('LSP tools not detected');
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
level: astGrep || lspTools.length > 0 ? 'available' : 'not-detected',
|
|
104
|
+
astGrep: astGrep
|
|
105
|
+
? { available: true, command: astGrep.command, version: astGrep.version }
|
|
106
|
+
: { available: false, command: null, version: null },
|
|
107
|
+
lsp: {
|
|
108
|
+
available: lspTools.length > 0,
|
|
109
|
+
primary: lspTools[0] || null,
|
|
110
|
+
tools: lspTools
|
|
111
|
+
},
|
|
112
|
+
gaps
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function lspSummary(lsp) {
|
|
117
|
+
if (!lsp || !lsp.available) return 'not detected';
|
|
118
|
+
return lsp.tools.map(tool => tool.command).join(', ');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function summary(report) {
|
|
122
|
+
if (!report) return 'not detected';
|
|
123
|
+
const parts = [];
|
|
124
|
+
if (report.astGrep && report.astGrep.available) {
|
|
125
|
+
parts.push(`ast-grep via ${report.astGrep.command}`);
|
|
126
|
+
}
|
|
127
|
+
if (report.lsp && report.lsp.available) {
|
|
128
|
+
parts.push(`LSP via ${lspSummary(report.lsp)}`);
|
|
129
|
+
}
|
|
130
|
+
return parts.length > 0 ? parts.join('; ') : 'not detected';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function render(report) {
|
|
134
|
+
const ast = report && report.astGrep && report.astGrep.available
|
|
135
|
+
? `${report.astGrep.command} (${report.astGrep.version})`
|
|
136
|
+
: 'not detected';
|
|
137
|
+
const lsp = report && report.lsp && report.lsp.available
|
|
138
|
+
? lspSummary(report.lsp)
|
|
139
|
+
: 'not detected';
|
|
140
|
+
const gaps = report && report.gaps && report.gaps.length > 0
|
|
141
|
+
? report.gaps.join('; ')
|
|
142
|
+
: 'none';
|
|
143
|
+
return [
|
|
144
|
+
'Code intelligence:',
|
|
145
|
+
` Structural search: ${ast}`,
|
|
146
|
+
` LSP tools: ${lsp}`,
|
|
147
|
+
` Gaps: ${gaps}`
|
|
148
|
+
].join('\n');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
module.exports = {
|
|
152
|
+
detect,
|
|
153
|
+
summary,
|
|
154
|
+
render,
|
|
155
|
+
_private: {
|
|
156
|
+
AST_GREP_CANDIDATES,
|
|
157
|
+
LSP_CANDIDATES,
|
|
158
|
+
commandVersion,
|
|
159
|
+
firstLine
|
|
160
|
+
}
|
|
161
|
+
};
|
package/lib/context-writer.js
CHANGED
|
@@ -99,7 +99,7 @@ function buildCanonicalContent(state, opts = {}) {
|
|
|
99
99
|
lines.push('- `/god-next` - what to run next, with reason');
|
|
100
100
|
lines.push('- `/god-mode` - run the full autonomous project run');
|
|
101
101
|
lines.push('- `/god-sync` - refresh artifacts, context, and source-system sync-back');
|
|
102
|
-
lines.push('- `/god-migrate` - import or sync
|
|
102
|
+
lines.push('- `/god-migrate` - import or sync legacy planning, BMAD, or Superpowers context');
|
|
103
103
|
lines.push('- `/god-context refresh` - refresh AI-tool awareness for this project');
|
|
104
104
|
lines.push('');
|
|
105
105
|
|