@devtrack-solution/codesdd 1.2.3 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/.sdd/skills/curated/devtrack-api/SKILL.md +98 -12
  2. package/.sdd/skills/curated/devtrack-api/agents/claude-code.yaml +10 -0
  3. package/.sdd/skills/curated/devtrack-api/agents/codex.yaml +10 -0
  4. package/.sdd/skills/curated/devtrack-api/agents/cursor.yaml +10 -0
  5. package/.sdd/skills/curated/devtrack-api/agents/gemini.yaml +10 -0
  6. package/.sdd/skills/curated/devtrack-api/agents/kimi.yaml +10 -0
  7. package/.sdd/skills/curated/devtrack-api/agents/openai.yaml +5 -3
  8. package/.sdd/skills/curated/devtrack-api/agents/opencode.yaml +12 -0
  9. package/.sdd/skills/curated/devtrack-api/references/application-presentation.md +61 -5
  10. package/.sdd/skills/curated/devtrack-api/references/consumer-sync-policy.md +15 -3
  11. package/.sdd/skills/curated/devtrack-api/references/contract-pack.yaml +1951 -0
  12. package/.sdd/skills/curated/devtrack-api/references/domain-modeling.md +16 -14
  13. package/.sdd/skills/curated/devtrack-api/references/field-validation-protocol.md +40 -0
  14. package/.sdd/skills/curated/devtrack-api/references/foundation-layout.md +19 -2
  15. package/.sdd/skills/curated/devtrack-api/references/generated-artifact-invalidation.md +97 -0
  16. package/.sdd/skills/curated/devtrack-api/references/implementation-checklist.md +30 -1
  17. package/.sdd/skills/curated/devtrack-api/references/portable-agent-contract.md +42 -0
  18. package/.sdd/skills/curated/devtrack-api/references/testing-validation.md +22 -1
  19. package/.sdd/skills/curated/devtrack-api/references/typeorm-infrastructure.md +9 -7
  20. package/README.md +280 -29
  21. package/dist/applications/sdd/index.d.ts +16 -0
  22. package/dist/applications/sdd/index.js +16 -0
  23. package/dist/cli/program.js +180 -11
  24. package/dist/commands/config.js +197 -10
  25. package/dist/commands/sdd/execution.js +408 -16
  26. package/dist/commands/sdd/plugin.js +5 -0
  27. package/dist/commands/sdd/shared.d.ts +1 -0
  28. package/dist/commands/sdd/shared.js +10 -0
  29. package/dist/commands/sdd.js +157 -7
  30. package/dist/core/cli/command-matrix.d.ts +18 -0
  31. package/dist/core/cli/command-matrix.js +157 -0
  32. package/dist/core/cli-command-quality.js +11 -0
  33. package/dist/core/completions/command-registry.js +45 -0
  34. package/dist/core/config-schema.d.ts +31 -1
  35. package/dist/core/config-schema.js +79 -5
  36. package/dist/core/config.d.ts +1 -0
  37. package/dist/core/config.js +11 -0
  38. package/dist/core/global-config.d.ts +29 -0
  39. package/dist/core/init.d.ts +2 -2
  40. package/dist/core/init.js +13 -14
  41. package/dist/core/sdd/agent-binding.d.ts +19 -19
  42. package/dist/core/sdd/agent-runtime-contract.d.ts +204 -0
  43. package/dist/core/sdd/agent-runtime-contract.js +200 -0
  44. package/dist/core/sdd/allocator-recovery.d.ts +14 -0
  45. package/dist/core/sdd/allocator-recovery.js +30 -0
  46. package/dist/core/sdd/allocator-security.d.ts +18 -0
  47. package/dist/core/sdd/allocator-security.js +36 -0
  48. package/dist/core/sdd/api-foundation-baseline.d.ts +111 -0
  49. package/dist/core/sdd/api-foundation-baseline.js +151 -0
  50. package/dist/core/sdd/api-foundation-parity.d.ts +114 -0
  51. package/dist/core/sdd/api-foundation-parity.js +131 -0
  52. package/dist/core/sdd/api-profile-catalog.d.ts +36 -0
  53. package/dist/core/sdd/api-profile-catalog.js +132 -0
  54. package/dist/core/sdd/api-profile-dry-run-projection.d.ts +93 -0
  55. package/dist/core/sdd/api-profile-dry-run-projection.js +370 -0
  56. package/dist/core/sdd/api-profile-recipes.d.ts +82 -0
  57. package/dist/core/sdd/api-profile-recipes.js +484 -0
  58. package/dist/core/sdd/artifact-id-allocator.d.ts +368 -0
  59. package/dist/core/sdd/artifact-id-allocator.js +510 -0
  60. package/dist/core/sdd/check.d.ts +52 -1
  61. package/dist/core/sdd/check.js +326 -11
  62. package/dist/core/sdd/coordination/coordination-adapters.d.ts +15 -8
  63. package/dist/core/sdd/coordination/coordination-adapters.js +43 -15
  64. package/dist/core/sdd/coordination/index.d.ts +1 -0
  65. package/dist/core/sdd/coordination/index.js +1 -0
  66. package/dist/core/sdd/coordination/redis-runtime.d.ts +131 -0
  67. package/dist/core/sdd/coordination/redis-runtime.js +698 -0
  68. package/dist/core/sdd/deepagent-contracts.d.ts +99 -5
  69. package/dist/core/sdd/deepagent-contracts.js +62 -0
  70. package/dist/core/sdd/deepagents/reversa-subagents.d.ts +3 -3
  71. package/dist/core/sdd/default-bootstrap-files.d.ts +2 -2
  72. package/dist/core/sdd/default-bootstrap-files.js +14 -10
  73. package/dist/core/sdd/default-skills.js +115 -9
  74. package/dist/core/sdd/devtrack-api-appliance.d.ts +42 -1
  75. package/dist/core/sdd/devtrack-api-appliance.js +159 -32
  76. package/dist/core/sdd/devtrack-api-architecture.d.ts +16 -0
  77. package/dist/core/sdd/devtrack-api-architecture.js +86 -0
  78. package/dist/core/sdd/docs-sync.js +24 -18
  79. package/dist/core/sdd/domain/capability-diff.d.ts +63 -0
  80. package/dist/core/sdd/domain/capability-diff.js +200 -0
  81. package/dist/core/sdd/domain/change-safety-guardrails.d.ts +74 -0
  82. package/dist/core/sdd/domain/change-safety-guardrails.js +333 -0
  83. package/dist/core/sdd/domain/semantic-intent-classifier.d.ts +29 -0
  84. package/dist/core/sdd/domain/semantic-intent-classifier.js +117 -0
  85. package/dist/core/sdd/enterprise-mutating-command-gate.d.ts +27 -0
  86. package/dist/core/sdd/enterprise-mutating-command-gate.js +104 -0
  87. package/dist/core/sdd/enterprise-provenance-gates.d.ts +20 -0
  88. package/dist/core/sdd/enterprise-provenance-gates.js +63 -0
  89. package/dist/core/sdd/enterprise-provisioning-policy.d.ts +26 -0
  90. package/dist/core/sdd/enterprise-provisioning-policy.js +104 -0
  91. package/dist/core/sdd/foundation-artifact-map-validator.d.ts +16 -0
  92. package/dist/core/sdd/foundation-artifact-map-validator.js +71 -0
  93. package/dist/core/sdd/foundation-layer-manifest.d.ts +24 -0
  94. package/dist/core/sdd/foundation-layer-manifest.js +117 -0
  95. package/dist/core/sdd/governance-schemas.d.ts +2 -2
  96. package/dist/core/sdd/governance-schemas.js +11 -2
  97. package/dist/core/sdd/intent-guard.d.ts +22 -0
  98. package/dist/core/sdd/intent-guard.js +67 -0
  99. package/dist/core/sdd/json-schema.js +13 -1
  100. package/dist/core/sdd/legacy-operations.js +169 -5
  101. package/dist/core/sdd/migrate-workspace.js +39 -0
  102. package/dist/core/sdd/package-security-gates.d.ts +21 -0
  103. package/dist/core/sdd/package-security-gates.js +121 -0
  104. package/dist/core/sdd/package-structure-gate.d.ts +85 -3
  105. package/dist/core/sdd/package-structure-gate.js +384 -11
  106. package/dist/core/sdd/parallel-feat-automation.d.ts +185 -7
  107. package/dist/core/sdd/parallel-feat-automation.js +212 -0
  108. package/dist/core/sdd/plugin-broker.d.ts +223 -4
  109. package/dist/core/sdd/plugin-broker.js +10 -0
  110. package/dist/core/sdd/plugin-cli.d.ts +30 -0
  111. package/dist/core/sdd/plugin-cli.js +70 -3
  112. package/dist/core/sdd/plugin-evidence.d.ts +73 -0
  113. package/dist/core/sdd/plugin-manifest.d.ts +69 -1
  114. package/dist/core/sdd/plugin-manifest.js +10 -0
  115. package/dist/core/sdd/plugin-policy-pack.d.ts +1 -1
  116. package/dist/core/sdd/plugin-policy.js +6 -1
  117. package/dist/core/sdd/plugin-registry.d.ts +138 -2
  118. package/dist/core/sdd/plugin-sdk-contract.d.ts +363 -0
  119. package/dist/core/sdd/plugin-sdk-contract.js +268 -0
  120. package/dist/core/sdd/plugin-skill-binding.d.ts +1 -1
  121. package/dist/core/sdd/quality-validation.d.ts +89 -16
  122. package/dist/core/sdd/release-readiness.d.ts +68 -0
  123. package/dist/core/sdd/release-readiness.js +767 -0
  124. package/dist/core/sdd/reversa-architecture-extractor.d.ts +13 -0
  125. package/dist/core/sdd/reversa-architecture-extractor.js +89 -0
  126. package/dist/core/sdd/reversa-artifact-writer.d.ts +18 -0
  127. package/dist/core/sdd/reversa-artifact-writer.js +40 -0
  128. package/dist/core/sdd/reversa-command-policy.d.ts +136 -0
  129. package/dist/core/sdd/reversa-command-policy.js +361 -0
  130. package/dist/core/sdd/reversa-data-extractor.d.ts +11 -0
  131. package/dist/core/sdd/reversa-data-extractor.js +73 -0
  132. package/dist/core/sdd/reversa-equivalence.d.ts +20 -0
  133. package/dist/core/sdd/reversa-equivalence.js +34 -0
  134. package/dist/core/sdd/reversa-evidence.d.ts +298 -0
  135. package/dist/core/sdd/reversa-evidence.js +118 -0
  136. package/dist/core/sdd/reversa-reconstruction.d.ts +29 -0
  137. package/dist/core/sdd/reversa-reconstruction.js +32 -0
  138. package/dist/core/sdd/reversa-rules-extractor.d.ts +12 -0
  139. package/dist/core/sdd/reversa-rules-extractor.js +86 -0
  140. package/dist/core/sdd/reversa-source-safety.d.ts +19 -0
  141. package/dist/core/sdd/reversa-source-safety.js +105 -0
  142. package/dist/core/sdd/reversa-surface-scout.d.ts +13 -0
  143. package/dist/core/sdd/reversa-surface-scout.js +85 -0
  144. package/dist/core/sdd/reversa-ux-mapper.d.ts +11 -0
  145. package/dist/core/sdd/reversa-ux-mapper.js +73 -0
  146. package/dist/core/sdd/runtime-boundary-contract.d.ts +45 -0
  147. package/dist/core/sdd/runtime-boundary-contract.js +90 -0
  148. package/dist/core/sdd/sdk-agent-plugin-quality-gates.d.ts +150 -0
  149. package/dist/core/sdd/sdk-agent-plugin-quality-gates.js +258 -0
  150. package/dist/core/sdd/services/agent-run.service.d.ts +38 -6
  151. package/dist/core/sdd/services/agent-run.service.js +73 -1
  152. package/dist/core/sdd/services/archive-quality-coherence.service.d.ts +17 -0
  153. package/dist/core/sdd/services/archive-quality-coherence.service.js +141 -0
  154. package/dist/core/sdd/services/capability-diff.service.d.ts +18 -0
  155. package/dist/core/sdd/services/capability-diff.service.js +26 -0
  156. package/dist/core/sdd/services/change-safety-preflight.service.d.ts +17 -0
  157. package/dist/core/sdd/services/change-safety-preflight.service.js +17 -0
  158. package/dist/core/sdd/services/context.service.d.ts +43 -340
  159. package/dist/core/sdd/services/context.service.js +323 -9
  160. package/dist/core/sdd/services/decide.service.js +1 -1
  161. package/dist/core/sdd/services/finalize.service.d.ts +27 -0
  162. package/dist/core/sdd/services/finalize.service.js +226 -18
  163. package/dist/core/sdd/services/frontend-impact.service.d.ts +1 -1
  164. package/dist/core/sdd/services/historical-quality-regression.service.d.ts +35 -0
  165. package/dist/core/sdd/services/historical-quality-regression.service.js +228 -0
  166. package/dist/core/sdd/services/ingest-deposito.service.js +1 -1
  167. package/dist/core/sdd/services/planning-execution-coherence.service.d.ts +45 -0
  168. package/dist/core/sdd/services/planning-execution-coherence.service.js +225 -0
  169. package/dist/core/sdd/services/semantic-intent-classifier.service.d.ts +6 -0
  170. package/dist/core/sdd/services/semantic-intent-classifier.service.js +7 -0
  171. package/dist/core/sdd/state.d.ts +1 -0
  172. package/dist/core/sdd/state.js +266 -34
  173. package/dist/core/sdd/store/sdd-stores.js +2 -2
  174. package/dist/core/sdd/structural-health.d.ts +13 -13
  175. package/dist/core/sdd/types.d.ts +30 -15
  176. package/dist/core/sdd/types.js +4 -0
  177. package/dist/core/sdd/views.js +17 -0
  178. package/dist/core/sdd/workspace-schemas.d.ts +428 -7
  179. package/dist/core/sdd/workspace-schemas.js +223 -70
  180. package/dist/core/shared/skill-generation.d.ts +2 -0
  181. package/dist/core/shared/skill-generation.js +19 -2
  182. package/dist/core/shared/tool-detection.d.ts +19 -0
  183. package/dist/core/shared/tool-detection.js +89 -0
  184. package/dist/domains/sdd/index.d.ts +6 -0
  185. package/dist/domains/sdd/index.js +6 -0
  186. package/dist/infrastructures/sdd/index.d.ts +7 -0
  187. package/dist/infrastructures/sdd/index.js +6 -0
  188. package/dist/presentations/cli/sdd/index.d.ts +3 -0
  189. package/dist/presentations/cli/sdd/index.js +3 -0
  190. package/dist/shared/sdd/index.d.ts +3 -0
  191. package/dist/shared/sdd/index.js +2 -0
  192. package/package.json +14 -10
  193. package/schemas/sdd/2-plan.schema.json +207 -2
  194. package/schemas/sdd/5-quality.schema.json +324 -25
  195. package/schemas/sdd/agent-runtime-command-plan.schema.json +212 -0
  196. package/schemas/sdd/agent-runtime-opencode-run-evidence.schema.json +270 -0
  197. package/schemas/sdd/codesdd-plugin.schema.json +171 -0
  198. package/schemas/sdd/deepagent-run-request.schema.json +316 -0
  199. package/schemas/sdd/parallel-feat-automation-plan.schema.json +89 -0
  200. package/schemas/sdd/parallel-feat-scheduler-request.schema.json +116 -0
  201. package/schemas/sdd/parallel-feat-scheduler-result.schema.json +404 -0
  202. package/schemas/sdd/plugin-artifact-manifest.schema.json +109 -0
  203. package/schemas/sdd/plugin-artifact-map.schema.json +223 -0
  204. package/schemas/sdd/plugin-evidence-manifest.schema.json +109 -0
  205. package/schemas/sdd/plugin-language-runtime.schema.json +103 -0
  206. package/schemas/sdd/plugin-package-governance.schema.json +74 -0
  207. package/schemas/sdd/plugin-registry.schema.json +171 -0
  208. package/schemas/sdd/plugin-runtime-invocation-plan.schema.json +109 -0
  209. package/schemas/sdd/quality-evidence-bundle.schema.json +109 -0
  210. package/schemas/sdd/reversa-evidence-bundle.schema.json +466 -0
  211. package/schemas/sdd/sdk-agent-plugin-quality-gate-input.schema.json +168 -0
  212. package/schemas/sdd/sdk-agent-plugin-quality-gate-report.schema.json +160 -0
  213. package/schemas/sdd/workspace-catalog.schema.json +5298 -1409
@@ -0,0 +1,200 @@
1
+ import { createHash } from 'node:crypto';
2
+ export const CAPABILITY_KINDS = [
3
+ 'route',
4
+ 'page',
5
+ 'cli_command',
6
+ 'public_contract',
7
+ 'schema',
8
+ 'event',
9
+ 'core_flow',
10
+ 'governance_state',
11
+ ];
12
+ export const CAPABILITY_CHANGE_TYPES = ['added', 'removed', 'modified', 'unchanged'];
13
+ export const CAPABILITY_RISK_LEVELS = ['none', 'low', 'medium', 'high', 'critical'];
14
+ const PUBLIC_SURFACE_KINDS = new Set([
15
+ 'route',
16
+ 'page',
17
+ 'cli_command',
18
+ 'public_contract',
19
+ 'schema',
20
+ 'event',
21
+ ]);
22
+ const CRITICAL_KIND_WEIGHTS = new Map([
23
+ ['core_flow', 'critical'],
24
+ ['governance_state', 'critical'],
25
+ ]);
26
+ const RISK_SCORE = {
27
+ none: 0,
28
+ low: 25,
29
+ medium: 50,
30
+ high: 75,
31
+ critical: 100,
32
+ };
33
+ export function buildCapabilityInventory(items) {
34
+ return {
35
+ schema_version: 1,
36
+ contract: 'capability-inventory/v1',
37
+ items: normalizeCapabilityItems(items),
38
+ };
39
+ }
40
+ export function diffCapabilityInventories(before, after) {
41
+ const beforeByKey = indexByCapabilityKey(before.items);
42
+ const afterByKey = indexByCapabilityKey(after.items);
43
+ const keys = [...new Set([...beforeByKey.keys(), ...afterByKey.keys()])].sort();
44
+ const entries = keys.map((key) => {
45
+ const beforeItem = beforeByKey.get(key);
46
+ const afterItem = afterByKey.get(key);
47
+ const item = afterItem ?? beforeItem;
48
+ if (!item) {
49
+ throw new Error(`Capability key ${key} resolved without an inventory item.`);
50
+ }
51
+ if (!beforeItem)
52
+ return { kind: item.kind, id: item.id, change: 'added', after: afterItem };
53
+ if (!afterItem)
54
+ return { kind: item.kind, id: item.id, change: 'removed', before: beforeItem };
55
+ if (beforeItem.fingerprint !== afterItem.fingerprint) {
56
+ return { kind: item.kind, id: item.id, change: 'modified', before: beforeItem, after: afterItem };
57
+ }
58
+ return { kind: item.kind, id: item.id, change: 'unchanged', before: beforeItem, after: afterItem };
59
+ });
60
+ return {
61
+ schema_version: 1,
62
+ contract: 'capability-diff-report/v1',
63
+ entries,
64
+ counts: countDiffEntries(entries),
65
+ };
66
+ }
67
+ export function scoreCapabilityDiffRisk(input) {
68
+ const signals = [];
69
+ const presentKinds = new Set(input.diff.entries.map((entry) => entry.kind));
70
+ for (const requiredKind of input.required_kinds ?? []) {
71
+ if (!presentKinds.has(requiredKind)) {
72
+ signals.push({
73
+ code: 'required_capability_inventory_missing',
74
+ level: CRITICAL_KIND_WEIGHTS.get(requiredKind) ?? 'high',
75
+ message: `Required capability inventory kind ${requiredKind} is missing from before/after diff evidence.`,
76
+ capability_ref: requiredKind,
77
+ });
78
+ }
79
+ }
80
+ for (const entry of input.diff.entries) {
81
+ if (entry.change === 'removed') {
82
+ signals.push(riskForRemovedCapability(entry));
83
+ }
84
+ if (entry.change === 'modified' && PUBLIC_SURFACE_KINDS.has(entry.kind)) {
85
+ signals.push({
86
+ code: 'public_capability_modified',
87
+ level: 'medium',
88
+ message: `Public capability ${capabilityRef(entry)} changed.`,
89
+ capability_ref: capabilityRef(entry),
90
+ path: entry.after?.path ?? entry.before?.path,
91
+ });
92
+ }
93
+ if (entry.change === 'added' && PUBLIC_SURFACE_KINDS.has(entry.kind)) {
94
+ signals.push({
95
+ code: 'public_capability_added',
96
+ level: 'low',
97
+ message: `Public capability ${capabilityRef(entry)} was added.`,
98
+ capability_ref: capabilityRef(entry),
99
+ path: entry.after?.path,
100
+ });
101
+ }
102
+ }
103
+ if (input.change_safety?.status === 'blocked') {
104
+ signals.push(...input.change_safety.violations.map((violation) => ({
105
+ code: `change_safety_${violation.code}`,
106
+ level: 'critical',
107
+ message: violation.message,
108
+ path: violation.path,
109
+ })));
110
+ }
111
+ for (const plannedChange of input.planned_changes ?? []) {
112
+ if (plannedChange.operation === 'delete' || plannedChange.operation === 'rename' || plannedChange.operation === 'replace') {
113
+ signals.push({
114
+ code: 'destructive_planned_change',
115
+ level: 'high',
116
+ message: `Planned ${plannedChange.operation} change affects ${plannedChange.path}.`,
117
+ path: plannedChange.path,
118
+ });
119
+ }
120
+ }
121
+ const level = maxRiskLevel(signals.map((signal) => signal.level));
122
+ return {
123
+ schema_version: 1,
124
+ contract: 'deterministic-capability-risk/v1',
125
+ level,
126
+ score: RISK_SCORE[level],
127
+ signals: sortRiskSignals(signals),
128
+ };
129
+ }
130
+ export function capabilityKey(item) {
131
+ return `${item.kind}:${item.id}`;
132
+ }
133
+ function normalizeCapabilityItems(items) {
134
+ const byKey = new Map();
135
+ for (const item of items) {
136
+ const normalized = {
137
+ kind: item.kind,
138
+ id: item.id.trim(),
139
+ path: item.path?.trim(),
140
+ metadata: item.metadata ?? {},
141
+ fingerprint: item.fingerprint ?? fingerprintCapabilityItem(item),
142
+ };
143
+ byKey.set(capabilityKey(normalized), normalized);
144
+ }
145
+ return [...byKey.values()].sort((left, right) => capabilityKey(left).localeCompare(capabilityKey(right)));
146
+ }
147
+ function fingerprintCapabilityItem(item) {
148
+ const stable = stableStringify({
149
+ kind: item.kind,
150
+ id: item.id.trim(),
151
+ path: item.path?.trim() ?? '',
152
+ metadata: item.metadata ?? {},
153
+ });
154
+ return createHash('sha256').update(stable).digest('hex');
155
+ }
156
+ function indexByCapabilityKey(items) {
157
+ return new Map(items.map((item) => [capabilityKey(item), item]));
158
+ }
159
+ function countDiffEntries(entries) {
160
+ return entries.reduce((counts, entry) => {
161
+ counts[entry.change] += 1;
162
+ return counts;
163
+ }, { added: 0, removed: 0, modified: 0, unchanged: 0 });
164
+ }
165
+ function riskForRemovedCapability(entry) {
166
+ const criticalLevel = CRITICAL_KIND_WEIGHTS.get(entry.kind);
167
+ const level = criticalLevel ?? (PUBLIC_SURFACE_KINDS.has(entry.kind) ? 'high' : 'medium');
168
+ return {
169
+ code: 'capability_removed',
170
+ level,
171
+ message: `Capability ${capabilityRef(entry)} was removed.`,
172
+ capability_ref: capabilityRef(entry),
173
+ path: entry.before?.path,
174
+ };
175
+ }
176
+ function capabilityRef(entry) {
177
+ return `${entry.kind}:${entry.id}`;
178
+ }
179
+ function maxRiskLevel(levels) {
180
+ if (levels.length === 0)
181
+ return 'none';
182
+ return levels.reduce((max, level) => (RISK_SCORE[level] > RISK_SCORE[max] ? level : max), 'none');
183
+ }
184
+ function sortRiskSignals(signals) {
185
+ return [...signals].sort((left, right) => RISK_SCORE[right.level] - RISK_SCORE[left.level] ||
186
+ left.code.localeCompare(right.code) ||
187
+ (left.capability_ref ?? '').localeCompare(right.capability_ref ?? '') ||
188
+ (left.path ?? '').localeCompare(right.path ?? ''));
189
+ }
190
+ function stableStringify(value) {
191
+ if (Array.isArray(value)) {
192
+ return `[${value.map((entry) => stableStringify(entry)).join(',')}]`;
193
+ }
194
+ if (value && typeof value === 'object') {
195
+ const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right));
196
+ return `{${entries.map(([key, entry]) => `${JSON.stringify(key)}:${stableStringify(entry)}`).join(',')}}`;
197
+ }
198
+ return JSON.stringify(value);
199
+ }
200
+ //# sourceMappingURL=capability-diff.js.map
@@ -0,0 +1,74 @@
1
+ export declare const CHANGE_SAFETY_OPERATIONS: readonly ["add", "modify", "remove", "replace", "refactor", "optimize"];
2
+ export type ChangeSafetyOperation = (typeof CHANGE_SAFETY_OPERATIONS)[number];
3
+ export type PlannedFileOperation = 'create' | 'modify' | 'delete' | 'rename' | 'replace';
4
+ export interface ExplicitModificationIntent {
5
+ operation?: string;
6
+ }
7
+ export interface ContextLock {
8
+ allowed_paths?: string[];
9
+ forbidden_paths?: string[];
10
+ protected_core?: string[];
11
+ }
12
+ export interface ChangeBudget {
13
+ max_files_changed?: number;
14
+ max_new_files?: number;
15
+ max_deleted_files?: number;
16
+ }
17
+ export interface GovernedOverride {
18
+ feature_id?: string;
19
+ intent?: string;
20
+ rationale?: string;
21
+ write_scope?: string[];
22
+ expected_deletions?: string[];
23
+ rollback_plan?: string;
24
+ compensating_control?: string;
25
+ approver?: string;
26
+ expires_at?: string;
27
+ }
28
+ export interface PlannedFileChange {
29
+ path: string;
30
+ operation: PlannedFileOperation;
31
+ previous_path?: string;
32
+ }
33
+ export interface ChangeSafetyContract {
34
+ explicit_modification_intent?: ExplicitModificationIntent;
35
+ intent?: ExplicitModificationIntent;
36
+ context_lock?: ContextLock;
37
+ change_budget?: ChangeBudget;
38
+ governed_override?: GovernedOverride;
39
+ }
40
+ export type ChangeSafetyViolationCode = 'planned_changes_missing' | 'intent_missing' | 'intent_invalid' | 'add_intent_destructive_change' | 'context_lock_outside_allowed_paths' | 'context_lock_forbidden_path' | 'protected_core_change' | 'change_budget_files_exceeded' | 'change_budget_new_files_exceeded' | 'change_budget_deleted_files_exceeded' | 'governed_override_required' | 'governed_override_field_missing' | 'governed_override_feature_mismatch' | 'governed_override_intent_mismatch' | 'governed_override_expires_at_invalid' | 'governed_override_expired' | 'governed_override_scope_mismatch' | 'governed_override_deletions_mismatch';
41
+ export interface ChangeSafetyViolation {
42
+ code: ChangeSafetyViolationCode;
43
+ message: string;
44
+ path?: string;
45
+ limit?: number;
46
+ actual?: number;
47
+ }
48
+ export interface ChangeSafetyCounts {
49
+ files_changed: number;
50
+ new_files: number;
51
+ deleted_files: number;
52
+ }
53
+ export interface ChangeSafetyEvaluation {
54
+ status: 'allowed' | 'blocked';
55
+ operation: ChangeSafetyOperation | '';
56
+ violations: ChangeSafetyViolation[];
57
+ counts: ChangeSafetyCounts;
58
+ governed_override: GovernedOverrideEvaluation;
59
+ }
60
+ export interface ChangeSafetyEvaluationOptions {
61
+ feature_id?: string;
62
+ now?: Date | string;
63
+ }
64
+ export interface GovernedOverrideEvaluation {
65
+ required: boolean;
66
+ status: 'not_required' | 'valid' | 'invalid';
67
+ violations: ChangeSafetyViolation[];
68
+ }
69
+ export declare function isChangeSafetyOperation(value: string | undefined): value is ChangeSafetyOperation;
70
+ export declare function evaluateChangeSafety(contract: ChangeSafetyContract, plannedChanges: PlannedFileChange[], options?: ChangeSafetyEvaluationOptions): ChangeSafetyEvaluation;
71
+ export declare function countPlannedChanges(plannedChanges: PlannedFileChange[]): ChangeSafetyCounts;
72
+ export declare function normalizeProjectPath(value: string): string;
73
+ export declare function pathMatchesPattern(candidatePath: string, pattern: string): boolean;
74
+ //# sourceMappingURL=change-safety-guardrails.d.ts.map
@@ -0,0 +1,333 @@
1
+ export const CHANGE_SAFETY_OPERATIONS = ['add', 'modify', 'remove', 'replace', 'refactor', 'optimize'];
2
+ const DESTRUCTIVE_ADD_OPERATIONS = new Set(['delete', 'replace', 'rename']);
3
+ const GOVERNED_OVERRIDE_REQUIRED_FIELDS = [
4
+ 'feature_id',
5
+ 'intent',
6
+ 'rationale',
7
+ 'rollback_plan',
8
+ 'compensating_control',
9
+ 'approver',
10
+ 'expires_at',
11
+ ];
12
+ export function isChangeSafetyOperation(value) {
13
+ return CHANGE_SAFETY_OPERATIONS.includes(value);
14
+ }
15
+ export function evaluateChangeSafety(contract, plannedChanges, options = {}) {
16
+ const violations = [];
17
+ const operation = contract.explicit_modification_intent?.operation ?? contract.intent?.operation;
18
+ if (plannedChanges.length === 0) {
19
+ violations.push({
20
+ code: 'planned_changes_missing',
21
+ message: 'Mutating change requires at least one planned file change.',
22
+ });
23
+ }
24
+ if (!operation) {
25
+ violations.push({
26
+ code: 'intent_missing',
27
+ message: 'Mutating change requires explicit_modification_intent.operation.',
28
+ });
29
+ }
30
+ else if (!isChangeSafetyOperation(operation)) {
31
+ violations.push({
32
+ code: 'intent_invalid',
33
+ message: `Invalid explicit_modification_intent.operation "${operation}".`,
34
+ });
35
+ }
36
+ const normalizedOperation = isChangeSafetyOperation(operation) ? operation : '';
37
+ const contextLock = contract.context_lock ?? {};
38
+ const governedOverride = evaluateGovernedOverride(contract, plannedChanges, normalizedOperation, options);
39
+ violations.push(...governedOverride.violations);
40
+ const hasValidGovernedOverride = governedOverride.status === 'valid';
41
+ for (const change of plannedChanges) {
42
+ const normalizedPath = normalizeProjectPath(change.path);
43
+ const previousPath = change.previous_path ? normalizeProjectPath(change.previous_path) : '';
44
+ const pathsToCheck = previousPath ? [normalizedPath, previousPath] : [normalizedPath];
45
+ if (normalizedOperation === 'add' && DESTRUCTIVE_ADD_OPERATIONS.has(change.operation)) {
46
+ violations.push({
47
+ code: 'add_intent_destructive_change',
48
+ message: '`operation: add` cannot delete, rename, or replace existing files.',
49
+ path: normalizedPath,
50
+ });
51
+ }
52
+ for (const candidatePath of pathsToCheck) {
53
+ if (isOutsideAllowedPaths(candidatePath, contextLock.allowed_paths)) {
54
+ violations.push({
55
+ code: 'context_lock_outside_allowed_paths',
56
+ message: `Path "${candidatePath}" is outside context_lock.allowed_paths.`,
57
+ path: candidatePath,
58
+ });
59
+ }
60
+ if (matchesAnyPattern(candidatePath, contextLock.forbidden_paths)) {
61
+ violations.push({
62
+ code: 'context_lock_forbidden_path',
63
+ message: `Path "${candidatePath}" matches context_lock.forbidden_paths.`,
64
+ path: candidatePath,
65
+ });
66
+ }
67
+ if (matchesAnyPattern(candidatePath, contextLock.protected_core) && !hasValidGovernedOverride) {
68
+ violations.push({
69
+ code: 'protected_core_change',
70
+ message: `Path "${candidatePath}" matches context_lock.protected_core and requires explicit override.`,
71
+ path: candidatePath,
72
+ });
73
+ }
74
+ }
75
+ }
76
+ const counts = countPlannedChanges(plannedChanges);
77
+ violations.push(...evaluateChangeBudget(contract.change_budget, counts));
78
+ return {
79
+ status: violations.length > 0 ? 'blocked' : 'allowed',
80
+ operation: normalizedOperation,
81
+ violations,
82
+ counts,
83
+ governed_override: governedOverride,
84
+ };
85
+ }
86
+ export function countPlannedChanges(plannedChanges) {
87
+ const changedPaths = new Set();
88
+ let newFiles = 0;
89
+ let deletedFiles = 0;
90
+ for (const change of plannedChanges) {
91
+ changedPaths.add(normalizeProjectPath(change.path));
92
+ if (change.previous_path) {
93
+ changedPaths.add(normalizeProjectPath(change.previous_path));
94
+ }
95
+ if (change.operation === 'create') {
96
+ newFiles += 1;
97
+ }
98
+ if (change.operation === 'delete' || change.operation === 'replace') {
99
+ deletedFiles += 1;
100
+ }
101
+ if (change.operation === 'rename') {
102
+ newFiles += 1;
103
+ deletedFiles += 1;
104
+ }
105
+ }
106
+ return {
107
+ files_changed: changedPaths.size,
108
+ new_files: newFiles,
109
+ deleted_files: deletedFiles,
110
+ };
111
+ }
112
+ export function normalizeProjectPath(value) {
113
+ return value
114
+ .replace(/\\/g, '/')
115
+ .replace(/^\.\/+/, '')
116
+ .split('/')
117
+ .filter((segment) => segment.length > 0 && segment !== '.')
118
+ .join('/');
119
+ }
120
+ function evaluateGovernedOverride(contract, plannedChanges, operation, options) {
121
+ const requiredPaths = collectGovernedOverrideRequiredPaths(contract.context_lock, plannedChanges);
122
+ if (requiredPaths.length === 0) {
123
+ return {
124
+ required: false,
125
+ status: 'not_required',
126
+ violations: [],
127
+ };
128
+ }
129
+ const override = contract.governed_override;
130
+ if (!override) {
131
+ return {
132
+ required: true,
133
+ status: 'invalid',
134
+ violations: [
135
+ {
136
+ code: 'governed_override_required',
137
+ message: 'Replacement or protected-core change requires change_safety.governed_override.',
138
+ },
139
+ ],
140
+ };
141
+ }
142
+ const violations = [];
143
+ for (const field of GOVERNED_OVERRIDE_REQUIRED_FIELDS) {
144
+ if (!isNonEmptyString(override[field])) {
145
+ violations.push({
146
+ code: 'governed_override_field_missing',
147
+ message: `change_safety.governed_override.${field} is required.`,
148
+ });
149
+ }
150
+ }
151
+ if (!Array.isArray(override.write_scope) || override.write_scope.length === 0) {
152
+ violations.push({
153
+ code: 'governed_override_field_missing',
154
+ message: 'change_safety.governed_override.write_scope must include at least one path pattern.',
155
+ });
156
+ }
157
+ if (!Array.isArray(override.expected_deletions)) {
158
+ violations.push({
159
+ code: 'governed_override_field_missing',
160
+ message: 'change_safety.governed_override.expected_deletions must be declared.',
161
+ });
162
+ }
163
+ if (options.feature_id && override.feature_id && override.feature_id !== options.feature_id) {
164
+ violations.push({
165
+ code: 'governed_override_feature_mismatch',
166
+ message: `change_safety.governed_override.feature_id "${override.feature_id}" does not match "${options.feature_id}".`,
167
+ });
168
+ }
169
+ if (operation && override.intent && override.intent !== operation) {
170
+ violations.push({
171
+ code: 'governed_override_intent_mismatch',
172
+ message: `change_safety.governed_override.intent "${override.intent}" does not match explicit intent "${operation}".`,
173
+ });
174
+ }
175
+ violations.push(...evaluateOverrideExpiration(override.expires_at, options.now));
176
+ const writeScope = override.write_scope ?? [];
177
+ for (const candidatePath of requiredPaths) {
178
+ if (!matchesAnyPattern(candidatePath, writeScope)) {
179
+ violations.push({
180
+ code: 'governed_override_scope_mismatch',
181
+ message: `Path "${candidatePath}" is outside change_safety.governed_override.write_scope.`,
182
+ path: candidatePath,
183
+ });
184
+ }
185
+ }
186
+ const expectedDeletions = override.expected_deletions;
187
+ if (Array.isArray(expectedDeletions)) {
188
+ const actualDeletions = collectDestructivePaths(plannedChanges);
189
+ const declaredDeletions = normalizeSortedUnique(expectedDeletions);
190
+ if (!sameStringList(actualDeletions, declaredDeletions)) {
191
+ violations.push({
192
+ code: 'governed_override_deletions_mismatch',
193
+ message: `change_safety.governed_override.expected_deletions must match planned destructive paths. Expected ${JSON.stringify(actualDeletions)}, received ${JSON.stringify(declaredDeletions)}.`,
194
+ });
195
+ }
196
+ }
197
+ return {
198
+ required: true,
199
+ status: violations.length === 0 ? 'valid' : 'invalid',
200
+ violations,
201
+ };
202
+ }
203
+ function collectGovernedOverrideRequiredPaths(contextLock, plannedChanges) {
204
+ const required = new Set();
205
+ for (const change of plannedChanges) {
206
+ const affectedPaths = getAffectedPaths(change);
207
+ if (change.operation === 'replace') {
208
+ affectedPaths.forEach((path) => required.add(path));
209
+ }
210
+ for (const candidatePath of affectedPaths) {
211
+ if (matchesAnyPattern(candidatePath, contextLock?.protected_core)) {
212
+ required.add(candidatePath);
213
+ }
214
+ }
215
+ }
216
+ return [...required].sort();
217
+ }
218
+ function collectDestructivePaths(plannedChanges) {
219
+ const paths = new Set();
220
+ for (const change of plannedChanges) {
221
+ if (change.operation === 'delete' || change.operation === 'replace') {
222
+ paths.add(normalizeProjectPath(change.path));
223
+ }
224
+ if (change.operation === 'rename') {
225
+ paths.add(normalizeProjectPath(change.previous_path ?? change.path));
226
+ }
227
+ }
228
+ return [...paths].sort();
229
+ }
230
+ function getAffectedPaths(change) {
231
+ const paths = [normalizeProjectPath(change.path)];
232
+ if (change.previous_path) {
233
+ paths.push(normalizeProjectPath(change.previous_path));
234
+ }
235
+ return paths;
236
+ }
237
+ function evaluateOverrideExpiration(expiresAt, now) {
238
+ if (!expiresAt)
239
+ return [];
240
+ const expiresAtMs = Date.parse(expiresAt);
241
+ if (!Number.isFinite(expiresAtMs)) {
242
+ return [
243
+ {
244
+ code: 'governed_override_expires_at_invalid',
245
+ message: 'change_safety.governed_override.expires_at must be a valid ISO timestamp.',
246
+ },
247
+ ];
248
+ }
249
+ const nowMs = now ? new Date(now).getTime() : Date.now();
250
+ if (expiresAtMs <= nowMs) {
251
+ return [
252
+ {
253
+ code: 'governed_override_expired',
254
+ message: 'change_safety.governed_override.expires_at has expired.',
255
+ },
256
+ ];
257
+ }
258
+ return [];
259
+ }
260
+ function normalizeSortedUnique(values) {
261
+ return [...new Set(values.map(normalizeProjectPath))].sort();
262
+ }
263
+ function sameStringList(left, right) {
264
+ return left.length === right.length && left.every((value, index) => value === right[index]);
265
+ }
266
+ function isNonEmptyString(value) {
267
+ return typeof value === 'string' && value.trim().length > 0;
268
+ }
269
+ function evaluateChangeBudget(budget, counts) {
270
+ if (!budget)
271
+ return [];
272
+ const violations = [];
273
+ if (exceedsBudget(counts.files_changed, budget.max_files_changed)) {
274
+ violations.push({
275
+ code: 'change_budget_files_exceeded',
276
+ message: `Changed files count ${counts.files_changed} exceeds change_budget.max_files_changed ${budget.max_files_changed}.`,
277
+ limit: budget.max_files_changed,
278
+ actual: counts.files_changed,
279
+ });
280
+ }
281
+ if (exceedsBudget(counts.new_files, budget.max_new_files)) {
282
+ violations.push({
283
+ code: 'change_budget_new_files_exceeded',
284
+ message: `New files count ${counts.new_files} exceeds change_budget.max_new_files ${budget.max_new_files}.`,
285
+ limit: budget.max_new_files,
286
+ actual: counts.new_files,
287
+ });
288
+ }
289
+ if (exceedsBudget(counts.deleted_files, budget.max_deleted_files)) {
290
+ violations.push({
291
+ code: 'change_budget_deleted_files_exceeded',
292
+ message: `Deleted files count ${counts.deleted_files} exceeds change_budget.max_deleted_files ${budget.max_deleted_files}.`,
293
+ limit: budget.max_deleted_files,
294
+ actual: counts.deleted_files,
295
+ });
296
+ }
297
+ return violations;
298
+ }
299
+ function exceedsBudget(actual, limit) {
300
+ return typeof limit === 'number' && actual > limit;
301
+ }
302
+ function isOutsideAllowedPaths(candidatePath, allowedPatterns) {
303
+ if (!allowedPatterns || allowedPatterns.length === 0)
304
+ return false;
305
+ return !matchesAnyPattern(candidatePath, allowedPatterns);
306
+ }
307
+ function matchesAnyPattern(candidatePath, patterns) {
308
+ if (!patterns || patterns.length === 0)
309
+ return false;
310
+ return patterns.some((pattern) => pathMatchesPattern(candidatePath, pattern));
311
+ }
312
+ export function pathMatchesPattern(candidatePath, pattern) {
313
+ const normalizedPath = normalizeProjectPath(candidatePath);
314
+ const exactDirectory = /[\\/]$/.test(pattern);
315
+ const normalizedPattern = normalizeProjectPath(pattern);
316
+ if (!normalizedPattern)
317
+ return false;
318
+ if (exactDirectory) {
319
+ return normalizedPath === normalizedPattern || normalizedPath.startsWith(`${normalizedPattern}/`);
320
+ }
321
+ const regex = globToRegExp(normalizedPattern);
322
+ return regex.test(normalizedPath);
323
+ }
324
+ function globToRegExp(pattern) {
325
+ const placeholder = '\u0000';
326
+ const escaped = pattern
327
+ .split('**')
328
+ .map((part) => part.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '[^/]*'))
329
+ .join(placeholder);
330
+ const source = escaped.replaceAll(placeholder, '.*');
331
+ return new RegExp(`^${source}$`);
332
+ }
333
+ //# sourceMappingURL=change-safety-guardrails.js.map
@@ -0,0 +1,29 @@
1
+ import type { CapabilityDiffReport, CapabilityRiskReport } from './capability-diff.js';
2
+ import type { ChangeSafetyOperation } from './change-safety-guardrails.js';
3
+ export declare const SEMANTIC_INTENT_CLASSES: readonly ["incremental", "refactor", "replacement", "ambiguous"];
4
+ export type SemanticIntentClass = (typeof SEMANTIC_INTENT_CLASSES)[number];
5
+ export interface SemanticIntentClassifierInput {
6
+ objective?: string;
7
+ declared_operation?: ChangeSafetyOperation | '';
8
+ capability_diff?: CapabilityDiffReport;
9
+ deterministic_risk?: CapabilityRiskReport;
10
+ }
11
+ export interface SemanticIntentSignal {
12
+ code: string;
13
+ message: string;
14
+ weight: number;
15
+ }
16
+ export interface SemanticIntentClassification {
17
+ schema_version: 1;
18
+ contract: 'semantic-intent-classification/v1';
19
+ status: 'allowed' | 'blocked';
20
+ classification: SemanticIntentClass;
21
+ fail_closed: true;
22
+ triggered: boolean;
23
+ confidence: number;
24
+ reasons: string[];
25
+ signals: SemanticIntentSignal[];
26
+ }
27
+ export declare function shouldRunSemanticIntentClassifier(input: SemanticIntentClassifierInput): boolean;
28
+ export declare function classifySemanticIntent(input: SemanticIntentClassifierInput): SemanticIntentClassification;
29
+ //# sourceMappingURL=semantic-intent-classifier.d.ts.map