gsdd-cli 0.18.5 → 0.19.0
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/LICENSE +21 -21
- package/README.md +609 -608
- package/agents/DISTILLATION.md +421 -421
- package/agents/README.md +62 -62
- package/agents/approach-explorer.md +361 -361
- package/agents/debugger.md +82 -82
- package/agents/executor.md +394 -394
- package/agents/integration-checker.md +318 -318
- package/agents/mapper.md +103 -103
- package/agents/planner.md +313 -313
- package/agents/researcher.md +84 -84
- package/agents/roadmapper.md +296 -296
- package/agents/synthesizer.md +236 -236
- package/agents/verifier.md +337 -337
- package/bin/adapters/agents.mjs +34 -34
- package/bin/adapters/claude.mjs +191 -191
- package/bin/adapters/codex.mjs +85 -85
- package/bin/adapters/index.mjs +20 -20
- package/bin/adapters/opencode.mjs +278 -278
- package/bin/gsdd.mjs +123 -116
- package/bin/lib/cli-utils.mjs +28 -28
- package/bin/lib/evidence-contract.mjs +112 -112
- package/bin/lib/file-ops.mjs +186 -144
- package/bin/lib/health-truth.mjs +181 -178
- package/bin/lib/health.mjs +246 -226
- package/bin/lib/init-flow.mjs +247 -231
- package/bin/lib/init-prompts.mjs +248 -247
- package/bin/lib/init-runtime.mjs +191 -190
- package/bin/lib/init.mjs +17 -17
- package/bin/lib/lifecycle-preflight.mjs +347 -325
- package/bin/lib/lifecycle-state.mjs +351 -267
- package/bin/lib/manifest.mjs +116 -114
- package/bin/lib/models.mjs +411 -411
- package/bin/lib/phase.mjs +360 -358
- package/bin/lib/plan-constants.mjs +30 -30
- package/bin/lib/provenance.mjs +109 -106
- package/bin/lib/rendering.mjs +115 -83
- package/bin/lib/runtime-freshness.mjs +214 -214
- package/bin/lib/templates.mjs +225 -224
- package/bin/lib/workspace-root.mjs +2 -1
- package/distilled/DESIGN.md +2333 -2323
- package/distilled/EVIDENCE-INDEX.md +394 -392
- package/distilled/README.md +196 -193
- package/distilled/SKILL.md +86 -85
- package/distilled/templates/agents.block.md +21 -21
- package/distilled/templates/agents.md +6 -6
- package/distilled/templates/approach.md +232 -232
- package/distilled/templates/auth-matrix.md +78 -78
- package/distilled/templates/brownfield-change/CHANGE.md +99 -0
- package/distilled/templates/brownfield-change/HANDOFF.md +38 -0
- package/distilled/templates/brownfield-change/VERIFICATION.md +56 -0
- package/distilled/templates/codebase/architecture.md +110 -110
- package/distilled/templates/codebase/concerns.md +95 -95
- package/distilled/templates/codebase/conventions.md +193 -193
- package/distilled/templates/codebase/stack.md +96 -96
- package/distilled/templates/delegates/approach-explorer.md +25 -25
- package/distilled/templates/delegates/mapper-arch.md +26 -26
- package/distilled/templates/delegates/mapper-concerns.md +27 -27
- package/distilled/templates/delegates/mapper-quality.md +28 -28
- package/distilled/templates/delegates/mapper-tech.md +25 -25
- package/distilled/templates/delegates/plan-checker.md +68 -68
- package/distilled/templates/delegates/researcher-architecture.md +30 -30
- package/distilled/templates/delegates/researcher-features.md +30 -30
- package/distilled/templates/delegates/researcher-pitfalls.md +30 -30
- package/distilled/templates/delegates/researcher-stack.md +30 -30
- package/distilled/templates/delegates/researcher-synthesizer.md +31 -31
- package/distilled/templates/research/architecture.md +57 -57
- package/distilled/templates/research/features.md +23 -23
- package/distilled/templates/research/pitfalls.md +46 -46
- package/distilled/templates/research/stack.md +45 -45
- package/distilled/templates/research/summary.md +67 -67
- package/distilled/templates/roadmap.md +74 -62
- package/distilled/templates/spec.md +110 -110
- package/distilled/workflows/audit-milestone.md +275 -271
- package/distilled/workflows/complete-milestone.md +336 -332
- package/distilled/workflows/execute.md +454 -449
- package/distilled/workflows/map-codebase.md +253 -253
- package/distilled/workflows/new-milestone.md +242 -238
- package/distilled/workflows/new-project.md +398 -398
- package/distilled/workflows/pause.md +160 -156
- package/distilled/workflows/plan-milestone-gaps.md +183 -183
- package/distilled/workflows/plan.md +451 -447
- package/distilled/workflows/progress.md +227 -223
- package/distilled/workflows/quick.md +351 -347
- package/distilled/workflows/resume.md +220 -212
- package/distilled/workflows/verify-work.md +260 -260
- package/distilled/workflows/verify.md +431 -429
- package/docs/BROWNFIELD-PROOF.md +95 -95
- package/docs/RUNTIME-SUPPORT.md +80 -69
- package/docs/USER-GUIDE.md +394 -386
- package/docs/VERIFICATION-DISCIPLINE.md +59 -59
- package/docs/claude/context-monitor.md +98 -98
- package/docs/proof/consumer-node-cli/README.md +37 -37
- package/docs/proof/consumer-node-cli/ROADMAP.md +14 -14
- package/docs/proof/consumer-node-cli/SPEC.md +17 -17
- package/docs/proof/consumer-node-cli/brief.md +9 -9
- package/docs/proof/consumer-node-cli/phases/01-foundation/01-01-PLAN.md +34 -34
- package/docs/proof/consumer-node-cli/phases/01-foundation/01-01-SUMMARY.md +10 -10
- package/docs/proof/consumer-node-cli/phases/01-foundation/01-VERIFICATION.md +30 -30
- package/package.json +62 -61
package/bin/lib/file-ops.mjs
CHANGED
|
@@ -1,139 +1,181 @@
|
|
|
1
|
-
import { cpSync, existsSync, mkdirSync, readFileSync, statSync, unlinkSync, writeFileSync } from 'fs';
|
|
1
|
+
import { cpSync, existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, statSync, unlinkSync, writeFileSync } from 'fs';
|
|
2
2
|
import { dirname, isAbsolute, relative, resolve } from 'path';
|
|
3
3
|
import { output, parseFlagValue } from './cli-utils.mjs';
|
|
4
4
|
import { resolveWorkspaceContext } from './workspace-root.mjs';
|
|
5
|
-
|
|
6
|
-
class FileOpError extends Error {}
|
|
7
|
-
|
|
8
|
-
function fail(message) {
|
|
9
|
-
console.error(message);
|
|
10
|
-
throw new FileOpError(message);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function resolveWorkspacePath(cwd, target) {
|
|
14
|
-
const workspaceRoot = resolve(cwd);
|
|
15
|
-
const resolved = resolve(workspaceRoot, target);
|
|
16
|
-
const rel = relative(workspaceRoot, resolved);
|
|
17
|
-
|
|
18
|
-
if (rel === '' || (!rel.startsWith('..') && !isAbsolute(rel))) {
|
|
19
|
-
return resolved;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
fail(`Path must stay inside the workspace: ${target}`);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (!
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
5
|
+
|
|
6
|
+
class FileOpError extends Error {}
|
|
7
|
+
|
|
8
|
+
function fail(message) {
|
|
9
|
+
console.error(message);
|
|
10
|
+
throw new FileOpError(message);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function resolveWorkspacePath(cwd, target) {
|
|
14
|
+
const workspaceRoot = resolve(cwd);
|
|
15
|
+
const resolved = resolve(workspaceRoot, target);
|
|
16
|
+
const rel = relative(workspaceRoot, resolved);
|
|
17
|
+
|
|
18
|
+
if (rel === '' || (!rel.startsWith('..') && !isAbsolute(rel))) {
|
|
19
|
+
return resolved;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
fail(`Path must stay inside the workspace: ${target}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function ensureRealPathInsideWorkspace(workspaceRoot, candidate, label) {
|
|
26
|
+
const realWorkspaceRoot = realpathSync(workspaceRoot);
|
|
27
|
+
const realCandidate = realpathSync(candidate);
|
|
28
|
+
const rel = relative(realWorkspaceRoot, realCandidate);
|
|
29
|
+
if (rel === '' || (!rel.startsWith('..') && !isAbsolute(rel))) {
|
|
30
|
+
return realCandidate;
|
|
31
|
+
}
|
|
32
|
+
fail(`${label} must stay inside the workspace: ${candidate}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function ensureExistingFilePathInsideWorkspace(workspaceRoot, candidate, label) {
|
|
36
|
+
const stats = lstatSync(candidate);
|
|
37
|
+
if (stats.isSymbolicLink()) {
|
|
38
|
+
fail(`${label} cannot be a symlink: ${candidate}`);
|
|
39
|
+
}
|
|
40
|
+
return ensureRealPathInsideWorkspace(workspaceRoot, candidate, label);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function ensureParentPathInsideWorkspace(workspaceRoot, candidate, label) {
|
|
44
|
+
let current = dirname(candidate);
|
|
45
|
+
while (!existsSync(current)) {
|
|
46
|
+
const parent = dirname(current);
|
|
47
|
+
if (parent === current) {
|
|
48
|
+
fail(`${label} must stay inside the workspace: ${candidate}`);
|
|
49
|
+
}
|
|
50
|
+
current = parent;
|
|
51
|
+
}
|
|
52
|
+
ensureExistingFilePathInsideWorkspace(workspaceRoot, current, label);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getMissingBehavior(args) {
|
|
56
|
+
const parsed = parseFlagValue(args, '--missing');
|
|
57
|
+
if (!parsed.present) return 'error';
|
|
58
|
+
if (parsed.invalid) fail('Usage: --missing <error|ok>');
|
|
59
|
+
if (!['error', 'ok'].includes(parsed.value)) fail('Usage: --missing <error|ok>');
|
|
60
|
+
return parsed.value;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function cmdCopy(cwd, args) {
|
|
64
|
+
const [sourceArg, destinationArg, ...flags] = args;
|
|
65
|
+
if (!sourceArg || !destinationArg) {
|
|
66
|
+
fail('Usage: gsdd file-op copy <source> <destination> [--missing <error|ok>]');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const missingBehavior = getMissingBehavior(flags);
|
|
70
|
+
const workspaceRoot = resolve(cwd);
|
|
71
|
+
const source = resolveWorkspacePath(cwd, sourceArg);
|
|
72
|
+
const destination = resolveWorkspacePath(cwd, destinationArg);
|
|
73
|
+
|
|
74
|
+
if (!existsSync(source)) {
|
|
75
|
+
if (missingBehavior === 'ok') {
|
|
76
|
+
output({ operation: 'copy', source: sourceArg, destination: destinationArg, changed: false, reason: 'missing_source' });
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
fail(`Source file does not exist: ${sourceArg}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (statSync(source).isDirectory()) {
|
|
83
|
+
fail(`Copy only supports files in this phase: ${sourceArg}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
ensureExistingFilePathInsideWorkspace(workspaceRoot, source, 'Source path');
|
|
87
|
+
if (existsSync(destination)) {
|
|
88
|
+
ensureExistingFilePathInsideWorkspace(workspaceRoot, destination, 'Destination path');
|
|
89
|
+
}
|
|
90
|
+
ensureParentPathInsideWorkspace(workspaceRoot, destination, 'Destination path');
|
|
91
|
+
|
|
92
|
+
mkdirSync(dirname(destination), { recursive: true });
|
|
93
|
+
cpSync(source, destination, { force: true });
|
|
94
|
+
output({ operation: 'copy', source: sourceArg, destination: destinationArg, changed: true });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function cmdDelete(cwd, args) {
|
|
98
|
+
const [targetArg, ...flags] = args;
|
|
99
|
+
if (!targetArg) {
|
|
100
|
+
fail('Usage: gsdd file-op delete <target> [--missing <error|ok>]');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const missingBehavior = getMissingBehavior(flags);
|
|
104
|
+
const workspaceRoot = resolve(cwd);
|
|
105
|
+
const target = resolveWorkspacePath(cwd, targetArg);
|
|
106
|
+
|
|
107
|
+
if (!existsSync(target)) {
|
|
108
|
+
if (missingBehavior === 'ok') {
|
|
109
|
+
output({ operation: 'delete', target: targetArg, changed: false, reason: 'missing_target' });
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
fail(`Target file does not exist: ${targetArg}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (statSync(target).isDirectory()) {
|
|
116
|
+
fail(`Delete only supports files in this phase: ${targetArg}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
ensureExistingFilePathInsideWorkspace(workspaceRoot, target, 'Target path');
|
|
120
|
+
unlinkSync(target);
|
|
121
|
+
output({ operation: 'delete', target: targetArg, changed: true });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function cmdRegexSub(cwd, args) {
|
|
125
|
+
const [targetArg, pattern, replacement, ...flags] = args;
|
|
126
|
+
if (!targetArg || pattern === undefined || replacement === undefined) {
|
|
127
|
+
fail('Usage: gsdd file-op regex-sub <target> <pattern> <replacement> [--flags <flags>] [--missing <error|ok>]');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const regexFlags = parseFlagValue(flags, '--flags');
|
|
131
|
+
if (regexFlags.present && regexFlags.invalid) {
|
|
132
|
+
fail('Usage: --flags <regex-flags>');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const missingBehavior = getMissingBehavior(flags);
|
|
136
|
+
const workspaceRoot = resolve(cwd);
|
|
137
|
+
const target = resolveWorkspacePath(cwd, targetArg);
|
|
138
|
+
|
|
139
|
+
if (!existsSync(target)) {
|
|
140
|
+
if (missingBehavior === 'ok') {
|
|
141
|
+
output({ operation: 'regex-sub', target: targetArg, changed: false, reason: 'missing_target' });
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
fail(`Target file does not exist: ${targetArg}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (statSync(target).isDirectory()) {
|
|
148
|
+
fail(`regex-sub only supports files in this phase: ${targetArg}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
ensureExistingFilePathInsideWorkspace(workspaceRoot, target, 'Target path');
|
|
152
|
+
|
|
153
|
+
let regex;
|
|
154
|
+
try {
|
|
155
|
+
regex = new RegExp(pattern, regexFlags.value || 'g');
|
|
156
|
+
} catch (error) {
|
|
157
|
+
fail(`Invalid regex pattern: ${error.message}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const source = readFileSync(target, 'utf-8');
|
|
161
|
+
let replacementCount = 0;
|
|
162
|
+
if (regex.global) {
|
|
163
|
+
const matches = source.match(regex);
|
|
164
|
+
replacementCount = matches ? matches.length : 0;
|
|
165
|
+
} else {
|
|
166
|
+
replacementCount = regex.test(source) ? 1 : 0;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (replacementCount === 0) {
|
|
170
|
+
fail(`Pattern did not match any text in ${targetArg}`);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const updated = source.replace(regex, replacement);
|
|
174
|
+
const changed = updated !== source;
|
|
175
|
+
writeFileSync(target, updated);
|
|
176
|
+
output({ operation: 'regex-sub', target: targetArg, changed, replacements: replacementCount });
|
|
177
|
+
}
|
|
178
|
+
|
|
137
179
|
export function cmdFileOp(...args) {
|
|
138
180
|
const { args: normalizedArgs, workspaceRoot, invalid, error } = resolveWorkspaceContext(args);
|
|
139
181
|
if (invalid) {
|
|
@@ -154,14 +196,14 @@ export function cmdFileOp(...args) {
|
|
|
154
196
|
case 'regex-sub':
|
|
155
197
|
cmdRegexSub(workspaceRoot, rest);
|
|
156
198
|
return;
|
|
157
|
-
default:
|
|
158
|
-
fail('Usage: gsdd file-op <copy|delete|regex-sub> ...');
|
|
159
|
-
}
|
|
160
|
-
} catch (error) {
|
|
161
|
-
if (error instanceof FileOpError) {
|
|
162
|
-
process.exitCode = 1;
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
throw error;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
199
|
+
default:
|
|
200
|
+
fail('Usage: gsdd file-op <copy|delete|regex-sub> ...');
|
|
201
|
+
}
|
|
202
|
+
} catch (error) {
|
|
203
|
+
if (error instanceof FileOpError) {
|
|
204
|
+
process.exitCode = 1;
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
}
|