@planu/cli 1.11.0 → 1.12.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 (179) hide show
  1. package/dist/config/license-plans.json +27 -2
  2. package/dist/engine/api-compat/compatibility-checker.d.ts +4 -0
  3. package/dist/engine/api-compat/compatibility-checker.d.ts.map +1 -0
  4. package/dist/engine/api-compat/compatibility-checker.js +118 -0
  5. package/dist/engine/api-compat/compatibility-checker.js.map +1 -0
  6. package/dist/engine/checkpoint/checkpoint-manager.d.ts +22 -0
  7. package/dist/engine/checkpoint/checkpoint-manager.d.ts.map +1 -0
  8. package/dist/engine/checkpoint/checkpoint-manager.js +76 -0
  9. package/dist/engine/checkpoint/checkpoint-manager.js.map +1 -0
  10. package/dist/engine/checkpoint/policy-engine.d.ts +10 -0
  11. package/dist/engine/checkpoint/policy-engine.d.ts.map +1 -0
  12. package/dist/engine/checkpoint/policy-engine.js +87 -0
  13. package/dist/engine/checkpoint/policy-engine.js.map +1 -0
  14. package/dist/engine/compliance/auto-remediator.d.ts +9 -0
  15. package/dist/engine/compliance/auto-remediator.d.ts.map +1 -0
  16. package/dist/engine/compliance/auto-remediator.js +118 -0
  17. package/dist/engine/compliance/auto-remediator.js.map +1 -0
  18. package/dist/engine/context-profile/profile-catalog.d.ts +5 -0
  19. package/dist/engine/context-profile/profile-catalog.d.ts.map +1 -0
  20. package/dist/engine/context-profile/profile-catalog.js +145 -0
  21. package/dist/engine/context-profile/profile-catalog.js.map +1 -0
  22. package/dist/engine/critical-path/path-analyzer.d.ts +3 -0
  23. package/dist/engine/critical-path/path-analyzer.d.ts.map +1 -0
  24. package/dist/engine/critical-path/path-analyzer.js +145 -0
  25. package/dist/engine/critical-path/path-analyzer.js.map +1 -0
  26. package/dist/engine/drift/violation-resolver.d.ts +9 -0
  27. package/dist/engine/drift/violation-resolver.d.ts.map +1 -0
  28. package/dist/engine/drift/violation-resolver.js +128 -0
  29. package/dist/engine/drift/violation-resolver.js.map +1 -0
  30. package/dist/engine/ears/criterion-scorer.d.ts +7 -0
  31. package/dist/engine/ears/criterion-scorer.d.ts.map +1 -0
  32. package/dist/engine/ears/criterion-scorer.js +87 -0
  33. package/dist/engine/ears/criterion-scorer.js.map +1 -0
  34. package/dist/engine/ears/pattern-matcher.d.ts +5 -0
  35. package/dist/engine/ears/pattern-matcher.d.ts.map +1 -0
  36. package/dist/engine/ears/pattern-matcher.js +48 -0
  37. package/dist/engine/ears/pattern-matcher.js.map +1 -0
  38. package/dist/engine/ears/rewriter.d.ts +7 -0
  39. package/dist/engine/ears/rewriter.d.ts.map +1 -0
  40. package/dist/engine/ears/rewriter.js +45 -0
  41. package/dist/engine/ears/rewriter.js.map +1 -0
  42. package/dist/engine/ears/spec-linter.d.ts +7 -0
  43. package/dist/engine/ears/spec-linter.d.ts.map +1 -0
  44. package/dist/engine/ears/spec-linter.js +127 -0
  45. package/dist/engine/ears/spec-linter.js.map +1 -0
  46. package/dist/engine/health/auto-fixer.d.ts +7 -0
  47. package/dist/engine/health/auto-fixer.d.ts.map +1 -0
  48. package/dist/engine/health/auto-fixer.js +130 -0
  49. package/dist/engine/health/auto-fixer.js.map +1 -0
  50. package/dist/engine/mcp-catalog/catalog-advisor.d.ts +3 -0
  51. package/dist/engine/mcp-catalog/catalog-advisor.d.ts.map +1 -0
  52. package/dist/engine/mcp-catalog/catalog-advisor.js +180 -0
  53. package/dist/engine/mcp-catalog/catalog-advisor.js.map +1 -0
  54. package/dist/engine/similar-problems/similarity-finder.d.ts +3 -0
  55. package/dist/engine/similar-problems/similarity-finder.d.ts.map +1 -0
  56. package/dist/engine/similar-problems/similarity-finder.js +144 -0
  57. package/dist/engine/similar-problems/similarity-finder.js.map +1 -0
  58. package/dist/engine/sync/asana-puller.d.ts +9 -0
  59. package/dist/engine/sync/asana-puller.d.ts.map +1 -0
  60. package/dist/engine/sync/asana-puller.js +91 -0
  61. package/dist/engine/sync/asana-puller.js.map +1 -0
  62. package/dist/engine/sync/conflict-resolver.d.ts +17 -0
  63. package/dist/engine/sync/conflict-resolver.d.ts.map +1 -0
  64. package/dist/engine/sync/conflict-resolver.js +58 -0
  65. package/dist/engine/sync/conflict-resolver.js.map +1 -0
  66. package/dist/engine/sync/monday-puller.d.ts +9 -0
  67. package/dist/engine/sync/monday-puller.d.ts.map +1 -0
  68. package/dist/engine/sync/monday-puller.js +110 -0
  69. package/dist/engine/sync/monday-puller.js.map +1 -0
  70. package/dist/engine/sync/notion-puller.d.ts +15 -0
  71. package/dist/engine/sync/notion-puller.d.ts.map +1 -0
  72. package/dist/engine/sync/notion-puller.js +101 -0
  73. package/dist/engine/sync/notion-puller.js.map +1 -0
  74. package/dist/engine/verifier/code-scanner.d.ts +8 -0
  75. package/dist/engine/verifier/code-scanner.d.ts.map +1 -0
  76. package/dist/engine/verifier/code-scanner.js +73 -0
  77. package/dist/engine/verifier/code-scanner.js.map +1 -0
  78. package/dist/engine/verifier/compliance-scorer.d.ts +17 -0
  79. package/dist/engine/verifier/compliance-scorer.d.ts.map +1 -0
  80. package/dist/engine/verifier/compliance-scorer.js +131 -0
  81. package/dist/engine/verifier/compliance-scorer.js.map +1 -0
  82. package/dist/engine/verifier/criterion-matcher.d.ts +15 -0
  83. package/dist/engine/verifier/criterion-matcher.d.ts.map +1 -0
  84. package/dist/engine/verifier/criterion-matcher.js +210 -0
  85. package/dist/engine/verifier/criterion-matcher.js.map +1 -0
  86. package/dist/index.js +14 -0
  87. package/dist/index.js.map +1 -1
  88. package/dist/storage/compliance-score-store.d.ts +16 -0
  89. package/dist/storage/compliance-score-store.d.ts.map +1 -0
  90. package/dist/storage/compliance-score-store.js +30 -0
  91. package/dist/storage/compliance-score-store.js.map +1 -0
  92. package/dist/storage/context-profile-store.d.ts +14 -0
  93. package/dist/storage/context-profile-store.d.ts.map +1 -0
  94. package/dist/storage/context-profile-store.js +34 -0
  95. package/dist/storage/context-profile-store.js.map +1 -0
  96. package/dist/storage/workflow-checkpoint-store.d.ts +16 -0
  97. package/dist/storage/workflow-checkpoint-store.d.ts.map +1 -0
  98. package/dist/storage/workflow-checkpoint-store.js +71 -0
  99. package/dist/storage/workflow-checkpoint-store.js.map +1 -0
  100. package/dist/tools/checkpoint/approve-checkpoint-handler.d.ts +3 -0
  101. package/dist/tools/checkpoint/approve-checkpoint-handler.d.ts.map +1 -0
  102. package/dist/tools/checkpoint/approve-checkpoint-handler.js +32 -0
  103. package/dist/tools/checkpoint/approve-checkpoint-handler.js.map +1 -0
  104. package/dist/tools/checkpoint/configure-policy-handler.d.ts +3 -0
  105. package/dist/tools/checkpoint/configure-policy-handler.d.ts.map +1 -0
  106. package/dist/tools/checkpoint/configure-policy-handler.js +60 -0
  107. package/dist/tools/checkpoint/configure-policy-handler.js.map +1 -0
  108. package/dist/tools/checkpoint/list-checkpoints-handler.d.ts +3 -0
  109. package/dist/tools/checkpoint/list-checkpoints-handler.d.ts.map +1 -0
  110. package/dist/tools/checkpoint/list-checkpoints-handler.js +25 -0
  111. package/dist/tools/checkpoint/list-checkpoints-handler.js.map +1 -0
  112. package/dist/tools/checkpoint/reject-checkpoint-handler.d.ts +3 -0
  113. package/dist/tools/checkpoint/reject-checkpoint-handler.d.ts.map +1 -0
  114. package/dist/tools/checkpoint/reject-checkpoint-handler.js +32 -0
  115. package/dist/tools/checkpoint/reject-checkpoint-handler.js.map +1 -0
  116. package/dist/tools/checkpoint/require-checkpoint-handler.d.ts +3 -0
  117. package/dist/tools/checkpoint/require-checkpoint-handler.d.ts.map +1 -0
  118. package/dist/tools/checkpoint/require-checkpoint-handler.js +44 -0
  119. package/dist/tools/checkpoint/require-checkpoint-handler.js.map +1 -0
  120. package/dist/tools/pull-sync-handler.d.ts +25 -0
  121. package/dist/tools/pull-sync-handler.d.ts.map +1 -0
  122. package/dist/tools/pull-sync-handler.js +161 -0
  123. package/dist/tools/pull-sync-handler.js.map +1 -0
  124. package/dist/tools/register-auto-remediation.d.ts +3 -0
  125. package/dist/tools/register-auto-remediation.d.ts.map +1 -0
  126. package/dist/tools/register-auto-remediation.js +174 -0
  127. package/dist/tools/register-auto-remediation.js.map +1 -0
  128. package/dist/tools/register-checkpoints.d.ts +3 -0
  129. package/dist/tools/register-checkpoints.d.ts.map +1 -0
  130. package/dist/tools/register-checkpoints.js +134 -0
  131. package/dist/tools/register-checkpoints.js.map +1 -0
  132. package/dist/tools/register-context-profile.d.ts +3 -0
  133. package/dist/tools/register-context-profile.d.ts.map +1 -0
  134. package/dist/tools/register-context-profile.js +106 -0
  135. package/dist/tools/register-context-profile.js.map +1 -0
  136. package/dist/tools/register-ears.d.ts +3 -0
  137. package/dist/tools/register-ears.d.ts.map +1 -0
  138. package/dist/tools/register-ears.js +148 -0
  139. package/dist/tools/register-ears.js.map +1 -0
  140. package/dist/tools/register-enterprise-compliance.js +1 -1
  141. package/dist/tools/register-enterprise-compliance.js.map +1 -1
  142. package/dist/tools/register-pull-sync.d.ts +3 -0
  143. package/dist/tools/register-pull-sync.d.ts.map +1 -0
  144. package/dist/tools/register-pull-sync.js +71 -0
  145. package/dist/tools/register-pull-sync.js.map +1 -0
  146. package/dist/tools/register-spec405-tools.d.ts +7 -0
  147. package/dist/tools/register-spec405-tools.d.ts.map +1 -0
  148. package/dist/tools/register-spec405-tools.js +194 -0
  149. package/dist/tools/register-spec405-tools.js.map +1 -0
  150. package/dist/tools/register-verifier.d.ts +3 -0
  151. package/dist/tools/register-verifier.d.ts.map +1 -0
  152. package/dist/tools/register-verifier.js +141 -0
  153. package/dist/tools/register-verifier.js.map +1 -0
  154. package/dist/types/analysis.d.ts +98 -0
  155. package/dist/types/analysis.d.ts.map +1 -1
  156. package/dist/types/context-profile.d.ts +22 -0
  157. package/dist/types/context-profile.d.ts.map +1 -0
  158. package/dist/types/context-profile.js +2 -0
  159. package/dist/types/context-profile.js.map +1 -0
  160. package/dist/types/ears.d.ts +34 -0
  161. package/dist/types/ears.d.ts.map +1 -0
  162. package/dist/types/ears.js +3 -0
  163. package/dist/types/ears.js.map +1 -0
  164. package/dist/types/health.d.ts +40 -0
  165. package/dist/types/health.d.ts.map +1 -0
  166. package/dist/types/health.js +3 -0
  167. package/dist/types/health.js.map +1 -0
  168. package/dist/types/index.d.ts +4 -0
  169. package/dist/types/index.d.ts.map +1 -1
  170. package/dist/types/index.js +4 -0
  171. package/dist/types/index.js.map +1 -1
  172. package/dist/types/notion-asana-monday.d.ts +38 -0
  173. package/dist/types/notion-asana-monday.d.ts.map +1 -1
  174. package/dist/types/workflow-checkpoint.d.ts +66 -0
  175. package/dist/types/workflow-checkpoint.d.ts.map +1 -0
  176. package/dist/types/workflow-checkpoint.js +4 -0
  177. package/dist/types/workflow-checkpoint.js.map +1 -0
  178. package/package.json +1 -1
  179. package/src/config/license-plans.json +27 -2
@@ -92,7 +92,10 @@
92
92
  "update_status",
93
93
  "validate",
94
94
  "worker_status",
95
- "security_scan"
95
+ "security_scan",
96
+ "set_context_profile",
97
+ "get_context_profile",
98
+ "list_context_profiles"
96
99
  ],
97
100
  "proTools": [
98
101
  "a2a_delegate",
@@ -432,7 +435,29 @@
432
435
  "record_spend",
433
436
  "discover_mcp_gateways",
434
437
  "federation_discovery_status",
435
- "dogfood_status"
438
+ "dogfood_status",
439
+ "generate_compliance_evidence",
440
+ "check_api_compatibility_v2",
441
+ "critical_path_analyzer_v2",
442
+ "similar_problems_finder_v2",
443
+ "suggest_mcp_catalog",
444
+ "verify_spec_compliance",
445
+ "compliance_score_report",
446
+ "auto_fix_health",
447
+ "auto_remediate_compliance",
448
+ "resolve_drift_violations",
449
+ "pull_from_notion",
450
+ "pull_from_asana",
451
+ "pull_from_monday",
452
+ "sync_all_integrations",
453
+ "validate_criteria_quality",
454
+ "rewrite_criteria_ears",
455
+ "ears_lint",
456
+ "configure_checkpoint_policy",
457
+ "require_checkpoint",
458
+ "approve_checkpoint",
459
+ "reject_checkpoint",
460
+ "list_pending_checkpoints"
436
461
  ],
437
462
  "alwaysAllowed": [
438
463
  "activate_license",
@@ -0,0 +1,4 @@
1
+ import type { ApiCompatibilityResult } from '../../types/index.js';
2
+ export declare function findSpecFile(projectPath: string, specId: string): Promise<string | null>;
3
+ export declare function checkApiCompatibility(specId1: string, specId2: string, projectPath: string): Promise<ApiCompatibilityResult>;
4
+ //# sourceMappingURL=compatibility-checker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compatibility-checker.d.ts","sourceRoot":"","sources":["../../../src/engine/api-compat/compatibility-checker.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,sBAAsB,EAAa,MAAM,sBAAsB,CAAC;AAgB9E,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAI9F;AA8ED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,sBAAsB,CAAC,CAqCjC"}
@@ -0,0 +1,118 @@
1
+ // engine/api-compat/compatibility-checker.ts — SPEC-405
2
+ // Compare two spec files' API surfaces to determine compatibility.
3
+ import { readFile } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { glob } from 'glob';
6
+ // ---------------------------------------------------------------------------
7
+ // Regex patterns for API surface extraction
8
+ // ---------------------------------------------------------------------------
9
+ const REST_PATTERN = /\b(GET|POST|PUT|PATCH|DELETE)\s+(\/[^\s`'")\]]+)/gi;
10
+ const GRAPHQL_TYPE_PATTERN = /\btype\s+(\w+)\s*\{/gi;
11
+ const GRAPHQL_MUTATION_PATTERN = /\bmutation\s+(\w+)\s*[({]/gi;
12
+ const GRAPHQL_QUERY_PATTERN = /\bquery\s+(\w+)\s*[({]/gi;
13
+ const EVENT_PATTERN = /\bevent[:\s]+["'`]?([A-Za-z][A-Za-z0-9_.:-]+)["'`]?/gi;
14
+ // ---------------------------------------------------------------------------
15
+ // Spec file discovery
16
+ // ---------------------------------------------------------------------------
17
+ export async function findSpecFile(projectPath, specId) {
18
+ const pattern = join(projectPath, 'planu', 'specs', `${specId}-*`, 'spec.md');
19
+ const matches = await glob(pattern, { nodir: true });
20
+ return matches[0] ?? null;
21
+ }
22
+ async function readSpecMd(projectPath, specId) {
23
+ const filePath = await findSpecFile(projectPath, specId);
24
+ if (!filePath) {
25
+ return null;
26
+ }
27
+ try {
28
+ return await readFile(filePath, 'utf-8');
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
34
+ // ---------------------------------------------------------------------------
35
+ // API surface extraction
36
+ // ---------------------------------------------------------------------------
37
+ function extractApiSurface(content) {
38
+ const items = new Set();
39
+ let m;
40
+ const restRe = new RegExp(REST_PATTERN.source, 'gi');
41
+ while ((m = restRe.exec(content)) !== null) {
42
+ if (m[1] && m[2]) {
43
+ items.add(`REST:${m[1].toUpperCase()} ${m[2]}`);
44
+ }
45
+ }
46
+ const gqlTypeRe = new RegExp(GRAPHQL_TYPE_PATTERN.source, 'gi');
47
+ while ((m = gqlTypeRe.exec(content)) !== null) {
48
+ if (m[1]) {
49
+ items.add(`GQL_TYPE:${m[1]}`);
50
+ }
51
+ }
52
+ const gqlMutRe = new RegExp(GRAPHQL_MUTATION_PATTERN.source, 'gi');
53
+ while ((m = gqlMutRe.exec(content)) !== null) {
54
+ if (m[1]) {
55
+ items.add(`GQL_MUTATION:${m[1]}`);
56
+ }
57
+ }
58
+ const gqlQryRe = new RegExp(GRAPHQL_QUERY_PATTERN.source, 'gi');
59
+ while ((m = gqlQryRe.exec(content)) !== null) {
60
+ if (m[1]) {
61
+ items.add(`GQL_QUERY:${m[1]}`);
62
+ }
63
+ }
64
+ const eventRe = new RegExp(EVENT_PATTERN.source, 'gi');
65
+ while ((m = eventRe.exec(content)) !== null) {
66
+ if (m[1]) {
67
+ items.add(`EVENT:${m[1]}`);
68
+ }
69
+ }
70
+ return items;
71
+ }
72
+ // ---------------------------------------------------------------------------
73
+ // Compatibility scoring
74
+ // ---------------------------------------------------------------------------
75
+ function computeScore(breakingCount, additiveCount, totalItems) {
76
+ if (totalItems === 0) {
77
+ return 100;
78
+ }
79
+ const breakingPenalty = (breakingCount / totalItems) * 80;
80
+ const additivePenalty = (additiveCount / totalItems) * 10;
81
+ return Math.max(0, Math.round(100 - breakingPenalty - additivePenalty));
82
+ }
83
+ // ---------------------------------------------------------------------------
84
+ // Public function
85
+ // ---------------------------------------------------------------------------
86
+ export async function checkApiCompatibility(specId1, specId2, projectPath) {
87
+ const [content1, content2] = await Promise.all([
88
+ readSpecMd(projectPath, specId1),
89
+ readSpecMd(projectPath, specId2),
90
+ ]);
91
+ const surface1 = extractApiSurface(content1 ?? '');
92
+ const surface2 = extractApiSurface(content2 ?? '');
93
+ const breaking = [];
94
+ const additive = [];
95
+ // Items in spec1 but not in spec2 → removed (breaking)
96
+ for (const item of surface1) {
97
+ if (!surface2.has(item)) {
98
+ breaking.push({ type: 'removed', item, severity: 'breaking' });
99
+ }
100
+ }
101
+ // Items in spec2 but not in spec1 → added (additive)
102
+ for (const item of surface2) {
103
+ if (!surface1.has(item)) {
104
+ additive.push({ type: 'added', item, severity: 'additive' });
105
+ }
106
+ }
107
+ const totalItems = surface1.size + surface2.size;
108
+ const score = computeScore(breaking.length, additive.length, totalItems);
109
+ return {
110
+ compatible: breaking.length === 0,
111
+ specId1,
112
+ specId2,
113
+ breakingChanges: breaking,
114
+ additiveChanges: additive,
115
+ score,
116
+ };
117
+ }
118
+ //# sourceMappingURL=compatibility-checker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compatibility-checker.js","sourceRoot":"","sources":["../../../src/engine/api-compat/compatibility-checker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { WorkflowCheckpoint, CheckpointPolicy } from '../../types/index.js';
2
+ /**
3
+ * Creates a new pending checkpoint for the given spec transition.
4
+ * If the policy has autoApproveAfterHours set, schedules the auto-approve time.
5
+ */
6
+ export declare function requestCheckpoint(projectPath: string, specId: string, policy: CheckpointPolicy, requestedBy: string): Promise<WorkflowCheckpoint>;
7
+ /**
8
+ * Approves a pending checkpoint.
9
+ * Returns the updated checkpoint and a flag indicating the blocked transition can now proceed.
10
+ */
11
+ export declare function approveCheckpoint(projectPath: string, checkpointId: string, approvedBy: string): Promise<{
12
+ checkpoint: WorkflowCheckpoint;
13
+ transitionApplied: boolean;
14
+ }>;
15
+ /** Rejects a pending checkpoint with a mandatory reason. */
16
+ export declare function rejectCheckpoint(projectPath: string, checkpointId: string, rejectedBy: string, reason: string): Promise<WorkflowCheckpoint>;
17
+ /**
18
+ * Scans all pending checkpoints for a project and auto-approves any that have
19
+ * passed their autoApproveAt deadline. Returns the list of auto-approved checkpoints.
20
+ */
21
+ export declare function checkAutoApprovals(projectPath: string): Promise<WorkflowCheckpoint[]>;
22
+ //# sourceMappingURL=checkpoint-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkpoint-manager.d.ts","sourceRoot":"","sources":["../../../src/engine/checkpoint/checkpoint-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAYjF;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,gBAAgB,EACxB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,kBAAkB,CAAC,CAmB7B;AAMD;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,UAAU,EAAE,kBAAkB,CAAC;IAAC,iBAAiB,EAAE,OAAO,CAAA;CAAE,CAAC,CAMzE;AAMD,4DAA4D;AAC5D,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,kBAAkB,CAAC,CAM7B;AAMD;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAmB3F"}
@@ -0,0 +1,76 @@
1
+ // engine/checkpoint/checkpoint-manager.ts — Checkpoint lifecycle management (SPEC-411)
2
+ import { hashProjectPath } from '../../storage/base-store.js';
3
+ import { createWorkflowCheckpoint, resolveWorkflowCheckpoint, getPendingWorkflowCheckpoints, } from '../../storage/workflow-checkpoint-store.js';
4
+ // ---------------------------------------------------------------------------
5
+ // Request
6
+ // ---------------------------------------------------------------------------
7
+ /**
8
+ * Creates a new pending checkpoint for the given spec transition.
9
+ * If the policy has autoApproveAfterHours set, schedules the auto-approve time.
10
+ */
11
+ export async function requestCheckpoint(projectPath, specId, policy, requestedBy) {
12
+ const projectId = hashProjectPath(projectPath);
13
+ const autoApproveAt = policy.autoApproveAfterHours !== undefined
14
+ ? new Date(Date.now() + policy.autoApproveAfterHours * 3_600_000).toISOString()
15
+ : undefined;
16
+ return createWorkflowCheckpoint(projectPath, {
17
+ specId,
18
+ projectId,
19
+ policyId: policy.id,
20
+ blockingTransition: policy.transition,
21
+ requiredRole: policy.requiredRole,
22
+ requestedBy,
23
+ requestedAt: new Date().toISOString(),
24
+ status: 'pending',
25
+ autoApproveAt,
26
+ });
27
+ }
28
+ // ---------------------------------------------------------------------------
29
+ // Approve
30
+ // ---------------------------------------------------------------------------
31
+ /**
32
+ * Approves a pending checkpoint.
33
+ * Returns the updated checkpoint and a flag indicating the blocked transition can now proceed.
34
+ */
35
+ export async function approveCheckpoint(projectPath, checkpointId, approvedBy) {
36
+ const checkpoint = await resolveWorkflowCheckpoint(projectPath, checkpointId, {
37
+ status: 'approved',
38
+ resolvedBy: approvedBy,
39
+ });
40
+ return { checkpoint, transitionApplied: true };
41
+ }
42
+ // ---------------------------------------------------------------------------
43
+ // Reject
44
+ // ---------------------------------------------------------------------------
45
+ /** Rejects a pending checkpoint with a mandatory reason. */
46
+ export async function rejectCheckpoint(projectPath, checkpointId, rejectedBy, reason) {
47
+ return resolveWorkflowCheckpoint(projectPath, checkpointId, {
48
+ status: 'rejected',
49
+ resolvedBy: rejectedBy,
50
+ rejectionReason: reason,
51
+ });
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // Auto-approve
55
+ // ---------------------------------------------------------------------------
56
+ /**
57
+ * Scans all pending checkpoints for a project and auto-approves any that have
58
+ * passed their autoApproveAt deadline. Returns the list of auto-approved checkpoints.
59
+ */
60
+ export async function checkAutoApprovals(projectPath) {
61
+ const pending = await getPendingWorkflowCheckpoints(projectPath);
62
+ const now = Date.now();
63
+ const autoApproved = [];
64
+ for (const checkpoint of pending) {
65
+ if (checkpoint.autoApproveAt !== undefined &&
66
+ new Date(checkpoint.autoApproveAt).getTime() <= now) {
67
+ const updated = await resolveWorkflowCheckpoint(projectPath, checkpoint.id, {
68
+ status: 'approved',
69
+ resolvedBy: 'system:auto-approve',
70
+ });
71
+ autoApproved.push(updated);
72
+ }
73
+ }
74
+ return autoApproved;
75
+ }
76
+ //# sourceMappingURL=checkpoint-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkpoint-manager.js","sourceRoot":"","sources":["../../../src/engine/checkpoint/checkpoint-manager.ts"],"names":[],"mappings":"AAAA,uFAAuF;AAGvF,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EACL,wBAAwB,EACxB,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,4CAA4C,CAAC;AAEpD,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,WAAmB,EACnB,MAAc,EACd,MAAwB,EACxB,WAAmB;IAEnB,MAAM,SAAS,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAE/C,MAAM,aAAa,GACjB,MAAM,CAAC,qBAAqB,KAAK,SAAS;QACxC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAAC,WAAW,EAAE;QAC/E,CAAC,CAAC,SAAS,CAAC;IAEhB,OAAO,wBAAwB,CAAC,WAAW,EAAE;QAC3C,MAAM;QACN,SAAS;QACT,QAAQ,EAAE,MAAM,CAAC,EAAE;QACnB,kBAAkB,EAAE,MAAM,CAAC,UAAU;QACrC,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,WAAW;QACX,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrC,MAAM,EAAE,SAAS;QACjB,aAAa;KACd,CAAC,CAAC;AACL,CAAC;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,WAAmB,EACnB,YAAoB,EACpB,UAAkB;IAElB,MAAM,UAAU,GAAG,MAAM,yBAAyB,CAAC,WAAW,EAAE,YAAY,EAAE;QAC5E,MAAM,EAAE,UAAU;QAClB,UAAU,EAAE,UAAU;KACvB,CAAC,CAAC;IACH,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC;AACjD,CAAC;AAED,8EAA8E;AAC9E,SAAS;AACT,8EAA8E;AAE9E,4DAA4D;AAC5D,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,WAAmB,EACnB,YAAoB,EACpB,UAAkB,EAClB,MAAc;IAEd,OAAO,yBAAyB,CAAC,WAAW,EAAE,YAAY,EAAE;QAC1D,MAAM,EAAE,UAAU;QAClB,UAAU,EAAE,UAAU;QACtB,eAAe,EAAE,MAAM;KACxB,CAAC,CAAC;AACL,CAAC;AAED,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,WAAmB;IAC1D,MAAM,OAAO,GAAG,MAAM,6BAA6B,CAAC,WAAW,CAAC,CAAC;IACjE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,YAAY,GAAyB,EAAE,CAAC;IAE9C,KAAK,MAAM,UAAU,IAAI,OAAO,EAAE,CAAC;QACjC,IACE,UAAU,CAAC,aAAa,KAAK,SAAS;YACtC,IAAI,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE,IAAI,GAAG,EACnD,CAAC;YACD,MAAM,OAAO,GAAG,MAAM,yBAAyB,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,EAAE;gBAC1E,MAAM,EAAE,UAAU;gBAClB,UAAU,EAAE,qBAAqB;aAClC,CAAC,CAAC;YACH,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { CheckpointPolicy, WorkflowCheckpointConfig, WorkflowSpecStatus, CheckpointPolicyPreset } from '../../types/index.js';
2
+ export declare const POLICY_PRESETS: Record<string, CheckpointPolicyPreset>;
3
+ /**
4
+ * Returns the matching policy if the given transition requires a checkpoint,
5
+ * or null if the transition is free to proceed.
6
+ */
7
+ export declare function requiresCheckpoint(config: WorkflowCheckpointConfig, fromStatus: WorkflowSpecStatus, toStatus: WorkflowSpecStatus): CheckpointPolicy | null;
8
+ export declare function loadCheckpointConfig(projectPath: string): Promise<WorkflowCheckpointConfig>;
9
+ export declare function saveCheckpointConfig(projectPath: string, config: WorkflowCheckpointConfig): Promise<void>;
10
+ //# sourceMappingURL=policy-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-engine.d.ts","sourceRoot":"","sources":["../../../src/engine/checkpoint/policy-engine.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,wBAAwB,EACxB,kBAAkB,EAClB,sBAAsB,EACvB,MAAM,sBAAsB,CAAC;AAO9B,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAsDjE,CAAC;AAMF;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,wBAAwB,EAChC,UAAU,EAAE,kBAAkB,EAC9B,QAAQ,EAAE,kBAAkB,GAC3B,gBAAgB,GAAG,IAAI,CAGzB;AAYD,wBAAsB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAGjG;AAED,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAGf"}
@@ -0,0 +1,87 @@
1
+ // engine/checkpoint/policy-engine.ts — Checkpoint policy evaluation (SPEC-411)
2
+ import { readJson, writeJson, projectDataDir, hashProjectPath } from '../../storage/base-store.js';
3
+ // ---------------------------------------------------------------------------
4
+ // Built-in presets
5
+ // ---------------------------------------------------------------------------
6
+ export const POLICY_PRESETS = {
7
+ strict: {
8
+ name: 'strict',
9
+ description: 'All major transitions require explicit approval',
10
+ policies: [
11
+ {
12
+ transition: 'draft->review',
13
+ requiredRole: 'developer',
14
+ description: 'Self-review before submitting',
15
+ },
16
+ {
17
+ transition: 'review->approved',
18
+ requiredRole: 'tech_lead',
19
+ description: 'Tech lead must approve before work starts',
20
+ },
21
+ {
22
+ transition: 'approved->implementing',
23
+ requiredRole: 'product_owner',
24
+ description: 'PO confirms priority before devs start',
25
+ },
26
+ {
27
+ transition: 'implementing->done',
28
+ requiredRole: 'qa',
29
+ description: 'QA must verify before marking done',
30
+ },
31
+ ],
32
+ },
33
+ balanced: {
34
+ name: 'balanced',
35
+ description: 'Only critical transitions need approval',
36
+ policies: [
37
+ {
38
+ transition: 'review->approved',
39
+ requiredRole: 'tech_lead',
40
+ description: 'Tech lead approves specs',
41
+ },
42
+ {
43
+ transition: 'implementing->done',
44
+ requiredRole: 'qa',
45
+ description: 'QA verifies completion',
46
+ },
47
+ ],
48
+ },
49
+ relaxed: {
50
+ name: 'relaxed',
51
+ description: 'Only final completion needs approval',
52
+ policies: [
53
+ {
54
+ transition: 'implementing->done',
55
+ requiredRole: 'tech_lead',
56
+ description: 'Lead confirms done',
57
+ },
58
+ ],
59
+ },
60
+ };
61
+ // ---------------------------------------------------------------------------
62
+ // Policy evaluation
63
+ // ---------------------------------------------------------------------------
64
+ /**
65
+ * Returns the matching policy if the given transition requires a checkpoint,
66
+ * or null if the transition is free to proceed.
67
+ */
68
+ export function requiresCheckpoint(config, fromStatus, toStatus) {
69
+ const transition = `${fromStatus}->${toStatus}`;
70
+ return config.policies.find((p) => p.transition === transition) ?? null;
71
+ }
72
+ // ---------------------------------------------------------------------------
73
+ // Config persistence
74
+ // ---------------------------------------------------------------------------
75
+ function configFilePath(projectId) {
76
+ return `${projectDataDir(projectId)}/checkpoint-config.json`;
77
+ }
78
+ const EMPTY_CONFIG = { policies: [] };
79
+ export async function loadCheckpointConfig(projectPath) {
80
+ const projectId = hashProjectPath(projectPath);
81
+ return readJson(configFilePath(projectId), EMPTY_CONFIG);
82
+ }
83
+ export async function saveCheckpointConfig(projectPath, config) {
84
+ const projectId = hashProjectPath(projectPath);
85
+ await writeJson(configFilePath(projectId), config);
86
+ }
87
+ //# sourceMappingURL=policy-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-engine.js","sourceRoot":"","sources":["../../../src/engine/checkpoint/policy-engine.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAQ/E,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAEnG,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,MAAM,CAAC,MAAM,cAAc,GAA2C;IACpE,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,iDAAiD;QAC9D,QAAQ,EAAE;YACR;gBACE,UAAU,EAAE,eAAe;gBAC3B,YAAY,EAAE,WAAW;gBACzB,WAAW,EAAE,+BAA+B;aAC7C;YACD;gBACE,UAAU,EAAE,kBAAkB;gBAC9B,YAAY,EAAE,WAAW;gBACzB,WAAW,EAAE,2CAA2C;aACzD;YACD;gBACE,UAAU,EAAE,wBAAwB;gBACpC,YAAY,EAAE,eAAe;gBAC7B,WAAW,EAAE,wCAAwC;aACtD;YACD;gBACE,UAAU,EAAE,oBAAoB;gBAChC,YAAY,EAAE,IAAI;gBAClB,WAAW,EAAE,oCAAoC;aAClD;SACF;KACF;IACD,QAAQ,EAAE;QACR,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,yCAAyC;QACtD,QAAQ,EAAE;YACR;gBACE,UAAU,EAAE,kBAAkB;gBAC9B,YAAY,EAAE,WAAW;gBACzB,WAAW,EAAE,0BAA0B;aACxC;YACD;gBACE,UAAU,EAAE,oBAAoB;gBAChC,YAAY,EAAE,IAAI;gBAClB,WAAW,EAAE,wBAAwB;aACtC;SACF;KACF;IACD,OAAO,EAAE;QACP,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,sCAAsC;QACnD,QAAQ,EAAE;YACR;gBACE,UAAU,EAAE,oBAAoB;gBAChC,YAAY,EAAE,WAAW;gBACzB,WAAW,EAAE,oBAAoB;aAClC;SACF;KACF;CACF,CAAC;AAEF,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAgC,EAChC,UAA8B,EAC9B,QAA4B;IAE5B,MAAM,UAAU,GAAG,GAAG,UAAU,KAAK,QAAQ,EAAW,CAAC;IACzD,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,IAAI,IAAI,CAAC;AAC1E,CAAC;AAED,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E,SAAS,cAAc,CAAC,SAAiB;IACvC,OAAO,GAAG,cAAc,CAAC,SAAS,CAAC,yBAAyB,CAAC;AAC/D,CAAC;AAED,MAAM,YAAY,GAA6B,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAEhE,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,WAAmB;IAC5D,MAAM,SAAS,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAC/C,OAAO,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,YAAY,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,WAAmB,EACnB,MAAgC;IAEhC,MAAM,SAAS,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAC/C,MAAM,SAAS,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC;AACrD,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { ComplianceRemediationResult } from '../../types/health.js';
2
+ type RemediationFramework = 'SOC2' | 'GDPR' | 'HIPAA' | 'ISO27001';
3
+ /**
4
+ * For each compliance gap, creates a stub spec so the team has a tracked
5
+ * work item. When dryRun=true, returns findings without writing any files.
6
+ */
7
+ export declare function autoRemediateCompliance(projectPath: string, projectId: string, framework: RemediationFramework, dryRun?: boolean): Promise<ComplianceRemediationResult>;
8
+ export {};
9
+ //# sourceMappingURL=auto-remediator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-remediator.d.ts","sourceRoot":"","sources":["../../../src/engine/compliance/auto-remediator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,2BAA2B,EAAgB,MAAM,uBAAuB,CAAC;AAUvF,KAAK,oBAAoB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,CAAC;AA4FnE;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,oBAAoB,EAC/B,MAAM,UAAQ,GACb,OAAO,CAAC,2BAA2B,CAAC,CAoDtC"}
@@ -0,0 +1,118 @@
1
+ // engine/compliance/auto-remediator.ts — Auto-remediation for compliance gaps (SPEC-408)
2
+ import { mkdir, writeFile, access } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { specStore } from '../../storage/index.js';
5
+ import { analyzeComplianceGaps } from './gap-analyzer.js';
6
+ const FRAMEWORK_MAP = {
7
+ SOC2: 'soc2-type2',
8
+ GDPR: 'gdpr',
9
+ HIPAA: 'hipaa',
10
+ ISO27001: 'iso27001',
11
+ };
12
+ // ---------------------------------------------------------------------------
13
+ // Spec file writer
14
+ // ---------------------------------------------------------------------------
15
+ async function specDirExists(specDir) {
16
+ try {
17
+ await access(specDir);
18
+ return true;
19
+ }
20
+ catch {
21
+ return false;
22
+ }
23
+ }
24
+ async function writeStubSpec(projectPath, specId, title, framework, criteria, dryRun) {
25
+ if (dryRun) {
26
+ return;
27
+ }
28
+ const specDir = join(projectPath, 'planu', 'specs', specId);
29
+ await mkdir(specDir, { recursive: true });
30
+ const criteriaLines = criteria.map((c) => `- [ ] ${c}`).join('\n');
31
+ const now = new Date().toISOString();
32
+ const specContent = [
33
+ '---',
34
+ `id: ${specId}`,
35
+ `title: "${title}"`,
36
+ `status: draft`,
37
+ `tags: [compliance, ${framework.toLowerCase()}, auto-generated]`,
38
+ `createdAt: ${now}`,
39
+ '---',
40
+ '',
41
+ `# ${title}`,
42
+ '',
43
+ `Auto-generated compliance spec for ${framework} framework.`,
44
+ '',
45
+ '## Acceptance Criteria',
46
+ '',
47
+ criteriaLines,
48
+ '',
49
+ ].join('\n');
50
+ await writeFile(join(specDir, 'spec.md'), specContent, 'utf-8');
51
+ await writeFile(join(specDir, 'progress.md'), `# ${specId} — Progress\n\nstatus: draft\n`, 'utf-8');
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // Manual action builders
55
+ // ---------------------------------------------------------------------------
56
+ function buildManualAction(controlId, controlName, criteria) {
57
+ return {
58
+ control: controlId,
59
+ description: `${controlName} requires manual process implementation`,
60
+ steps: [
61
+ `Review control ${controlId}: ${controlName}`,
62
+ 'Identify existing policies and procedures that address this control',
63
+ 'Document evidence in a spec or decision record',
64
+ ...criteria.map((c) => `Verify: ${c}`),
65
+ ],
66
+ };
67
+ }
68
+ // ---------------------------------------------------------------------------
69
+ // Public API
70
+ // ---------------------------------------------------------------------------
71
+ /**
72
+ * For each compliance gap, creates a stub spec so the team has a tracked
73
+ * work item. When dryRun=true, returns findings without writing any files.
74
+ */
75
+ export async function autoRemediateCompliance(projectPath, projectId, framework, dryRun = false) {
76
+ const catalogFramework = FRAMEWORK_MAP[framework];
77
+ const specs = await specStore.listSpecs(projectId);
78
+ const specInputs = specs.map((s) => ({
79
+ id: s.id,
80
+ title: s.title,
81
+ description: '',
82
+ status: s.status,
83
+ }));
84
+ const gapResult = analyzeComplianceGaps(catalogFramework, specInputs);
85
+ const createdSpecs = [];
86
+ const alreadyCovered = [];
87
+ const manualActionRequired = [];
88
+ const timestamp = Date.now();
89
+ for (const control of gapResult.coverage) {
90
+ if (control.status === 'passing') {
91
+ alreadyCovered.push(control.controlId);
92
+ continue;
93
+ }
94
+ if (control.status === 'missing') {
95
+ const slugControl = control.controlId.toLowerCase().replace(/[^a-z0-9]/g, '-');
96
+ const specId = `SPEC-auto-${slugControl}-${timestamp}`;
97
+ const title = `${framework} ${control.controlId} — ${control.controlName}`;
98
+ const specDir = join(projectPath, 'planu', 'specs', specId);
99
+ if (await specDirExists(specDir)) {
100
+ alreadyCovered.push(control.controlId);
101
+ continue;
102
+ }
103
+ await writeStubSpec(projectPath, specId, title, framework, control.requiredCriteria, dryRun);
104
+ createdSpecs.push(specId);
105
+ }
106
+ else {
107
+ // partial — manual action to complete coverage
108
+ manualActionRequired.push(buildManualAction(control.controlId, control.controlName, control.requiredCriteria));
109
+ }
110
+ }
111
+ return {
112
+ framework,
113
+ createdSpecs,
114
+ alreadyCovered,
115
+ manualActionRequired,
116
+ };
117
+ }
118
+ //# sourceMappingURL=auto-remediator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-remediator.js","sourceRoot":"","sources":["../../../src/engine/compliance/auto-remediator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { ContextProfile, WorkPhase } from '../../types/context-profile.js';
2
+ export declare const PROFILE_CATALOG: Record<WorkPhase, ContextProfile>;
3
+ export declare function getProfile(phase: WorkPhase): ContextProfile;
4
+ export declare function getAllProfiles(): ContextProfile[];
5
+ //# sourceMappingURL=profile-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-catalog.d.ts","sourceRoot":"","sources":["../../../src/engine/context-profile/profile-catalog.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAEhF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,SAAS,EAAE,cAAc,CAyI7D,CAAC;AAEF,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,cAAc,CAE3D;AAED,wBAAgB,cAAc,IAAI,cAAc,EAAE,CAEjD"}