godpowers 3.13.0 → 3.13.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.
@@ -10,6 +10,7 @@ const fs = require('fs');
10
10
  const path = require('path');
11
11
 
12
12
  const { parseSimpleYaml } = require('./intent');
13
+ const { read, write } = require('./sync-fs');
13
14
 
14
15
  const LOG_PATH = '.godpowers/surface/ROUTE-QUALITY-SYNC.md';
15
16
  const CONTEXTUAL_NEXT_VALUES = new Set([
@@ -100,18 +101,6 @@ const TIER_GATE_COMMANDS = new Set([
100
101
  '/god-harden'
101
102
  ]);
102
103
 
103
- function read(projectRoot, relPath) {
104
- const file = path.join(projectRoot, relPath);
105
- if (!fs.existsSync(file)) return '';
106
- return fs.readFileSync(file, 'utf8');
107
- }
108
-
109
- function write(projectRoot, relPath, content) {
110
- const file = path.join(projectRoot, relPath);
111
- fs.mkdirSync(path.dirname(file), { recursive: true });
112
- fs.writeFileSync(file, content);
113
- }
114
-
115
104
  function listFiles(projectRoot, relDir, pattern) {
116
105
  const dir = path.join(projectRoot, relDir);
117
106
  if (!fs.existsSync(dir)) return [];
package/lib/state.js CHANGED
@@ -53,10 +53,26 @@ const SUBSTEP_LABELS = {
53
53
  * @property {number} ordinal One-based step position.
54
54
  */
55
55
 
56
+ // Canonical project-relative location of the state file. Other modules that
57
+ // need to name state.json (gates, dispatch findings, audits) import this rather
58
+ // than re-typing the literal (ARC-002).
59
+ const STATE_FILE = '.godpowers/state.json';
60
+
56
61
  function statePath(projectRoot) {
57
62
  return path.join(projectRoot, '.godpowers', 'state.json');
58
63
  }
59
64
 
65
+ // A typed error so callers (e.g. the CLI dispatcher) can detect corrupt state
66
+ // by `err.code === 'CORRUPT_STATE'` instead of matching the message prose.
67
+ function corruptStateError(file, cause) {
68
+ const err = new Error(
69
+ `Corrupt state file at ${file}: ${cause.message}. ` +
70
+ `Fix the JSON or remove the file to let Godpowers reinitialize it.`
71
+ );
72
+ err.code = 'CORRUPT_STATE';
73
+ return err;
74
+ }
75
+
60
76
  function tierNumber(tierKey) {
61
77
  const match = String(tierKey).match(/^tier-(\d+)$/);
62
78
  return match ? Number(match[1]) : Number.MAX_SAFE_INTEGER;
@@ -88,10 +104,7 @@ function read(projectRoot) {
88
104
  try {
89
105
  return JSON.parse(raw);
90
106
  } catch (e) {
91
- throw new Error(
92
- `Corrupt state file at ${file}: ${e.message}. ` +
93
- `Fix the JSON or remove the file to let Godpowers reinitialize it.`
94
- );
107
+ throw corruptStateError(file, e);
95
108
  }
96
109
  }
97
110
 
@@ -144,10 +157,7 @@ async function readAsync(projectRoot) {
144
157
  try {
145
158
  return JSON.parse(raw);
146
159
  } catch (e) {
147
- throw new Error(
148
- `Corrupt state file at ${file}: ${e.message}. ` +
149
- `Fix the JSON or remove the file to let Godpowers reinitialize it.`
150
- );
160
+ throw corruptStateError(file, e);
151
161
  }
152
162
  }
153
163
 
@@ -421,6 +431,7 @@ module.exports = {
421
431
  updateSubStepAsync,
422
432
  hashFile,
423
433
  detectDrift,
434
+ STATE_FILE,
424
435
  statePath,
425
436
  isInitialized,
426
437
  isInitializedState,
package/lib/sync-fs.js ADDED
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Shared filesystem helpers for the lib/*-sync.js family.
3
+ *
4
+ * Every sync module used to redefine its own byte-identical read/write/exists/
5
+ * readJson against a project root (ARC-001). They now share these so a change
6
+ * to path handling or read semantics lives in one place. Module-specific log
7
+ * writers (appendLog) stay per-module because their headers and formats differ.
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+
13
+ function read(projectRoot, relPath) {
14
+ const file = path.join(projectRoot, relPath);
15
+ if (!fs.existsSync(file)) return '';
16
+ return fs.readFileSync(file, 'utf8');
17
+ }
18
+
19
+ function write(projectRoot, relPath, content) {
20
+ const file = path.join(projectRoot, relPath);
21
+ fs.mkdirSync(path.dirname(file), { recursive: true });
22
+ fs.writeFileSync(file, content);
23
+ }
24
+
25
+ function exists(projectRoot, relPath) {
26
+ return fs.existsSync(path.join(projectRoot, relPath));
27
+ }
28
+
29
+ function readJson(projectRoot, relPath) {
30
+ try {
31
+ return JSON.parse(read(projectRoot, relPath));
32
+ } catch (err) {
33
+ return null;
34
+ }
35
+ }
36
+
37
+ module.exports = { read, write, exists, readJson };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Small shared string helpers (QUAL-002).
3
+ *
4
+ * slugify is the canonical home for the "lowercase, collapse non-alphanumerics
5
+ * to '-', strip edge '-', truncate to 40 chars" contract. lib/evidence.js keeps
6
+ * its own copy on purpose: that module is vendored from the upstream engine and
7
+ * its helpers are provenance-tracked, so it must not import first-party code.
8
+ */
9
+
10
+ function slugify(text, fallback = '') {
11
+ const slug = String(text == null ? '' : text)
12
+ .toLowerCase()
13
+ .replace(/[^a-z0-9]+/g, '-')
14
+ .replace(/^-+|-+$/g, '')
15
+ .slice(0, 40);
16
+ return slug || fallback;
17
+ }
18
+
19
+ module.exports = { slugify };
@@ -6,6 +6,10 @@
6
6
  */
7
7
 
8
8
  const HELPER_GROUPS = {
9
+ 'context-bootstrap': [
10
+ 'pillars-detect',
11
+ 'pillars-init'
12
+ ],
9
13
  'standard-closeout': [
10
14
  'repo-doc-sync',
11
15
  'repo-surface-sync',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "godpowers",
3
- "version": "3.13.0",
3
+ "version": "3.13.1",
4
4
  "description": "AI-powered development system: 120 slash commands and 40 specialist agents that take a project from raw idea to hardened production. Runs inside Claude Code, Codex, Cursor, Windsurf, Gemini, and 10+ other AI coding tools.",
5
5
  "bin": {
6
6
  "godpowers": "./bin/install.js"
@@ -24,7 +24,7 @@
24
24
  "test:e2e": "node tests/integration/full-arc.test.js",
25
25
  "test:mcp": "npm --workspace @godpowers/mcp test",
26
26
  "coverage": "c8 --reporter=text --reporter=lcov node scripts/run-tests.js",
27
- "coverage:lib": "c8 --include=lib/**/*.js --check-coverage --lines 90 --reporter=text node scripts/run-tests.js",
27
+ "coverage:lib": "c8 --include=lib/**/*.js --check-coverage --lines 90 --branches 75 --reporter=text node scripts/run-tests.js",
28
28
  "test:audit": "npm audit --omit=dev && git diff --check && npm run test:surface",
29
29
  "pack:check": "node scripts/check-package-contents.js",
30
30
  "pack:mcp:check": "npm --workspace @godpowers/mcp run pack:check",
@@ -115,6 +115,13 @@ This converts existing Godpowers artifacts into managed source references in
115
115
  the relevant pillar files, so old projects are Pillar-ized as part of being
116
116
  Godpower-ized.
117
117
 
118
+ In the greenfield `full-arc` workflow this start-of-arc step is surfaced as the
119
+ tier-0 `context` job, whose `context-bootstrap` helper group expands to
120
+ `pillars-detect` (`lib/pillars.detect`) and `pillars-init` (`lib/pillars.init`).
121
+ The job uses `god-orchestrator` as a local runtime call, not a `god-context-writer`
122
+ spawn, so it changes nothing about the behavior described above; it only makes the
123
+ init visible in `/god-mode --plan` alongside the closeout `pillars-sync-plan`.
124
+
118
125
  Before each major command, compute the task-specific Pillars load set with
119
126
  `lib/pillars.computeLoadSet(projectRoot, taskText)`. Load `agents/context.md`
120
127
  and `agents/repo.md` first, then the routed primary pillars and their direct
@@ -3,6 +3,15 @@
3
3
  # the agents in the order this file specifies. To preview without running,
4
4
  # use `/god-mode --workflow=<name> --plan`.
5
5
  #
6
+ # Native Pillars context (AGENTS.md + agents/context.md + agents/repo.md) is
7
+ # woven through this arc by the orchestrator's local runtime, not a specialist
8
+ # agent. It is now visible at both ends: the tier-0 `context` preamble runs
9
+ # context-bootstrap (lib/pillars.detect then lib/pillars.init) so a greenfield
10
+ # project is Pillar-ized before planning, and the `final-sync` standard-closeout
11
+ # runs pillars-sync-plan (lib/pillars.planArtifactSync) so the pillars reflect
12
+ # the artifacts the arc produced. Both are local runtime calls; see
13
+ # references/orchestration/GOD-ORCHESTRATOR-RUNBOOK.md "Native Pillars context".
14
+ #
6
15
  apiVersion: godpowers/v1
7
16
  kind: Workflow
8
17
  metadata:
@@ -15,8 +24,17 @@ metadata:
15
24
  on: [/god-mode]
16
25
 
17
26
  jobs:
27
+ context:
28
+ tier: 0
29
+ uses: god-orchestrator@^1.0.0
30
+ local-helper-groups:
31
+ - context-bootstrap
32
+ with:
33
+ action: pillars-bootstrap
34
+
18
35
  prd:
19
36
  tier: 1
37
+ needs: context
20
38
  uses: god-pm@^1.0.0
21
39
  with:
22
40
  template: PRD.md