@rasensio/aidlc 1.8.0 → 1.9.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 (106) hide show
  1. package/dist/cli.js +2 -0
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/add-action.d.ts.map +1 -1
  4. package/dist/commands/add-action.js +2 -3
  5. package/dist/commands/add-action.js.map +1 -1
  6. package/dist/commands/add-skill.d.ts +28 -0
  7. package/dist/commands/add-skill.d.ts.map +1 -0
  8. package/dist/commands/add-skill.js +315 -0
  9. package/dist/commands/add-skill.js.map +1 -0
  10. package/dist/commands/add.d.ts +25 -0
  11. package/dist/commands/add.d.ts.map +1 -0
  12. package/dist/commands/add.js +29 -0
  13. package/dist/commands/add.js.map +1 -0
  14. package/dist/commands/cost.d.ts +2 -0
  15. package/dist/commands/cost.d.ts.map +1 -1
  16. package/dist/commands/cost.js +16 -1
  17. package/dist/commands/cost.js.map +1 -1
  18. package/dist/commands/init.d.ts.map +1 -1
  19. package/dist/commands/init.js +1 -10
  20. package/dist/commands/init.js.map +1 -1
  21. package/dist/commands/update.d.ts.map +1 -1
  22. package/dist/commands/update.js +1 -9
  23. package/dist/commands/update.js.map +1 -1
  24. package/dist/compile/adapters/claude-code.d.ts.map +1 -1
  25. package/dist/compile/adapters/claude-code.js +3 -24
  26. package/dist/compile/adapters/claude-code.js.map +1 -1
  27. package/dist/compile/adapters/codex.d.ts.map +1 -1
  28. package/dist/compile/adapters/codex.js +3 -2
  29. package/dist/compile/adapters/codex.js.map +1 -1
  30. package/dist/compile/adapters/cursor.d.ts.map +1 -1
  31. package/dist/compile/adapters/cursor.js +4 -2
  32. package/dist/compile/adapters/cursor.js.map +1 -1
  33. package/dist/compile/adapters/kiro.d.ts.map +1 -1
  34. package/dist/compile/adapters/kiro.js +6 -10
  35. package/dist/compile/adapters/kiro.js.map +1 -1
  36. package/dist/compile/adapters/windsurf.d.ts.map +1 -1
  37. package/dist/compile/adapters/windsurf.js +9 -11
  38. package/dist/compile/adapters/windsurf.js.map +1 -1
  39. package/dist/compile/content-root.d.ts +22 -0
  40. package/dist/compile/content-root.d.ts.map +1 -0
  41. package/dist/compile/content-root.js +28 -0
  42. package/dist/compile/content-root.js.map +1 -0
  43. package/dist/compile/limits.d.ts +20 -0
  44. package/dist/compile/limits.d.ts.map +1 -0
  45. package/dist/compile/limits.js +20 -0
  46. package/dist/compile/limits.js.map +1 -0
  47. package/dist/compile/naming.d.ts +92 -0
  48. package/dist/compile/naming.d.ts.map +1 -0
  49. package/dist/compile/naming.js +105 -0
  50. package/dist/compile/naming.js.map +1 -0
  51. package/dist/cost/providers/claude-code.d.ts +2 -0
  52. package/dist/cost/providers/claude-code.d.ts.map +1 -1
  53. package/dist/cost/providers/claude-code.js +34 -12
  54. package/dist/cost/providers/claude-code.js.map +1 -1
  55. package/dist/cost/providers/kiro.d.ts.map +1 -1
  56. package/dist/cost/providers/kiro.js +23 -10
  57. package/dist/cost/providers/kiro.js.map +1 -1
  58. package/dist/cost/providers/provider.d.ts +9 -4
  59. package/dist/cost/providers/provider.d.ts.map +1 -1
  60. package/dist/cost/providers/provider.js.map +1 -1
  61. package/dist/cost/recorder.d.ts +27 -3
  62. package/dist/cost/recorder.d.ts.map +1 -1
  63. package/dist/cost/recorder.js +116 -11
  64. package/dist/cost/recorder.js.map +1 -1
  65. package/dist/cost/sync.js +2 -2
  66. package/dist/cost/sync.js.map +1 -1
  67. package/dist/cost/types.d.ts +20 -0
  68. package/dist/cost/types.d.ts.map +1 -1
  69. package/dist/cost/types.js +2 -0
  70. package/dist/cost/types.js.map +1 -1
  71. package/dist/doctor/migrations/index.d.ts.map +1 -1
  72. package/dist/doctor/migrations/index.js +2 -0
  73. package/dist/doctor/migrations/index.js.map +1 -1
  74. package/dist/doctor/migrations/prune-capture-log.d.ts +11 -0
  75. package/dist/doctor/migrations/prune-capture-log.d.ts.map +1 -0
  76. package/dist/doctor/migrations/prune-capture-log.js +31 -0
  77. package/dist/doctor/migrations/prune-capture-log.js.map +1 -0
  78. package/dist/operational/discover.d.ts +89 -0
  79. package/dist/operational/discover.d.ts.map +1 -0
  80. package/dist/operational/discover.js +132 -0
  81. package/dist/operational/discover.js.map +1 -0
  82. package/dist/operational/emit.d.ts +93 -0
  83. package/dist/operational/emit.d.ts.map +1 -0
  84. package/dist/operational/emit.js +227 -0
  85. package/dist/operational/emit.js.map +1 -0
  86. package/dist/operational/knowledge.d.ts +64 -0
  87. package/dist/operational/knowledge.d.ts.map +1 -0
  88. package/dist/operational/knowledge.js +144 -0
  89. package/dist/operational/knowledge.js.map +1 -0
  90. package/dist/operational/packagers.d.ts +67 -0
  91. package/dist/operational/packagers.d.ts.map +1 -0
  92. package/dist/operational/packagers.js +252 -0
  93. package/dist/operational/packagers.js.map +1 -0
  94. package/dist/operational/redact.d.ts +49 -0
  95. package/dist/operational/redact.d.ts.map +1 -0
  96. package/dist/operational/redact.js +135 -0
  97. package/dist/operational/redact.js.map +1 -0
  98. package/dist/operational/schema.d.ts +80 -0
  99. package/dist/operational/schema.d.ts.map +1 -0
  100. package/dist/operational/schema.js +205 -0
  101. package/dist/operational/schema.js.map +1 -0
  102. package/dist/operational/verify.d.ts +100 -0
  103. package/dist/operational/verify.d.ts.map +1 -0
  104. package/dist/operational/verify.js +175 -0
  105. package/dist/operational/verify.js.map +1 -0
  106. package/package.json +2 -2
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Discovery and re-emit for operational skills.
3
+ *
4
+ * Re-emit (AC-18) exists so a skill can be packaged for a newly added platform
5
+ * without rewriting it, and so a content-package update can reach skills generated
6
+ * earlier. It refreshes the machine-managed verification section and
7
+ * `content_version`, and leaves every user-authored byte alone — which is how
8
+ * AC-50 is scoped in the design rather than violated.
9
+ *
10
+ * Requirements: AC-17, AC-18, AC-36, AC-50
11
+ *
12
+ * @module
13
+ */
14
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
15
+ import { join } from 'node:path';
16
+ import { OPERATIONAL_DIR, canonicalBodyPath } from './packagers.js';
17
+ import { parseOperationalSkill } from './schema.js';
18
+ import { extractVerifySteps, replaceVerifySection, wrapVerifySection, } from './verify.js';
19
+ import { executePlanStaged, dryRunPlanStaged, planEmit } from './emit.js';
20
+ /**
21
+ * Enumerate canonical operational-skill bodies.
22
+ *
23
+ * Matches `*.md` exactly and excludes anything containing `.tmp`, so a staged or
24
+ * abandoned temp file is never mistaken for a skill.
25
+ *
26
+ * @param projectRoot - Absolute project root.
27
+ * @returns Parsed skills plus any files that failed to parse.
28
+ */
29
+ export function discoverOperationalSkills(projectRoot) {
30
+ const dir = join(projectRoot, OPERATIONAL_DIR);
31
+ const skills = [];
32
+ const problems = [];
33
+ if (!existsSync(dir)) {
34
+ return { skills, problems };
35
+ }
36
+ // Sorted so discovery order — and therefore index content — is deterministic.
37
+ for (const entry of readdirSync(dir).sort()) {
38
+ if (!entry.endsWith('.md') || entry.includes('.tmp'))
39
+ continue;
40
+ const rel = `${OPERATIONAL_DIR}/${entry}`;
41
+ try {
42
+ const skill = parseOperationalSkill(readFileSync(join(dir, entry), 'utf8'));
43
+ skills.push({ skill, path: rel });
44
+ }
45
+ catch (err) {
46
+ problems.push({ path: rel, reason: err.message });
47
+ }
48
+ }
49
+ return { skills, problems };
50
+ }
51
+ /** Load a single operational skill by name. */
52
+ export function loadOperationalSkill(projectRoot, name) {
53
+ const abs = join(projectRoot, canonicalBodyPath(name));
54
+ if (!existsSync(abs))
55
+ return null;
56
+ return parseOperationalSkill(readFileSync(abs, 'utf8'));
57
+ }
58
+ /**
59
+ * Refresh the machine-managed parts of a skill from the content package.
60
+ *
61
+ * Replaces only the bytes between the verify-steps delimiters and updates
62
+ * `content_version`. When the body has no managed region — a hand-authored file, or
63
+ * one whose markers were removed — the section is appended rather than silently
64
+ * skipped, so verification is never absent (AC-35).
65
+ *
66
+ * @param skill - The skill to refresh.
67
+ * @param contentRoot - Content package root.
68
+ * @param contentVersion - Version to stamp.
69
+ * @returns A new skill; the input is not mutated.
70
+ */
71
+ export function refreshManagedSections(skill, contentRoot, contentVersion) {
72
+ const steps = extractVerifySteps(contentRoot);
73
+ const replaced = replaceVerifySection(skill.body, steps);
74
+ const body = replaced ?? `${skill.body.replace(/\n+$/, '')}\n\n${wrapVerifySection(steps)}\n`;
75
+ return {
76
+ meta: { ...skill.meta, content_version: contentVersion },
77
+ body,
78
+ };
79
+ }
80
+ /**
81
+ * Re-emit one or all operational skills.
82
+ *
83
+ * Deliberately overwrites platform-derived files — they are, by definition, this
84
+ * command's own prior output, which is AC-50's stated exception to AC-10's
85
+ * no-silent-overwrite rule.
86
+ *
87
+ * @param opts - Re-emit options.
88
+ * @returns Which skills were re-emitted and what changed on disk.
89
+ * @throws When a named skill does not exist, or a configured platform lacks packaging.
90
+ */
91
+ export function reEmit(opts) {
92
+ const { skills: discovered, problems } = discoverOperationalSkills(opts.projectRoot);
93
+ const targets = opts.name
94
+ ? discovered.filter((d) => d.skill.meta.name === opts.name)
95
+ : discovered;
96
+ if (opts.name && targets.length === 0) {
97
+ throw new Error(`no operational skill named '${opts.name}' in ${OPERATIONAL_DIR}/` +
98
+ (problems.length > 0
99
+ ? ` (${problems.length} file(s) failed to parse — see warnings)`
100
+ : ''));
101
+ }
102
+ // Refresh every target first, so index artifacts describe post-refresh state.
103
+ const refreshed = targets.map((d) => refreshManagedSections(d.skill, opts.contentRoot, opts.contentVersion));
104
+ // The full set as it will exist after this run, for index platforms.
105
+ const byName = new Map(discovered.map((d) => [d.skill.meta.name, d.skill]));
106
+ for (const s of refreshed)
107
+ byName.set(s.meta.name, s);
108
+ const allSkills = [...byName.values()];
109
+ const filesWritten = [];
110
+ const filesSkipped = [];
111
+ const warnings = [];
112
+ for (const skill of refreshed) {
113
+ const plan = planEmit({
114
+ skill,
115
+ platforms: opts.platforms,
116
+ projectRoot: opts.projectRoot,
117
+ allSkills,
118
+ });
119
+ const report = opts.dryRun
120
+ ? dryRunPlanStaged(plan, opts.projectRoot)
121
+ : executePlanStaged(plan, opts.projectRoot);
122
+ filesWritten.push(...report.filesWritten);
123
+ filesSkipped.push(...report.filesSkipped);
124
+ warnings.push(...report.warnings);
125
+ }
126
+ return {
127
+ names: refreshed.map((s) => s.meta.name),
128
+ report: { filesWritten, filesSkipped, warnings },
129
+ problems,
130
+ };
131
+ }
132
+ //# sourceMappingURL=discover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.js","sourceRoot":"","sources":["../../src/operational/discover.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Operational-skill emission: plan building and staged, all-or-nothing execution.
3
+ *
4
+ * Reuses `InstallPlan`/`FileOp` — the same types the framework adapters produce —
5
+ * which buys skip-if-identical idempotence (NFR-7), dry-run equivalence, and
6
+ * `mergeBlock` support for codex without touching `SkillMeta` (AC-33).
7
+ *
8
+ * `executePlan` writes op-by-op, so a mid-plan failure leaves a partial tree. That
9
+ * is unacceptable under AC-45 and unrepairable under AC-10's collision refusal, so
10
+ * emission uses `executePlanStaged` instead: resolve and validate everything,
11
+ * stage every byte into one scratch directory, then commit by rename.
12
+ *
13
+ * Requirements: AC-15, AC-17, AC-45, AC-47, NFR-7
14
+ *
15
+ * @module
16
+ */
17
+ import type { InstallPlan, PlatformId } from '../core/types.js';
18
+ import { type OperationalSkill } from './schema.js';
19
+ /** Inputs for one emission. */
20
+ export interface EmitRequest {
21
+ /** The skill being emitted (its canonical body is (re)written). */
22
+ skill: OperationalSkill;
23
+ /** Platforms from `.aidlc/config.yaml`. */
24
+ platforms: PlatformId[];
25
+ /** Absolute project root. */
26
+ projectRoot: string;
27
+ /**
28
+ * Every operational skill in the project, including `skill`. Index platforms
29
+ * need the full set; per-skill platforms ignore it.
30
+ */
31
+ allSkills: OperationalSkill[];
32
+ }
33
+ /** Result of applying (or simulating) an operational plan. */
34
+ export interface EmitReport {
35
+ filesWritten: string[];
36
+ filesSkipped: string[];
37
+ warnings: string[];
38
+ }
39
+ /** Thrown when staging or committing fails. */
40
+ export declare class EmitError extends Error {
41
+ /** Ops whose rename already completed, when a commit fails part-way. */
42
+ readonly committed: string[];
43
+ constructor(reason: string,
44
+ /** Ops whose rename already completed, when a commit fails part-way. */
45
+ committed?: string[]);
46
+ }
47
+ /**
48
+ * Build the InstallPlan for one operational skill.
49
+ *
50
+ * Every packager is resolved **before** any op is produced, so a mixed
51
+ * supported/unsupported `platforms:` list throws during planning with nothing
52
+ * staged — AC-47's all-or-nothing guarantee.
53
+ *
54
+ * @param req - The emission request.
55
+ * @returns A plan whose ops cover the canonical body plus every platform artifact.
56
+ * @throws {UnsupportedPlatformError} When any configured platform lacks packaging.
57
+ */
58
+ export declare function planEmit(req: EmitRequest): InstallPlan;
59
+ /**
60
+ * Apply a plan atomically-as-possible.
61
+ *
62
+ * Three phases:
63
+ * 1. **Resolve and validate** — compute final content for every op. Pure. Every
64
+ * predictable failure lands here, before a single byte is written.
65
+ * 2. **Stage** — write each op into one scratch directory outside every path the
66
+ * project enumerates. On failure, remove the scratch dir and abort; the tree is
67
+ * exactly as it was.
68
+ * 3. **Commit** — create parent directories, then rename each staged file onto its
69
+ * target.
70
+ *
71
+ * Honest bound: phase 3 is a rename sequence, not one transaction. A failure there
72
+ * reports which renames completed, and the residual state is repaired by
73
+ * `--re-emit`, which is idempotent. Directories this run created are removed on a
74
+ * phase-3 failure only when still empty.
75
+ *
76
+ * Skip-if-identical is preserved, so re-emitting unchanged input writes nothing
77
+ * (NFR-7, AC-17).
78
+ *
79
+ * @param plan - The plan to apply.
80
+ * @param rootDir - Absolute project root.
81
+ * @returns What was written and skipped.
82
+ */
83
+ export declare function executePlanStaged(plan: InstallPlan, rootDir: string): EmitReport;
84
+ /**
85
+ * Simulate `executePlanStaged` without touching the filesystem.
86
+ *
87
+ * Uses the same resolution, so `--dry-run` is provably equivalent to a real run.
88
+ *
89
+ * @param plan - The plan to simulate.
90
+ * @param rootDir - Absolute project root.
91
+ */
92
+ export declare function dryRunPlanStaged(plan: InstallPlan, rootDir: string): EmitReport;
93
+ //# sourceMappingURL=emit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../src/operational/emit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAYH,OAAO,KAAK,EAAU,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAIxE,OAAO,EAA6B,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAM/E,+BAA+B;AAC/B,MAAM,WAAW,WAAW;IAC1B,mEAAmE;IACnE,KAAK,EAAE,gBAAgB,CAAC;IACxB,2CAA2C;IAC3C,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,SAAS,EAAE,gBAAgB,EAAE,CAAC;CAC/B;AAED,8DAA8D;AAC9D,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,+CAA+C;AAC/C,qBAAa,SAAU,SAAQ,KAAK;IAGhC,wEAAwE;aACxD,SAAS,EAAE,MAAM,EAAE;gBAFnC,MAAM,EAAE,MAAM;IACd,wEAAwE;IACxD,SAAS,GAAE,MAAM,EAAO;CAK3C;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,WAAW,GAAG,WAAW,CA4CtD;AA6BD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CA6EhF;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CAgB/E"}
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Operational-skill emission: plan building and staged, all-or-nothing execution.
3
+ *
4
+ * Reuses `InstallPlan`/`FileOp` — the same types the framework adapters produce —
5
+ * which buys skip-if-identical idempotence (NFR-7), dry-run equivalence, and
6
+ * `mergeBlock` support for codex without touching `SkillMeta` (AC-33).
7
+ *
8
+ * `executePlan` writes op-by-op, so a mid-plan failure leaves a partial tree. That
9
+ * is unacceptable under AC-45 and unrepairable under AC-10's collision refusal, so
10
+ * emission uses `executePlanStaged` instead: resolve and validate everything,
11
+ * stage every byte into one scratch directory, then commit by rename.
12
+ *
13
+ * Requirements: AC-15, AC-17, AC-45, AC-47, NFR-7
14
+ *
15
+ * @module
16
+ */
17
+ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync, } from 'node:fs';
18
+ import { dirname, join, relative, sep } from 'node:path';
19
+ import { adapters } from '../compile/adapters/index.js';
20
+ import { mergeBlock } from '../compile/merger.js';
21
+ import { canonicalBodyPath, packagerFor } from './packagers.js';
22
+ import { serializeOperationalSkill } from './schema.js';
23
+ /** Thrown when staging or committing fails. */
24
+ export class EmitError extends Error {
25
+ committed;
26
+ constructor(reason,
27
+ /** Ops whose rename already completed, when a commit fails part-way. */
28
+ committed = []) {
29
+ super(reason);
30
+ this.committed = committed;
31
+ this.name = 'EmitError';
32
+ }
33
+ }
34
+ // ---------------------------------------------------------------------------
35
+ // Planning
36
+ // ---------------------------------------------------------------------------
37
+ /**
38
+ * Build the InstallPlan for one operational skill.
39
+ *
40
+ * Every packager is resolved **before** any op is produced, so a mixed
41
+ * supported/unsupported `platforms:` list throws during planning with nothing
42
+ * staged — AC-47's all-or-nothing guarantee.
43
+ *
44
+ * @param req - The emission request.
45
+ * @returns A plan whose ops cover the canonical body plus every platform artifact.
46
+ * @throws {UnsupportedPlatformError} When any configured platform lacks packaging.
47
+ */
48
+ export function planEmit(req) {
49
+ // Resolve first — this is the AC-47 gate.
50
+ const packagers = req.platforms.map((p) => packagerFor(p));
51
+ const ops = [];
52
+ const warnings = [];
53
+ // 1. Canonical body — the single source of full instructions (AC-13).
54
+ ops.push({
55
+ kind: 'create',
56
+ path: canonicalBodyPath(req.skill.meta.name),
57
+ content: serializeOperationalSkill(req.skill),
58
+ });
59
+ // 2. Per-skill platform artifacts.
60
+ for (const packager of packagers) {
61
+ ops.push(...packager.plan(req.skill));
62
+ }
63
+ // 3. Index artifacts, one per index-shaped platform.
64
+ for (const packager of packagers) {
65
+ if (!packager.planIndex)
66
+ continue;
67
+ const op = packager.planIndex(req.allSkills);
68
+ if (op)
69
+ ops.push(op);
70
+ }
71
+ // 4. Platform validators, where the platform defines one. This is how the
72
+ // ownership-marker placement stays honest: a first-line comment before
73
+ // frontmatter fails claude-code's and cursor's own checks.
74
+ for (const op of ops) {
75
+ for (const platform of req.platforms) {
76
+ const adapter = adapters.get(platform);
77
+ if (!adapter)
78
+ continue;
79
+ const result = adapter.validate(op);
80
+ warnings.push(...result.warnings);
81
+ if (!result.valid) {
82
+ throw new EmitError(`emitted file ${op.path} fails ${platform} validation: ${result.errors.join('; ')}`);
83
+ }
84
+ }
85
+ }
86
+ return { ops, warnings };
87
+ }
88
+ // ---------------------------------------------------------------------------
89
+ // Content resolution
90
+ // ---------------------------------------------------------------------------
91
+ /** Final on-disk content for one op, including merge-block composition. */
92
+ function resolveContent(op, rootDir) {
93
+ if (op.kind === 'merge-block') {
94
+ const abs = join(rootDir, op.path);
95
+ const existing = existsSync(abs) ? readFileSync(abs, 'utf8') : '';
96
+ return mergeBlock(existing, op.blockId, op.content);
97
+ }
98
+ return op.content;
99
+ }
100
+ /** Reject any op path that escapes the project root. */
101
+ function assertInsideRoot(rootDir, opPath) {
102
+ const abs = join(rootDir, opPath);
103
+ const rel = relative(rootDir, abs);
104
+ if (rel.startsWith('..') || rel.startsWith(`..${sep}`)) {
105
+ throw new EmitError(`refusing to write outside the project root: ${opPath}`);
106
+ }
107
+ }
108
+ // ---------------------------------------------------------------------------
109
+ // Staged execution (AC-45)
110
+ // ---------------------------------------------------------------------------
111
+ /**
112
+ * Apply a plan atomically-as-possible.
113
+ *
114
+ * Three phases:
115
+ * 1. **Resolve and validate** — compute final content for every op. Pure. Every
116
+ * predictable failure lands here, before a single byte is written.
117
+ * 2. **Stage** — write each op into one scratch directory outside every path the
118
+ * project enumerates. On failure, remove the scratch dir and abort; the tree is
119
+ * exactly as it was.
120
+ * 3. **Commit** — create parent directories, then rename each staged file onto its
121
+ * target.
122
+ *
123
+ * Honest bound: phase 3 is a rename sequence, not one transaction. A failure there
124
+ * reports which renames completed, and the residual state is repaired by
125
+ * `--re-emit`, which is idempotent. Directories this run created are removed on a
126
+ * phase-3 failure only when still empty.
127
+ *
128
+ * Skip-if-identical is preserved, so re-emitting unchanged input writes nothing
129
+ * (NFR-7, AC-17).
130
+ *
131
+ * @param plan - The plan to apply.
132
+ * @param rootDir - Absolute project root.
133
+ * @returns What was written and skipped.
134
+ */
135
+ export function executePlanStaged(plan, rootDir) {
136
+ // --- Phase 1: resolve + validate ---------------------------------------
137
+ const resolved = [];
138
+ for (const op of plan.ops) {
139
+ assertInsideRoot(rootDir, op.path);
140
+ resolved.push({
141
+ op,
142
+ content: resolveContent(op, rootDir),
143
+ abs: join(rootDir, op.path),
144
+ });
145
+ }
146
+ const toWrite = resolved.filter((r) => !(existsSync(r.abs) && readFileSync(r.abs, 'utf8') === r.content));
147
+ const filesSkipped = resolved
148
+ .filter((r) => !toWrite.includes(r))
149
+ .map((r) => r.op.path);
150
+ if (toWrite.length === 0) {
151
+ return { filesWritten: [], filesSkipped, warnings: [...plan.warnings] };
152
+ }
153
+ // --- Phase 2: stage ----------------------------------------------------
154
+ const scratch = join(rootDir, '.aidlc', `.tmp-emit-${process.pid}`);
155
+ const staged = [];
156
+ try {
157
+ mkdirSync(scratch, { recursive: true });
158
+ for (let i = 0; i < toWrite.length; i++) {
159
+ const { op, content, abs } = toWrite[i];
160
+ // Flat, index-keyed names: no nesting to recreate, and no chance of a
161
+ // staged file colliding with another op's directory.
162
+ const tmp = join(scratch, `${i}.staged`);
163
+ writeFileSync(tmp, content, 'utf8');
164
+ staged.push({ tmp, abs, path: op.path });
165
+ }
166
+ }
167
+ catch (err) {
168
+ rmSync(scratch, { recursive: true, force: true });
169
+ throw new EmitError(`staging failed, nothing was written: ${err.message}`);
170
+ }
171
+ // --- Phase 3: commit ---------------------------------------------------
172
+ const filesWritten = [];
173
+ const createdDirs = [];
174
+ try {
175
+ for (const { tmp, abs, path } of staged) {
176
+ const dir = dirname(abs);
177
+ if (!existsSync(dir)) {
178
+ mkdirSync(dir, { recursive: true });
179
+ createdDirs.push(dir);
180
+ }
181
+ renameSync(tmp, abs);
182
+ filesWritten.push(path);
183
+ }
184
+ }
185
+ catch (err) {
186
+ // Remove directories we created that are still empty, so a failed commit
187
+ // does not leave scaffolding behind.
188
+ for (const dir of createdDirs.reverse()) {
189
+ try {
190
+ rmSync(dir, { recursive: false });
191
+ }
192
+ catch {
193
+ // Non-empty (a rename landed inside it) — leave it.
194
+ }
195
+ }
196
+ rmSync(scratch, { recursive: true, force: true });
197
+ throw new EmitError(`commit failed after writing ${filesWritten.length}/${staged.length} files: ` +
198
+ `${err.message}. Repair with: aidlc add skill --re-emit`, filesWritten);
199
+ }
200
+ rmSync(scratch, { recursive: true, force: true });
201
+ return { filesWritten, filesSkipped, warnings: [...plan.warnings] };
202
+ }
203
+ /**
204
+ * Simulate `executePlanStaged` without touching the filesystem.
205
+ *
206
+ * Uses the same resolution, so `--dry-run` is provably equivalent to a real run.
207
+ *
208
+ * @param plan - The plan to simulate.
209
+ * @param rootDir - Absolute project root.
210
+ */
211
+ export function dryRunPlanStaged(plan, rootDir) {
212
+ const filesWritten = [];
213
+ const filesSkipped = [];
214
+ for (const op of plan.ops) {
215
+ assertInsideRoot(rootDir, op.path);
216
+ const abs = join(rootDir, op.path);
217
+ const content = resolveContent(op, rootDir);
218
+ if (existsSync(abs) && readFileSync(abs, 'utf8') === content) {
219
+ filesSkipped.push(op.path);
220
+ }
221
+ else {
222
+ filesWritten.push(op.path);
223
+ }
224
+ }
225
+ return { filesWritten, filesSkipped, warnings: [...plan.warnings] };
226
+ }
227
+ //# sourceMappingURL=emit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.js","sourceRoot":"","sources":["../../src/operational/emit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Knowledge-graph registration for operational skills.
3
+ *
4
+ * Registers each generated skill so `aidlc knowledge query <name>` finds it and a
5
+ * developer returning months later does not write a second skill for the same job
6
+ * (US-6, AC-28…AC-30, AC-49).
7
+ *
8
+ * Two properties are load-bearing and neither is free:
9
+ *
10
+ * - **The entity type is not gate-counted.** `custom:operational-skill` rather than
11
+ * `module`, because the ideation seeding gate counts `module`, `convention`, and
12
+ * `depends-on` (`knowledge/gate-criterion.ts`). Registering skills as modules
13
+ * would let generated files satisfy a lifecycle gate meant to measure real
14
+ * architecture.
15
+ * - **The id is namespaced and collisions are refused.** `addEntity` merges into any
16
+ * pre-existing entity with the same id, and `mergeEntities` never overrides
17
+ * `type` — so an unnamespaced id colliding with an existing `module` would stay
18
+ * gate-counted *and* clobber an architecture fact. Registration therefore checks
19
+ * the resolved type first and refuses rather than merging.
20
+ *
21
+ * Registration is best-effort: failure warns and generation still succeeds (AC-30).
22
+ *
23
+ * Requirements: AC-28, AC-29, AC-30, AC-49
24
+ *
25
+ * @module
26
+ */
27
+ import type { OperationalSkill } from './schema.js';
28
+ /** Entity type for operational skills — deliberately not gate-counted (AC-28). */
29
+ export declare const OPERATIONAL_ENTITY_TYPE = "custom:operational-skill";
30
+ /** Id prefix keeping operational entities out of the general id namespace. */
31
+ export declare const OPERATIONAL_ID_PREFIX = "operational-skill-";
32
+ /** Outcome of a registration attempt. */
33
+ export interface RegistrationResult {
34
+ /** True when the entity now exists with the operational type. */
35
+ registered: boolean;
36
+ /** Non-fatal explanation when `registered` is false, or a merge note. */
37
+ warning?: string;
38
+ /** The entity id used. */
39
+ id: string;
40
+ }
41
+ /** Namespaced entity id for a skill name. */
42
+ export declare function operationalEntityId(name: string): string;
43
+ /**
44
+ * Register (or repair) an operational skill in the knowledge graph.
45
+ *
46
+ * Never throws: a graph problem must not lose a skill the user already confirmed
47
+ * (AC-30). Re-running for a skill whose files exist but whose entity is missing
48
+ * recreates it, which is the AC-49 repair path.
49
+ *
50
+ * @param projectRoot - Absolute project root.
51
+ * @param skill - The skill to register.
52
+ * @returns Whether the entity is now present, plus any warning to surface.
53
+ */
54
+ export declare function registerOperationalSkill(projectRoot: string, skill: OperationalSkill): RegistrationResult;
55
+ /**
56
+ * Is this skill already registered with the operational type?
57
+ *
58
+ * Used to decide whether a re-run needs to repair registration (AC-49).
59
+ *
60
+ * @param projectRoot - Absolute project root.
61
+ * @param name - Skill name.
62
+ */
63
+ export declare function isOperationalSkillRegistered(projectRoot: string, name: string): boolean;
64
+ //# sourceMappingURL=knowledge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge.d.ts","sourceRoot":"","sources":["../../src/operational/knowledge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,kFAAkF;AAClF,eAAO,MAAM,uBAAuB,6BAA6B,CAAC;AAElE,8EAA8E;AAC9E,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAE1D,yCAAyC;AACzC,MAAM,WAAW,kBAAkB;IACjC,iEAAiE;IACjE,UAAU,EAAE,OAAO,CAAC;IACpB,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0BAA0B;IAC1B,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,6CAA6C;AAC7C,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,gBAAgB,GACtB,kBAAkB,CAiEpB;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAoBvF"}