project-iris 0.0.12 → 0.0.14

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 (189) hide show
  1. package/README.md +214 -323
  2. package/bin/cli.js +21 -0
  3. package/flows/aidlc/README.md +372 -0
  4. package/flows/aidlc/agents/construction-agent.md +79 -0
  5. package/flows/aidlc/agents/inception-agent.md +97 -0
  6. package/flows/aidlc/agents/master-agent.md +61 -0
  7. package/flows/aidlc/agents/operations-agent.md +89 -0
  8. package/flows/aidlc/commands/construction-agent.md +63 -0
  9. package/flows/aidlc/commands/inception-agent.md +55 -0
  10. package/flows/aidlc/commands/master-agent.md +47 -0
  11. package/flows/aidlc/commands/operations-agent.md +77 -0
  12. package/flows/aidlc/context-config.yaml +67 -0
  13. package/flows/aidlc/memory-bank.yaml +104 -0
  14. package/flows/aidlc/quick-start.md +322 -0
  15. package/flows/aidlc/skills/construction/bolt-list.md +163 -0
  16. package/flows/aidlc/skills/construction/bolt-replan.md +345 -0
  17. package/flows/aidlc/skills/construction/bolt-start.md +442 -0
  18. package/flows/aidlc/skills/construction/bolt-status.md +185 -0
  19. package/flows/aidlc/skills/construction/navigator.md +196 -0
  20. package/flows/aidlc/skills/inception/bolt-plan.md +372 -0
  21. package/flows/aidlc/skills/inception/context.md +171 -0
  22. package/flows/aidlc/skills/inception/intent-create.md +211 -0
  23. package/flows/aidlc/skills/inception/intent-list.md +124 -0
  24. package/flows/aidlc/skills/inception/navigator.md +207 -0
  25. package/flows/aidlc/skills/inception/requirements.md +227 -0
  26. package/flows/aidlc/skills/inception/review.md +248 -0
  27. package/flows/aidlc/skills/inception/story-create.md +304 -0
  28. package/flows/aidlc/skills/inception/units.md +278 -0
  29. package/flows/aidlc/skills/master/analyze-context.md +239 -0
  30. package/flows/aidlc/skills/master/answer-question.md +141 -0
  31. package/flows/aidlc/skills/master/explain-flow.md +158 -0
  32. package/flows/aidlc/skills/master/project-init.md +281 -0
  33. package/flows/aidlc/skills/master/route-request.md +126 -0
  34. package/flows/aidlc/skills/operations/build.md +237 -0
  35. package/flows/aidlc/skills/operations/deploy.md +259 -0
  36. package/flows/aidlc/skills/operations/monitor.md +265 -0
  37. package/flows/aidlc/skills/operations/navigator.md +209 -0
  38. package/flows/aidlc/skills/operations/verify.md +224 -0
  39. package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/construction/bolt-types/ddd-construction-bolt.md +3 -3
  40. package/{dist → flows/aidlc}/templates/construction/bolt-types/spike-bolt.md +2 -2
  41. package/flows/aidlc/templates/construction/construction-log-template.md +129 -0
  42. package/flows/aidlc/templates/construction/standards/coding-standards.md +29 -0
  43. package/flows/aidlc/templates/construction/standards/system-architecture.md +22 -0
  44. package/flows/aidlc/templates/construction/standards/tech-stack.md +19 -0
  45. package/flows/aidlc/templates/inception/inception-log-template.md +134 -0
  46. package/flows/aidlc/templates/inception/project/README.md +55 -0
  47. package/flows/aidlc/templates/standards/catalog.yaml +345 -0
  48. package/flows/aidlc/templates/standards/coding-standards.guide.md +553 -0
  49. package/flows/aidlc/templates/standards/data-stack.guide.md +162 -0
  50. package/flows/aidlc/templates/standards/tech-stack.guide.md +280 -0
  51. package/lib/InstallerFactory.js +36 -0
  52. package/lib/analytics/env-detector.js +92 -0
  53. package/lib/analytics/index.js +22 -0
  54. package/lib/analytics/machine-id.js +33 -0
  55. package/lib/analytics/tracker.js +232 -0
  56. package/lib/cli-utils.js +342 -0
  57. package/lib/constants.js +32 -0
  58. package/lib/installer.js +402 -0
  59. package/lib/installers/AntigravityInstaller.js +22 -0
  60. package/lib/installers/ClaudeInstaller.js +85 -0
  61. package/lib/installers/ClineInstaller.js +21 -0
  62. package/lib/installers/CodexInstaller.js +21 -0
  63. package/lib/installers/CopilotInstaller.js +113 -0
  64. package/lib/installers/CursorInstaller.js +63 -0
  65. package/lib/installers/GeminiInstaller.js +75 -0
  66. package/lib/installers/KiroInstaller.js +22 -0
  67. package/lib/installers/OpenCodeInstaller.js +22 -0
  68. package/lib/installers/RooInstaller.js +22 -0
  69. package/lib/installers/ToolInstaller.js +73 -0
  70. package/lib/installers/WindsurfInstaller.js +22 -0
  71. package/lib/markdown-validator.ts +175 -0
  72. package/lib/yaml-validator.ts +99 -0
  73. package/package.json +105 -32
  74. package/scripts/artifact-validator.js +594 -0
  75. package/scripts/bolt-complete.js +606 -0
  76. package/scripts/status-integrity.js +598 -0
  77. package/dist/bridge/agent-runner.js +0 -190
  78. package/dist/bridge/connector-factory.js +0 -31
  79. package/dist/bridge/connectors/antigravity-connector.js +0 -18
  80. package/dist/bridge/connectors/cursor-connector.js +0 -31
  81. package/dist/bridge/connectors/in-process-connector.js +0 -29
  82. package/dist/bridge/connectors/vscode-connector.js +0 -31
  83. package/dist/bridge/connectors/windsurf-connector.js +0 -23
  84. package/dist/bridge/filesystem-connector.js +0 -110
  85. package/dist/bridge/helper.js +0 -203
  86. package/dist/bridge/types.js +0 -10
  87. package/dist/cli.js +0 -40
  88. package/dist/commands/ask.js +0 -259
  89. package/dist/commands/bridge.js +0 -88
  90. package/dist/commands/create.js +0 -25
  91. package/dist/commands/develop.js +0 -141
  92. package/dist/commands/doctor.js +0 -102
  93. package/dist/commands/flow.js +0 -301
  94. package/dist/commands/framework.js +0 -273
  95. package/dist/commands/generate.js +0 -59
  96. package/dist/commands/install.js +0 -100
  97. package/dist/commands/pack.js +0 -33
  98. package/dist/commands/phase.js +0 -38
  99. package/dist/commands/run.js +0 -199
  100. package/dist/commands/status.js +0 -114
  101. package/dist/commands/uninstall.js +0 -14
  102. package/dist/commands/use.js +0 -20
  103. package/dist/commands/validate.js +0 -102
  104. package/dist/framework/framework-loader.js +0 -97
  105. package/dist/framework/framework-paths.js +0 -48
  106. package/dist/framework/framework-types.js +0 -15
  107. package/dist/iris/artifact-checker.js +0 -78
  108. package/dist/iris/artifacts/config.js +0 -68
  109. package/dist/iris/artifacts/generator.js +0 -88
  110. package/dist/iris/artifacts/types.js +0 -1
  111. package/dist/iris/bundle.js +0 -44
  112. package/dist/iris/doctrine/collector.js +0 -124
  113. package/dist/iris/fixer.js +0 -149
  114. package/dist/iris/flows/manifest.js +0 -124
  115. package/dist/iris/framework-context.js +0 -49
  116. package/dist/iris/framework-manager.js +0 -215
  117. package/dist/iris/fs/atomic.js +0 -22
  118. package/dist/iris/guard.js +0 -38
  119. package/dist/iris/importers/index.js +0 -9
  120. package/dist/iris/importers/types.js +0 -8
  121. package/dist/iris/importers/writer.js +0 -139
  122. package/dist/iris/include.js +0 -49
  123. package/dist/iris/installer.js +0 -334
  124. package/dist/iris/interactive/env.js +0 -21
  125. package/dist/iris/interactive/intent-interview.js +0 -345
  126. package/dist/iris/interactive/intent-schema.js +0 -28
  127. package/dist/iris/interactive/interview-io.js +0 -22
  128. package/dist/iris/interview/config.js +0 -71
  129. package/dist/iris/interview/types.js +0 -16
  130. package/dist/iris/interview/utils.js +0 -38
  131. package/dist/iris/manifest.js +0 -54
  132. package/dist/iris/packer.js +0 -325
  133. package/dist/iris/parsers/unit-parser.js +0 -43
  134. package/dist/iris/paths.js +0 -18
  135. package/dist/iris/policy.js +0 -133
  136. package/dist/iris/proc.js +0 -56
  137. package/dist/iris/report.js +0 -53
  138. package/dist/iris/resolver.js +0 -66
  139. package/dist/iris/router.js +0 -114
  140. package/dist/iris/routes.js +0 -189
  141. package/dist/iris/run-state.js +0 -146
  142. package/dist/iris/state.js +0 -113
  143. package/dist/iris/templates.js +0 -70
  144. package/dist/iris/tmp.js +0 -24
  145. package/dist/iris/uninstaller.js +0 -181
  146. package/dist/iris/utils/interpolate.js +0 -42
  147. package/dist/iris/validator.js +0 -391
  148. package/dist/iris/workflow/config.js +0 -51
  149. package/dist/iris/workflow/engine.js +0 -129
  150. package/dist/iris/workflow/steps.js +0 -448
  151. package/dist/iris/workflow/types.js +0 -1
  152. package/dist/iris_bundle/frameworks/iris-core/framework.yaml +0 -9
  153. package/dist/iris_bundle/frameworks/iris-core/memory/memory-bank.yaml +0 -1
  154. package/dist/iris_bundle/frameworks/iris-core/policy.yaml +0 -7
  155. package/dist/iris_bundle/frameworks/iris-core/templates/config/memory-bank.yaml +0 -1
  156. package/dist/iris_bundle/frameworks/iris-core/templates/construction/bolt-types/spike-bolt.md +0 -240
  157. package/dist/lib.js +0 -96
  158. package/dist/templates/construction/bolt-template.md +0 -226
  159. package/dist/templates/construction/bolt-types/ddd-construction-bolt/adr-template.md +0 -49
  160. package/dist/templates/construction/bolt-types/ddd-construction-bolt/ddd-01-domain-model-template.md +0 -55
  161. package/dist/templates/construction/bolt-types/ddd-construction-bolt/ddd-02-technical-design-template.md +0 -67
  162. package/dist/templates/construction/bolt-types/ddd-construction-bolt/ddd-03-test-report-template.md +0 -62
  163. package/dist/templates/construction/bolt-types/ddd-construction-bolt.md +0 -528
  164. package/dist/templates/construction/bolt-types/simple-construction-bolt.md +0 -347
  165. package/dist/templates/inception/requirements-template.md +0 -144
  166. package/dist/templates/inception/stories-template.md +0 -38
  167. package/dist/templates/inception/story-template.md +0 -147
  168. package/dist/templates/inception/system-context-template.md +0 -29
  169. package/dist/templates/inception/unit-brief-template.md +0 -177
  170. package/dist/templates/inception/units-template.md +0 -52
  171. package/dist/utils/exit-codes.js +0 -7
  172. package/dist/utils/logo.js +0 -17
  173. package/dist/workflows/bolt-execution.js +0 -238
  174. package/dist/workflows/bolt-plan.js +0 -221
  175. package/dist/workflows/intent-inception.js +0 -285
  176. package/dist/workflows/memory-bank-generator.js +0 -180
  177. package/dist/workflows/reporting.js +0 -74
  178. /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/construction/bolt-template.md +0 -0
  179. /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/construction/bolt-types/ddd-construction-bolt/adr-template.md +0 -0
  180. /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/construction/bolt-types/ddd-construction-bolt/ddd-01-domain-model-template.md +0 -0
  181. /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/construction/bolt-types/ddd-construction-bolt/ddd-02-technical-design-template.md +0 -0
  182. /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/construction/bolt-types/ddd-construction-bolt/ddd-03-test-report-template.md +0 -0
  183. /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/construction/bolt-types/simple-construction-bolt.md +0 -0
  184. /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/inception/requirements-template.md +0 -0
  185. /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/inception/stories-template.md +0 -0
  186. /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/inception/story-template.md +0 -0
  187. /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/inception/system-context-template.md +0 -0
  188. /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/inception/unit-brief-template.md +0 -0
  189. /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/inception/units-template.md +0 -0
@@ -1,66 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { fileURLToPath } from "url";
4
- // Get __dirname equivalent in ESM
5
- const __filename = fileURLToPath(import.meta.url);
6
- const __dirname = path.dirname(__filename);
7
- /**
8
- * Resolves the root directory of the active IRIS configuration (.iris folder).
9
- * Strategy:
10
- * 1. Check <repoRoot>/.iris
11
- * 2. Fallback to bundled <package>/.iris (e.g. ../iris_bundle/.iris)
12
- */
13
- export function resolveIrisRoot(repoRoot) {
14
- const repoIris = path.join(repoRoot, ".iris");
15
- // Check for policy.yaml to confirm this is a valid IRIS configuration authority
16
- if (fs.existsSync(path.join(repoIris, "policy.yaml"))) {
17
- return { path: repoIris, source: "repo" };
18
- }
19
- // Fallback to bundled
20
- // We assume this file is in .../iris/resolver.js|ts
21
- // And bundle is in .../iris_bundle/.iris
22
- let bundledIris = path.resolve(__dirname, "../iris_bundle/.iris");
23
- // Safety check (bundled should always exist, but in dev vs prod checks...)
24
- if (!fs.existsSync(bundledIris)) {
25
- // Try finding it in src if we are in dist (dev environment fallback)
26
- const srcBundle = path.resolve(__dirname, "../../src/iris_bundle/.iris");
27
- if (fs.existsSync(srcBundle)) {
28
- bundledIris = srcBundle;
29
- }
30
- else {
31
- console.warn(`[IRIS] Warning: Bundled IRIS not found at ${bundledIris}`);
32
- }
33
- }
34
- return { path: bundledIris, source: "bundled" };
35
- }
36
- /**
37
- * Resolves a relative path (like ".iris/policy.yaml" or "memory-bank/foo.md")
38
- * to its absolute physical location on disk, respecting the IRIS source authority.
39
- */
40
- export function resolveArtifactPath(repoRoot, relativePath) {
41
- if (path.isAbsolute(relativePath)) {
42
- return relativePath;
43
- }
44
- if (relativePath.startsWith(".iris/") || relativePath === ".iris") {
45
- const root = resolveIrisRoot(repoRoot);
46
- if (relativePath === ".iris")
47
- return root.path;
48
- // internal path inside .iris
49
- const subPath = relativePath.substring(6); // remove ".iris/"
50
- return path.join(root.path, subPath);
51
- }
52
- // Standard repo file
53
- return path.join(repoRoot, relativePath);
54
- }
55
- /**
56
- * Debug helper to show resolution status
57
- */
58
- export function getIrisDebugInfo(repoRoot) {
59
- const root = resolveIrisRoot(repoRoot);
60
- return {
61
- repoRoot,
62
- irisRoot: root.path,
63
- source: root.source,
64
- bundledPath: path.resolve(__dirname, "../iris_bundle/.iris")
65
- };
66
- }
@@ -1,114 +0,0 @@
1
- export function routeIntent(intent, routesConfig) {
2
- const candidates = [];
3
- for (const route of routesConfig.routes) {
4
- // 1. Check exclusions
5
- if (checkExclusion(intent, route.exclude)) {
6
- continue;
7
- }
8
- // 2. Score Match
9
- const { score, matches } = scoreRoute(intent, route);
10
- // Qualification:
11
- if (score > 0) {
12
- candidates.push({ route, score, matches });
13
- }
14
- }
15
- // Sort: 1. Score desc, 2. Longest match count desc, 3. Route order (stable sort)
16
- candidates.sort((a, b) => {
17
- if (b.score !== a.score)
18
- return b.score - a.score;
19
- if (b.matches.length !== a.matches.length)
20
- return b.matches.length - a.matches.length;
21
- return 0;
22
- });
23
- if (candidates.length > 0) {
24
- return {
25
- route: candidates[0].route,
26
- score: candidates[0].score,
27
- matches: candidates[0].matches
28
- };
29
- }
30
- // Default
31
- return {
32
- route: "default",
33
- score: 0,
34
- matches: []
35
- };
36
- }
37
- function checkExclusion(intent, exclude) {
38
- if (!exclude)
39
- return false;
40
- const lower = intent.toLowerCase();
41
- // Any / Any Keywords
42
- const anyList = [...(exclude.any || []), ...(exclude.any_keywords || [])];
43
- if (anyList.length > 0) {
44
- for (const kw of anyList) {
45
- if (lower.includes(kw.toLowerCase()))
46
- return true;
47
- }
48
- }
49
- // Regex
50
- if (exclude.regex) {
51
- for (const pattern of exclude.regex) {
52
- try {
53
- if (new RegExp(pattern, "i").test(intent))
54
- return true;
55
- }
56
- catch (e) {
57
- console.warn(`Invalid exclude regex: ${pattern}`);
58
- }
59
- }
60
- }
61
- return false;
62
- }
63
- function scoreRoute(intent, route) {
64
- let score = 0;
65
- const matches = [];
66
- const lower = intent.toLowerCase();
67
- const rules = route.match;
68
- // 1. Check ALL
69
- const allList = [...(rules.all || []), ...(rules.all_keywords || [])];
70
- if (allList.length > 0) {
71
- for (const kw of allList) {
72
- if (lower.includes(kw.toLowerCase())) {
73
- score += 1;
74
- matches.push(`all:${kw}`);
75
- }
76
- else {
77
- return { score: 0, matches: [] }; // Failed ALL condition
78
- }
79
- }
80
- }
81
- // 2. Check ANY + Phrases
82
- const anyList = [
83
- ...(rules.any || []),
84
- ...(rules.any_keywords || []),
85
- ...(rules.phrases || [])
86
- ];
87
- if (anyList.length > 0) {
88
- for (const kw of anyList) {
89
- if (lower.includes(kw.toLowerCase())) {
90
- score += 1;
91
- matches.push(`any:${kw}`);
92
- }
93
- }
94
- }
95
- // 3. Check Regex
96
- if (rules.regex) {
97
- for (const pattern of rules.regex) {
98
- try {
99
- if (new RegExp(pattern, "i").test(intent)) {
100
- score += 2;
101
- matches.push(`regex:${pattern}`);
102
- }
103
- }
104
- catch (e) {
105
- console.warn(`Invalid match regex in route ${route.route_id}: ${pattern}`);
106
- }
107
- }
108
- }
109
- // Boost
110
- if (score > 0 && route.boost) {
111
- score += route.boost;
112
- }
113
- return { score, matches };
114
- }
@@ -1,189 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import yaml from "js-yaml";
4
- import { repoRoot } from "../lib.js";
5
- import { resolveArtifactPath } from "./resolver.js";
6
- import kleur from "kleur";
7
- // --- Errors ---
8
- export class RoutesError extends Error {
9
- constructor(message) {
10
- super(message);
11
- this.name = "RoutesError";
12
- }
13
- }
14
- export class RoutesLoadError extends RoutesError {
15
- cause;
16
- constructor(message, cause) {
17
- super(message);
18
- this.cause = cause;
19
- this.name = "RoutesLoadError";
20
- }
21
- }
22
- export class RoutesOverlayMissingError extends RoutesError {
23
- constructor(message) {
24
- super(message);
25
- this.name = "RoutesOverlayMissingError";
26
- }
27
- }
28
- // --- Loaders ---
29
- export function loadBaseRoutes(framework, root) {
30
- try {
31
- const r = root || repoRoot();
32
- // 1. Framework Priority
33
- if (framework && framework.files.routes && fs.existsSync(framework.files.routes)) {
34
- const content = fs.readFileSync(framework.files.routes, "utf8");
35
- const doc = yaml.load(content);
36
- validateRoutes(doc, "framework-base");
37
- validateRoutes(doc, "framework-base");
38
- doc.routes.forEach(r => r._source = "base");
39
- Object.defineProperty(doc, '_meta', {
40
- value: { sourceKind: "framework", sourcePath: framework.files.routes },
41
- enumerable: false,
42
- writable: true
43
- });
44
- return doc;
45
- }
46
- // 2. Legacy Fallback
47
- const legacyPath = resolveArtifactPath(r, ".iris/routes.yaml");
48
- if (fs.existsSync(legacyPath)) {
49
- if (framework) {
50
- console.error(kleur.yellow(`IRIS_WARNING IRIS_DEPRECATED_LEGACY_ROUTES: framework=${framework.manifest.id} missing routes.yaml; using .iris/routes.yaml`));
51
- }
52
- const content = fs.readFileSync(legacyPath, "utf8");
53
- const doc = yaml.load(content);
54
- validateRoutes(doc, "legacy-base");
55
- doc.routes.forEach(r => r._source = "base");
56
- Object.defineProperty(doc, '_meta', {
57
- value: { sourceKind: "legacy", sourcePath: legacyPath },
58
- enumerable: false,
59
- writable: true
60
- });
61
- return doc;
62
- }
63
- throw new RoutesLoadError(`Missing required routes.yaml (Checked framework '${framework?.manifest.id || 'none'}' and legacy .iris/routes.yaml)`);
64
- }
65
- catch (error) {
66
- if (error instanceof RoutesError)
67
- throw error;
68
- throw new RoutesLoadError("Failed to load base routes", error);
69
- }
70
- }
71
- export const loadRoutes = (root) => loadBaseRoutes(null, root);
72
- /**
73
- * Loads Effective Routes: Base + User Repo Overlay.
74
- */
75
- export function loadEffectiveRoutes(framework, root, activeFlowId) {
76
- // 1. Load Base (Framework or Legacy)
77
- // Note: base is required. loadBaseRoutes throws if missing.
78
- const r = root || repoRoot();
79
- const base = loadBaseRoutes(framework, r);
80
- // Determine Overlay Namespace: Flow ID (if active) OR Framework ID (if loaded)
81
- const overlayNamespace = activeFlowId || framework?.manifest.id;
82
- if (!overlayNamespace)
83
- return base;
84
- try {
85
- // User Repo Overlay: .iris/overlays/<namespace>/routes.yaml
86
- // This allows the user to override routing via flow OR framework namespace.
87
- const overlayPath = path.join(r, ".iris/overlays", overlayNamespace, "routes.yaml");
88
- if (fs.existsSync(overlayPath)) {
89
- const content = fs.readFileSync(overlayPath, "utf8");
90
- const overlay = (yaml.load(content) || {});
91
- const merged = mergeRoutes(base, overlay);
92
- Object.defineProperty(merged, '_meta', {
93
- value: {
94
- sourceKind: "mixed",
95
- sourcePath: overlayPath
96
- },
97
- enumerable: false,
98
- writable: true
99
- });
100
- return merged;
101
- }
102
- // Return base if no overlay found (Optional)
103
- // Ensure we throw if explicit namespace was requested but not found?
104
- // The test expects RoutesOverlayMissingError if "missing" flow is passed.
105
- // Assuming if overlayNamespace is provided, we EXPECT an overlay.
106
- if (overlayNamespace) {
107
- // Only throw if this was an EXPLICIT flow request (activeFlowId is set)
108
- // If it fell back to framework ID, treat overlay as optional.
109
- if (activeFlowId) {
110
- throw new RoutesOverlayMissingError(`Routes overlay not found for namespace '${overlayNamespace}' at ${overlayPath}`);
111
- }
112
- // else: explicit overlay not found for base framework -> return base (safe)
113
- }
114
- return base;
115
- }
116
- catch (error) {
117
- if (error instanceof RoutesError)
118
- throw error;
119
- throw new RoutesLoadError(`Failed to load effective routes for namespace '${overlayNamespace}'`, error);
120
- }
121
- }
122
- /**
123
- * Merges routes purely.
124
- */
125
- export function mergeRoutes(base, overlay) {
126
- // Deep clone base
127
- const result = JSON.parse(JSON.stringify(base));
128
- // 1. Merge Default
129
- if (overlay.default) {
130
- result.default = { ...result.default, ...overlay.default };
131
- }
132
- if (!overlay.routes || !Array.isArray(overlay.routes)) {
133
- return result;
134
- }
135
- // Validate Overlay Routes first
136
- overlay.routes.forEach(r => validateRoute(r, "overlay"));
137
- // 2. Merge Routes
138
- const baseMap = new Map();
139
- result.routes.forEach((r, idx) => baseMap.set(r.route_id, idx));
140
- const newRoutes = [];
141
- for (const oRoute of overlay.routes) {
142
- if (baseMap.has(oRoute.route_id)) {
143
- // Override
144
- const idx = baseMap.get(oRoute.route_id);
145
- result.routes[idx] = {
146
- ...result.routes[idx],
147
- ...oRoute,
148
- _source: "merged"
149
- };
150
- }
151
- else {
152
- // New
153
- newRoutes.push({
154
- ...oRoute,
155
- _source: "overlay"
156
- });
157
- }
158
- }
159
- // Prepend new routes
160
- if (newRoutes.length > 0) {
161
- result.routes.unshift(...newRoutes);
162
- }
163
- // Validate Final Result (Uniqueness check)
164
- validateRoutes(result, "effective");
165
- return result;
166
- }
167
- // --- Validation Helpers ---
168
- function validateRoutes(routes, context) {
169
- if (!routes || !routes.routes) {
170
- throw new RoutesLoadError(`Invalid routes format (${context}): 'routes' array missing.`);
171
- }
172
- const seenIds = new Set();
173
- routes.routes.forEach(r => {
174
- validateRoute(r, context);
175
- if (seenIds.has(r.route_id)) {
176
- throw new RoutesLoadError(`Duplicate route_id found (${context}): '${r.route_id}'`);
177
- }
178
- seenIds.add(r.route_id);
179
- });
180
- }
181
- function validateRoute(r, context) {
182
- if (!r.route_id || typeof r.route_id !== "string" || !r.route_id.trim()) {
183
- throw new RoutesLoadError(`Invalid route in ${context}: route_id must be a non-empty string.`);
184
- }
185
- // Normalize Phase
186
- if (r.phase) {
187
- r.phase = r.phase.toLowerCase();
188
- }
189
- }
@@ -1,146 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { randomUUID } from "crypto";
4
- import { WorkflowStage } from "../bridge/types.js";
5
- const RUNS_DIR = path.join(process.cwd(), ".iris/runs");
6
- import { generateIntentId } from "./utils/interpolate.js";
7
- /**
8
- * Create a new workflow run
9
- */
10
- export function createRun(intent, ideId, gateMode = "manual") {
11
- const runId = randomUUID();
12
- const now = new Date().toISOString();
13
- const intentId = generateIntentId({ goal: intent }); // Fallback to intent processing if draft is missing
14
- const runState = {
15
- runId,
16
- intent,
17
- intentId,
18
- ideId,
19
- stage: WorkflowStage.INTENT_INCEPTION,
20
- gateMode,
21
- artifacts: [],
22
- bolts: [],
23
- currentBoltIndex: 0,
24
- pendingTasks: [],
25
- events: [],
26
- createdAt: now,
27
- updatedAt: now
28
- };
29
- saveRun(runState);
30
- return runState;
31
- }
32
- /**
33
- * Load a run by ID
34
- */
35
- export function loadRun(runId) {
36
- const runPath = path.join(RUNS_DIR, `${runId}.json`);
37
- if (!fs.existsSync(runPath)) {
38
- throw new Error(`Run not found: ${runId}`);
39
- }
40
- const content = fs.readFileSync(runPath, "utf8");
41
- return JSON.parse(content);
42
- }
43
- /**
44
- * Save run state
45
- */
46
- export function saveRun(state) {
47
- if (!fs.existsSync(RUNS_DIR)) {
48
- fs.mkdirSync(RUNS_DIR, { recursive: true });
49
- }
50
- state.updatedAt = new Date().toISOString();
51
- const runPath = path.join(RUNS_DIR, `${state.runId}.json`);
52
- fs.writeFileSync(runPath, JSON.stringify(state, null, 2), "utf8");
53
- // Also save a small state snapshot for quick resume
54
- const statePath = path.join(RUNS_DIR, `${state.runId}.state.json`);
55
- const snapshot = {
56
- runId: state.runId,
57
- stage: state.stage,
58
- currentBoltIndex: state.currentBoltIndex,
59
- updatedAt: state.updatedAt
60
- };
61
- fs.writeFileSync(statePath, JSON.stringify(snapshot, null, 2), "utf8");
62
- }
63
- /**
64
- * Append an event to the run
65
- */
66
- export function appendEvent(runId, event) {
67
- const state = loadRun(runId);
68
- const fullEvent = {
69
- ...event,
70
- timestamp: new Date().toISOString()
71
- };
72
- state.events.push(fullEvent);
73
- saveRun(state);
74
- }
75
- /**
76
- * Generate a human-readable summary of the run
77
- */
78
- export function generateRunSummary(runId) {
79
- const state = loadRun(runId);
80
- let summary = `# IRIS Workflow Run: ${runId}\n\n`;
81
- summary += `**Intent:** ${state.intent}\n`;
82
- summary += `**IDE:** ${state.ideId}\n`;
83
- summary += `**Stage:** ${state.stage}\n`;
84
- summary += `**Created:** ${state.createdAt}\n`;
85
- summary += `**Updated:** ${state.updatedAt}\n\n`;
86
- summary += `## Artifacts Created\n\n`;
87
- if (state.artifacts.length > 0) {
88
- summary += state.artifacts.map(a => `- \`${a}\``).join("\n") + "\n\n";
89
- }
90
- else {
91
- summary += "*No artifacts yet*\n\n";
92
- }
93
- summary += `## Bolts\n\n`;
94
- if (state.bolts.length > 0) {
95
- state.bolts.forEach(bolt => {
96
- summary += `### ${bolt.id} (${bolt.status})\n`;
97
- if (bolt.designCompleted)
98
- summary += "- ✓ Design\n";
99
- if (bolt.implementationCompleted)
100
- summary += "- ✓ Implementation\n";
101
- if (bolt.testingCompleted)
102
- summary += "- ✓ Testing\n";
103
- summary += "\n";
104
- });
105
- }
106
- else {
107
- summary += "*No bolts yet*\n\n";
108
- }
109
- summary += `## Event Log\n\n`;
110
- state.events.forEach(event => {
111
- summary += `**${event.timestamp}** [${event.stage}] ${event.action}\n`;
112
- if (event.message)
113
- summary += ` ${event.message}\n`;
114
- if (event.userGateDecision)
115
- summary += ` Gate: ${event.userGateDecision}\n`;
116
- summary += "\n";
117
- });
118
- return summary;
119
- }
120
- /**
121
- * Save run summary to markdown file
122
- */
123
- export function saveRunSummary(runId) {
124
- const summary = generateRunSummary(runId);
125
- const summaryPath = path.join(RUNS_DIR, `${runId}.md`);
126
- fs.writeFileSync(summaryPath, summary, "utf8");
127
- }
128
- /**
129
- * List all runs
130
- */
131
- export function listRuns() {
132
- if (!fs.existsSync(RUNS_DIR)) {
133
- return [];
134
- }
135
- const files = fs.readdirSync(RUNS_DIR);
136
- const stateFiles = files.filter(f => f.endsWith(".state.json"));
137
- return stateFiles.map(file => {
138
- const content = fs.readFileSync(path.join(RUNS_DIR, file), "utf8");
139
- const snapshot = JSON.parse(content);
140
- return {
141
- runId: snapshot.runId,
142
- stage: snapshot.stage,
143
- updatedAt: snapshot.updatedAt
144
- };
145
- }).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
146
- }
@@ -1,113 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import yaml from "js-yaml";
4
- import { EXIT_CODES } from "../utils/exit-codes.js";
5
- const STATE_FILE_PATH = path.join(process.cwd(), ".iris/state.yaml");
6
- export const DEFAULT_STATE = {
7
- version: 1,
8
- framework: {
9
- current: "iris-core",
10
- version: null,
11
- },
12
- phase: {
13
- current: "inception",
14
- requested: null,
15
- },
16
- active: {
17
- intent_id: null,
18
- unit_id: null,
19
- bolt_id: null,
20
- flow: null,
21
- },
22
- last_validation: {
23
- at: null,
24
- result: null,
25
- },
26
- };
27
- export function loadState() {
28
- try {
29
- if (!fs.existsSync(STATE_FILE_PATH)) {
30
- // Auto-create directory if it doesn't exist
31
- const dir = path.dirname(STATE_FILE_PATH);
32
- if (!fs.existsSync(dir)) {
33
- fs.mkdirSync(dir, { recursive: true });
34
- }
35
- saveState(DEFAULT_STATE);
36
- return DEFAULT_STATE;
37
- }
38
- const content = fs.readFileSync(STATE_FILE_PATH, "utf8");
39
- const doc = yaml.load(content);
40
- // Start with defaults to ensure all fields exist (deep merge strategy)
41
- // We manually merge top-level objects to avoid losing nested defaults
42
- const merged = {
43
- ...DEFAULT_STATE,
44
- ...doc,
45
- framework: { ...DEFAULT_STATE.framework, ...doc.framework },
46
- phase: { ...DEFAULT_STATE.phase, ...doc.phase },
47
- active: { ...DEFAULT_STATE.active, ...doc.active },
48
- last_validation: { ...DEFAULT_STATE.last_validation, ...doc.last_validation },
49
- // Optional fields
50
- ide: doc.ide ? { ...doc.ide } : undefined,
51
- bridge: doc.bridge ? { ...doc.bridge } : undefined,
52
- };
53
- // Migration/Fixup for legacy/bundled schema
54
- if (doc.current_phase && !doc.phase) {
55
- merged.phase = {
56
- current: doc.current_phase.toLowerCase(), // Normalize to lowercase
57
- requested: null
58
- };
59
- }
60
- // Ensure flow exists (backward compatibility)
61
- if (merged.active.flow === undefined)
62
- merged.active.flow = null;
63
- return merged;
64
- }
65
- catch (error) {
66
- console.error("Failed to load or create .iris/state.yaml:", error);
67
- process.exit(EXIT_CODES.STATE_ERROR);
68
- }
69
- }
70
- export function saveState(state) {
71
- try {
72
- const content = yaml.dump(state);
73
- fs.writeFileSync(STATE_FILE_PATH, content, "utf8");
74
- }
75
- catch (error) {
76
- console.error("Failed to write .iris/state.yaml:", error);
77
- process.exit(EXIT_CODES.STATE_ERROR);
78
- }
79
- }
80
- /**
81
- * Get the selected IDE from state, or null if not set
82
- */
83
- export function getSelectedIde() {
84
- const state = loadState();
85
- return state.ide?.id || null;
86
- }
87
- /**
88
- * Set the selected IDE in state
89
- */
90
- export function setSelectedIde(ideId) {
91
- const state = loadState();
92
- state.ide = {
93
- id: ideId,
94
- selected_at: new Date().toISOString()
95
- };
96
- saveState(state);
97
- }
98
- /**
99
- * Get the active framework info
100
- */
101
- export function getActiveFramework(state = loadState()) {
102
- return state.framework;
103
- }
104
- /**
105
- * Set the active framework
106
- */
107
- export function setActiveFramework(state, id, version = null) {
108
- state.framework = {
109
- current: id,
110
- version: version
111
- };
112
- saveState(state);
113
- }
@@ -1,70 +0,0 @@
1
- export const UNIT_BRIEF_TEMPLATE = `---
2
- id: {{unitId}}
3
- status: draft
4
- ---
5
-
6
- # Unit Brief: {{title}}
7
-
8
- ## Objective
9
- {{summary}}
10
-
11
- ## Scope
12
- ### In Scope
13
- - [ ] Implementation item 1
14
- - [ ] Implementation item 2
15
-
16
- ### Out of Scope
17
- - Non-goals for this unit
18
-
19
- ## Acceptance Criteria
20
- - [ ] Criteria 1
21
- - [ ] Criteria 2
22
-
23
- ## Risks
24
- - Risk 1
25
- `;
26
- export const BOLT_TEMPLATE = `---
27
- id: {{boltId}}
28
- unit: {{unitId}}
29
- status: draft
30
- type: feature
31
- files:
32
- - src/index.ts
33
- cwd: .
34
- commands:
35
- test: npm test
36
- ---
37
-
38
- # Bolt: {{title}}
39
-
40
- ## Implementation Plan
41
- - [ ] Step 1
42
- - [ ] Step 2
43
-
44
- ## Files to Touch
45
- - src/index.ts
46
-
47
- ## Verification Plan
48
- ### Automated Tests
49
- - \`npm test\`
50
-
51
- ### Manual Verification
52
- - Check output
53
- `;
54
- export const TEST_REPORT_TEMPLATE = `---
55
- bolt: {{boltId}}
56
- status: {{status}}
57
- timestamp: {{timestamp}}
58
- ---
59
-
60
- # Test Report: {{title}}
61
-
62
- ## Summary
63
- Status: {{status}}
64
- Time: {{timestamp}}
65
-
66
- ## Output
67
- \`\`\`
68
- {{output}}
69
- \`\`\`
70
- `;