@flancer32/skill-adsm-ctx 0.2.1 → 0.4.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.
Files changed (103) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +45 -18
  3. package/bin/adsm-ctx.mjs +44 -0
  4. package/migrations/README.md +5 -1
  5. package/package.json +65 -11
  6. package/skill/SKILL.md +5 -4
  7. package/skill/references/context-lifecycle.md +14 -6
  8. package/skill/references/design-questionnaire.md +13 -1
  9. package/skill/references/document-projections.md +40 -80
  10. package/skill/references/documentation-compression.md +3 -2
  11. package/skill/references/documentation-quality-audit.md +37 -14
  12. package/skill/references/orchestration-model.md +4 -3
  13. package/skill/references/semantic-skins.md +65 -0
  14. package/skill/references/specialized-skills.md +5 -2
  15. package/skill/references/upgrade-policy.md +16 -6
  16. package/skill/templates/ctx/adsm.json +4 -1
  17. package/skill/templates/ctx/docs/AGENTS.md +3 -0
  18. package/skill/templates/ctx/docs/code/testing.md +4 -0
  19. package/skill/templates/work/context/semantic-skin.md +11 -22
  20. package/src/Cli/Command/Design.mjs +17 -0
  21. package/src/Cli/Command/Init.mjs +22 -0
  22. package/src/Cli/Command/InstallSkill.mjs +18 -0
  23. package/src/Cli/Command/Upgrade.mjs +19 -0
  24. package/src/Cli/Command/Validate.mjs +19 -0
  25. package/src/Design/Service.mjs +9 -7
  26. package/src/Shared/Constants.mjs +5 -5
  27. package/src/Shared/Metadata.mjs +1 -0
  28. package/src/Upgrade/Service.mjs +3 -3
  29. package/src/Validate/Service.mjs +217 -259
  30. package/types.d.ts +5 -2
  31. package/.github/workflows/flows-app.yaml +0 -95
  32. package/AGENTS.md +0 -112
  33. package/bin/cli.mjs +0 -55
  34. package/ctx/AGENTS.md +0 -44
  35. package/ctx/README.md +0 -24
  36. package/ctx/adsm.json +0 -5
  37. package/ctx/agent/AGENTS.md +0 -41
  38. package/ctx/agent/flows/.img/flancer32-skill-adsm-ctx-github-flows.png +0 -0
  39. package/ctx/agent/flows/AGENTS.md +0 -37
  40. package/ctx/agent/flows/cfg/issues/labeled/accepted/profile.json +0 -25
  41. package/ctx/agent/flows/cfg/issues/labeled/accepted/prompt.md +0 -104
  42. package/ctx/agent/flows/cfg/issues/labeled/clarification-provided/profile.json +0 -15
  43. package/ctx/agent/flows/cfg/issues/labeled/clarification-provided/prompt.md +0 -63
  44. package/ctx/agent/flows/cfg/issues/opened/admission/profile.json +0 -14
  45. package/ctx/agent/flows/cfg/issues/opened/admission/prompt.md +0 -110
  46. package/ctx/agent/flows/cfg/profile.json +0 -40
  47. package/ctx/agent/flows/cfg/pull_request/closed/merged/profile.json +0 -15
  48. package/ctx/agent/flows/cfg/pull_request/closed/merged/prompt.md +0 -41
  49. package/ctx/agent/flows/cfg/pull_request/labeled/needs-fix/profile.json +0 -25
  50. package/ctx/agent/flows/cfg/pull_request/labeled/needs-fix/prompt.md +0 -79
  51. package/ctx/agent/flows/cfg/pull_request/labeled/ready-for-validation/profile.json +0 -15
  52. package/ctx/agent/flows/cfg/pull_request/labeled/ready-for-validation/prompt.md +0 -72
  53. package/ctx/agent/flows/cfg/pull_request/labeled/verified/profile.json +0 -15
  54. package/ctx/agent/flows/cfg/pull_request/labeled/verified/prompt.md +0 -48
  55. package/ctx/agent/flows/deployment.md +0 -116
  56. package/ctx/agent/flows/labels.md +0 -108
  57. package/ctx/agent/flows/overview.md +0 -82
  58. package/ctx/agent/prompt/cli/ai-intro.md +0 -141
  59. package/ctx/assets/.gitkeep +0 -1
  60. package/ctx/docs/AGENTS.md +0 -121
  61. package/ctx/docs/ai-intro.md +0 -37
  62. package/ctx/docs/architecture/AGENTS.md +0 -98
  63. package/ctx/docs/architecture/behavior.md +0 -68
  64. package/ctx/docs/architecture/checklists.md +0 -48
  65. package/ctx/docs/architecture/constraints.md +0 -53
  66. package/ctx/docs/architecture/constraints.skin.en.md +0 -38
  67. package/ctx/docs/architecture/decisions.md +0 -118
  68. package/ctx/docs/architecture/integration.md +0 -31
  69. package/ctx/docs/architecture/overview.md +0 -76
  70. package/ctx/docs/architecture/state.md +0 -50
  71. package/ctx/docs/architecture/structure.md +0 -38
  72. package/ctx/docs/architecture/supervision.md +0 -71
  73. package/ctx/docs/code/AGENTS.md +0 -51
  74. package/ctx/docs/code/overview.md +0 -53
  75. package/ctx/docs/code/testing.md +0 -26
  76. package/ctx/docs/environment/AGENTS.md +0 -50
  77. package/ctx/docs/environment/overview.md +0 -33
  78. package/ctx/docs/filesystem.md +0 -44
  79. package/ctx/docs/product/AGENTS.md +0 -51
  80. package/ctx/docs/product/domain.md +0 -63
  81. package/ctx/docs/product/domain.skin.en.md +0 -40
  82. package/ctx/docs/product/glossary.md +0 -31
  83. package/ctx/docs/product/overview.md +0 -112
  84. package/ctx/docs/product/overview.skin.en.md +0 -38
  85. package/ctx/docs/product/roles.md +0 -17
  86. package/ctx/docs/product/use-cases.md +0 -15
  87. package/src/Bootstrap/Cli.mjs +0 -62
  88. package/src/Bootstrap.mjs +0 -108
  89. package/test/integration/.gitkeep +0 -1
  90. package/test/integration/cli-help.test.mjs +0 -15
  91. package/test/integration/cli-init-validate.test.mjs +0 -223
  92. package/test/integration/cli-install-skill.test.mjs +0 -41
  93. package/test/unit/Bootstrap/Cli.test.mjs +0 -23
  94. package/test/unit/Bootstrap.test.mjs +0 -53
  95. package/test/unit/Design/Service.test.mjs +0 -11
  96. package/test/unit/Init/Service.test.mjs +0 -51
  97. package/test/unit/Shared/Constants.test.mjs +0 -21
  98. package/test/unit/Shared/CopyDirectory.test.mjs +0 -31
  99. package/test/unit/Shared/Metadata.test.mjs +0 -9
  100. package/test/unit/Shared/Path.test.mjs +0 -11
  101. package/test/unit/Skill/Installer.test.mjs +0 -20
  102. package/test/unit/Upgrade/Service.test.mjs +0 -13
  103. package/test/unit/Validate/Service.test.mjs +0 -760
package/src/Bootstrap.mjs DELETED
@@ -1,108 +0,0 @@
1
- // @ts-check
2
-
3
- /**
4
- * @namespace Fl32_Skill_Adsm_Ctx_Bootstrap
5
- * @description TeqFW root CLI application component for ADSM context lifecycle operations.
6
- */
7
-
8
- export default class Bootstrap {
9
- /**
10
- * @param {object} deps
11
- * @param {Fl32_Skill_Adsm_Ctx_Bootstrap_Cli} deps.cli
12
- * @param {Fl32_Skill_Adsm_Ctx_Design_Service} deps.design
13
- * @param {Fl32_Skill_Adsm_Ctx_Init_Service} deps.init
14
- * @param {Fl32_Skill_Adsm_Ctx_Skill_Installer} deps.installer
15
- * @param {Fl32_Skill_Adsm_Ctx_Upgrade_Service} deps.upgrade
16
- * @param {Fl32_Skill_Adsm_Ctx_Validate_Service} deps.validate
17
- */
18
- constructor({cli, design, init, installer, upgrade, validate}) {
19
- let stopping = false;
20
-
21
- /**
22
- * Runs the CLI application once.
23
- *
24
- * @param {object} params
25
- * @param {string[]} params.cliArgs
26
- * @param {string} params.projectRoot
27
- * @returns {Promise<number>}
28
- */
29
- this.run = async ({cliArgs = [], projectRoot}) => {
30
- const parsed = cli.parse({cliArgs, projectRoot});
31
-
32
- if (parsed.helpRequested) {
33
- process.stderr.write(`${parsed.usage}\n`);
34
- return 0;
35
- }
36
-
37
- if (parsed.errors.length > 0) {
38
- process.stderr.write(`${parsed.errors.join("\n")}\n`);
39
- process.stderr.write(`${parsed.usage}\n`);
40
- return 2;
41
- }
42
-
43
- if (parsed.command === "init") {
44
- const result = await init.execute({targetPath: parsed.targetPath});
45
- process.stdout.write(`${formatInitReport(result)}\n`);
46
- return 0;
47
- }
48
-
49
- if (parsed.command === "design") {
50
- process.stdout.write(`${await design.execute({targetPath: parsed.targetPath})}\n`);
51
- return 0;
52
- }
53
-
54
- if (parsed.command === "validate") {
55
- const result = await validate.execute({targetPath: parsed.targetPath});
56
- process.stdout.write(`${validate.format({result})}\n`);
57
- return result.ok ? 0 : 1;
58
- }
59
-
60
- if (parsed.command === "upgrade") {
61
- const result = await upgrade.execute({targetPath: parsed.targetPath});
62
- process.stdout.write(`${result.message}\n`);
63
- return result.ok ? 0 : 1;
64
- }
65
-
66
- if (parsed.command === "install-skill") {
67
- const targetDir = await installer.execute({targetRoot: parsed.targetPath});
68
- process.stdout.write(`Installed skill payload to ${targetDir}\n`);
69
- return 0;
70
- }
71
-
72
- process.stderr.write(`${parsed.usage}\n`);
73
- return 2;
74
- };
75
-
76
- /**
77
- * Stops the application.
78
- *
79
- * @returns {Promise<void>}
80
- */
81
- this.stop = async () => {
82
- if (stopping) return;
83
- stopping = true;
84
- };
85
- }
86
- }
87
-
88
- /**
89
- * @param {{ctxRoot: string, created: string[], skipped: string[]}} result
90
- * @returns {string}
91
- */
92
- function formatInitReport(result) {
93
- const lines = [
94
- `Initialized ADSM context in ${result.ctxRoot}`,
95
- ...result.created.map((entry) => `Created: ${entry}`),
96
- ...result.skipped.map((entry) => `Skipped: ${entry}`),
97
- ];
98
- return lines.join("\n");
99
- }
100
-
101
- export const __deps__ = Object.freeze({
102
- cli: "Fl32_Skill_Adsm_Ctx_Bootstrap_Cli$",
103
- design: "Fl32_Skill_Adsm_Ctx_Design_Service$",
104
- init: "Fl32_Skill_Adsm_Ctx_Init_Service$",
105
- installer: "Fl32_Skill_Adsm_Ctx_Skill_Installer$",
106
- upgrade: "Fl32_Skill_Adsm_Ctx_Upgrade_Service$",
107
- validate: "Fl32_Skill_Adsm_Ctx_Validate_Service$",
108
- });
@@ -1 +0,0 @@
1
-
@@ -1,15 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import path from 'node:path';
4
- import {spawnSync} from 'node:child_process';
5
- import {fileURLToPath} from 'node:url';
6
-
7
- const __filename = fileURLToPath(import.meta.url);
8
- const __dirname = path.dirname(__filename);
9
- const cliPath = path.join(__dirname, '..', '..', 'bin', 'cli.mjs');
10
-
11
- test('cli help works', () => {
12
- const result = spawnSync('node', [cliPath, '--help'], {encoding: 'utf8'});
13
- assert.equal(result.status, 0);
14
- assert.match(result.stderr, /Usage: adsm-ctx/);
15
- });
@@ -1,223 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import {spawnSync} from 'node:child_process';
6
- import {fileURLToPath} from 'node:url';
7
-
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
- const cliPath = path.join(__dirname, '..', '..', 'bin', 'cli.mjs');
11
-
12
- test('cli init creates files in current working directory by default', () => {
13
- const sandboxRoot = fs.mkdtempSync(path.join('/tmp', 'adsm-ctx-cli-init-'));
14
- const result = spawnSync('node', [cliPath, 'init'], {cwd: sandboxRoot, encoding: 'utf8'});
15
-
16
- try {
17
- assert.equal(result.status, 0, result.stderr);
18
- assert.ok(fs.existsSync(path.join(sandboxRoot, 'ctx', 'adsm.json')));
19
- const filesystemDoc = fs.readFileSync(path.join(sandboxRoot, 'ctx', 'docs', 'filesystem.md'), 'utf8');
20
- const productDomainDoc = fs.readFileSync(path.join(sandboxRoot, 'ctx', 'docs', 'product', 'domain.md'), 'utf8');
21
- assert.match(filesystemDoc, /This starter is not a completed repository map/);
22
- assert.doesNotMatch(filesystemDoc, /npm package repository/);
23
- assert.doesNotMatch(filesystemDoc, /node_modules/);
24
- assert.match(productDomainDoc, /- Changed: `\d{8}`/);
25
- assert.doesNotMatch(productDomainDoc, /- Changed: `YYYYMMDD`/);
26
- assert.match(result.stdout, /Initialized ADSM context in /);
27
- } finally {
28
- fs.rmSync(sandboxRoot, {recursive: true, force: true});
29
- }
30
- });
31
-
32
- test('cli validate succeeds after init in a clean project', () => {
33
- const sandboxRoot = fs.mkdtempSync(path.join('/tmp', 'adsm-ctx-cli-validate-ok-'));
34
-
35
- try {
36
- const initResult = spawnSync('node', [cliPath, 'init'], {cwd: sandboxRoot, encoding: 'utf8'});
37
- const validateResult = spawnSync('node', [cliPath, 'validate'], {cwd: sandboxRoot, encoding: 'utf8'});
38
-
39
- assert.equal(initResult.status, 0, initResult.stderr);
40
- assert.equal(validateResult.status, 0, validateResult.stderr);
41
- assert.match(validateResult.stdout, /ADSM context validation passed/);
42
- assert.match(validateResult.stdout, /Errors: 0/);
43
- assert.match(validateResult.stdout, /Warnings: 0/);
44
- } finally {
45
- fs.rmSync(sandboxRoot, {recursive: true, force: true});
46
- }
47
- });
48
-
49
- test('cli init does not overwrite existing metadata and validate succeeds after init', () => {
50
- const sandboxRoot = fs.mkdtempSync(path.join('/tmp', 'adsm-ctx-cli-safe-init-'));
51
-
52
- try {
53
- fs.mkdirSync(path.join(sandboxRoot, 'ctx'), {recursive: true});
54
- fs.writeFileSync(path.join(sandboxRoot, 'ctx', 'adsm.json'), '{"schema":"custom","version":"9.9.9"}\n');
55
-
56
- const initResult = spawnSync('node', [cliPath, 'init'], {cwd: sandboxRoot, encoding: 'utf8'});
57
- const validateResult = spawnSync('node', [cliPath, 'validate'], {cwd: sandboxRoot, encoding: 'utf8'});
58
-
59
- assert.equal(initResult.status, 0, initResult.stderr);
60
- assert.match(fs.readFileSync(path.join(sandboxRoot, 'ctx', 'adsm.json'), 'utf8'), /"schema":"custom"/);
61
- assert.equal(validateResult.status, 1);
62
- assert.match(validateResult.stdout, /Unexpected schema: custom/);
63
- } finally {
64
- fs.rmSync(sandboxRoot, {recursive: true, force: true});
65
- }
66
- });
67
-
68
- test('cli validate reports missing context in empty directory', () => {
69
- const sandboxRoot = fs.mkdtempSync(path.join('/tmp', 'adsm-ctx-cli-empty-'));
70
-
71
- try {
72
- const result = spawnSync('node', [cliPath, 'validate'], {cwd: sandboxRoot, encoding: 'utf8'});
73
- assert.equal(result.status, 1);
74
- assert.match(result.stdout, /Missing: ctx/);
75
- assert.match(result.stdout, /Missing ctx\/adsm\.json/);
76
- } finally {
77
- fs.rmSync(sandboxRoot, {recursive: true, force: true});
78
- }
79
- });
80
-
81
- test('cli validate reports invalid skin structure and reference', () => {
82
- const sandboxRoot = fs.mkdtempSync(path.join('/tmp', 'adsm-ctx-cli-invalid-skin-'));
83
-
84
- try {
85
- const initResult = spawnSync('node', [cliPath, 'init'], {cwd: sandboxRoot, encoding: 'utf8'});
86
- assert.equal(initResult.status, 0, initResult.stderr);
87
-
88
- fs.writeFileSync(path.join(sandboxRoot, 'ctx', 'docs', 'product', 'domain.skin.en.md'), [
89
- '# Product Domain Skin',
90
- '',
91
- '- Path: `ctx/docs/product/domain.skin.en.md`',
92
- '- Changed: `20260708`',
93
- '',
94
- '## Purpose',
95
- '',
96
- 'Human-facing control.',
97
- '',
98
- '## Scope',
99
- '',
100
- 'Includes:',
101
- '',
102
- '- domain identity.',
103
- '',
104
- '## Invariants',
105
- '',
106
- '- Keep the domain stable.',
107
- '- invariant 1.',
108
- '- invariant 2.',
109
- '- invariant 3.',
110
- '- invariant 4.',
111
- '- invariant 5.',
112
- '- invariant 6.',
113
- '- invariant 7.',
114
- '- invariant 8.',
115
- '- invariant 9.',
116
- '- invariant 10.',
117
- '- invariant 11.',
118
- '- invariant 12.',
119
- '',
120
- '## Agent Document',
121
- '',
122
- '`other.md`',
123
- '',
124
- ].join('\n'));
125
-
126
- const result = spawnSync('node', [cliPath, 'validate'], {cwd: sandboxRoot, encoding: 'utf8'});
127
- assert.equal(result.status, 1);
128
- assert.match(result.stdout, /Missing skin section "Mental Model": ctx\/docs\/product\/domain\.skin\.en\.md/);
129
- assert.match(result.stdout, /Missing Excludes: block in Scope: ctx\/docs\/product\/domain\.skin\.en\.md/);
130
- assert.match(result.stdout, /Skin agent document mismatch: ctx\/docs\/product\/domain\.skin\.en\.md references ctx\/docs\/product\/other\.md but expected ctx\/docs\/product\/domain\.md/);
131
- } finally {
132
- fs.rmSync(sandboxRoot, {recursive: true, force: true});
133
- }
134
- });
135
-
136
- test('cli validate reports broken local markdown links as errors', () => {
137
- const sandboxRoot = fs.mkdtempSync(path.join('/tmp', 'adsm-ctx-cli-broken-link-'));
138
-
139
- try {
140
- const initResult = spawnSync('node', [cliPath, 'init'], {cwd: sandboxRoot, encoding: 'utf8'});
141
- assert.equal(initResult.status, 0, initResult.stderr);
142
-
143
- fs.writeFileSync(path.join(sandboxRoot, 'ctx', 'docs', 'product', 'overview.md'), [
144
- '# Product Overview',
145
- '',
146
- '- Path: `ctx/docs/product/overview.md`',
147
- '- Changed: `20260708`',
148
- '',
149
- 'See [domain](./missing.md).',
150
- '',
151
- ].join('\n'));
152
-
153
- const result = spawnSync('node', [cliPath, 'validate'], {cwd: sandboxRoot, encoding: 'utf8'});
154
- assert.equal(result.status, 1);
155
- assert.match(result.stdout, /Missing linked document: \.\/missing\.md resolves to ctx\/docs\/product\/missing\.md/);
156
- assert.match(result.stdout, /Errors: [1-9]/);
157
- } finally {
158
- fs.rmSync(sandboxRoot, {recursive: true, force: true});
159
- }
160
- });
161
-
162
- test('cli validate succeeds with warnings only', () => {
163
- const sandboxRoot = fs.mkdtempSync(path.join('/tmp', 'adsm-ctx-cli-warning-only-'));
164
-
165
- try {
166
- const initResult = spawnSync('node', [cliPath, 'init'], {cwd: sandboxRoot, encoding: 'utf8'});
167
- assert.equal(initResult.status, 0, initResult.stderr);
168
-
169
- fs.writeFileSync(path.join(sandboxRoot, 'ctx', 'docs', 'product', 'domain.skin.en.md'), [
170
- '# Product Domain Skin',
171
- '',
172
- '- Path: `ctx/docs/product/domain.skin.en.md`',
173
- '- Changed: `20260708`',
174
- '',
175
- '## Purpose',
176
- '',
177
- 'See [domain](./domain.md#purpose) while keeping the human-facing summary compact.',
178
- '',
179
- '## Mental Model',
180
- '',
181
- 'This is the human semantic frame.',
182
- '',
183
- '## Scope',
184
- '',
185
- 'Includes:',
186
- '',
187
- '- domain identity.',
188
- '',
189
- 'Excludes:',
190
- '',
191
- '- operational overload.',
192
- '',
193
- '## Invariants',
194
- '',
195
- '- Keep the domain stable.',
196
- '- invariant 1.',
197
- '- invariant 2.',
198
- '- invariant 3.',
199
- '- invariant 4.',
200
- '- invariant 5.',
201
- '- invariant 6.',
202
- '- invariant 7.',
203
- '- invariant 8.',
204
- '- invariant 9.',
205
- '- invariant 10.',
206
- '- invariant 11.',
207
- '- invariant 12.',
208
- '',
209
- '## Agent Document',
210
- '',
211
- '`domain.md`',
212
- '',
213
- ].join('\n'));
214
-
215
- const result = spawnSync('node', [cliPath, 'validate'], {cwd: sandboxRoot, encoding: 'utf8'});
216
- assert.equal(result.status, 0, result.stderr);
217
- assert.match(result.stdout, /passed with warnings/i);
218
- assert.match(result.stdout, /Errors: 0/);
219
- assert.match(result.stdout, /Warnings: [1-9]/);
220
- } finally {
221
- fs.rmSync(sandboxRoot, {recursive: true, force: true});
222
- }
223
- });
@@ -1,41 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import {spawnSync} from 'node:child_process';
6
- import {fileURLToPath} from 'node:url';
7
-
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
- const cliPath = path.join(__dirname, '..', '..', 'bin', 'cli.mjs');
11
-
12
- test('cli install-skill installs current payload and replaces stale target content', () => {
13
- const sandboxRoot = fs.mkdtempSync(path.join('/tmp', 'adsm-ctx-cli-install-skill-'));
14
- const skillDir = path.join(sandboxRoot, 'adsm-ctx');
15
- const staleFile = path.join(skillDir, 'stale.txt');
16
- const installedSkill = path.join(skillDir, 'SKILL.md');
17
- const installedReference = path.join(skillDir, 'references', 'context-lifecycle.md');
18
- const installedTemplate = path.join(skillDir, 'templates', 'ctx', 'docs', 'architecture', 'overview.md');
19
-
20
- try {
21
- fs.mkdirSync(skillDir, {recursive: true});
22
- fs.writeFileSync(staleFile, 'obsolete payload\n');
23
- fs.writeFileSync(installedSkill, 'outdated skill\n');
24
-
25
- const result = spawnSync('node', [cliPath, 'install-skill', sandboxRoot], {encoding: 'utf8'});
26
-
27
- assert.equal(result.status, 0, result.stderr);
28
- assert.match(result.stdout, new RegExp(`Installed skill payload to ${escapeRegExp(skillDir)}`));
29
- assert.ok(fs.existsSync(installedSkill));
30
- assert.ok(fs.existsSync(installedReference));
31
- assert.ok(fs.existsSync(installedTemplate));
32
- assert.match(fs.readFileSync(installedSkill, 'utf8'), /name: adsm-ctx/);
33
- assert.equal(fs.existsSync(staleFile), false);
34
- } finally {
35
- fs.rmSync(sandboxRoot, {recursive: true, force: true});
36
- }
37
- });
38
-
39
- function escapeRegExp(value) {
40
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
41
- }
@@ -1,23 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
-
4
- import Cli from '../../../src/Bootstrap/Cli.mjs';
5
-
6
- test('Cli uses project root as default target path', () => {
7
- const cli = new Cli({pathService: {resolve: (value) => `/abs/${value}`}});
8
- const result = cli.parse({cliArgs: ['init'], projectRoot: '/cwd'});
9
- assert.equal(result.targetPath, '/cwd');
10
- assert.equal(result.command, 'init');
11
- });
12
-
13
- test('Cli resolves explicit target path', () => {
14
- const cli = new Cli({pathService: {resolve: (value) => `/abs/${value}`}});
15
- const result = cli.parse({cliArgs: ['validate', 'demo'], projectRoot: '/cwd'});
16
- assert.equal(result.targetPath, '/abs/demo');
17
- });
18
-
19
- test('Cli requires target root for install-skill', () => {
20
- const cli = new Cli({pathService: {resolve: (value) => value}});
21
- const result = cli.parse({cliArgs: ['install-skill'], projectRoot: '/cwd'});
22
- assert.match(result.errors.join('\n'), /install-skill <skills-root>/);
23
- });
@@ -1,53 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
-
4
- import Bootstrap from '../../src/Bootstrap.mjs';
5
-
6
- test('Bootstrap routes init command and reports created and skipped entries', async () => {
7
- const writes = {stdout: [], stderr: []};
8
- const stdoutWrite = process.stdout.write;
9
- const stderrWrite = process.stderr.write;
10
- process.stdout.write = (chunk) => { writes.stdout.push(String(chunk)); return true; };
11
- process.stderr.write = (chunk) => { writes.stderr.push(String(chunk)); return true; };
12
-
13
- try {
14
- const app = new Bootstrap({
15
- cli: {parse: () => ({command: 'init', errors: [], helpRequested: false, targetPath: '/project', usage: 'usage'})},
16
- design: {execute: async () => ''},
17
- init: {execute: async () => ({ctxRoot: '/project/ctx', created: ['ctx'], skipped: ['ctx/adsm.json']})},
18
- installer: {execute: async () => ''},
19
- upgrade: {execute: async () => ({ok: true, message: ''})},
20
- validate: {execute: async () => ({ok: true}), format: () => ''},
21
- });
22
-
23
- const code = await app.run({cliArgs: ['init'], projectRoot: '/project'});
24
- assert.equal(code, 0);
25
- assert.match(writes.stdout.join(''), /Created: ctx/);
26
- assert.match(writes.stdout.join(''), /Skipped: ctx\/adsm\.json/);
27
- } finally {
28
- process.stdout.write = stdoutWrite;
29
- process.stderr.write = stderrWrite;
30
- }
31
- });
32
-
33
- test('Bootstrap prints help and exits with zero', async () => {
34
- const writes = {stdout: [], stderr: []};
35
- const stderrWrite = process.stderr.write;
36
- process.stderr.write = (chunk) => { writes.stderr.push(String(chunk)); return true; };
37
-
38
- try {
39
- const app = new Bootstrap({
40
- cli: {parse: () => ({errors: [], helpRequested: true, usage: 'usage'})},
41
- design: {execute: async () => ''},
42
- init: {execute: async () => ({})},
43
- installer: {execute: async () => ''},
44
- upgrade: {execute: async () => ({ok: true, message: ''})},
45
- validate: {execute: async () => ({ok: true}), format: () => ''},
46
- });
47
- const code = await app.run({cliArgs: ['--help'], projectRoot: '/project'});
48
- assert.equal(code, 0);
49
- assert.equal(writes.stderr.join(''), 'usage\n');
50
- } finally {
51
- process.stderr.write = stderrWrite;
52
- }
53
- });
@@ -1,11 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
-
4
- import Service from '../../../src/Design/Service.mjs';
5
-
6
- test('Design service references questionnaire and orchestration', async () => {
7
- const service = new Service();
8
- const result = await service.execute({targetPath: '/project'});
9
- assert.match(result, /design-questionnaire\.md/);
10
- assert.match(result, /specialized ADSM skills/);
11
- });
@@ -1,51 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
-
4
- import Service from '../../../src/Init/Service.mjs';
5
-
6
- test('Init service creates metadata only when missing', async () => {
7
- const writes = [];
8
- const fs = {
9
- existing: new Set(),
10
- existsSync(path) { return this.existing.has(path); },
11
- mkdirSync(path) { this.existing.add(path); },
12
- writeFileSync(path, content) { this.existing.add(path); writes.push({path, content}); },
13
- };
14
- const copyDirectory = {
15
- copyMissing: ({created}) => created.push('ctx'),
16
- };
17
- const service = new Service({
18
- copyDirectory,
19
- fs,
20
- metadata: {create: () => ({schema: 'adsm-context', version: '0.1.0'})},
21
- pathService: {join: (...parts) => parts.join('/'), resolve: (value) => value},
22
- url: {fileURLToPath: () => '/templates/ctx'},
23
- });
24
-
25
- const result = await service.execute({targetPath: '/project'});
26
- assert.equal(result.projectRoot, '/project');
27
- assert.ok(result.created.includes('ctx'));
28
- assert.ok(result.created.includes('AGENTS.md'));
29
- assert.ok(result.created.includes('ctx/adsm.json'));
30
- assert.match(writes.find((item) => item.path === '/project/ctx/adsm.json').content, /"version": "0\.1\.0"/);
31
- });
32
-
33
- test('Init service skips existing root agents and metadata', async () => {
34
- const fs = {
35
- existing: new Set(['/project/AGENTS.md', '/project/ctx/adsm.json']),
36
- existsSync(path) { return this.existing.has(path); },
37
- mkdirSync() {},
38
- writeFileSync() { throw new Error('unexpected write'); },
39
- };
40
- const service = new Service({
41
- copyDirectory: {copyMissing() {}},
42
- fs,
43
- metadata: {create: () => ({schema: 'adsm-context', version: '0.1.0'})},
44
- pathService: {join: (...parts) => parts.join('/'), resolve: (value) => value},
45
- url: {fileURLToPath: () => '/templates/ctx'},
46
- });
47
-
48
- const result = await service.execute({targetPath: '/project'});
49
- assert.ok(result.skipped.includes('AGENTS.md'));
50
- assert.ok(result.skipped.includes('ctx/adsm.json'));
51
- });
@@ -1,21 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
-
4
- import Constants from '../../../src/Shared/Constants.mjs';
5
-
6
- test('Constants publish required baseline markers', () => {
7
- const constants = new Constants();
8
- assert.equal(constants.CONTEXT_SCHEMA, 'adsm-context');
9
- assert.equal(constants.CONTEXT_VERSION, '0.1.0');
10
- assert.equal(constants.SKIN_WORD_WARN, 160);
11
- assert.equal(constants.SKIN_WORD_ERROR, 240);
12
- assert.equal(constants.SKIN_LIST_WARN, 12);
13
- assert.equal(constants.SKIN_LIST_ERROR, 20);
14
- assert.equal(constants.DOC_LEVEL_MAX_DIRECTORIES, 9);
15
- assert.equal(constants.DOC_LEVEL_MAX_FILES, 9);
16
- assert.ok(constants.REQUIRED_PATHS.includes('ctx/adsm.json'));
17
- assert.deepEqual(constants.DOC_LEVELS, ['product', 'architecture', 'environment', 'code']);
18
- assert.ok(constants.REQUIRED_PATHS.includes('ctx/docs/architecture'));
19
- assert.equal(constants.REQUIRED_PATHS.includes('ctx/docs/product/overview.md'), false);
20
- assert.equal(constants.REQUIRED_PATHS.includes('ctx/docs/filesystem.md'), false);
21
- });
@@ -1,31 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
-
4
- import CopyDirectory from '../../../src/Shared/CopyDirectory.mjs';
5
-
6
- test('CopyDirectory copies only missing files', () => {
7
- const copied = [];
8
- const fs = {
9
- existing: new Set(['/target', '/target/exists.txt']),
10
- existsSync(path) { return this.existing.has(path); },
11
- mkdirSync(path) { this.existing.add(path); },
12
- readdirSync(path) {
13
- if (path === '/source') {
14
- return [
15
- {name: 'exists.txt', isDirectory: () => false},
16
- {name: 'missing.txt', isDirectory: () => false},
17
- ];
18
- }
19
- return [];
20
- },
21
- copyFileSync(source, target) { copied.push({source, target}); this.existing.add(target); },
22
- };
23
- const service = new CopyDirectory({fs, pathService: {join: (...parts) => parts.join('/')}});
24
- const created = [];
25
- const skipped = [];
26
- service.copyMissing({created, skipped, pathPrefix: 'ctx', sourcePath: '/source', targetPath: '/target'});
27
-
28
- assert.deepEqual(copied, [{source: '/source/missing.txt', target: '/target/missing.txt'}]);
29
- assert.ok(created.includes('ctx/missing.txt'));
30
- assert.ok(skipped.includes('ctx/exists.txt'));
31
- });
@@ -1,9 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
-
4
- import Metadata from '../../../src/Shared/Metadata.mjs';
5
-
6
- test('Metadata creates baseline payload without hardcoded date field', () => {
7
- const metadata = new Metadata({constants: {CONTEXT_SCHEMA: 'adsm-context', CONTEXT_VERSION: '0.1.0'}});
8
- assert.deepEqual(metadata.create(), {schema: 'adsm-context', version: '0.1.0'});
9
- });
@@ -1,11 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
-
4
- import PathService from '../../../src/Shared/Path.mjs';
5
-
6
- test('Path service delegates resolve and join', () => {
7
- const path = {resolve: (value) => `/root/${value}`, join: (...parts) => parts.join('/')};
8
- const service = new PathService({path});
9
- assert.equal(service.resolve('demo'), '/root/demo');
10
- assert.equal(service.join('a', 'b'), 'a/b');
11
- });
@@ -1,20 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
-
4
- import Installer from '../../../src/Skill/Installer.mjs';
5
-
6
- test('Installer removes target and copies skill payload', async () => {
7
- const removed = [];
8
- const copied = [];
9
- const installer = new Installer({
10
- copyDirectory: {execute: (params) => copied.push(params)},
11
- fs: {rmSync: (target, options) => removed.push({target, options})},
12
- pathService: {join: (...parts) => parts.join('/'), resolve: (value) => `/abs/${value}`},
13
- url: {fileURLToPath: () => '/repo/skill'},
14
- });
15
-
16
- const result = await installer.execute({targetRoot: 'skills'});
17
- assert.equal(result, '/abs/skills/adsm-ctx');
18
- assert.deepEqual(removed[0], {target: '/abs/skills/adsm-ctx', options: {recursive: true, force: true}});
19
- assert.deepEqual(copied[0], {sourcePath: '/repo/skill', targetPath: '/abs/skills/adsm-ctx'});
20
- });
@@ -1,13 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
-
4
- import Service from '../../../src/Upgrade/Service.mjs';
5
-
6
- test('Upgrade service reports missing metadata', async () => {
7
- const service = new Service({
8
- fs: {existsSync: () => false},
9
- pathService: {join: (...parts) => parts.join('/'), resolve: (value) => value},
10
- });
11
- const result = await service.execute({targetPath: '/project'});
12
- assert.equal(result.ok, false);
13
- });