@ktpartners/dgs-platform 2.7.1 → 2.7.3
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/commands/dgs/capture-principle.md +1 -1
- package/deliver-great-systems/bin/dgs-tools.cjs +2 -1
- package/deliver-great-systems/bin/lib/commands.cjs +22 -1
- package/deliver-great-systems/bin/lib/commands.test.cjs +325 -0
- package/deliver-great-systems/bin/lib/init.cjs +76 -1
- package/deliver-great-systems/bin/lib/init.test.cjs +173 -0
- package/deliver-great-systems/workflows/add-idea.md +1 -1
- package/deliver-great-systems/workflows/add-todo.md +1 -1
- package/deliver-great-systems/workflows/approve-spec.md +1 -1
- package/deliver-great-systems/workflows/audit-phase.md +1 -1
- package/deliver-great-systems/workflows/complete-milestone.md +1 -1
- package/deliver-great-systems/workflows/execute-phase.md +3 -1
- package/deliver-great-systems/workflows/import-spec.md +1 -1
- package/deliver-great-systems/workflows/new-milestone.md +5 -5
- package/deliver-great-systems/workflows/new-project.md +4 -4
- package/deliver-great-systems/workflows/plan-phase.md +1 -1
- package/deliver-great-systems/workflows/quick.md +1 -1
- package/deliver-great-systems/workflows/refine-spec.md +1 -1
- package/deliver-great-systems/workflows/update-idea.md +2 -2
- package/deliver-great-systems/workflows/verify-work.md +3 -3
- package/deliver-great-systems/workflows/write-spec.md +3 -3
- package/package.json +1 -1
|
@@ -124,7 +124,7 @@ Use today's date for the `Added` field.
|
|
|
124
124
|
|
|
125
125
|
If `commit_docs` is true:
|
|
126
126
|
```bash
|
|
127
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "docs: capture design principle - {title}" --files .planning/docs/product/DESIGN-PRINCIPLES.md
|
|
127
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "docs: capture design principle - {title}" --push --files .planning/docs/product/DESIGN-PRINCIPLES.md
|
|
128
128
|
```
|
|
129
129
|
|
|
130
130
|
If `commit_docs` is false, just save the file without committing.
|
|
@@ -699,6 +699,7 @@ async function main() {
|
|
|
699
699
|
|
|
700
700
|
// Existing single-repo commit logic
|
|
701
701
|
const amend = args.includes('--amend');
|
|
702
|
+
const push = args.includes('--push');
|
|
702
703
|
const message = args[1];
|
|
703
704
|
// Parse --files flag (collect args after --files, stopping at other flags)
|
|
704
705
|
const filesIndex = args.indexOf('--files');
|
|
@@ -706,7 +707,7 @@ async function main() {
|
|
|
706
707
|
// Parse --phase-dir flag (available for context, passed through if supported)
|
|
707
708
|
const phaseDirIdx = args.indexOf('--phase-dir');
|
|
708
709
|
const phaseDir = phaseDirIdx !== -1 ? args[phaseDirIdx + 1] : null;
|
|
709
|
-
commands.cmdCommit(cwd, message, files, raw, amend);
|
|
710
|
+
commands.cmdCommit(cwd, message, files, raw, amend, push);
|
|
710
711
|
break;
|
|
711
712
|
}
|
|
712
713
|
|
|
@@ -214,7 +214,7 @@ function cmdResolveModel(cwd, agentType, raw) {
|
|
|
214
214
|
output(result, raw, model);
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
-
function cmdCommit(cwd, message, files, raw, amend) {
|
|
217
|
+
function cmdCommit(cwd, message, files, raw, amend, push) {
|
|
218
218
|
if (!message && !amend) {
|
|
219
219
|
error('commit message required');
|
|
220
220
|
}
|
|
@@ -259,6 +259,27 @@ function cmdCommit(cwd, message, files, raw, amend) {
|
|
|
259
259
|
const hashResult = execGit(cwd, ['rev-parse', '--short', 'HEAD']);
|
|
260
260
|
const hash = hashResult.exitCode === 0 ? hashResult.stdout : null;
|
|
261
261
|
const result = { committed: true, hash, reason: 'committed' };
|
|
262
|
+
|
|
263
|
+
// Handle push if requested
|
|
264
|
+
if (push) {
|
|
265
|
+
const syncPush = config.sync_push || 'off';
|
|
266
|
+
|
|
267
|
+
if (syncPush === 'auto') {
|
|
268
|
+
try {
|
|
269
|
+
const { pushAll } = require('./sync.cjs');
|
|
270
|
+
const pushResult = pushAll(cwd, { force: true });
|
|
271
|
+
result.pushed = pushResult.ok;
|
|
272
|
+
result.push_result = pushResult;
|
|
273
|
+
} catch (err) {
|
|
274
|
+
result.pushed = false;
|
|
275
|
+
result.push_result = { ok: false, error: err.message };
|
|
276
|
+
}
|
|
277
|
+
} else if (syncPush === 'prompt') {
|
|
278
|
+
result.needs_push = true;
|
|
279
|
+
}
|
|
280
|
+
// 'off' or any other value: no push fields added
|
|
281
|
+
}
|
|
282
|
+
|
|
262
283
|
output(result, raw, hash || 'committed');
|
|
263
284
|
}
|
|
264
285
|
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for commands.cjs — cmdCommit --push behavior
|
|
3
|
+
*
|
|
4
|
+
* Uses Node.js built-in test runner (node:test) and assert (node:assert).
|
|
5
|
+
* Tests use real temp git repos with mocked pushAll to verify push integration.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { describe, it, beforeEach, afterEach } = require('node:test');
|
|
9
|
+
const assert = require('node:assert/strict');
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const { execSync } = require('child_process');
|
|
13
|
+
|
|
14
|
+
const { createTempProject } = require('./test-helpers.cjs');
|
|
15
|
+
|
|
16
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Capture JSON output from cmdCommit by intercepting console.log.
|
|
20
|
+
* cmdCommit calls output() which calls console.log(JSON.stringify(...)).
|
|
21
|
+
*/
|
|
22
|
+
function captureCommitOutput(fn) {
|
|
23
|
+
const logs = [];
|
|
24
|
+
const origLog = console.log;
|
|
25
|
+
console.log = (...args) => logs.push(args.join(' '));
|
|
26
|
+
try {
|
|
27
|
+
fn();
|
|
28
|
+
} finally {
|
|
29
|
+
console.log = origLog;
|
|
30
|
+
}
|
|
31
|
+
// Parse the last JSON output line
|
|
32
|
+
for (let i = logs.length - 1; i >= 0; i--) {
|
|
33
|
+
try {
|
|
34
|
+
return JSON.parse(logs[i]);
|
|
35
|
+
} catch { /* not JSON, skip */ }
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Set up a temp project with git, write a file, and return the fixture.
|
|
42
|
+
*/
|
|
43
|
+
function setupGitFixture(syncPush) {
|
|
44
|
+
const configOverrides = {};
|
|
45
|
+
if (syncPush) {
|
|
46
|
+
configOverrides.git = { sync_push: syncPush };
|
|
47
|
+
}
|
|
48
|
+
const fixture = createTempProject({
|
|
49
|
+
withGit: true,
|
|
50
|
+
withConfig: configOverrides,
|
|
51
|
+
});
|
|
52
|
+
return fixture;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Write a new file and stage it so there's something to commit.
|
|
57
|
+
*/
|
|
58
|
+
function writeAndStageFile(cwd, name, content) {
|
|
59
|
+
const filePath = path.join(cwd, name);
|
|
60
|
+
fs.writeFileSync(filePath, content || `content-${Date.now()}`);
|
|
61
|
+
execSync(`git add "${name}"`, { cwd, stdio: 'pipe' });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Mock pushAll on the sync.cjs module exports.
|
|
66
|
+
* Since cmdCommit does a lazy require('./sync.cjs') and destructures pushAll,
|
|
67
|
+
* we need to replace it on the cached module BEFORE cmdCommit runs.
|
|
68
|
+
*/
|
|
69
|
+
function mockPushAll(mockFn) {
|
|
70
|
+
const syncPath = require.resolve('./sync.cjs');
|
|
71
|
+
const syncModule = require(syncPath);
|
|
72
|
+
const original = syncModule.pushAll;
|
|
73
|
+
syncModule.pushAll = mockFn;
|
|
74
|
+
return () => { syncModule.pushAll = original; };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ─── Tests ────────────────────────────────────────────────────────────────────
|
|
78
|
+
|
|
79
|
+
describe('cmdCommit with push=false (default behavior)', () => {
|
|
80
|
+
let fixture;
|
|
81
|
+
let commands;
|
|
82
|
+
|
|
83
|
+
beforeEach(() => {
|
|
84
|
+
fixture = setupGitFixture('auto');
|
|
85
|
+
commands = require('./commands.cjs');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
afterEach(() => {
|
|
89
|
+
fixture.cleanup();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('commits without push fields when push is false', () => {
|
|
93
|
+
writeAndStageFile(fixture.cwd, 'test-no-push.txt');
|
|
94
|
+
const result = captureCommitOutput(() => {
|
|
95
|
+
commands.cmdCommit(fixture.cwd, 'test commit no push', [], true, false, false);
|
|
96
|
+
});
|
|
97
|
+
assert.equal(result.committed, true);
|
|
98
|
+
assert.ok(result.hash);
|
|
99
|
+
assert.equal(result.reason, 'committed');
|
|
100
|
+
assert.equal(result.pushed, undefined, 'pushed should not be set');
|
|
101
|
+
assert.equal(result.push_result, undefined, 'push_result should not be set');
|
|
102
|
+
assert.equal(result.needs_push, undefined, 'needs_push should not be set');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('commits without push fields when push is undefined', () => {
|
|
106
|
+
writeAndStageFile(fixture.cwd, 'test-no-push-undef.txt');
|
|
107
|
+
const result = captureCommitOutput(() => {
|
|
108
|
+
commands.cmdCommit(fixture.cwd, 'test commit no push undef', [], true, false);
|
|
109
|
+
});
|
|
110
|
+
assert.equal(result.committed, true);
|
|
111
|
+
assert.equal(result.pushed, undefined);
|
|
112
|
+
assert.equal(result.needs_push, undefined);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('cmdCommit with push=true, sync_push=auto, pushAll succeeds', () => {
|
|
117
|
+
let fixture;
|
|
118
|
+
let commands;
|
|
119
|
+
let restorePushAll;
|
|
120
|
+
|
|
121
|
+
beforeEach(() => {
|
|
122
|
+
fixture = setupGitFixture('auto');
|
|
123
|
+
restorePushAll = mockPushAll(() => ({
|
|
124
|
+
ok: true,
|
|
125
|
+
results: [{ repo: 'test', status: 'pushed', commits: 1, message: 'Pushed 1 commit' }],
|
|
126
|
+
summary: '1 pushed',
|
|
127
|
+
}));
|
|
128
|
+
commands = require('./commands.cjs');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
afterEach(() => {
|
|
132
|
+
restorePushAll();
|
|
133
|
+
fixture.cleanup();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('returns pushed=true and push_result with ok=true', () => {
|
|
137
|
+
writeAndStageFile(fixture.cwd, 'test-auto-push-ok.txt');
|
|
138
|
+
const result = captureCommitOutput(() => {
|
|
139
|
+
commands.cmdCommit(fixture.cwd, 'test commit auto push ok', [], true, false, true);
|
|
140
|
+
});
|
|
141
|
+
assert.equal(result.committed, true);
|
|
142
|
+
assert.ok(result.hash);
|
|
143
|
+
assert.equal(result.pushed, true);
|
|
144
|
+
assert.ok(result.push_result);
|
|
145
|
+
assert.equal(result.push_result.ok, true);
|
|
146
|
+
assert.equal(result.needs_push, undefined, 'needs_push should not be set in auto mode');
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe('cmdCommit with push=true, sync_push=auto, pushAll fails', () => {
|
|
151
|
+
let fixture;
|
|
152
|
+
let commands;
|
|
153
|
+
let restorePushAll;
|
|
154
|
+
|
|
155
|
+
beforeEach(() => {
|
|
156
|
+
fixture = setupGitFixture('auto');
|
|
157
|
+
restorePushAll = mockPushAll(() => ({
|
|
158
|
+
ok: false,
|
|
159
|
+
results: [{ repo: 'test', status: 'failed', commits: null, message: 'Push rejected' }],
|
|
160
|
+
summary: '1 failed',
|
|
161
|
+
}));
|
|
162
|
+
commands = require('./commands.cjs');
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
afterEach(() => {
|
|
166
|
+
restorePushAll();
|
|
167
|
+
fixture.cleanup();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('returns committed=true, pushed=false, push_result with ok=false', () => {
|
|
171
|
+
writeAndStageFile(fixture.cwd, 'test-auto-push-fail.txt');
|
|
172
|
+
const result = captureCommitOutput(() => {
|
|
173
|
+
commands.cmdCommit(fixture.cwd, 'test commit auto push fail', [], true, false, true);
|
|
174
|
+
});
|
|
175
|
+
assert.equal(result.committed, true, 'commit must succeed even if push fails');
|
|
176
|
+
assert.ok(result.hash);
|
|
177
|
+
assert.equal(result.pushed, false);
|
|
178
|
+
assert.ok(result.push_result);
|
|
179
|
+
assert.equal(result.push_result.ok, false);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
describe('cmdCommit with push=true, sync_push=auto, pushAll throws', () => {
|
|
184
|
+
let fixture;
|
|
185
|
+
let commands;
|
|
186
|
+
let restorePushAll;
|
|
187
|
+
|
|
188
|
+
beforeEach(() => {
|
|
189
|
+
fixture = setupGitFixture('auto');
|
|
190
|
+
restorePushAll = mockPushAll(() => {
|
|
191
|
+
throw new Error('Network unreachable');
|
|
192
|
+
});
|
|
193
|
+
commands = require('./commands.cjs');
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
afterEach(() => {
|
|
197
|
+
restorePushAll();
|
|
198
|
+
fixture.cleanup();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('returns committed=true, pushed=false, push_result with error message', () => {
|
|
202
|
+
writeAndStageFile(fixture.cwd, 'test-auto-push-throw.txt');
|
|
203
|
+
const result = captureCommitOutput(() => {
|
|
204
|
+
commands.cmdCommit(fixture.cwd, 'test commit auto push throw', [], true, false, true);
|
|
205
|
+
});
|
|
206
|
+
assert.equal(result.committed, true, 'commit must succeed even if pushAll throws');
|
|
207
|
+
assert.ok(result.hash);
|
|
208
|
+
assert.equal(result.pushed, false);
|
|
209
|
+
assert.ok(result.push_result);
|
|
210
|
+
assert.equal(result.push_result.ok, false);
|
|
211
|
+
assert.ok(result.push_result.error.includes('Network unreachable'));
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
describe('cmdCommit with push=true, sync_push=prompt', () => {
|
|
216
|
+
let fixture;
|
|
217
|
+
let commands;
|
|
218
|
+
|
|
219
|
+
beforeEach(() => {
|
|
220
|
+
fixture = setupGitFixture('prompt');
|
|
221
|
+
commands = require('./commands.cjs');
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
afterEach(() => {
|
|
225
|
+
fixture.cleanup();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('returns needs_push=true, no pushed or push_result fields', () => {
|
|
229
|
+
writeAndStageFile(fixture.cwd, 'test-prompt-push.txt');
|
|
230
|
+
const result = captureCommitOutput(() => {
|
|
231
|
+
commands.cmdCommit(fixture.cwd, 'test commit prompt push', [], true, false, true);
|
|
232
|
+
});
|
|
233
|
+
assert.equal(result.committed, true);
|
|
234
|
+
assert.ok(result.hash);
|
|
235
|
+
assert.equal(result.needs_push, true);
|
|
236
|
+
assert.equal(result.pushed, undefined, 'pushed should not be set in prompt mode');
|
|
237
|
+
assert.equal(result.push_result, undefined, 'push_result should not be set in prompt mode');
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
describe('cmdCommit with push=true, sync_push=off', () => {
|
|
242
|
+
let fixture;
|
|
243
|
+
let commands;
|
|
244
|
+
|
|
245
|
+
beforeEach(() => {
|
|
246
|
+
fixture = setupGitFixture('off');
|
|
247
|
+
commands = require('./commands.cjs');
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
afterEach(() => {
|
|
251
|
+
fixture.cleanup();
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('returns no push-related fields (same as push=false)', () => {
|
|
255
|
+
writeAndStageFile(fixture.cwd, 'test-off-push.txt');
|
|
256
|
+
const result = captureCommitOutput(() => {
|
|
257
|
+
commands.cmdCommit(fixture.cwd, 'test commit off push', [], true, false, true);
|
|
258
|
+
});
|
|
259
|
+
assert.equal(result.committed, true);
|
|
260
|
+
assert.ok(result.hash);
|
|
261
|
+
assert.equal(result.pushed, undefined, 'pushed should not be set when sync_push=off');
|
|
262
|
+
assert.equal(result.push_result, undefined, 'push_result should not be set when sync_push=off');
|
|
263
|
+
assert.equal(result.needs_push, undefined, 'needs_push should not be set when sync_push=off');
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
describe('cmdCommit with push=true but nothing to commit', () => {
|
|
268
|
+
let fixture;
|
|
269
|
+
let commands;
|
|
270
|
+
let pushAllCalled;
|
|
271
|
+
let restorePushAll;
|
|
272
|
+
|
|
273
|
+
beforeEach(() => {
|
|
274
|
+
fixture = setupGitFixture('auto');
|
|
275
|
+
pushAllCalled = false;
|
|
276
|
+
restorePushAll = mockPushAll(() => {
|
|
277
|
+
pushAllCalled = true;
|
|
278
|
+
return { ok: true, results: [], summary: '' };
|
|
279
|
+
});
|
|
280
|
+
commands = require('./commands.cjs');
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
afterEach(() => {
|
|
284
|
+
restorePushAll();
|
|
285
|
+
fixture.cleanup();
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it('does not attempt push when commit has nothing to commit', () => {
|
|
289
|
+
// Don't write any new file -- nothing to commit
|
|
290
|
+
const result = captureCommitOutput(() => {
|
|
291
|
+
commands.cmdCommit(fixture.cwd, 'test nothing to commit', [], true, false, true);
|
|
292
|
+
});
|
|
293
|
+
assert.equal(result.committed, false);
|
|
294
|
+
assert.equal(result.reason, 'nothing_to_commit');
|
|
295
|
+
assert.equal(pushAllCalled, false, 'pushAll should not be called when nothing to commit');
|
|
296
|
+
assert.equal(result.pushed, undefined);
|
|
297
|
+
assert.equal(result.needs_push, undefined);
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
describe('cmdCommit with push=true, sync_push unset (defaults to off)', () => {
|
|
302
|
+
let fixture;
|
|
303
|
+
let commands;
|
|
304
|
+
|
|
305
|
+
beforeEach(() => {
|
|
306
|
+
// No sync_push in config -- should default to 'off'
|
|
307
|
+
fixture = setupGitFixture(undefined);
|
|
308
|
+
commands = require('./commands.cjs');
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
afterEach(() => {
|
|
312
|
+
fixture.cleanup();
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('returns no push-related fields when sync_push is not configured', () => {
|
|
316
|
+
writeAndStageFile(fixture.cwd, 'test-unset-push.txt');
|
|
317
|
+
const result = captureCommitOutput(() => {
|
|
318
|
+
commands.cmdCommit(fixture.cwd, 'test commit unset push', [], true, false, true);
|
|
319
|
+
});
|
|
320
|
+
assert.equal(result.committed, true);
|
|
321
|
+
assert.equal(result.pushed, undefined);
|
|
322
|
+
assert.equal(result.push_result, undefined);
|
|
323
|
+
assert.equal(result.needs_push, undefined);
|
|
324
|
+
});
|
|
325
|
+
});
|
|
@@ -9,7 +9,7 @@ const { loadConfig, resolveModelInternal, findPhaseInternal, getRoadmapPhaseInte
|
|
|
9
9
|
const { requireGitIdentity, formatAuthorString } = require('./identity.cjs');
|
|
10
10
|
const { getPlanningRoot, PROJECTS_DIR } = require('./paths.cjs');
|
|
11
11
|
const { parseReposMd, validateReposMdEager } = require('./repos.cjs');
|
|
12
|
-
const { getCadence } = require('./sync.cjs');
|
|
12
|
+
const { getCadence, pullAll } = require('./sync.cjs');
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Safely resolve the current git author string.
|
|
@@ -25,6 +25,67 @@ function resolveAuthorSafe(cwd) {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
// ─── Sync Pull Helper ────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Apply sync pull logic to an init result object.
|
|
32
|
+
*
|
|
33
|
+
* Enriches the result with `needs_pull` and optionally `pull_result` based on
|
|
34
|
+
* the sync_pull config and cadence_pull for this workflow. This moves pull
|
|
35
|
+
* orchestration into init itself so workflows get pull state in their JSON
|
|
36
|
+
* without needing to manually orchestrate sync commands.
|
|
37
|
+
*
|
|
38
|
+
* Modes:
|
|
39
|
+
* - cadence_pull=false OR sync_pull="off": sets needs_pull=false, no pull
|
|
40
|
+
* - sync_pull="prompt": sets needs_pull=true, no pull (workflow prompts user)
|
|
41
|
+
* - sync_pull="auto": executes pullAll, sets needs_pull=false, adds pull_result
|
|
42
|
+
*
|
|
43
|
+
* CRITICAL: Never throws — init must always return its JSON.
|
|
44
|
+
*
|
|
45
|
+
* @param {string} cwd - Working directory
|
|
46
|
+
* @param {string} workflowName - Workflow name for logging
|
|
47
|
+
* @param {Object} result - The init result object to enrich (mutated in place)
|
|
48
|
+
*/
|
|
49
|
+
function applySyncPull(cwd, workflowName, result) {
|
|
50
|
+
const syncPull = result.sync_pull;
|
|
51
|
+
const cadencePull = result.cadence_pull;
|
|
52
|
+
|
|
53
|
+
// No pull: cadence says no, or mode is off
|
|
54
|
+
if (!cadencePull || syncPull === 'off') {
|
|
55
|
+
result.needs_pull = false;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Prompt mode: signal that pull is needed but don't execute
|
|
60
|
+
if (syncPull === 'prompt') {
|
|
61
|
+
result.needs_pull = true;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Auto mode: execute pull immediately
|
|
66
|
+
if (syncPull === 'auto') {
|
|
67
|
+
result.needs_pull = false;
|
|
68
|
+
try {
|
|
69
|
+
const pullResult = pullAll(cwd, { force: true });
|
|
70
|
+
result.pull_result = {
|
|
71
|
+
action: pullResult.ok ? 'pulled' : 'failed',
|
|
72
|
+
ok: pullResult.ok,
|
|
73
|
+
summary: pullResult.summary,
|
|
74
|
+
};
|
|
75
|
+
} catch (err) {
|
|
76
|
+
result.pull_result = {
|
|
77
|
+
action: 'failed',
|
|
78
|
+
ok: false,
|
|
79
|
+
summary: err.message,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Unknown mode: treat as off
|
|
86
|
+
result.needs_pull = false;
|
|
87
|
+
}
|
|
88
|
+
|
|
28
89
|
// ─── v2 Project Context Resolution ──────────────────────────────────────────
|
|
29
90
|
|
|
30
91
|
/**
|
|
@@ -232,6 +293,7 @@ function cmdInitExecutePhase(cwd, phase, raw) {
|
|
|
232
293
|
v2_hint: ctx.v2_hint || null,
|
|
233
294
|
};
|
|
234
295
|
|
|
296
|
+
applySyncPull(cwd, 'execute-phase', result);
|
|
235
297
|
output(result, raw);
|
|
236
298
|
}
|
|
237
299
|
|
|
@@ -327,6 +389,7 @@ function cmdInitPlanPhase(cwd, phase, raw) {
|
|
|
327
389
|
} catch {}
|
|
328
390
|
}
|
|
329
391
|
|
|
392
|
+
applySyncPull(cwd, 'plan-phase', result);
|
|
330
393
|
output(result, raw);
|
|
331
394
|
}
|
|
332
395
|
|
|
@@ -406,6 +469,7 @@ function cmdInitNewProject(cwd, raw) {
|
|
|
406
469
|
v2_hint: ctx.v2_hint || null,
|
|
407
470
|
};
|
|
408
471
|
|
|
472
|
+
applySyncPull(cwd, 'new-project', result);
|
|
409
473
|
output(result, raw);
|
|
410
474
|
}
|
|
411
475
|
|
|
@@ -454,6 +518,7 @@ function cmdInitNewMilestone(cwd, raw) {
|
|
|
454
518
|
v2_hint: ctx.v2_hint || null,
|
|
455
519
|
};
|
|
456
520
|
|
|
521
|
+
applySyncPull(cwd, 'new-milestone', result);
|
|
457
522
|
output(result, raw);
|
|
458
523
|
}
|
|
459
524
|
|
|
@@ -521,6 +586,7 @@ function cmdInitQuick(cwd, description, raw) {
|
|
|
521
586
|
v2_hint: ctx.v2_hint || null,
|
|
522
587
|
};
|
|
523
588
|
|
|
589
|
+
applySyncPull(cwd, 'quick', result);
|
|
524
590
|
output(result, raw);
|
|
525
591
|
}
|
|
526
592
|
|
|
@@ -569,6 +635,7 @@ function cmdInitResume(cwd, raw) {
|
|
|
569
635
|
v2_hint: ctx.v2_hint || null,
|
|
570
636
|
};
|
|
571
637
|
|
|
638
|
+
applySyncPull(cwd, 'resume-work', result);
|
|
572
639
|
output(result, raw);
|
|
573
640
|
}
|
|
574
641
|
|
|
@@ -612,6 +679,7 @@ function cmdInitVerifyWork(cwd, phase, raw) {
|
|
|
612
679
|
guard: ctx.guard,
|
|
613
680
|
};
|
|
614
681
|
|
|
682
|
+
applySyncPull(cwd, 'verify-work', result);
|
|
615
683
|
output(result, raw);
|
|
616
684
|
}
|
|
617
685
|
|
|
@@ -655,6 +723,7 @@ function cmdInitAuditPhase(cwd, phase, raw) {
|
|
|
655
723
|
guard: ctx.guard,
|
|
656
724
|
};
|
|
657
725
|
|
|
726
|
+
applySyncPull(cwd, 'audit-phase', result);
|
|
658
727
|
output(result, raw);
|
|
659
728
|
}
|
|
660
729
|
|
|
@@ -755,6 +824,7 @@ function cmdInitPhaseOp(cwd, phase, raw, workflow) {
|
|
|
755
824
|
} catch {}
|
|
756
825
|
}
|
|
757
826
|
|
|
827
|
+
applySyncPull(cwd, workflow || 'plan-phase', result);
|
|
758
828
|
output(result, raw);
|
|
759
829
|
}
|
|
760
830
|
|
|
@@ -834,6 +904,7 @@ function cmdInitTodos(cwd, area, raw, workflow) {
|
|
|
834
904
|
v2_hint: ctx.v2_hint || null,
|
|
835
905
|
};
|
|
836
906
|
|
|
907
|
+
applySyncPull(cwd, workflow || 'check-todos', result);
|
|
837
908
|
output(result, raw);
|
|
838
909
|
}
|
|
839
910
|
|
|
@@ -927,6 +998,7 @@ function cmdInitMilestoneOp(cwd, raw, workflow) {
|
|
|
927
998
|
v2_hint: ctx.v2_hint || null,
|
|
928
999
|
};
|
|
929
1000
|
|
|
1001
|
+
applySyncPull(cwd, workflow || 'complete-milestone', result);
|
|
930
1002
|
output(result, raw);
|
|
931
1003
|
}
|
|
932
1004
|
|
|
@@ -1033,6 +1105,7 @@ function cmdInitMapCodebase(cwd, onlyRepo, raw) {
|
|
|
1033
1105
|
v2_hint: ctx.v2_hint || null,
|
|
1034
1106
|
};
|
|
1035
1107
|
|
|
1108
|
+
applySyncPull(cwd, 'map-codebase', result);
|
|
1036
1109
|
output(result, raw);
|
|
1037
1110
|
}
|
|
1038
1111
|
|
|
@@ -1149,6 +1222,7 @@ function cmdInitProgress(cwd, raw) {
|
|
|
1149
1222
|
v2_hint: ctx.v2_hint || null,
|
|
1150
1223
|
};
|
|
1151
1224
|
|
|
1225
|
+
applySyncPull(cwd, 'progress', result);
|
|
1152
1226
|
output(result, raw);
|
|
1153
1227
|
}
|
|
1154
1228
|
|
|
@@ -1166,4 +1240,5 @@ module.exports = {
|
|
|
1166
1240
|
cmdInitMilestoneOp,
|
|
1167
1241
|
cmdInitMapCodebase,
|
|
1168
1242
|
cmdInitProgress,
|
|
1243
|
+
applySyncPull,
|
|
1169
1244
|
};
|
|
@@ -1210,6 +1210,179 @@ describe('branch_name with {project} resolution', () => {
|
|
|
1210
1210
|
|
|
1211
1211
|
// ─── Backward Compatibility ──────────────────────────────────────────────────
|
|
1212
1212
|
|
|
1213
|
+
// ─── Sync Pull: needs_pull field tests ────────────────────────────────────────
|
|
1214
|
+
|
|
1215
|
+
// Helper: v1 fixture with custom git.sync_pull setting
|
|
1216
|
+
function v1FixtureWithSyncPull(syncPull) {
|
|
1217
|
+
return createFixture({
|
|
1218
|
+
'.planning/config.json': JSON.stringify({ git: { sync_pull: syncPull } }),
|
|
1219
|
+
'.planning/STATE.md': '# State',
|
|
1220
|
+
'.planning/ROADMAP.md': '# Roadmap\n\n## Phases\n\n- [ ] **Phase 1: Test Phase** - A test\n',
|
|
1221
|
+
'.planning/REQUIREMENTS.md': '# Requirements',
|
|
1222
|
+
'.planning/PROJECT.md': '# Project',
|
|
1223
|
+
'.planning/phases/01-test-phase/01-CONTEXT.md': '# Context',
|
|
1224
|
+
'.planning/phases/01-test-phase/01-01-PLAN.md': '---\nphase: 01-test-phase\nplan: 01\n---\n# Plan',
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
describe('init commands include needs_pull field (sync_pull off)', () => {
|
|
1229
|
+
let fixture;
|
|
1230
|
+
|
|
1231
|
+
beforeEach(() => {
|
|
1232
|
+
fixture = v1Fixture();
|
|
1233
|
+
});
|
|
1234
|
+
|
|
1235
|
+
afterEach(() => {
|
|
1236
|
+
fixture.cleanup();
|
|
1237
|
+
});
|
|
1238
|
+
|
|
1239
|
+
it('init execute-phase returns needs_pull false when sync_pull is off', () => {
|
|
1240
|
+
const result = runInit(fixture.cwd, 'execute-phase 1');
|
|
1241
|
+
assert.equal(result.needs_pull, false);
|
|
1242
|
+
});
|
|
1243
|
+
|
|
1244
|
+
it('init plan-phase returns needs_pull false when sync_pull is off', () => {
|
|
1245
|
+
const result = runInit(fixture.cwd, 'plan-phase 1');
|
|
1246
|
+
assert.equal(result.needs_pull, false);
|
|
1247
|
+
});
|
|
1248
|
+
|
|
1249
|
+
it('init quick returns needs_pull false when sync_pull is off', () => {
|
|
1250
|
+
const result = runInit(fixture.cwd, 'quick "test task"');
|
|
1251
|
+
assert.equal(result.needs_pull, false);
|
|
1252
|
+
});
|
|
1253
|
+
|
|
1254
|
+
it('init progress returns needs_pull false when sync_pull is off', () => {
|
|
1255
|
+
const result = runInit(fixture.cwd, 'progress');
|
|
1256
|
+
assert.equal(result.needs_pull, false);
|
|
1257
|
+
});
|
|
1258
|
+
|
|
1259
|
+
it('init new-project returns needs_pull false when sync_pull is off', () => {
|
|
1260
|
+
const result = runInit(fixture.cwd, 'new-project');
|
|
1261
|
+
assert.equal(result.needs_pull, false);
|
|
1262
|
+
});
|
|
1263
|
+
|
|
1264
|
+
it('init resume returns needs_pull false when sync_pull is off', () => {
|
|
1265
|
+
const result = runInit(fixture.cwd, 'resume');
|
|
1266
|
+
assert.equal(result.needs_pull, false);
|
|
1267
|
+
});
|
|
1268
|
+
|
|
1269
|
+
it('init milestone-op returns needs_pull false when sync_pull is off', () => {
|
|
1270
|
+
const result = runInit(fixture.cwd, 'milestone-op');
|
|
1271
|
+
assert.equal(result.needs_pull, false);
|
|
1272
|
+
});
|
|
1273
|
+
|
|
1274
|
+
it('init map-codebase returns needs_pull false when sync_pull is off', () => {
|
|
1275
|
+
const result = runInit(fixture.cwd, 'map-codebase');
|
|
1276
|
+
assert.equal(result.needs_pull, false);
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
it('no pull_result when sync_pull is off', () => {
|
|
1280
|
+
const result = runInit(fixture.cwd, 'execute-phase 1');
|
|
1281
|
+
assert.equal(result.pull_result, undefined);
|
|
1282
|
+
});
|
|
1283
|
+
});
|
|
1284
|
+
|
|
1285
|
+
describe('init with sync_pull prompt returns needs_pull true', () => {
|
|
1286
|
+
let fixture;
|
|
1287
|
+
|
|
1288
|
+
beforeEach(() => {
|
|
1289
|
+
fixture = v1FixtureWithSyncPull('prompt');
|
|
1290
|
+
});
|
|
1291
|
+
|
|
1292
|
+
afterEach(() => {
|
|
1293
|
+
fixture.cleanup();
|
|
1294
|
+
});
|
|
1295
|
+
|
|
1296
|
+
it('init execute-phase returns needs_pull true when sync_pull is prompt and cadence says pull', () => {
|
|
1297
|
+
const result = runInit(fixture.cwd, 'execute-phase 1');
|
|
1298
|
+
assert.equal(result.needs_pull, true);
|
|
1299
|
+
assert.equal(result.pull_result, undefined);
|
|
1300
|
+
});
|
|
1301
|
+
|
|
1302
|
+
it('init plan-phase returns needs_pull true when sync_pull is prompt', () => {
|
|
1303
|
+
const result = runInit(fixture.cwd, 'plan-phase 1');
|
|
1304
|
+
assert.equal(result.needs_pull, true);
|
|
1305
|
+
assert.equal(result.pull_result, undefined);
|
|
1306
|
+
});
|
|
1307
|
+
|
|
1308
|
+
it('init quick returns needs_pull true when sync_pull is prompt', () => {
|
|
1309
|
+
const result = runInit(fixture.cwd, 'quick "test task"');
|
|
1310
|
+
assert.equal(result.needs_pull, true);
|
|
1311
|
+
assert.equal(result.pull_result, undefined);
|
|
1312
|
+
});
|
|
1313
|
+
|
|
1314
|
+
it('init resume returns needs_pull true when sync_pull is prompt (cadence_pull is true for resume-work)', () => {
|
|
1315
|
+
const result = runInit(fixture.cwd, 'resume');
|
|
1316
|
+
assert.equal(result.needs_pull, true);
|
|
1317
|
+
assert.equal(result.pull_result, undefined);
|
|
1318
|
+
});
|
|
1319
|
+
});
|
|
1320
|
+
|
|
1321
|
+
describe('init with sync_pull auto but no remote returns pull_result', () => {
|
|
1322
|
+
let fixture;
|
|
1323
|
+
|
|
1324
|
+
beforeEach(() => {
|
|
1325
|
+
fixture = v1FixtureWithSyncPull('auto');
|
|
1326
|
+
});
|
|
1327
|
+
|
|
1328
|
+
afterEach(() => {
|
|
1329
|
+
fixture.cleanup();
|
|
1330
|
+
});
|
|
1331
|
+
|
|
1332
|
+
it('init execute-phase returns needs_pull false and pull_result when sync_pull is auto', () => {
|
|
1333
|
+
const result = runInit(fixture.cwd, 'execute-phase 1');
|
|
1334
|
+
assert.equal(result.needs_pull, false);
|
|
1335
|
+
assert.ok(result.pull_result, 'pull_result should be an object');
|
|
1336
|
+
assert.ok('action' in result.pull_result, 'pull_result should have action field');
|
|
1337
|
+
assert.ok('ok' in result.pull_result, 'pull_result should have ok field');
|
|
1338
|
+
assert.ok('summary' in result.pull_result, 'pull_result should have summary field');
|
|
1339
|
+
});
|
|
1340
|
+
|
|
1341
|
+
it('pull_result never causes init to throw', () => {
|
|
1342
|
+
// This should not throw even though the fixture has no git remote
|
|
1343
|
+
const result = runInit(fixture.cwd, 'execute-phase 1');
|
|
1344
|
+
assert.ok(result, 'init should return result even when pull has no remote');
|
|
1345
|
+
assert.equal(result.needs_pull, false);
|
|
1346
|
+
});
|
|
1347
|
+
|
|
1348
|
+
it('init plan-phase returns pull_result when sync_pull is auto', () => {
|
|
1349
|
+
const result = runInit(fixture.cwd, 'plan-phase 1');
|
|
1350
|
+
assert.equal(result.needs_pull, false);
|
|
1351
|
+
assert.ok(result.pull_result, 'pull_result should be an object');
|
|
1352
|
+
});
|
|
1353
|
+
});
|
|
1354
|
+
|
|
1355
|
+
describe('init with cadence_pull false skips pull regardless of sync mode', () => {
|
|
1356
|
+
let fixture;
|
|
1357
|
+
|
|
1358
|
+
beforeEach(() => {
|
|
1359
|
+
// map-codebase has cadence { pull: false, push: true }
|
|
1360
|
+
fixture = v1FixtureWithSyncPull('prompt');
|
|
1361
|
+
});
|
|
1362
|
+
|
|
1363
|
+
afterEach(() => {
|
|
1364
|
+
fixture.cleanup();
|
|
1365
|
+
});
|
|
1366
|
+
|
|
1367
|
+
it('init map-codebase returns needs_pull false because cadence_pull is false', () => {
|
|
1368
|
+
const result = runInit(fixture.cwd, 'map-codebase');
|
|
1369
|
+
assert.equal(result.cadence_pull, false, 'map-codebase cadence should have pull: false');
|
|
1370
|
+
assert.equal(result.needs_pull, false);
|
|
1371
|
+
});
|
|
1372
|
+
|
|
1373
|
+
it('init map-codebase returns no pull_result even with sync_pull auto', () => {
|
|
1374
|
+
// Change to auto mode
|
|
1375
|
+
const autoFixture = v1FixtureWithSyncPull('auto');
|
|
1376
|
+
try {
|
|
1377
|
+
const result = runInit(autoFixture.cwd, 'map-codebase');
|
|
1378
|
+
assert.equal(result.needs_pull, false);
|
|
1379
|
+
assert.equal(result.pull_result, undefined, 'No pull_result when cadence_pull is false');
|
|
1380
|
+
} finally {
|
|
1381
|
+
autoFixture.cleanup();
|
|
1382
|
+
}
|
|
1383
|
+
});
|
|
1384
|
+
});
|
|
1385
|
+
|
|
1213
1386
|
describe('backward compatibility: v1 output is superset of old shape', () => {
|
|
1214
1387
|
let fixture;
|
|
1215
1388
|
|
|
@@ -72,7 +72,7 @@ Parse the JSON result to get `id`, `filename`, `path`.
|
|
|
72
72
|
|
|
73
73
|
<step name="git_commit">
|
|
74
74
|
```bash
|
|
75
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "ideas: add #${id} - ${title}" --files ${project_root}/ideas/pending/${filename} ${project_root}/ideas/manifest.json
|
|
75
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "ideas: add #${id} - ${title}" --push --files ${project_root}/ideas/pending/${filename} ${project_root}/ideas/manifest.json
|
|
76
76
|
```
|
|
77
77
|
</step>
|
|
78
78
|
|
|
@@ -123,7 +123,7 @@ If STATE.md exists (use `state_path` from init):
|
|
|
123
123
|
Commit the todo and any updated state:
|
|
124
124
|
|
|
125
125
|
```bash
|
|
126
|
-
node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "docs: capture todo - [title]" --files ${pending_dir}/[filename] ${state_path}
|
|
126
|
+
node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "docs: capture todo - [title]" --push --files ${pending_dir}/[filename] ${state_path}
|
|
127
127
|
```
|
|
128
128
|
|
|
129
129
|
Tool respects `commit_docs` config and gitignore automatically.
|
|
@@ -162,7 +162,7 @@ Perform the approval state transition and audit trail update.
|
|
|
162
162
|
|
|
163
163
|
4. Commit the changes:
|
|
164
164
|
```bash
|
|
165
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: approve $SPEC_ID v$VERSION" --files "$SPEC_FILE_PATH"
|
|
165
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: approve $SPEC_ID v$VERSION" --push --files "$SPEC_FILE_PATH"
|
|
166
166
|
```
|
|
167
167
|
</step>
|
|
168
168
|
|
|
@@ -278,7 +278,7 @@ When `RERUN_FAILED_MODE` is true, the structural verifier also reruns, but only
|
|
|
278
278
|
**Commit the UAT file:**
|
|
279
279
|
|
|
280
280
|
```bash
|
|
281
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "[AUDIT] audit(${PHASE_ARG}): ${test_failures} test failures, ${structural_gaps} structural gaps" --files "${uat_path}" "${log_path}"
|
|
281
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "[AUDIT] audit(${PHASE_ARG}): ${test_failures} test failures, ${structural_gaps} structural gaps" --push --files "${uat_path}" "${log_path}"
|
|
282
282
|
```
|
|
283
283
|
</step>
|
|
284
284
|
|
|
@@ -1211,7 +1211,7 @@ git push origin v[X.Y]
|
|
|
1211
1211
|
Commit milestone completion.
|
|
1212
1212
|
|
|
1213
1213
|
```bash
|
|
1214
|
-
node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "chore: complete v[X.Y] milestone" --files ${project_root}/milestones/v[X.Y]-ROADMAP.md ${project_root}/milestones/v[X.Y]-REQUIREMENTS.md ${project_root}/v[X.Y]-MILESTONE-AUDIT.md ${project_root}/MILESTONES.md ${project_path} ${state_path}
|
|
1214
|
+
node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "chore: complete v[X.Y] milestone" --push --files ${project_root}/milestones/v[X.Y]-ROADMAP.md ${project_root}/milestones/v[X.Y]-REQUIREMENTS.md ${project_root}/v[X.Y]-MILESTONE-AUDIT.md ${project_root}/MILESTONES.md ${project_path} ${state_path}
|
|
1215
1215
|
```
|
|
1216
1216
|
```
|
|
1217
1217
|
|
|
@@ -527,8 +527,10 @@ The CLI handles:
|
|
|
527
527
|
Extract from result: `next_phase`, `next_phase_name`, `is_last_phase`.
|
|
528
528
|
|
|
529
529
|
```bash
|
|
530
|
-
node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "docs(phase-{X}): complete phase execution" --files ${roadmap_path} ${state_path} ${requirements_path} ${phase_dir}/*-VERIFICATION.md
|
|
530
|
+
node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "docs(phase-{X}): complete phase execution" --push --files ${roadmap_path} ${state_path} ${requirements_path} ${phase_dir}/*-VERIFICATION.md
|
|
531
531
|
```
|
|
532
|
+
|
|
533
|
+
Parse the commit result JSON. If `needs_push` is true (sync_push is "prompt" mode), handle push prompting via the existing sync_after step. If `pushed` is true, the push already happened atomically with the commit -- skip the sync_after push for this commit (avoid double-push). If `pushed` is false and `push_result` exists, log the push warning but do not halt.
|
|
532
534
|
</step>
|
|
533
535
|
|
|
534
536
|
<step name="sync_after">
|
|
@@ -264,7 +264,7 @@ Original: will be saved to ${project_root}/{attachment_path}
|
|
|
264
264
|
|
|
265
265
|
**Execute the commit:**
|
|
266
266
|
```bash
|
|
267
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: import {id} - {title} (from {original-filename})" --files ${project_root}/specs/spec-{slug}.md ${project_root}/{attachment_path} ${project_root}/specs/spec-{slug}/docs/INDEX.md ${project_root}/specs/spec-{slug}/docs/.names.json
|
|
267
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: import {id} - {title} (from {original-filename})" --push --files ${project_root}/specs/spec-{slug}.md ${project_root}/{attachment_path} ${project_root}/specs/spec-{slug}/docs/INDEX.md ${project_root}/specs/spec-{slug}/docs/.names.json
|
|
268
268
|
```
|
|
269
269
|
The `dgs-tools.cjs commit` helper with `--files` stages only the specified files and commits them. This ensures other unstaged/uncommitted changes in the working tree are not included. The `.names.json` file is included because `docs add` creates it as internal metadata for INDEX rebuilds.
|
|
270
270
|
|
|
@@ -129,7 +129,7 @@ Last activity: [today] — Milestone v[X.Y] started (from spec [spec-id])
|
|
|
129
129
|
### Commit
|
|
130
130
|
|
|
131
131
|
```bash
|
|
132
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "docs: start milestone v[X.Y] [Name] (from spec)" --files ${project_path} ${state_path}
|
|
132
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "docs: start milestone v[X.Y] [Name] (from spec)" --push --files ${project_path} ${state_path}
|
|
133
133
|
```
|
|
134
134
|
|
|
135
135
|
### Link Spec to Milestone
|
|
@@ -143,7 +143,7 @@ node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs specs link-milestone --id
|
|
|
143
143
|
Include the updated spec file in a commit:
|
|
144
144
|
|
|
145
145
|
```bash
|
|
146
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: link $SPEC_ID to v$VERSION" --files ${project_root}/specs/$SPEC_FILENAME
|
|
146
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: link $SPEC_ID to v$VERSION" --push --files ${project_root}/specs/$SPEC_FILENAME
|
|
147
147
|
```
|
|
148
148
|
|
|
149
149
|
### Continue to Step 7
|
|
@@ -216,7 +216,7 @@ Keep Accumulated Context section from previous milestone.
|
|
|
216
216
|
Delete MILESTONE-CONTEXT.md if exists (consumed).
|
|
217
217
|
|
|
218
218
|
```bash
|
|
219
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "docs: start milestone v[X.Y] [Name]" --files ${project_path} ${state_path}
|
|
219
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "docs: start milestone v[X.Y] [Name]" --push --files ${project_path} ${state_path}
|
|
220
220
|
```
|
|
221
221
|
|
|
222
222
|
## 7. Load Context and Resolve Models
|
|
@@ -406,7 +406,7 @@ If "adjust": Return to scoping.
|
|
|
406
406
|
|
|
407
407
|
**Commit requirements:**
|
|
408
408
|
```bash
|
|
409
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "docs: define milestone v[X.Y] requirements" --files ${project_root}/REQUIREMENTS.md
|
|
409
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "docs: define milestone v[X.Y] requirements" --push --files ${project_root}/REQUIREMENTS.md
|
|
410
410
|
```
|
|
411
411
|
|
|
412
412
|
## 10. Create Roadmap
|
|
@@ -485,7 +485,7 @@ Success criteria:
|
|
|
485
485
|
|
|
486
486
|
**Commit roadmap** (after approval):
|
|
487
487
|
```bash
|
|
488
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "docs: create milestone v[X.Y] roadmap ([N] phases)" --files ${roadmap_path} ${state_path} ${project_root}/REQUIREMENTS.md
|
|
488
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "docs: create milestone v[X.Y] roadmap ([N] phases)" --push --files ${roadmap_path} ${state_path} ${project_root}/REQUIREMENTS.md
|
|
489
489
|
```
|
|
490
490
|
|
|
491
491
|
## 10.5. Overlap Check (v2 only)
|
|
@@ -420,7 +420,7 @@ Do not compress. Capture everything gathered.
|
|
|
420
420
|
|
|
421
421
|
```bash
|
|
422
422
|
mkdir -p .planning
|
|
423
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "docs: initialize project" --files ${project_path}
|
|
423
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "docs: initialize project" --push --files ${project_path}
|
|
424
424
|
```
|
|
425
425
|
|
|
426
426
|
## 5. Resolve Model Profile
|
|
@@ -829,7 +829,7 @@ If "adjust": Return to scoping.
|
|
|
829
829
|
**Commit requirements:**
|
|
830
830
|
|
|
831
831
|
```bash
|
|
832
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "docs: define v1 requirements" --files ${requirements_path}
|
|
832
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "docs: define v1 requirements" --push --files ${requirements_path}
|
|
833
833
|
```
|
|
834
834
|
|
|
835
835
|
## 8. Create Roadmap
|
|
@@ -960,7 +960,7 @@ Use AskUserQuestion:
|
|
|
960
960
|
**Commit roadmap (after approval or auto mode):**
|
|
961
961
|
|
|
962
962
|
```bash
|
|
963
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "docs: create roadmap ([N] phases)" --files ${roadmap_path} ${state_path} ${requirements_path}
|
|
963
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "docs: create roadmap ([N] phases)" --push --files ${roadmap_path} ${state_path} ${requirements_path}
|
|
964
964
|
```
|
|
965
965
|
|
|
966
966
|
### Link Spec to Milestone (spec-driven mode only)
|
|
@@ -974,7 +974,7 @@ node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs specs link-milestone --id
|
|
|
974
974
|
Include the updated spec file in a commit:
|
|
975
975
|
|
|
976
976
|
```bash
|
|
977
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: link $SPEC_ID to v1.0" --files $SPEC_PATH
|
|
977
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: link $SPEC_ID to v1.0" --push --files $SPEC_PATH
|
|
978
978
|
```
|
|
979
979
|
|
|
980
980
|
## 8.5. Overlap Check (v2 only)
|
|
@@ -163,7 +163,7 @@ Use full relative paths. Group by topic area.]
|
|
|
163
163
|
|
|
164
164
|
5. Commit:
|
|
165
165
|
```bash
|
|
166
|
-
node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "docs(${padded_phase}): generate context from PRD" --files "${phase_dir}/${padded_phase}-CONTEXT.md"
|
|
166
|
+
node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "docs(${padded_phase}): generate context from PRD" --push --files "${phase_dir}/${padded_phase}-CONTEXT.md"
|
|
167
167
|
```
|
|
168
168
|
|
|
169
169
|
6. Set `context_content` to the generated CONTEXT.md content and continue to step 5 (Handle Research).
|
|
@@ -776,7 +776,7 @@ Build file list:
|
|
|
776
776
|
- If `$FULL_MODE` and verification file exists: `${QUICK_DIR}/${quick_id}-VERIFICATION.md`
|
|
777
777
|
|
|
778
778
|
```bash
|
|
779
|
-
node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "docs(quick-${quick_id}): ${DESCRIPTION}" --files ${file_list}
|
|
779
|
+
node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "docs(quick-${quick_id}): ${DESCRIPTION}" --push --files ${file_list}
|
|
780
780
|
```
|
|
781
781
|
|
|
782
782
|
Get final commit hash:
|
|
@@ -239,7 +239,7 @@ All writes happen here, atomically at the end of the session. No file changes oc
|
|
|
239
239
|
|
|
240
240
|
10. **Commit the changes:**
|
|
241
241
|
```bash
|
|
242
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "refine(spec): $SPEC_SLUG v$NEW_VERSION -- $SUMMARY" --files "$SPEC_FILE_PATH"
|
|
242
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "refine(spec): $SPEC_SLUG v$NEW_VERSION -- $SUMMARY" --push --files "$SPEC_FILE_PATH"
|
|
243
243
|
```
|
|
244
244
|
</step>
|
|
245
245
|
|
|
@@ -124,12 +124,12 @@ LIST=$(node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs ideas list --raw)
|
|
|
124
124
|
Parse to find the idea's state and filename, then commit:
|
|
125
125
|
|
|
126
126
|
```bash
|
|
127
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "ideas: update #${id} - ${field}" --files ${path}
|
|
127
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "ideas: update #${id} - ${field}" --push --files ${path}
|
|
128
128
|
```
|
|
129
129
|
|
|
130
130
|
For note appends, use:
|
|
131
131
|
```bash
|
|
132
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "ideas: add note to #${id}" --files ${path}
|
|
132
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "ideas: add note to #${id}" --push --files ${path}
|
|
133
133
|
```
|
|
134
134
|
</step>
|
|
135
135
|
|
|
@@ -373,14 +373,14 @@ Clear Current Test section:
|
|
|
373
373
|
[testing complete]
|
|
374
374
|
```
|
|
375
375
|
|
|
376
|
-
Commit the UAT file:
|
|
376
|
+
Commit the UAT file and VERIFICATION.md:
|
|
377
377
|
```bash
|
|
378
|
-
node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "test({phase_num}): complete UAT - {passed} passed, {issues} issues" --files "${phase_dir}/{phase_num}-UAT.md"
|
|
378
|
+
node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "test({phase_num}): complete UAT - {passed} passed, {issues} issues" --push --files "${phase_dir}/{phase_num}-UAT.md" "${phase_dir}/{phase_num}-VERIFICATION.md"
|
|
379
379
|
```
|
|
380
380
|
|
|
381
381
|
If `AUTO_MODE` is true, prefix the commit message with `[AUTO] `:
|
|
382
382
|
```bash
|
|
383
|
-
node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "[AUTO] test({phase_num}): complete UAT - {passed} passed, {issues} issues" --files "${phase_dir}/{phase_num}-UAT.md"
|
|
383
|
+
node "$HOME/.claude/deliver-great-systems/bin/dgs-tools.cjs" commit "[AUTO] test({phase_num}): complete UAT - {passed} passed, {issues} issues" --push --files "${phase_dir}/{phase_num}-UAT.md" "${phase_dir}/{phase_num}-VERIFICATION.md"
|
|
384
384
|
```
|
|
385
385
|
|
|
386
386
|
Present summary:
|
|
@@ -222,7 +222,7 @@ node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs specs add-log-entry --id
|
|
|
222
222
|
|
|
223
223
|
Commit the draft:
|
|
224
224
|
```bash
|
|
225
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: draft $id from ideas $idea_ids" --files ${project_root}/specs/$filename
|
|
225
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: draft $id from ideas $idea_ids" --push --files ${project_root}/specs/$filename
|
|
226
226
|
```
|
|
227
227
|
|
|
228
228
|
Store `SPEC_ID` and `FILENAME` for subsequent steps.
|
|
@@ -289,7 +289,7 @@ Use AskUserQuestion: "Review the draft spec above. Type **approve** to send to r
|
|
|
289
289
|
|
|
290
290
|
After approval, commit any changes:
|
|
291
291
|
```bash
|
|
292
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: revise draft $SPEC_ID" --files ${project_root}/specs/$FILENAME
|
|
292
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: revise draft $SPEC_ID" --push --files ${project_root}/specs/$FILENAME
|
|
293
293
|
```
|
|
294
294
|
</step>
|
|
295
295
|
|
|
@@ -350,7 +350,7 @@ Estimated cost: ~$X.XX
|
|
|
350
350
|
**6. Commit updated spec:**
|
|
351
351
|
|
|
352
352
|
```bash
|
|
353
|
-
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: review $SPEC_ID (N rounds)" --files ${project_root}/specs/$FILENAME
|
|
353
|
+
node ~/.claude/deliver-great-systems/bin/dgs-tools.cjs commit "specs: review $SPEC_ID (N rounds)" --push --files ${project_root}/specs/$FILENAME
|
|
354
354
|
```
|
|
355
355
|
</step>
|
|
356
356
|
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"bugs": {
|
|
5
5
|
"url": "https://github.com/KT-Partners-Ltd/dgs-platform-docs/issues"
|
|
6
6
|
},
|
|
7
|
-
"version": "2.7.
|
|
7
|
+
"version": "2.7.3",
|
|
8
8
|
"description": "Deliver Great Systems Platform — A meta-prompting, context engineering and spec-driven development system for Claude Code and Gemini by KT Partners.",
|
|
9
9
|
"bin": {
|
|
10
10
|
"dgs": "bin/install.js"
|