@ktpartners/dgs-platform 2.8.0 → 3.0.4
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 +96 -0
- package/README.md +41 -13
- package/agents/dgs-plan-checker.md +29 -3
- package/agents/dgs-planner.md +10 -0
- package/commands/dgs/abandon-quick.md +28 -0
- package/commands/dgs/add-tests.md +2 -2
- package/commands/dgs/audit-milestone.md +2 -2
- package/commands/dgs/capture-principle.md +11 -11
- package/commands/dgs/cleanup.md +2 -2
- package/commands/dgs/complete-milestone.md +11 -11
- package/commands/dgs/complete-quick.md +28 -0
- package/commands/dgs/create-milestone-job.md +2 -2
- package/commands/dgs/debug.md +3 -3
- package/commands/dgs/develop-idea.md +1 -1
- package/commands/dgs/fast.md +3 -1
- package/commands/dgs/health.md +1 -1
- package/commands/dgs/map-codebase.md +6 -6
- package/commands/dgs/new-milestone.md +5 -5
- package/commands/dgs/new-project.md +6 -6
- package/commands/dgs/plan-milestone-gaps.md +1 -1
- package/commands/dgs/progress.md +3 -3
- package/commands/dgs/quick-abandon.md +8 -0
- package/commands/dgs/quick-complete.md +8 -0
- package/commands/dgs/quick.md +10 -3
- package/commands/dgs/research-idea.md +2 -2
- package/commands/dgs/research-phase.md +3 -3
- package/commands/dgs/switch-project.md +1 -1
- package/commands/dgs/write-spec.md +3 -3
- package/deliver-great-systems/bin/dgs-tools.cjs +284 -30
- package/deliver-great-systems/bin/lib/commands.cjs +316 -31
- package/deliver-great-systems/bin/lib/commands.test.cjs +336 -0
- package/deliver-great-systems/bin/lib/config.cjs +39 -6
- package/deliver-great-systems/bin/lib/context.cjs +120 -0
- package/deliver-great-systems/bin/lib/core.cjs +28 -11
- package/deliver-great-systems/bin/lib/execution.cjs +49 -17
- package/deliver-great-systems/bin/lib/flat-migration.test.cjs +396 -0
- package/deliver-great-systems/bin/lib/ideas.cjs +206 -91
- package/deliver-great-systems/bin/lib/ideas.test.cjs +244 -1
- package/deliver-great-systems/bin/lib/init.cjs +306 -39
- package/deliver-great-systems/bin/lib/init.test.cjs +416 -6
- package/deliver-great-systems/bin/lib/jobs.cjs +124 -21
- package/deliver-great-systems/bin/lib/jobs.test.cjs +193 -74
- package/deliver-great-systems/bin/lib/migration.cjs +409 -1
- package/deliver-great-systems/bin/lib/migration.test.cjs +158 -1
- package/deliver-great-systems/bin/lib/milestone.cjs +54 -29
- package/deliver-great-systems/bin/lib/phase.cjs +128 -2
- package/deliver-great-systems/bin/lib/phase.test.cjs +420 -0
- package/deliver-great-systems/bin/lib/projects.cjs +28 -8
- package/deliver-great-systems/bin/lib/projects.test.cjs +86 -0
- package/deliver-great-systems/bin/lib/quick.cjs +584 -0
- package/deliver-great-systems/bin/lib/quick.test.cjs +596 -0
- package/deliver-great-systems/bin/lib/repos.cjs +25 -1
- package/deliver-great-systems/bin/lib/roadmap.cjs +34 -13
- package/deliver-great-systems/bin/lib/specs.cjs +3 -81
- package/deliver-great-systems/bin/lib/state-transition-gate.test.cjs +160 -0
- package/deliver-great-systems/bin/lib/state.cjs +142 -54
- package/deliver-great-systems/bin/lib/sync.cjs +75 -0
- package/deliver-great-systems/bin/lib/verify.cjs +80 -1
- package/deliver-great-systems/bin/lib/worktrees.cjs +764 -0
- package/deliver-great-systems/bin/lib/worktrees.test.cjs +887 -0
- package/deliver-great-systems/templates/claude-md.md +16 -0
- package/deliver-great-systems/workflows/abandon-quick.md +89 -0
- package/deliver-great-systems/workflows/add-idea.md +3 -3
- package/deliver-great-systems/workflows/add-tests.md +14 -0
- package/deliver-great-systems/workflows/add-todo.md +1 -0
- package/deliver-great-systems/workflows/approve-spec.md +25 -4
- package/deliver-great-systems/workflows/audit-phase.md +15 -5
- package/deliver-great-systems/workflows/cancel-job.md +1 -1
- package/deliver-great-systems/workflows/check-todos.md +2 -3
- package/deliver-great-systems/workflows/complete-milestone.md +197 -22
- package/deliver-great-systems/workflows/complete-quick.md +68 -0
- package/deliver-great-systems/workflows/consolidate-ideas.md +1 -1
- package/deliver-great-systems/workflows/create-milestone-job.md +4 -4
- package/deliver-great-systems/workflows/develop-idea.md +11 -11
- package/deliver-great-systems/workflows/diagnose-issues.md +14 -0
- package/deliver-great-systems/workflows/discuss-idea.md +1 -1
- package/deliver-great-systems/workflows/execute-phase.md +121 -32
- package/deliver-great-systems/workflows/execute-plan.md +12 -21
- package/deliver-great-systems/workflows/help.md +33 -29
- package/deliver-great-systems/workflows/init-product.md +2 -18
- package/deliver-great-systems/workflows/new-milestone.md +40 -24
- package/deliver-great-systems/workflows/new-project.md +22 -680
- package/deliver-great-systems/workflows/progress-all.md +133 -0
- package/deliver-great-systems/workflows/quick-abandon.md +89 -0
- package/deliver-great-systems/workflows/quick-complete.md +68 -0
- package/deliver-great-systems/workflows/quick.md +152 -23
- package/deliver-great-systems/workflows/refine-spec.md +1 -1
- package/deliver-great-systems/workflows/research-idea.md +8 -8
- package/deliver-great-systems/workflows/resume-project.md +2 -2
- package/deliver-great-systems/workflows/run-job.md +8 -8
- package/deliver-great-systems/workflows/validate-phase.md +39 -1
- package/deliver-great-systems/workflows/verify-work.md +14 -0
- package/deliver-great-systems/workflows/write-spec.md +2 -2
- package/package.json +1 -1
|
@@ -378,6 +378,75 @@ function pullAll(cwd, options = {}) {
|
|
|
378
378
|
* @param {string[]|null} [options.repos=null] - Filter to push only specific repos by name
|
|
379
379
|
* @returns {{ ok: boolean, results: Array<{ repo: string, path: string, status: string, commits: number|null, message: string }>, problems?: Array, summary: string }}
|
|
380
380
|
*/
|
|
381
|
+
/**
|
|
382
|
+
* Push active worktree branches to remote as backup. Best-effort — failures
|
|
383
|
+
* are appended to results but do not block other sync operations.
|
|
384
|
+
*
|
|
385
|
+
* Reads worktree entries from config.local.json for the current project.
|
|
386
|
+
* Skips stale entries where the worktree directory no longer exists.
|
|
387
|
+
* Push-only — no pull of worktree branches (deferred to future).
|
|
388
|
+
*
|
|
389
|
+
* @param {string} cwd - Planning root
|
|
390
|
+
* @param {Array} results - Results array to append push outcomes to
|
|
391
|
+
*/
|
|
392
|
+
function _pushWorktreeBranches(cwd, results) {
|
|
393
|
+
const config = loadConfig(cwd);
|
|
394
|
+
const project = config.current_project;
|
|
395
|
+
if (!project) return;
|
|
396
|
+
|
|
397
|
+
let localConfig;
|
|
398
|
+
try {
|
|
399
|
+
const localPath = getLocalConfigPath(cwd);
|
|
400
|
+
if (!fs.existsSync(localPath)) return;
|
|
401
|
+
localConfig = JSON.parse(fs.readFileSync(localPath, 'utf-8'));
|
|
402
|
+
} catch {
|
|
403
|
+
return; // No config.local.json or invalid JSON — nothing to push
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const worktrees = (localConfig.projects && localConfig.projects[project] && localConfig.projects[project].worktrees) || {};
|
|
407
|
+
|
|
408
|
+
for (const [slug, entry] of Object.entries(worktrees)) {
|
|
409
|
+
const type = entry.type; // 'milestone' or 'quick'
|
|
410
|
+
const repos = entry.repos || {};
|
|
411
|
+
|
|
412
|
+
for (const [repoName, worktreePath] of Object.entries(repos)) {
|
|
413
|
+
// Skip stale worktrees (directory doesn't exist)
|
|
414
|
+
if (!fs.existsSync(worktreePath)) continue;
|
|
415
|
+
|
|
416
|
+
// Determine branch name based on type
|
|
417
|
+
const branchName = type === 'milestone' ? 'milestone/' + slug : 'quick/' + slug;
|
|
418
|
+
const label = repoName + ' (worktree: ' + slug + ')';
|
|
419
|
+
|
|
420
|
+
try {
|
|
421
|
+
// Check if worktree has a remote
|
|
422
|
+
if (!hasRemote(worktreePath)) continue;
|
|
423
|
+
|
|
424
|
+
// Push the worktree branch from the worktree directory
|
|
425
|
+
const pushResult = execGitWithTimeout(worktreePath, ['push', '-u', 'origin', branchName], 30000);
|
|
426
|
+
|
|
427
|
+
results.push({
|
|
428
|
+
repo: label,
|
|
429
|
+
path: worktreePath,
|
|
430
|
+
status: pushResult.exitCode === 0 ? 'pushed' : 'failed',
|
|
431
|
+
commits: 0,
|
|
432
|
+
message: pushResult.exitCode === 0
|
|
433
|
+
? 'Pushed worktree branch ' + branchName
|
|
434
|
+
: 'Failed to push ' + branchName + ': ' + (pushResult.stderr || '').trim(),
|
|
435
|
+
});
|
|
436
|
+
} catch (e) {
|
|
437
|
+
// Best-effort — failure does not block other operations
|
|
438
|
+
results.push({
|
|
439
|
+
repo: label,
|
|
440
|
+
path: worktreePath,
|
|
441
|
+
status: 'failed',
|
|
442
|
+
commits: 0,
|
|
443
|
+
message: 'Push failed: ' + (e.message || String(e)),
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
381
450
|
function pushAll(cwd, options = {}) {
|
|
382
451
|
const { dryRun = false, force = false, repos: repoFilter = null } = options;
|
|
383
452
|
let allRepos = collectSyncRepos(cwd);
|
|
@@ -468,6 +537,12 @@ function pushAll(cwd, options = {}) {
|
|
|
468
537
|
results.push({ repo: label, path: repo.path, status: 'pushed', commits: commitCount, message: `Pushed ${commitLabel}` });
|
|
469
538
|
}
|
|
470
539
|
|
|
540
|
+
// --- Worktree Branch Push ---
|
|
541
|
+
// Push active worktree branches as remote backup (best-effort, non-blocking)
|
|
542
|
+
if (!dryRun) {
|
|
543
|
+
_pushWorktreeBranches(cwd, results);
|
|
544
|
+
}
|
|
545
|
+
|
|
471
546
|
// Build summary
|
|
472
547
|
const pushed = results.filter(r => r.status === 'pushed').length;
|
|
473
548
|
const current = results.filter(r => r.status === 'current').length;
|
|
@@ -708,6 +708,86 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
708
708
|
}
|
|
709
709
|
}
|
|
710
710
|
|
|
711
|
+
// ─── Check 10: Uncommitted tracking files in completed phases ─────────────
|
|
712
|
+
// Surface the condition `phase finalize` was designed to prevent: a completed
|
|
713
|
+
// phase whose ROADMAP.md / STATE.md / REQUIREMENTS.md / VERIFICATION.md are
|
|
714
|
+
// modified in the working tree but not committed (e.g., Claude dropped the
|
|
715
|
+
// commit step between updating trackers and invoking `commit`).
|
|
716
|
+
try {
|
|
717
|
+
const { execGit } = require('./core.cjs');
|
|
718
|
+
const isGit = execGit(cwd, ['rev-parse', '--is-inside-work-tree']);
|
|
719
|
+
if (isGit.exitCode === 0 && isGit.stdout.trim() === 'true') {
|
|
720
|
+
// git resolves symlinks when reporting paths; normalize both sides against
|
|
721
|
+
// the real git root so relative paths compare correctly on macOS
|
|
722
|
+
// (/var/folders → /private/var/folders).
|
|
723
|
+
const gitRootRes = execGit(cwd, ['rev-parse', '--show-toplevel']);
|
|
724
|
+
const gitRoot = gitRootRes.exitCode === 0 ? gitRootRes.stdout.trim() : cwd;
|
|
725
|
+
const statusRes = execGit(cwd, ['status', '--porcelain']);
|
|
726
|
+
if (statusRes.exitCode === 0) {
|
|
727
|
+
// `git status --porcelain` emits "XY path" lines (X=index, Y=worktree,
|
|
728
|
+
// column 3 is a separator space, path starts at column 4). Note:
|
|
729
|
+
// execGit.stdout is already .trim()'d so lines may have lost a leading
|
|
730
|
+
// space when X=' ' (worktree-only changes). Extract the path from
|
|
731
|
+
// whatever follows the first whitespace group.
|
|
732
|
+
const dirtyPaths = statusRes.stdout
|
|
733
|
+
.split('\n')
|
|
734
|
+
.filter(Boolean)
|
|
735
|
+
.map(l => {
|
|
736
|
+
// Match "XY<space>path" OR "<space>Y<space>path" (leading space may be trimmed).
|
|
737
|
+
// A path after 2 status chars + 1 space begins at index 3 of the original,
|
|
738
|
+
// but lines like " M file" got left-trimmed to "M file" (only one status char).
|
|
739
|
+
// Normalize: skip the leading non-space + exactly one space.
|
|
740
|
+
const m = l.match(/^\S{1,2}\s(.+)$/);
|
|
741
|
+
return m ? m[1].trim() : l.trim();
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
// Identify completed phases from ROADMAP.md checkboxes
|
|
745
|
+
const completedPhases = new Set();
|
|
746
|
+
if (fs.existsSync(roadmapPath)) {
|
|
747
|
+
const rm = fs.readFileSync(roadmapPath, 'utf-8');
|
|
748
|
+
const re = /-\s*\[x\]\s*.*Phase\s+(\d+[A-Z]?(?:\.\d+)*)/gi;
|
|
749
|
+
let m;
|
|
750
|
+
while ((m = re.exec(rm)) !== null) completedPhases.add(m[1]);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// Tracking files at the planning root — compute relative to gitRoot
|
|
754
|
+
const trackingRoot = ['ROADMAP.md', 'STATE.md', 'REQUIREMENTS.md']
|
|
755
|
+
.map(f => path.relative(gitRoot, path.join(planningDir, f)));
|
|
756
|
+
|
|
757
|
+
// VERIFICATION.md files inside completed phase dirs
|
|
758
|
+
const trackingVerif = [];
|
|
759
|
+
if (completedPhases.size > 0) {
|
|
760
|
+
try {
|
|
761
|
+
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
|
762
|
+
for (const e of entries) {
|
|
763
|
+
if (!e.isDirectory()) continue;
|
|
764
|
+
const dm = e.name.match(/^(\d+[A-Z]?(?:\.\d+)*)/i);
|
|
765
|
+
if (!dm) continue;
|
|
766
|
+
const phaseNum = dm[1];
|
|
767
|
+
const unpadded = String(parseInt(phaseNum, 10));
|
|
768
|
+
if (!completedPhases.has(phaseNum) && !completedPhases.has(unpadded)) continue;
|
|
769
|
+
const phaseFiles = fs.readdirSync(path.join(phasesDir, e.name));
|
|
770
|
+
for (const f of phaseFiles) {
|
|
771
|
+
if (/-VERIFICATION\.md$/i.test(f)) {
|
|
772
|
+
trackingVerif.push(path.relative(gitRoot, path.join(phasesDir, e.name, f)));
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
} catch { /* ignore */ }
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
const allTracking = [...trackingRoot, ...trackingVerif];
|
|
780
|
+
const dirtyTracking = dirtyPaths.filter(p => allTracking.includes(p));
|
|
781
|
+
if (dirtyTracking.length > 0) {
|
|
782
|
+
addIssue('warning', 'W009',
|
|
783
|
+
`Uncommitted tracking files for completed phase(s): ${dirtyTracking.join(', ')}`,
|
|
784
|
+
'Run `dgs-tools phase finalize <phase>` for the relevant phase, or commit manually'
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
} catch { /* non-git or git error — skip silently */ }
|
|
790
|
+
|
|
711
791
|
// ─── Perform repairs if requested ─────────────────────────────────────────
|
|
712
792
|
const repairActions = [];
|
|
713
793
|
if (options.repair && repairs.length > 0) {
|
|
@@ -720,7 +800,6 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
720
800
|
model_profile: 'balanced',
|
|
721
801
|
commit_docs: true,
|
|
722
802
|
search_gitignored: false,
|
|
723
|
-
branching_strategy: 'none',
|
|
724
803
|
research: true,
|
|
725
804
|
plan_checker: true,
|
|
726
805
|
verifier: true,
|