@ktpartners/dgs-platform 2.9.0 → 3.3.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/CHANGELOG.md +197 -0
- package/README.md +34 -2
- package/agents/dgs-executor.md +124 -3
- package/agents/dgs-idea-researcher.md +447 -0
- package/agents/dgs-plan-checker.md +61 -3
- package/agents/dgs-planner.md +51 -8
- package/bin/install.js +44 -0
- package/commands/dgs/abandon-quick.md +28 -0
- package/commands/dgs/add-tests.md +2 -2
- package/commands/dgs/audit-milestone.md +4 -3
- 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/diff-report.md +124 -0
- 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 +8 -21
- package/commands/dgs/package-scan.md +43 -0
- 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 +3 -2
- package/commands/dgs/research-phase.md +3 -3
- package/commands/dgs/switch-project.md +14 -1
- package/commands/dgs/write-spec.md +3 -3
- package/deliver-great-systems/bin/dgs-tools.cjs +401 -32
- package/deliver-great-systems/bin/lib/audit-tolerance.cjs +77 -0
- package/deliver-great-systems/bin/lib/audit-tolerance.test.cjs +101 -0
- package/deliver-great-systems/bin/lib/commands.cjs +626 -46
- package/deliver-great-systems/bin/lib/commands.test.cjs +451 -0
- package/deliver-great-systems/bin/lib/commit-verify.test.cjs +236 -0
- package/deliver-great-systems/bin/lib/config.cjs +80 -6
- package/deliver-great-systems/bin/lib/config.test.cjs +309 -0
- package/deliver-great-systems/bin/lib/context.cjs +120 -0
- package/deliver-great-systems/bin/lib/core.cjs +35 -14
- package/deliver-great-systems/bin/lib/core.test.cjs +79 -1
- package/deliver-great-systems/bin/lib/execution.cjs +49 -17
- package/deliver-great-systems/bin/lib/fast-routing.cjs +199 -0
- package/deliver-great-systems/bin/lib/fast-routing.test.cjs +108 -0
- package/deliver-great-systems/bin/lib/final-commit-precondition.test.cjs +87 -0
- package/deliver-great-systems/bin/lib/fixtures/package-scan/bundler-audit-gemfile.json +21 -0
- package/deliver-great-systems/bin/lib/fixtures/package-scan/gate-parity-expected.md +186 -0
- package/deliver-great-systems/bin/lib/fixtures/package-scan/gate-parity-runresult.json +235 -0
- package/deliver-great-systems/bin/lib/fixtures/package-scan/govulncheck-import.json +3 -0
- package/deliver-great-systems/bin/lib/fixtures/package-scan/npm-audit-v10.json +37 -0
- package/deliver-great-systems/bin/lib/fixtures/package-scan/osv-clean.json +3 -0
- package/deliver-great-systems/bin/lib/fixtures/package-scan/osv-vulns.json +77 -0
- package/deliver-great-systems/bin/lib/fixtures/package-scan/pip-audit-requirements.json +28 -0
- package/deliver-great-systems/bin/lib/fixtures/package-scan/snyk-lodash.json +30 -0
- package/deliver-great-systems/bin/lib/fixtures/package-scan/snyk-workspaces.json +55 -0
- package/deliver-great-systems/bin/lib/flat-migration.test.cjs +396 -0
- package/deliver-great-systems/bin/lib/frontmatter.cjs +1 -1
- package/deliver-great-systems/bin/lib/governance.cjs +211 -0
- package/deliver-great-systems/bin/lib/governance.test.cjs +339 -0
- package/deliver-great-systems/bin/lib/health-untracked-phase.test.cjs +269 -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 +357 -61
- package/deliver-great-systems/bin/lib/init.test.cjs +625 -8
- package/deliver-great-systems/bin/lib/jobs.cjs +131 -25
- 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 +154 -31
- package/deliver-great-systems/bin/lib/milestone.test.cjs +203 -0
- package/deliver-great-systems/bin/lib/package-adapters.cjs +530 -0
- package/deliver-great-systems/bin/lib/package-adapters.test.cjs +618 -0
- package/deliver-great-systems/bin/lib/package-ecosystems.cjs +350 -0
- package/deliver-great-systems/bin/lib/package-ecosystems.test.cjs +348 -0
- package/deliver-great-systems/bin/lib/package-runner.cjs +199 -0
- package/deliver-great-systems/bin/lib/package-runner.test.cjs +198 -0
- package/deliver-great-systems/bin/lib/package-scan-provenance.cjs +56 -0
- package/deliver-great-systems/bin/lib/package-scan-provenance.test.cjs +103 -0
- package/deliver-great-systems/bin/lib/package-scan-report.cjs +1140 -0
- package/deliver-great-systems/bin/lib/package-scan-report.test.cjs +1963 -0
- package/deliver-great-systems/bin/lib/package-scan-skill.cjs +96 -0
- package/deliver-great-systems/bin/lib/package-scan-skill.test.cjs +136 -0
- package/deliver-great-systems/bin/lib/package-scan.cjs +919 -0
- package/deliver-great-systems/bin/lib/package-scan.test.cjs +2147 -0
- package/deliver-great-systems/bin/lib/phase.cjs +146 -3
- package/deliver-great-systems/bin/lib/phase.test.cjs +420 -0
- package/deliver-great-systems/bin/lib/plan-number-validity.test.cjs +48 -0
- package/deliver-great-systems/bin/lib/projects.cjs +65 -10
- package/deliver-great-systems/bin/lib/projects.test.cjs +198 -2
- package/deliver-great-systems/bin/lib/quick.cjs +739 -0
- package/deliver-great-systems/bin/lib/quick.test.cjs +730 -0
- package/deliver-great-systems/bin/lib/repos.cjs +37 -13
- package/deliver-great-systems/bin/lib/review.cjs +1821 -0
- 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 +147 -55
- package/deliver-great-systems/bin/lib/summary-frontmatter.cjs +54 -0
- package/deliver-great-systems/bin/lib/summary-frontmatter.test.cjs +78 -0
- package/deliver-great-systems/bin/lib/sweep-scope.test.cjs +263 -0
- package/deliver-great-systems/bin/lib/sync.cjs +75 -0
- package/deliver-great-systems/bin/lib/verify.cjs +198 -7
- package/deliver-great-systems/bin/lib/verify.test.cjs +82 -0
- package/deliver-great-systems/bin/lib/wave-0-template-rename.test.cjs +40 -0
- package/deliver-great-systems/bin/lib/worktrees.cjs +790 -0
- package/deliver-great-systems/bin/lib/worktrees.test.cjs +963 -0
- package/deliver-great-systems/references/agent-step-reliability.md +60 -0
- package/deliver-great-systems/references/conflict-resolution.md +4 -0
- package/deliver-great-systems/references/context-tiers.md +4 -0
- package/deliver-great-systems/references/package-scan-config.md +151 -0
- package/deliver-great-systems/references/questioning.md +0 -30
- package/deliver-great-systems/references/spec-review-loop.md +1 -2
- package/deliver-great-systems/references/workflow-conventions.md +29 -0
- package/deliver-great-systems/skills/dgs-tests/package-scan.md +44 -0
- package/deliver-great-systems/templates/REVIEW.md +35 -0
- package/deliver-great-systems/templates/VALIDATION.md +1 -1
- package/deliver-great-systems/templates/claude-md.md +27 -0
- package/deliver-great-systems/templates/package-scan-report.md +108 -0
- package/deliver-great-systems/templates/project.md +6 -170
- package/deliver-great-systems/templates/summary.md +3 -1
- 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-phase.md +5 -0
- 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-milestone.md +66 -10
- package/deliver-great-systems/workflows/audit-phase.md +15 -5
- package/deliver-great-systems/workflows/cancel-job.md +2 -2
- package/deliver-great-systems/workflows/check-todos.md +2 -3
- package/deliver-great-systems/workflows/codereview.md +103 -9
- package/deliver-great-systems/workflows/complete-milestone.md +218 -24
- package/deliver-great-systems/workflows/complete-quick.md +106 -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/discuss-phase.md +3 -2
- package/deliver-great-systems/workflows/execute-phase.md +209 -33
- package/deliver-great-systems/workflows/execute-plan.md +22 -22
- package/deliver-great-systems/workflows/help.md +53 -20
- package/deliver-great-systems/workflows/import-spec.md +65 -7
- package/deliver-great-systems/workflows/init-product.md +45 -167
- package/deliver-great-systems/workflows/new-milestone.md +140 -33
- package/deliver-great-systems/workflows/new-project.md +60 -331
- package/deliver-great-systems/workflows/package-scan.md +59 -0
- package/deliver-great-systems/workflows/plan-phase.md +79 -1
- 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 +106 -0
- package/deliver-great-systems/workflows/quick.md +328 -26
- package/deliver-great-systems/workflows/refine-spec.md +1 -1
- package/deliver-great-systems/workflows/research-idea.md +77 -139
- package/deliver-great-systems/workflows/resume-project.md +2 -2
- package/deliver-great-systems/workflows/run-job.md +29 -43
- package/deliver-great-systems/workflows/settings.md +13 -77
- 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 +11 -13
- package/hooks/dist/dgs-enforce-discipline.js +196 -0
- package/package.json +1 -1
- package/scripts/build-hooks.js +1 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* package-scan-skill.cjs — Plugin skill module for /dgs:package-scan.
|
|
3
|
+
*
|
|
4
|
+
* Companion to deliver-great-systems/skills/dgs-tests/package-scan.md. Where
|
|
5
|
+
* the .md file declares the plugin contract (test-gate spec §5a), this module
|
|
6
|
+
* exposes the prerequisites check as a Node callable the future test-gate
|
|
7
|
+
* orchestrator (skills.cjs) can consume without reimplementing manifest
|
|
8
|
+
* detection.
|
|
9
|
+
*
|
|
10
|
+
* Covers roadmap requirements: PKG-24 (plugin contract) + PKG-25 (prerequisites).
|
|
11
|
+
*
|
|
12
|
+
* Public API:
|
|
13
|
+
* checkPrerequisites(cwd) -> { available: boolean, reason: string }
|
|
14
|
+
*
|
|
15
|
+
* Never throws: absent REPOS.md, unreadable paths, missing files all resolve
|
|
16
|
+
* to { available: false, reason: <explanation> }. Invalid cwd (empty string,
|
|
17
|
+
* null, non-string) returns available=false with an explanatory reason.
|
|
18
|
+
*
|
|
19
|
+
* Design note: uses the raw REPOS.md path (not worktree-aware) intentionally —
|
|
20
|
+
* prerequisites are a static gate, not a scan; they reflect what the user has
|
|
21
|
+
* registered, not where the active worktree is. The scan orchestrator
|
|
22
|
+
* (package-scan.cjs collectScanTargets) does use resolveCodeContext for
|
|
23
|
+
* worktree-aware path resolution; that's the right choice for scans but not
|
|
24
|
+
* for gating.
|
|
25
|
+
*/
|
|
26
|
+
'use strict';
|
|
27
|
+
const fs = require('fs');
|
|
28
|
+
const path = require('path');
|
|
29
|
+
const { detectEcosystems } = require('./package-ecosystems.cjs');
|
|
30
|
+
const { parseReposMd } = require('./repos.cjs');
|
|
31
|
+
|
|
32
|
+
function _safeDetect(dir) {
|
|
33
|
+
try {
|
|
34
|
+
if (!dir || !fs.existsSync(dir)) return [];
|
|
35
|
+
return detectEcosystems(dir) || [];
|
|
36
|
+
} catch {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function checkPrerequisites(cwd) {
|
|
42
|
+
if (typeof cwd !== 'string' || cwd.length === 0) {
|
|
43
|
+
return {
|
|
44
|
+
available: false,
|
|
45
|
+
reason: 'checkPrerequisites requires a non-empty cwd string',
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const targets = [];
|
|
50
|
+
// Product root always considered a target.
|
|
51
|
+
targets.push({ name: '_product_root', dir: cwd });
|
|
52
|
+
|
|
53
|
+
// Registered repos from REPOS.md (if present). parseReposMd returns
|
|
54
|
+
// { repos: [...] } or null.
|
|
55
|
+
let parsed = null;
|
|
56
|
+
try {
|
|
57
|
+
parsed = parseReposMd(cwd);
|
|
58
|
+
} catch {
|
|
59
|
+
parsed = null;
|
|
60
|
+
}
|
|
61
|
+
const repos = (parsed && Array.isArray(parsed.repos)) ? parsed.repos : [];
|
|
62
|
+
for (const r of repos) {
|
|
63
|
+
if (!r || !r.path) continue;
|
|
64
|
+
const abs = path.isAbsolute(r.path) ? r.path : path.resolve(cwd, r.path);
|
|
65
|
+
targets.push({ name: r.name || r.path, dir: abs });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const hits = [];
|
|
69
|
+
for (const t of targets) {
|
|
70
|
+
const entries = _safeDetect(t.dir);
|
|
71
|
+
if (entries.length > 0) {
|
|
72
|
+
const ecos = Array.from(new Set(entries.map(e => e.ecosystem).filter(Boolean)));
|
|
73
|
+
hits.push({ name: t.name, ecosystems: ecos });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (hits.length === 0) {
|
|
78
|
+
return {
|
|
79
|
+
available: false,
|
|
80
|
+
reason: 'No recognised manifests found in any registered repo or at the product root',
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const summary = hits
|
|
84
|
+
.map(h => `${h.name} (${h.ecosystems.join(', ') || 'unknown'})`)
|
|
85
|
+
.join('; ');
|
|
86
|
+
return {
|
|
87
|
+
available: true,
|
|
88
|
+
reason: `Recognised manifests found in: ${summary}`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = {
|
|
93
|
+
checkPrerequisites,
|
|
94
|
+
// Exported for test seam (helps future consumers mock manifest detection).
|
|
95
|
+
_safeDetect,
|
|
96
|
+
};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* package-scan-skill.test.cjs — Unit tests for Phase 152 Plan 02
|
|
3
|
+
*
|
|
4
|
+
* Covers PKG-24 (plugin skill file at deliver-great-systems/skills/dgs-tests/package-scan.md)
|
|
5
|
+
* and PKG-25 (checkPrerequisites callable).
|
|
6
|
+
*/
|
|
7
|
+
'use strict';
|
|
8
|
+
const { describe, it } = require('node:test');
|
|
9
|
+
const assert = require('node:assert/strict');
|
|
10
|
+
const fs = require('node:fs');
|
|
11
|
+
const path = require('node:path');
|
|
12
|
+
const os = require('node:os');
|
|
13
|
+
const { execSync } = require('node:child_process');
|
|
14
|
+
const skill = require('./package-scan-skill.cjs');
|
|
15
|
+
const { resetPaths } = require('./paths.cjs');
|
|
16
|
+
|
|
17
|
+
function makeTmp() {
|
|
18
|
+
const d = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'pkg-skill-')));
|
|
19
|
+
// getPlanningRoot requires a git repository; initialise one so
|
|
20
|
+
// parseReposMd (which resolves via getPlanningRoot) works under test.
|
|
21
|
+
execSync('git init -q', { cwd: d });
|
|
22
|
+
resetPaths();
|
|
23
|
+
return d;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function cleanup(d) {
|
|
27
|
+
try { fs.rmSync(d, { recursive: true, force: true }); } catch {}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function writeReposMd(tmp, rows) {
|
|
31
|
+
let md = '# Repos\n\n';
|
|
32
|
+
md += '| Name | Path | GitHub URL | Description |\n';
|
|
33
|
+
md += '|------|------|------------|-------------|\n';
|
|
34
|
+
for (const r of rows) {
|
|
35
|
+
md += `| ${r.name} | ${r.path} | | |\n`;
|
|
36
|
+
}
|
|
37
|
+
fs.writeFileSync(path.join(tmp, 'REPOS.md'), md);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
describe('checkPrerequisites (PKG-25)', () => {
|
|
41
|
+
it('Scenario A: product root has package.json → available=true, reason mentions product root', () => {
|
|
42
|
+
const tmp = makeTmp();
|
|
43
|
+
try {
|
|
44
|
+
fs.writeFileSync(path.join(tmp, 'package.json'), '{}');
|
|
45
|
+
writeReposMd(tmp, []);
|
|
46
|
+
const r = skill.checkPrerequisites(tmp);
|
|
47
|
+
assert.strictEqual(r.available, true);
|
|
48
|
+
assert.match(r.reason, /_product_root|product root/i);
|
|
49
|
+
assert.match(r.reason, /node/);
|
|
50
|
+
} finally { cleanup(tmp); }
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('Scenario B: registered repo has go.mod → available=true, reason mentions repo', () => {
|
|
54
|
+
const tmp = makeTmp();
|
|
55
|
+
try {
|
|
56
|
+
fs.mkdirSync(path.join(tmp, 'backend'), { recursive: true });
|
|
57
|
+
fs.writeFileSync(path.join(tmp, 'backend', 'go.mod'), 'module test\n');
|
|
58
|
+
writeReposMd(tmp, [{ name: 'backend', path: './backend' }]);
|
|
59
|
+
const r = skill.checkPrerequisites(tmp);
|
|
60
|
+
assert.strictEqual(r.available, true);
|
|
61
|
+
assert.match(r.reason, /backend/);
|
|
62
|
+
assert.match(r.reason, /go/);
|
|
63
|
+
} finally { cleanup(tmp); }
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('Scenario C: no manifests anywhere → available=false, non-empty reason', () => {
|
|
67
|
+
const tmp = makeTmp();
|
|
68
|
+
try {
|
|
69
|
+
writeReposMd(tmp, []);
|
|
70
|
+
const r = skill.checkPrerequisites(tmp);
|
|
71
|
+
assert.strictEqual(r.available, false);
|
|
72
|
+
assert.ok(typeof r.reason === 'string' && r.reason.length > 0);
|
|
73
|
+
assert.match(r.reason, /no recognised manifests found/i);
|
|
74
|
+
} finally { cleanup(tmp); }
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('Scenario D: REPOS.md absent, product root has pyproject.toml → available=true', () => {
|
|
78
|
+
const tmp = makeTmp();
|
|
79
|
+
try {
|
|
80
|
+
fs.writeFileSync(path.join(tmp, 'pyproject.toml'), '[project]\nname="x"\n');
|
|
81
|
+
const r = skill.checkPrerequisites(tmp);
|
|
82
|
+
assert.strictEqual(r.available, true);
|
|
83
|
+
assert.match(r.reason, /python/);
|
|
84
|
+
} finally { cleanup(tmp); }
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('Scenario E: multiple manifests across multiple repos → available=true, reason enumerates both', () => {
|
|
88
|
+
const tmp = makeTmp();
|
|
89
|
+
try {
|
|
90
|
+
fs.mkdirSync(path.join(tmp, 'backend'), { recursive: true });
|
|
91
|
+
fs.writeFileSync(path.join(tmp, 'backend', 'go.mod'), 'module test\n');
|
|
92
|
+
fs.mkdirSync(path.join(tmp, 'frontend'), { recursive: true });
|
|
93
|
+
fs.writeFileSync(path.join(tmp, 'frontend', 'package.json'), '{}');
|
|
94
|
+
writeReposMd(tmp, [
|
|
95
|
+
{ name: 'backend', path: './backend' },
|
|
96
|
+
{ name: 'frontend', path: './frontend' },
|
|
97
|
+
]);
|
|
98
|
+
const r = skill.checkPrerequisites(tmp);
|
|
99
|
+
assert.strictEqual(r.available, true);
|
|
100
|
+
assert.match(r.reason, /backend/);
|
|
101
|
+
assert.match(r.reason, /frontend/);
|
|
102
|
+
assert.match(r.reason, /go/);
|
|
103
|
+
assert.match(r.reason, /node/);
|
|
104
|
+
} finally { cleanup(tmp); }
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('Scenario F: invariant — checkPrerequisites never throws (REPOS.md points at nonexistent path)', () => {
|
|
108
|
+
const tmp = makeTmp();
|
|
109
|
+
try {
|
|
110
|
+
writeReposMd(tmp, [{ name: 'missing', path: './does-not-exist' }]);
|
|
111
|
+
let r;
|
|
112
|
+
assert.doesNotThrow(() => { r = skill.checkPrerequisites(tmp); });
|
|
113
|
+
assert.strictEqual(r.available, false);
|
|
114
|
+
assert.ok(typeof r.reason === 'string' && r.reason.length > 0);
|
|
115
|
+
} finally { cleanup(tmp); }
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('invalid cwd (empty string) → available=false, no throw', () => {
|
|
119
|
+
let r;
|
|
120
|
+
assert.doesNotThrow(() => { r = skill.checkPrerequisites(''); });
|
|
121
|
+
assert.strictEqual(r.available, false);
|
|
122
|
+
assert.ok(typeof r.reason === 'string' && r.reason.length > 0);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('invalid cwd (null) → available=false, no throw', () => {
|
|
126
|
+
let r;
|
|
127
|
+
assert.doesNotThrow(() => { r = skill.checkPrerequisites(null); });
|
|
128
|
+
assert.strictEqual(r.available, false);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe('module contract (PKG-24)', () => {
|
|
133
|
+
it('exports checkPrerequisites as a function', () => {
|
|
134
|
+
assert.strictEqual(typeof skill.checkPrerequisites, 'function');
|
|
135
|
+
});
|
|
136
|
+
});
|