@flancer32/skill-adsm-ctx 0.3.0 → 0.5.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 (67) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +44 -37
  3. package/bin/adsm-ctx.mjs +1 -1
  4. package/package.json +4 -18
  5. package/{skill → skills/adsm-ctx}/SKILL.md +22 -5
  6. package/{skill → skills/adsm-ctx}/references/agents-hierarchy.md +1 -1
  7. package/skills/adsm-ctx/references/context-evolution.md +55 -0
  8. package/{skill → skills/adsm-ctx}/references/context-lifecycle.md +28 -9
  9. package/{skill → skills/adsm-ctx}/references/design-questionnaire.md +14 -2
  10. package/{skill → skills/adsm-ctx}/references/document-projections.md +39 -21
  11. package/{skill → skills/adsm-ctx}/references/documentation-compression.md +6 -5
  12. package/{skill → skills/adsm-ctx}/references/documentation-quality-audit.md +20 -5
  13. package/{skill → skills/adsm-ctx}/references/orchestration-model.md +10 -7
  14. package/{skill → skills/adsm-ctx}/references/semantic-skins.md +3 -1
  15. package/{skill → skills/adsm-ctx}/references/specialized-skills.md +6 -3
  16. package/skills/adsm-ctx/templates/AGENTS.md +19 -0
  17. package/skills/adsm-ctx/templates/ctx/AGENTS.md +46 -0
  18. package/{skill → skills/adsm-ctx}/templates/ctx/README.md +1 -1
  19. package/{skill → skills/adsm-ctx}/templates/ctx/adsm.json +4 -1
  20. package/skills/adsm-ctx/templates/ctx/agent/AGENTS.md +32 -0
  21. package/skills/adsm-ctx/templates/ctx/docs/AGENTS.md +64 -0
  22. package/skills/adsm-ctx/templates/ctx/docs/code/testing.md +17 -0
  23. package/skills/adsm-ctx/templates/ctx/docs/verification/AGENTS.md +31 -0
  24. package/src/Init/Service.mjs +5 -26
  25. package/src/Shared/Constants.mjs +7 -1
  26. package/src/Shared/Metadata.mjs +1 -0
  27. package/src/Skill/Installer.mjs +3 -3
  28. package/src/Validate/Service.mjs +282 -105
  29. package/types.d.ts +0 -4
  30. package/migrations/README.md +0 -9
  31. package/skill/references/upgrade-policy.md +0 -19
  32. package/skill/templates/AGENTS.md +0 -120
  33. package/skill/templates/ai/AGENTS.md +0 -59
  34. package/skill/templates/ctx/AGENTS.md +0 -45
  35. package/skill/templates/ctx/agent/AGENTS.md +0 -36
  36. package/skill/templates/ctx/docs/AGENTS.md +0 -55
  37. package/skill/templates/ctx/docs/code/testing.md +0 -13
  38. package/src/Cli/Command/Design.mjs +0 -17
  39. package/src/Cli/Command/Upgrade.mjs +0 -19
  40. package/src/Design/Service.mjs +0 -36
  41. package/src/Upgrade/Service.mjs +0 -44
  42. /package/{skill/templates/work → skills/adsm-ctx/assets}/context/semantic-skin.md +0 -0
  43. /package/{skill/templates/work → skills/adsm-ctx/assets}/report/documentation-compression.md +0 -0
  44. /package/{skill/templates/work → skills/adsm-ctx/assets}/report/documentation-quality-audit.md +0 -0
  45. /package/{skill → skills/adsm-ctx}/templates/ctx/assets/.gitkeep +0 -0
  46. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/ai-intro.md +0 -0
  47. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/architecture/AGENTS.md +0 -0
  48. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/architecture/behavior.md +0 -0
  49. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/architecture/checklists.md +0 -0
  50. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/architecture/constraints.md +0 -0
  51. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/architecture/decisions.md +0 -0
  52. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/architecture/integration.md +0 -0
  53. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/architecture/overview.md +0 -0
  54. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/architecture/state.md +0 -0
  55. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/architecture/structure.md +0 -0
  56. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/architecture/supervision.md +0 -0
  57. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/code/AGENTS.md +0 -0
  58. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/code/overview.md +0 -0
  59. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/environment/AGENTS.md +0 -0
  60. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/environment/overview.md +0 -0
  61. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/filesystem.md +0 -0
  62. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/product/AGENTS.md +0 -0
  63. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/product/domain.md +0 -0
  64. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/product/glossary.md +0 -0
  65. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/product/overview.md +0 -0
  66. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/product/roles.md +0 -0
  67. /package/{skill → skills/adsm-ctx}/templates/ctx/docs/product/use-cases.md +0 -0
@@ -5,7 +5,7 @@
5
5
  * @description Installs the bundled skill payload into a target skills directory.
6
6
  */
7
7
 
8
- const sourceRoot = new URL("../../skill/", import.meta.url);
8
+ const sourceRoot = new URL("../../skills/adsm-ctx/", import.meta.url);
9
9
 
10
10
  export default class Installer {
11
11
  /**
@@ -39,9 +39,9 @@ export default class Installer {
39
39
  }
40
40
  }
41
41
 
42
- export const __deps__ = Object.freeze({
42
+ export const __deps__ = Object.freeze({default: Object.freeze({
43
43
  copyDirectory: "Fl32_Skill_Adsm_Ctx_Shared_CopyDirectory$",
44
44
  fs: "node:fs",
45
45
  pathService: "Fl32_Skill_Adsm_Ctx_Shared_Path$",
46
46
  url: "node:url",
47
- });
47
+ })});
@@ -31,7 +31,7 @@ export default class Validate {
31
31
  * ruleId: string,
32
32
  * severity: "error" | "warning"
33
33
  * }[],
34
- * metadata: {schema: string, version: string, initializedAt?: string} | null,
34
+ * metadata: {capabilities?: string[], schema: string, version: string, initializedAt?: string} | null,
35
35
  * missingPaths: string[],
36
36
  * ok: boolean,
37
37
  * projectRoot: string,
@@ -40,7 +40,8 @@ export default class Validate {
40
40
  * bodies: string[],
41
41
  * orphanSkins: string[],
42
42
  * pairs: {body: string, skin: string}[],
43
- * skins: string[]
43
+ * skins: string[],
44
+ * verification: {categories: string[], present: boolean}
44
45
  * },
45
46
  * warningCount: number
46
47
  * }>}
@@ -54,10 +55,27 @@ export default class Validate {
54
55
  ruleId: "required-path",
55
56
  severity: "error",
56
57
  }));
57
- const metadata = readMetadata({constants, fs, pathService, projectRoot});
58
- const projection = inspectProjection({constants, fs, pathService, projectRoot});
59
-
60
- if (!metadata.ok) findings.push(metadata.finding);
58
+ const metadataResult = readMetadata({constants, fs, pathService, projectRoot});
59
+ const projection = inspectProjection({
60
+ constants,
61
+ fs,
62
+ metadata: metadataResult.ok ? metadataResult.metadata : null,
63
+ pathService,
64
+ projectRoot,
65
+ });
66
+
67
+ for (const entry of constants.REQUIRED_PATHS) {
68
+ const absolute = pathService.join(projectRoot, entry);
69
+ if (!fs.existsSync(absolute) || typeof fs.statSync !== "function") continue;
70
+ const stat = fs.statSync(absolute);
71
+ const file = entry.endsWith(".md") || entry.endsWith(".json");
72
+ if (file ? !stat.isFile() : !stat.isDirectory()) findings.push(createFinding({
73
+ message: `Required path has wrong filesystem type: ${entry}`,
74
+ path: entry, ruleId: "required-path-type", severity: "error",
75
+ }));
76
+ }
77
+ findings.push(...inspectAgentsHierarchy({fs, pathService, projectRoot}));
78
+ findings.push(...metadataResult.findings);
61
79
  findings.push(...projection.findings);
62
80
 
63
81
  const errorCount = findings.filter((entry) => entry.severity === "error").length;
@@ -66,7 +84,7 @@ export default class Validate {
66
84
  return {
67
85
  errorCount,
68
86
  findings,
69
- metadata: metadata.ok ? metadata.metadata : null,
87
+ metadata: metadataResult.metadata,
70
88
  missingPaths,
71
89
  ok: errorCount === 0,
72
90
  projectRoot,
@@ -104,7 +122,8 @@ export default class Validate {
104
122
  const lines = [
105
123
  status,
106
124
  `Project root: ${result.projectRoot}`,
107
- `Context version: ${result.metadata?.version ?? "unknown"}`,
125
+ `Context schema version: ${result.metadata?.version ?? "unknown"}`,
126
+ `Supported context schema version: ${constants.CONTEXT_VERSION}`,
108
127
  `Errors: ${result.errorCount}`,
109
128
  `Warnings: ${result.warningCount}`,
110
129
  ];
@@ -180,54 +199,82 @@ function parseSkinFilename(file) {
180
199
  * }}
181
200
  */
182
201
  function readMetadata({constants, fs, pathService, projectRoot}) {
202
+ const findings = [];
183
203
  const metadataPath = pathService.join(projectRoot, "ctx", "adsm.json");
184
204
  if (!fs.existsSync(metadataPath)) {
185
- return {
186
- ok: false,
187
- finding: createFinding({
188
- message: "Missing ctx/adsm.json",
189
- path: "ctx/adsm.json",
190
- ruleId: "metadata-file",
191
- severity: "error",
192
- }),
193
- };
205
+ findings.push(createFinding({
206
+ message: "Missing ctx/adsm.json",
207
+ path: "ctx/adsm.json",
208
+ ruleId: "metadata-file",
209
+ severity: "error",
210
+ }));
211
+ return {findings, metadata: null, ok: false};
194
212
  }
195
213
 
196
214
  try {
197
215
  const parsed = JSON.parse(fs.readFileSync(metadataPath, "utf8"));
198
216
  if (parsed.schema !== constants.CONTEXT_SCHEMA) {
199
- return {
200
- ok: false,
201
- finding: createFinding({
202
- message: `Unexpected schema: ${parsed.schema}`,
203
- path: "ctx/adsm.json",
204
- ruleId: "metadata-schema",
205
- severity: "error",
206
- }),
207
- };
217
+ findings.push(createFinding({
218
+ message: `Unexpected schema: ${parsed.schema}`,
219
+ path: "ctx/adsm.json",
220
+ ruleId: "metadata-schema",
221
+ severity: "error",
222
+ }));
208
223
  }
209
- if (!parsed.version) {
210
- return {
211
- ok: false,
212
- finding: createFinding({
213
- message: "Missing metadata version",
224
+ if (parsed.version !== constants.CONTEXT_VERSION) {
225
+ findings.push(createFinding({
226
+ message: ["0.1.0", "0.2.0", "0.3.0"].includes(parsed.version)
227
+ ? `Legacy schema ${parsed.version}; use skill adsm-ctx for agent-driven context evolution. Target schema: ${constants.CONTEXT_VERSION}.`
228
+ : `Unsupported metadata version: ${parsed.version}; investigate with skill adsm-ctx before changing schema metadata.`,
229
+ path: "ctx/adsm.json",
230
+ ruleId: "metadata-version",
231
+ severity: "error",
232
+ }));
233
+ }
234
+
235
+ if (Object.hasOwn(parsed, "capabilities")) {
236
+ if (!Array.isArray(parsed.capabilities)) {
237
+ findings.push(createFinding({
238
+ message: "Metadata capabilities must be an array of unique strings",
214
239
  path: "ctx/adsm.json",
215
- ruleId: "metadata-version",
240
+ ruleId: "metadata-capabilities",
216
241
  severity: "error",
217
- }),
218
- };
242
+ }));
243
+ } else {
244
+ const seen = new Set();
245
+ for (const capability of parsed.capabilities) {
246
+ if (typeof capability !== "string" || capability.length === 0 || seen.has(capability)) {
247
+ findings.push(createFinding({
248
+ message: "Metadata capabilities must be an array of unique non-empty strings",
249
+ path: "ctx/adsm.json",
250
+ ruleId: "metadata-capabilities",
251
+ severity: "error",
252
+ }));
253
+ break;
254
+ }
255
+ seen.add(capability);
256
+ if (!(constants.CONTEXT_CAPABILITIES ?? []).includes(capability)) {
257
+ findings.push(createFinding({
258
+ message: `Unknown context capability: ${capability}`,
259
+ path: "ctx/adsm.json",
260
+ ruleId: "metadata-capability-unknown",
261
+ severity: "warning",
262
+ }));
263
+ }
264
+ }
265
+ }
219
266
  }
220
- return {ok: true, metadata: parsed};
267
+
268
+ const ok = findings.every((entry) => entry.severity !== "error");
269
+ return {findings, metadata: parsed, ok};
221
270
  } catch (error) {
222
- return {
223
- ok: false,
224
- finding: createFinding({
225
- message: `Invalid metadata JSON: ${error instanceof Error ? error.message : "Unknown error"}`,
226
- path: "ctx/adsm.json",
227
- ruleId: "metadata-json",
228
- severity: "error",
229
- }),
230
- };
271
+ findings.push(createFinding({
272
+ message: `Invalid metadata JSON: ${error instanceof Error ? error.message : "Unknown error"}`,
273
+ path: "ctx/adsm.json",
274
+ ruleId: "metadata-json",
275
+ severity: "error",
276
+ }));
277
+ return {findings, metadata: null, ok: false};
231
278
  }
232
279
  }
233
280
 
@@ -253,7 +300,7 @@ function readMetadata({constants, fs, pathService, projectRoot}) {
253
300
  * }
254
301
  * }}
255
302
  */
256
- function inspectProjection({constants, fs, pathService, projectRoot}) {
303
+ function inspectProjection({constants, fs, metadata, pathService, projectRoot}) {
257
304
  const docsRoot = pathService.join(projectRoot, "ctx", "docs");
258
305
  const assetsRoot = pathService.join(projectRoot, "ctx", "assets");
259
306
  const findings = [];
@@ -303,6 +350,26 @@ function inspectProjection({constants, fs, pathService, projectRoot}) {
303
350
  pathService,
304
351
  projectRoot,
305
352
  }));
353
+ const verification = inspectVerificationBlock({
354
+ constants,
355
+ docsEntryMap,
356
+ fs,
357
+ pathService,
358
+ projectRoot,
359
+ });
360
+ findings.push(...verification.findings);
361
+ if (
362
+ verification.summary.present
363
+ && metadata
364
+ && !metadata.capabilities?.includes(constants.VERIFICATION_CAPABILITY)
365
+ ) {
366
+ findings.push(createFinding({
367
+ message: `Verification block is present without declared ${constants.VERIFICATION_CAPABILITY} capability`,
368
+ path: "ctx/adsm.json",
369
+ ruleId: "verification-capability-undocumented",
370
+ severity: "warning",
371
+ }));
372
+ }
306
373
 
307
374
  const markdownFiles = [];
308
375
  for (const file of listFiles({fs, pathService, root: docsRoot, prefix: "ctx/docs"})) {
@@ -365,10 +432,120 @@ function inspectProjection({constants, fs, pathService, projectRoot}) {
365
432
  orphanSkins,
366
433
  pairs,
367
434
  skins,
435
+ verification: verification.summary,
368
436
  },
369
437
  };
370
438
  }
371
439
 
440
+ /**
441
+ * Inspects the cross-cutting Verification Layer without treating it as a fifth
442
+ * declarative documentation level.
443
+ *
444
+ * @param {object} params
445
+ * @param {Fl32_Skill_Adsm_Ctx_Shared_Constants} params.constants
446
+ * @param {Map<string, {name: string, isDirectory: () => boolean, isFile: () => boolean}>} params.docsEntryMap
447
+ * @param {typeof import("node:fs")} params.fs
448
+ * @param {Fl32_Skill_Adsm_Ctx_Shared_Path} params.pathService
449
+ * @param {string} params.projectRoot
450
+ * @returns {{
451
+ * findings: {message: string, path: string, ruleId: string, severity: "error" | "warning"}[],
452
+ * summary: {categories: string[], present: boolean}
453
+ * }}
454
+ */
455
+ function inspectVerificationBlock({constants, docsEntryMap, fs, pathService, projectRoot}) {
456
+ const findings = [];
457
+ const summary = {categories: [], present: false};
458
+ const entry = docsEntryMap.get(constants.VERIFICATION_BLOCK);
459
+ if (!entry) return {findings, summary};
460
+
461
+ summary.present = true;
462
+ const verificationPath = `ctx/docs/${constants.VERIFICATION_BLOCK}`;
463
+ if (!entry.isDirectory()) {
464
+ findings.push(createFinding({
465
+ message: `Verification block is not a directory: ${verificationPath}`,
466
+ path: verificationPath,
467
+ ruleId: "verification-block",
468
+ severity: "error",
469
+ }));
470
+ return {findings, summary};
471
+ }
472
+
473
+ let entries = [];
474
+ try {
475
+ entries = listEntries({
476
+ fs,
477
+ root: pathService.join(projectRoot, ...verificationPath.split("/")),
478
+ });
479
+ } catch (error) {
480
+ findings.push(createFinding({
481
+ message: `Unreadable verification block (${error instanceof Error ? error.message : "Unknown error"})`,
482
+ path: verificationPath,
483
+ ruleId: "verification-block-readable",
484
+ severity: "error",
485
+ }));
486
+ return {findings, summary};
487
+ }
488
+
489
+ const agentsEntry = entries.find((candidate) => candidate.name === "AGENTS.md");
490
+ if (!agentsEntry?.isFile()) {
491
+ findings.push(createFinding({
492
+ message: `Verification block requires ${verificationPath}/AGENTS.md`,
493
+ path: `${verificationPath}/AGENTS.md`,
494
+ ruleId: "verification-agents",
495
+ severity: "error",
496
+ }));
497
+ }
498
+
499
+ const targets = constants.VERIFICATION_TARGETS ?? constants.DOC_LEVELS;
500
+ for (const child of entries) {
501
+ if (child.name === "AGENTS.md") continue;
502
+ if (!targets.includes(child.name)) {
503
+ if (child.isDirectory()) {
504
+ findings.push(createFinding({
505
+ message: `Unsupported verification category: ${child.name}`,
506
+ path: `${verificationPath}/${child.name}`,
507
+ ruleId: "verification-category",
508
+ severity: "error",
509
+ }));
510
+ }
511
+ continue;
512
+ }
513
+
514
+ if (!child.isDirectory()) {
515
+ findings.push(createFinding({
516
+ message: `Verification category is not a directory: ${child.name}`,
517
+ path: `${verificationPath}/${child.name}`,
518
+ ruleId: "verification-category",
519
+ severity: "error",
520
+ }));
521
+ continue;
522
+ }
523
+
524
+ summary.categories.push(child.name);
525
+ const categoryPath = `${verificationPath}/${child.name}`;
526
+ const documents = listFiles({
527
+ fs,
528
+ pathService,
529
+ prefix: categoryPath,
530
+ root: pathService.join(projectRoot, ...categoryPath.split("/")),
531
+ }).filter((file) => (
532
+ file.endsWith(".md")
533
+ && !file.endsWith("/AGENTS.md")
534
+ && !parseSkinFilename(file)
535
+ ));
536
+ if (documents.length === 0) {
537
+ findings.push(createFinding({
538
+ message: `Verification category has no durable specification: ${categoryPath}`,
539
+ path: categoryPath,
540
+ ruleId: "verification-empty-category",
541
+ severity: "error",
542
+ }));
543
+ }
544
+ }
545
+
546
+ return {findings, summary};
547
+ }
548
+
372
549
  /**
373
550
  * Warns when a documentation level exceeds the recommended direct-entry capacity
374
551
  * and requires its local AGENTS.md to make an intentional exception explicit.
@@ -578,6 +755,14 @@ function validateSkinDocument({bodySet, constants, file, skinInfo, text}) {
578
755
  severity: "error",
579
756
  }));
580
757
  }
758
+ if (/^#{1,6}\s+Agent Document\s*#*\s*$/mi.test(text)) {
759
+ findings.push(createFinding({
760
+ message: "Redundant Agent Document section: skin pairing is derived from its filename",
761
+ path: file,
762
+ ruleId: "skin-redundant-agent-document-section",
763
+ severity: "error",
764
+ }));
765
+ }
581
766
  return findings;
582
767
  }
583
768
 
@@ -650,66 +835,58 @@ function normalizeRelativeSegments(parts) {
650
835
  return result;
651
836
  }
652
837
 
653
- /**
654
- * @param {string} text
655
- * @returns {string}
656
- */
657
- function stripFencedCodeBlocks(text) {
658
- return text.replace(/```[\s\S]*?```/g, "");
659
- }
660
-
661
- /**
662
- * Extracts all human-facing skin content while excluding metadata and headings.
663
- *
664
- * @param {string} text
665
- * @returns {string}
666
- */
667
- function extractSkinMetricText(text) {
668
- return stripSkinPresentation(text);
669
- }
670
-
671
- /**
672
- * @param {string} text
673
- * @returns {string}
674
- */
675
- function stripSkinPresentation(text) {
676
- let insideLegacyReference = false;
677
- return stripFencedCodeBlocks(text)
678
- .split("\n")
679
- .filter((line) => {
680
- const trimmed = line.trim();
681
- if (/^##\s+Agent Document\s*$/.test(trimmed)) {
682
- insideLegacyReference = true;
683
- return false;
684
- }
685
- if (insideLegacyReference && /^##\s+/.test(trimmed)) insideLegacyReference = false;
686
- return !insideLegacyReference && !/^#/.test(trimmed) && !/^- (?:Path|Changed): `[^`]+`$/.test(trimmed);
687
- })
688
- .join("\n")
689
- .replace(/^\s*(?:Includes|Excludes):\s*$/gmu, "");
690
- }
691
-
692
- /**
693
- * @param {string} text
694
- * @returns {number}
695
- */
696
- function countWords(text) {
697
- const matches = stripFencedCodeBlocks(text).match(/(?:\p{L}[\p{L}\p{M}\p{N}'’_-]*|\p{N}+)/gu);
698
- return matches ? matches.length : 0;
699
- }
700
-
701
- /**
702
- * @param {string} text
703
- * @returns {number}
704
- */
705
- function countMeaningfulListItems(text) {
706
- return [...stripFencedCodeBlocks(text).matchAll(/^\s*(?:[-*+]|\d+[.)])\s+(.+)$/gmu)]
707
- .filter((match) => countWords(match[1]) > 0)
708
- .length;
709
- }
710
-
711
- export const __deps__ = Object.freeze({
838
+ export const __deps__ = Object.freeze({default: Object.freeze({
712
839
  constants: "Fl32_Skill_Adsm_Ctx_Shared_Constants$",
713
840
  fs: "node:fs",
714
841
  pathService: "Fl32_Skill_Adsm_Ctx_Shared_Path$",
715
- });
842
+ })});
843
+
844
+ /** Checks context-side routing sections; root repository instructions have a separate shape. */
845
+ function inspectAgentsHierarchy({fs, pathService, projectRoot}) {
846
+ const findings = [];
847
+ const root = pathService.join(projectRoot, "ctx");
848
+ if (!fs.existsSync(root)) return findings;
849
+ const visit = (directory, relative) => {
850
+ let entries;
851
+ try { entries = listEntries({fs, root: directory}); }
852
+ catch (error) {
853
+ findings.push(createFinding({message: `Cannot inspect context routing: ${error.message}`, path: relative, ruleId: "agents-readable", severity: "error"}));
854
+ return;
855
+ }
856
+ for (const entry of entries) {
857
+ const absolute = pathService.join(directory, entry.name);
858
+ const file = `${relative}/${entry.name}`;
859
+ if (entry.isDirectory()) visit(absolute, file);
860
+ else if (entry.isFile() && entry.name === "AGENTS.md") {
861
+ let text;
862
+ try { text = fs.readFileSync(absolute, "utf8"); }
863
+ catch (error) {
864
+ findings.push(createFinding({message: `Cannot read context AGENTS.md: ${error.message}`, path: file, ruleId: "agents-readable", severity: "error"}));
865
+ continue;
866
+ }
867
+ // Ignore fenced examples so sample headings cannot satisfy the document structure.
868
+ const headings = new Set();
869
+ let fence = null;
870
+ for (const line of text.split(/\r?\n/)) {
871
+ const marker = /^ {0,3}(`{3,}|~{3,})/.exec(line);
872
+ if (marker) {
873
+ if (!fence) fence = marker[1];
874
+ else if (marker[1][0] === fence[0] && marker[1].length >= fence.length) fence = null;
875
+ continue;
876
+ }
877
+ if (fence) continue;
878
+ const heading = /^ {0,3}##[ \t]+(.+?)[ \t]*$/.exec(line);
879
+ if (heading) headings.add(heading[1].replace(/[ \t]+#+[ \t]*$/, ""));
880
+ }
881
+ for (const section of ["Purpose", "Level Map", "Level Boundary"]) {
882
+ if (!headings.has(section)) findings.push(createFinding({
883
+ message: `Missing required section: ## ${section}. Add it to this context-side AGENTS.md.`,
884
+ path: file, ruleId: "agents-required-section", severity: "error",
885
+ }));
886
+ }
887
+ }
888
+ }
889
+ };
890
+ visit(root, "ctx");
891
+ return findings;
892
+ }
package/types.d.ts CHANGED
@@ -1,17 +1,13 @@
1
1
  declare global {
2
- type Fl32_Skill_Adsm_Ctx_Cli_Command_Design = import("./src/Cli/Command/Design.mjs").default;
3
2
  type Fl32_Skill_Adsm_Ctx_Cli_Command_Init = import("./src/Cli/Command/Init.mjs").default;
4
3
  type Fl32_Skill_Adsm_Ctx_Cli_Command_InstallSkill = import("./src/Cli/Command/InstallSkill.mjs").default;
5
- type Fl32_Skill_Adsm_Ctx_Cli_Command_Upgrade = import("./src/Cli/Command/Upgrade.mjs").default;
6
4
  type Fl32_Skill_Adsm_Ctx_Cli_Command_Validate = import("./src/Cli/Command/Validate.mjs").default;
7
- type Fl32_Skill_Adsm_Ctx_Design_Service = import("./src/Design/Service.mjs").default;
8
5
  type Fl32_Skill_Adsm_Ctx_Init_Service = import("./src/Init/Service.mjs").default;
9
6
  type Fl32_Skill_Adsm_Ctx_Shared_Constants = import("./src/Shared/Constants.mjs").default;
10
7
  type Fl32_Skill_Adsm_Ctx_Shared_CopyDirectory = import("./src/Shared/CopyDirectory.mjs").default;
11
8
  type Fl32_Skill_Adsm_Ctx_Shared_Metadata = import("./src/Shared/Metadata.mjs").default;
12
9
  type Fl32_Skill_Adsm_Ctx_Shared_Path = import("./src/Shared/Path.mjs").default;
13
10
  type Fl32_Skill_Adsm_Ctx_Skill_Installer = import("./src/Skill/Installer.mjs").default;
14
- type Fl32_Skill_Adsm_Ctx_Upgrade_Service = import("./src/Upgrade/Service.mjs").default;
15
11
  type Fl32_Skill_Adsm_Ctx_Validate_Service = import("./src/Validate/Service.mjs").default;
16
12
  }
17
13
 
@@ -1,9 +0,0 @@
1
- # Migrations
2
-
3
- This directory is reserved for future context migrations.
4
-
5
- Each migration should be:
6
-
7
- - versioned;
8
- - non-destructive by default;
9
- - explicit about prerequisites and post-upgrade manual steps.
@@ -1,19 +0,0 @@
1
- # Upgrade Policy
2
-
3
- - Path: `skill/references/upgrade-policy.md`
4
- - Changed: `20260708`
5
-
6
- Upgrades must be non-destructive by default.
7
-
8
- Safe upgrade behavior includes:
9
-
10
- - adding missing files and directories;
11
- - updating metadata when the migration rules are explicit;
12
- - preserving project-authored content unless replacement is proven safe.
13
- - detecting agent/skin pairs, orphan skins, and projection drift according to `skill/references/document-projections.md`;
14
- - preserving project-specific nested subdirectories under `ctx/docs/product/`, `ctx/docs/architecture/`, `ctx/docs/environment/`, and `ctx/docs/code/`;
15
- - keeping visual, generated, rendered, and auxiliary artifacts under `ctx/assets/**`.
16
-
17
- Unsafe cases should be reported for manual follow-up instead of applied automatically.
18
-
19
- Upgrade must not introduce required `README.md` files inside `ctx/docs/` and must not automatically rewrite human-controlled skins when agent/skin meaning is unclear.
@@ -1,120 +0,0 @@
1
- # Root Level
2
-
3
- - Path: `AGENTS.md`
4
- - Template Version: `20260720`
5
- - Changed: `YYYYMMDD`
6
-
7
- ## Purpose
8
-
9
- This file defines the root-level working rules for the project repository.
10
-
11
- This file is the first instruction source for every agent operating within the repository.
12
-
13
- ## Level Boundary
14
-
15
- Defines:
16
-
17
- - Root-level working boundaries between the repository, the cognitive context, and the software product.
18
- - Repository-topology rules needed to work safely when `ctx/` may be mounted separately.
19
- - Root-level protection and escalation rules for this project.
20
-
21
- Does NOT define:
22
-
23
- - Product-specific meaning, requirements, or domain knowledge.
24
- - Implementation-level structure such as source code, runtime details, or filesystem layout.
25
- - Task-specific instructions, workflows, or local operational procedures.
26
-
27
- ## ADSM Project Model
28
-
29
- An ADSM project consists of two interconnected spaces:
30
-
31
- - the **Cognitive Context** located in `./ctx/`
32
- - the **Software Product** located outside `./ctx/`
33
-
34
- The cognitive context is the long-term textual memory of the project.
35
-
36
- The cognitive context is the primary communication medium between Humans and Agents working on the project.
37
-
38
- The cognitive context is the authoritative knowledge source used by Agents when modifying the project.
39
-
40
- The software product is the implementation that must be kept consistent with the cognitive context.
41
-
42
- ## Human and Agent Roles
43
-
44
- The Human defines goals, authorizes work, evaluates outcomes, and evolves the project.
45
-
46
- The Agent interprets the cognitive context, performs assigned tasks, modifies the project within task boundaries, and maintains consistency between the cognitive context and the software product.
47
-
48
- The Agent operates through text and must treat project documentation as operational memory, not as secondary commentary.
49
-
50
- ## Cognitive Context
51
-
52
- The canonical execution location of the cognitive context is `./ctx/`.
53
-
54
- Project-specific knowledge, requirements, architecture, environment descriptions, and implementation guidance are defined within the cognitive context.
55
-
56
- The Agent must consult `./ctx/AGENTS.md` for project-specific instructions when `./ctx/` exists.
57
-
58
- The Agent must consult `./ctx/docs/filesystem.md` for the project filesystem structure and documentation layout when that file exists.
59
-
60
- Documentation distributed with the software product may exist outside `./ctx/`, but it does not replace, redefine, or supersede the cognitive context.
61
-
62
- ## Bootstrap and Repository Topology
63
-
64
- An ADSM project may use one repository or two repositories.
65
-
66
- In a one-repository topology, the software product and the cognitive context are versioned together.
67
-
68
- In a two-repository topology, the software product and the cognitive context are independent version-controlled repositories, and the cognitive context repository is mounted under `./ctx/`.
69
-
70
- The Agent must detect whether `./ctx/` is part of the current repository or an independent repository.
71
-
72
- The Agent must preserve repository boundaries.
73
-
74
- The Agent must not mix changes between independent repositories.
75
-
76
- The Agent must not remove, replace, relocate, or unmount `./ctx/`.
77
-
78
- If `./ctx/` does not exist, the Agent may perform bootstrap operations required to create the initial cognitive context structure.
79
-
80
- After bootstrap is complete, `./ctx/AGENTS.md` becomes the entry point for project-specific instructions.
81
-
82
- ## Context and Product Consistency
83
-
84
- The cognitive context is the source of truth for the project.
85
-
86
- If the cognitive context and the software product diverge, the Agent must treat the cognitive context as authoritative.
87
-
88
- The Agent must maintain consistency between the cognitive context and the software product.
89
-
90
- The Agent may modify the cognitive context when required by the assigned task and when the modification remains consistent with higher-level context constraints.
91
-
92
- The Agent may modify the software product when required by the assigned task and when the modification remains consistent with the cognitive context.
93
-
94
- ## AGENTS.md Hierarchy
95
-
96
- Additional `AGENTS.md` files may exist in subdirectories.
97
-
98
- The effective working context of the agent is the aggregate of all `AGENTS.md` files located along the path from the repository root to the target directory.
99
-
100
- Rules:
101
-
102
- - deeper levels override higher levels within their scope
103
- - root-level invariants cannot be overridden
104
- - all levels must remain mutually consistent
105
-
106
- ## Root File Protection
107
-
108
- This file defines root-level project control rules.
109
-
110
- The agent must not modify, replace, delete, relocate, or reinterpret this file unless explicitly instructed by the human.
111
-
112
- Violation of this rule constitutes an execution error.
113
-
114
- ## Secret Handling
115
-
116
- The Agent must never read, load, print, search for, or expose secret-bearing project files, including `.env` and `.env.*` files, credentials, private keys, tokens, or secret stores. This rule applies even when a file is Git-ignored and includes broad search or command output that could reveal its contents.
117
-
118
- The Agent may use a non-secret example template such as `.env.example` only to learn the configuration shape. It must not infer or request the value of any secret.
119
-
120
- If secret data is exposed accidentally, the Agent must stop handling that value, must not repeat it, and must tell the Human that the secret should be rotated or revoked.