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,97 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
- import yaml from 'js-yaml';
4
- import { FrameworkError } from './framework-types.js';
5
- import { resolveFrameworkRoot } from './framework-paths.js';
6
- export async function loadFramework(input, options) {
7
- const rootDir = resolveFrameworkRoot(input, options);
8
- // 1. Validate Root Directory
9
- if (!fs.existsSync(rootDir) || !fs.statSync(rootDir).isDirectory()) {
10
- throw new FrameworkError('NOT_FOUND', rootDir, `Framework directory not found: ${rootDir}`, 'Expected a valid directory at the resolved path.');
11
- }
12
- // 2. Locate Manifest
13
- let manifestPath = path.join(rootDir, 'framework.yaml');
14
- if (!fs.existsSync(manifestPath)) {
15
- manifestPath = path.join(rootDir, 'framework.yml');
16
- }
17
- if (!fs.existsSync(manifestPath)) {
18
- throw new FrameworkError('MISSING_MANIFEST', rootDir, `No framework.yaml (or .yml) found in ${rootDir}`);
19
- }
20
- // 3. Parse Manifest
21
- let raw;
22
- try {
23
- const content = fs.readFileSync(manifestPath, 'utf-8');
24
- raw = yaml.load(content);
25
- }
26
- catch (e) {
27
- throw new FrameworkError('INVALID_YAML', manifestPath, `Failed to parse framework manifest: ${e.message}`);
28
- }
29
- // 4. Validate Schema
30
- if (!raw || typeof raw !== 'object') {
31
- throw new FrameworkError('INVALID_SCHEMA', manifestPath, 'Manifest must be an object');
32
- }
33
- if (typeof raw.name !== 'string' || !raw.name) {
34
- throw new FrameworkError('INVALID_SCHEMA', manifestPath, 'Missing required field: name');
35
- }
36
- if (typeof raw.version !== 'string' || !raw.version) {
37
- throw new FrameworkError('INVALID_SCHEMA', manifestPath, 'Missing required field: version');
38
- }
39
- if (raw.id && typeof raw.id !== 'string') {
40
- throw new FrameworkError('INVALID_SCHEMA', manifestPath, 'Field "id" must be a string');
41
- }
42
- // Loose ID validation
43
- if (raw.id && !/^[a-z0-9-_/]+$/.test(raw.id)) {
44
- throw new FrameworkError('INVALID_SCHEMA', manifestPath, 'Field "id" contains invalid characters (allowed: [a-z0-9-_/])');
45
- }
46
- if (raw.extends && typeof raw.extends !== 'string' && !Array.isArray(raw.extends)) {
47
- throw new FrameworkError('INVALID_SCHEMA', manifestPath, 'Field "extends" must be a string or array of strings');
48
- }
49
- if (raw.overlays && (!Array.isArray(raw.overlays) || raw.overlays.some((o) => typeof o !== 'string'))) {
50
- throw new FrameworkError('INVALID_SCHEMA', manifestPath, 'Field "overlays" must be an array of strings');
51
- }
52
- const manifest = {
53
- name: raw.name,
54
- version: raw.version,
55
- id: raw.id,
56
- extends: raw.extends,
57
- overlays: raw.overlays,
58
- templatesDir: raw.templatesDir
59
- };
60
- // 5. Discover Files
61
- const files = {
62
- manifest: manifestPath
63
- };
64
- const tryFile = (name) => {
65
- const p = path.join(rootDir, name);
66
- return fs.existsSync(p) ? p : undefined;
67
- };
68
- files.policy = tryFile('policy.yaml');
69
- files.routes = tryFile('routes.yaml');
70
- files.artifacts = tryFile('artifacts.yaml');
71
- files.interview = tryFile('interview.yaml');
72
- files.pack = tryFile('pack.yaml');
73
- // 6. Handle Templates
74
- if (manifest.templatesDir) {
75
- const tplPath = path.resolve(rootDir, manifest.templatesDir);
76
- if (!fs.existsSync(tplPath) || !fs.statSync(tplPath).isDirectory()) {
77
- throw new FrameworkError('MISSING_FILE', tplPath, `Configured templatesDir not found: ${manifest.templatesDir}`);
78
- }
79
- files.templates = tplPath;
80
- }
81
- else {
82
- const defaultTpl = path.join(rootDir, 'templates');
83
- if (fs.existsSync(defaultTpl) && fs.statSync(defaultTpl).isDirectory()) {
84
- files.templates = defaultTpl;
85
- }
86
- }
87
- return {
88
- manifest,
89
- source: {
90
- kind: 'local', // Step 1 assumption
91
- path: rootDir,
92
- id: input
93
- },
94
- files,
95
- rootDir
96
- };
97
- }
@@ -1,48 +0,0 @@
1
- import * as path from 'path';
2
- import * as fs from 'fs';
3
- import { fileURLToPath } from 'url';
4
- const __filename = fileURLToPath(import.meta.url);
5
- const __dirname = path.dirname(__filename);
6
- /**
7
- * Resolves a framework input (name or path) to an absolute directory path.
8
- *
9
- * Heuristics:
10
- * - If input implies a path (starts with ./ or /, is absolute, contains separator),
11
- * it is resolved relative to repoRoot (unless absolute).
12
- * - Otherwise, it is treated as a framework name/ID.
13
- * 1. Check .iris/frameworks/<name> in repo.
14
- * 2. Check bundled frameworks.
15
- */
16
- export function resolveFrameworkRoot(input, options) {
17
- const { repoRoot } = options;
18
- // Strict heuristics to distinguish path from name
19
- const isPath = input.startsWith('.') ||
20
- input.startsWith('/') ||
21
- input.startsWith('\\') || // Windows explicit relative
22
- path.isAbsolute(input);
23
- if (isPath) {
24
- return path.resolve(repoRoot, input);
25
- }
26
- // Check Repo Local
27
- const localPath = path.resolve(repoRoot, '.iris/frameworks', input);
28
- if (fs.existsSync(localPath)) {
29
- return localPath;
30
- }
31
- // Check Bundled
32
- // Bundle structure assumption:
33
- // dist/framework/framework-paths.js -> ... -> src/iris_bundle/frameworks/
34
- // actually, in build: dist/iris_bundle/frameworks/<name>
35
- // In dev (ts-node): src/framework/framework-paths.ts -> ../iris_bundle/frameworks
36
- // Try reliable bundle resolution
37
- const candidates = [
38
- path.resolve(__dirname, '../../dist/iris_bundle/frameworks', input), // from dist/framework/
39
- path.resolve(__dirname, '../iris_bundle/frameworks', input), // from src/framework/
40
- path.resolve(__dirname, '../../src/iris_bundle/frameworks', input) // from src/framework/ (alt)
41
- ];
42
- for (const c of candidates) {
43
- if (fs.existsSync(c))
44
- return c;
45
- }
46
- // Fallback to local path so error message shows expected repo location
47
- return localPath;
48
- }
@@ -1,15 +0,0 @@
1
- /**
2
- * Core types for IRIS Framework abstraction.
3
- */
4
- export class FrameworkError extends Error {
5
- code;
6
- path;
7
- hint;
8
- constructor(code, path, message, hint) {
9
- super(message);
10
- this.code = code;
11
- this.path = path;
12
- this.hint = hint;
13
- this.name = 'FrameworkError';
14
- }
15
- }
@@ -1,78 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- /**
4
- * Normalizes an artifact path by:
5
- * - Removing CRLF (\r) characters
6
- * - Trimming whitespace
7
- * - Converting backslashes to forward slashes
8
- * - Removing trailing slashes (except for root)
9
- */
10
- export function normalizeArtifactPath(rawPath) {
11
- let normalized = rawPath;
12
- // Remove \r characters (CRLF normalization)
13
- normalized = normalized.replace(/\r/g, "");
14
- // Trim whitespace
15
- normalized = normalized.trim();
16
- // Convert backslashes to forward slashes
17
- normalized = normalized.replace(/\\/g, "/");
18
- // Remove trailing slashes (but keep single "/" for root)
19
- if (normalized.length > 1) {
20
- normalized = normalized.replace(/\/+$/, "");
21
- }
22
- return normalized;
23
- }
24
- /**
25
- * Infers whether a path represents a file or directory based on:
26
- * - Trailing slash → directory
27
- * - Has file extension → file
28
- * - No extension → directory
29
- */
30
- export function inferArtifactKind(normalizedPath) {
31
- // If original had trailing slash (before normalization), it's a directory
32
- // But we've already normalized, so check for extension
33
- const basename = path.basename(normalizedPath);
34
- const hasExtension = basename.includes(".") && !basename.startsWith(".");
35
- return hasExtension ? "file" : "directory";
36
- }
37
- /**
38
- * Checks if a raw path contains control characters
39
- */
40
- export function hasControlCharacters(rawPath) {
41
- // Check for common control characters: \r, \n, \t, etc.
42
- return /[\r\n\t\x00-\x1F]/.test(rawPath);
43
- }
44
- /**
45
- * Main artifact validation function.
46
- * Validates an artifact path and returns detailed information.
47
- */
48
- export function checkArtifact(repoRoot, rawPath, expectedType) {
49
- const normalized = normalizeArtifactPath(rawPath);
50
- const absolutePath = path.resolve(repoRoot, normalized);
51
- const hasControlChars = hasControlCharacters(rawPath);
52
- const inferredKind = expectedType || inferArtifactKind(normalized);
53
- let exists = false;
54
- let isDirectory = false;
55
- let isFile = false;
56
- try {
57
- exists = fs.existsSync(absolutePath);
58
- if (exists) {
59
- const stats = fs.statSync(absolutePath);
60
- isDirectory = stats.isDirectory();
61
- isFile = stats.isFile();
62
- }
63
- }
64
- catch (e) {
65
- // If stat fails, treat as non-existent
66
- exists = false;
67
- }
68
- return {
69
- exists,
70
- isDirectory,
71
- isFile,
72
- absolutePath,
73
- normalized,
74
- raw: rawPath,
75
- hasControlChars,
76
- inferredKind
77
- };
78
- }
@@ -1,68 +0,0 @@
1
- import fs from "fs";
2
- import yaml from "js-yaml";
3
- import kleur from "kleur";
4
- // Default Artifacts: Summary + User Stories
5
- export const DEFAULT_ARTIFACTS_CONFIG = {
6
- schemaVersion: 1,
7
- artifacts: [
8
- {
9
- id: "summary",
10
- type: "summary",
11
- mode: "template",
12
- output: {
13
- template: "# Summary\n\n**Goal**: {{goal}}\n\n**User**: {{userType}}\n**Phase**: {{projectPhase}}\n\n**Success Criteria**:\n{{successCriteria}}\n"
14
- }
15
- },
16
- {
17
- id: "user-stories",
18
- type: "stories",
19
- mode: "template",
20
- required: false, // Don't fail if fields missing, just skip or partial?
21
- // Wait, default should be robust.
22
- // If fields missing, template will fail.
23
- // Let's require standard fields.
24
- input: { from: ["goal", "userType"] },
25
- output: {
26
- template: "As a {{userType}}, I want to {{goal}}, so that [Value Placeholders]"
27
- }
28
- }
29
- ]
30
- };
31
- export function loadEffectiveArtifactsConfig(framework) {
32
- if (!framework || !framework.files.artifacts || !fs.existsSync(framework.files.artifacts)) {
33
- return DEFAULT_ARTIFACTS_CONFIG;
34
- }
35
- try {
36
- const content = fs.readFileSync(framework.files.artifacts, "utf8");
37
- const raw = yaml.load(content);
38
- if (raw.schemaVersion !== 1) {
39
- console.error(kleur.yellow(`IRIS_WARNING: Unsupported artifacts schema version ${raw.schemaVersion}. Using default.`));
40
- return DEFAULT_ARTIFACTS_CONFIG;
41
- }
42
- if (!Array.isArray(raw.artifacts)) {
43
- console.error(kleur.yellow(`IRIS_WARNING: Invalid artifacts.yaml (missing 'artifacts' array). Using default.`));
44
- return DEFAULT_ARTIFACTS_CONFIG;
45
- }
46
- // Validate fields against KNOWN_INTENT_FIELDS
47
- for (const art of raw.artifacts) {
48
- if (art.input?.from) {
49
- for (const field of art.input.from) {
50
- // Check against KNOWN fields (or allow unknown if we trust framework author? Plan said "Config Error")
51
- // Actually, plan says "Check missing input fields in draft".
52
- // But here we validate the CONFIG itself referencing known variables.
53
- // KNOWN_INTENT_FIELDS includes common ones.
54
- // Let's be lenient on config validation for now to support custom aliases,
55
- // but strict on generation (if draft misses it).
56
- }
57
- }
58
- }
59
- return {
60
- schemaVersion: raw.schemaVersion,
61
- artifacts: raw.artifacts
62
- };
63
- }
64
- catch (e) {
65
- console.error(kleur.yellow(`IRIS_WARNING: Failed to parse artifacts.yaml: ${e.message}. Using default.`));
66
- return DEFAULT_ARTIFACTS_CONFIG;
67
- }
68
- }
@@ -1,88 +0,0 @@
1
- import { getByPath, isMissing } from "../interview/utils.js";
2
- import { interpolateTokens } from "../utils/interpolate.js";
3
- // Error Codes
4
- export const ERRORS = {
5
- MODE_NOT_SUPPORTED: "ARTIFACT_MODE_NOT_SUPPORTED",
6
- INPUT_MISSING: "ARTIFACT_INPUT_MISSING",
7
- TEMPLATE_VAR_MISSING: "ARTIFACT_TEMPLATE_MISSING_VAR",
8
- UNSUPPORTED_ARRAY: "ARTIFACT_TEMPLATE_UNSUPPORTED_ARRAY_TYPE"
9
- };
10
- /**
11
- * Renders a simple template with {{var}} substitution.
12
- * Supports dot-paths.
13
- */
14
- function renderTemplate(template, context, artifactId) {
15
- // Strict regex: only alphanumeric, underscore, dot.
16
- // Trims whitespace inside braces.
17
- return template.replace(/\{\{\s*([a-zA-Z0-9_.]+)\s*\}\}/g, (match, path) => {
18
- const key = path.trim();
19
- // Safety: Prevent prototype pollution access
20
- if (key.includes('__proto__') || key.includes('constructor') || key.includes('prototype')) {
21
- throw new Error(`${ERRORS.TEMPLATE_VAR_MISSING}: Unsafe variable path '${key}' in artifact '${artifactId}'`);
22
- }
23
- const value = getByPath(context, key);
24
- if (value === undefined || value === null) {
25
- throw new Error(`${ERRORS.TEMPLATE_VAR_MISSING}: Artifact '${artifactId}' requires variable '${key}'`);
26
- }
27
- if (Array.isArray(value)) {
28
- // Check for objects (non-primitives)
29
- if (value.some(v => typeof v === 'object' && v !== null)) {
30
- throw new Error(`${ERRORS.UNSUPPORTED_ARRAY}: Artifact '${artifactId}' variable '${key}' contains objects (unsupported for joining).`);
31
- }
32
- return value.join('\n');
33
- }
34
- return String(value);
35
- });
36
- }
37
- export function generateArtifacts(draft, config, frameworkResolution, intentId = null) {
38
- const artifacts = [];
39
- for (const def of config.artifacts) {
40
- // 1. Mode Check
41
- if (def.mode === 'llm') {
42
- throw new Error(`${ERRORS.MODE_NOT_SUPPORTED}: LLM mode not supported yet (Artifact: ${def.id})`);
43
- }
44
- // 2. Input Validation (Declared requirements)
45
- if (def.input?.from) {
46
- const missing = def.input.from.filter(f => isMissing(getByPath(draft, f)));
47
- if (missing.length > 0) {
48
- throw new Error(`${ERRORS.INPUT_MISSING}: Artifact '${def.id}' requires missing fields: ${missing.join(', ')}`);
49
- }
50
- }
51
- // 3. Transformation (Template)
52
- if (def.output.template) {
53
- const content = renderTemplate(def.output.template, draft, def.id);
54
- // Interpolate 'out' path if specified
55
- let outPath;
56
- if (def.out) {
57
- try {
58
- outPath = interpolateTokens(def.out, { intentId: intentId || undefined });
59
- }
60
- catch (e) {
61
- throw new Error(`${ERRORS.TEMPLATE_VAR_MISSING}: Path interpolation failed for artifact '${def.id}': ${e.message}`);
62
- }
63
- }
64
- artifacts.push({
65
- id: def.id,
66
- type: def.type,
67
- content,
68
- path: outPath
69
- });
70
- }
71
- }
72
- const isFramework = frameworkResolution && frameworkResolution.files.artifacts;
73
- return {
74
- schemaVersion: 1,
75
- framework: {
76
- id: frameworkResolution?.manifest.id || "default",
77
- version: frameworkResolution?.manifest.version || null
78
- },
79
- intentId: intentId,
80
- artifacts,
81
- artifactsSource: {
82
- kind: isFramework ? "framework" : "default",
83
- path: isFramework ? frameworkResolution.files.artifacts : null,
84
- activeFrameworkId: frameworkResolution?.manifest.id || null
85
- },
86
- createdAt: new Date().toISOString()
87
- };
88
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,44 +0,0 @@
1
- import path from "path";
2
- import fs from "fs";
3
- import { fileURLToPath } from "url";
4
- const __filename = fileURLToPath(import.meta.url);
5
- const __dirname = path.dirname(__filename);
6
- /**
7
- * Resolves the root of the IRIS Bundle (src/iris_bundle or dist/iris_bundle)
8
- * independent of CWD.
9
- */
10
- export function getBundleRoot() {
11
- // 1. Production / Dist layout
12
- // __dirname is usually dist/iris or similar. Bundle in dist/iris_bundle
13
- // Check sibling of 'dist' if we are in dist/iris
14
- // Attempt 1: Sibling 'iris_bundle' in expected location relative to THIS file
15
- // Example: .../dist/iris/bundle.js -> .../dist/iris_bundle
16
- // Or: .../src/iris/bundle.ts -> .../src/iris_bundle
17
- const candidates = [
18
- path.resolve(__dirname, "../iris_bundle"), // Typical sibling in src/ or dist/
19
- path.resolve(__dirname, "../../src/iris_bundle"), // Dev fallback if running from dist but source present
20
- path.resolve(__dirname, "../../iris_bundle") // Another dist layout possibility
21
- ];
22
- for (const candidate of candidates) {
23
- if (fs.existsSync(candidate) && fs.existsSync(path.join(candidate, ".iris"))) {
24
- return candidate;
25
- }
26
- }
27
- // Fallback/Throw?
28
- // In dev environment, if src/iris_bundle exists relative to root?
29
- throw new Error(`Could not resolve IRIS bundle root. Searched: ${candidates.join(", ")}`);
30
- }
31
- export function getBundledFlowsDir() {
32
- return path.join(getBundleRoot(), ".iris/flows");
33
- }
34
- export function getBundledFrameworksDir() {
35
- return path.join(getBundleRoot(), "frameworks");
36
- }
37
- export function listBundledFlows() {
38
- const flowsDir = getBundledFlowsDir();
39
- if (!fs.existsSync(flowsDir))
40
- return [];
41
- return fs.readdirSync(flowsDir, { withFileTypes: true })
42
- .filter(ent => ent.isDirectory())
43
- .map(ent => ent.name);
44
- }
@@ -1,124 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import kleur from "kleur";
4
- import { loadFlowManifest, getFlowDoctrineRoot } from "../flows/manifest.js";
5
- // --- Cache ---
6
- const manifestCache = new Map();
7
- // --- Internal Helpers ---
8
- function getManifestCached(root, flowId) {
9
- const key = `${root}:${flowId}`;
10
- if (manifestCache.has(key)) {
11
- const cached = manifestCache.get(key);
12
- if (!cached)
13
- throw new Error(`Flow '${flowId}' manifest previously failed to load.`);
14
- return cached;
15
- }
16
- try {
17
- const m = loadFlowManifest(root, flowId);
18
- manifestCache.set(key, m);
19
- return m;
20
- }
21
- catch (e) {
22
- manifestCache.set(key, null); // Negative cache? Or just throw.
23
- // If manifest is required (active flow), we should throw.
24
- throw e;
25
- }
26
- }
27
- /**
28
- * Recursively walks a directory and returns map of relative -> absolute paths.
29
- */
30
- function walkDoctrineDir(dir, relativePrefix = "", index) {
31
- if (!fs.existsSync(dir))
32
- return;
33
- const entries = fs.readdirSync(dir, { withFileTypes: true });
34
- for (const entry of entries) {
35
- const relativePath = path.join(relativePrefix, entry.name);
36
- const absolutePath = path.join(dir, entry.name);
37
- if (entry.isDirectory()) {
38
- walkDoctrineDir(absolutePath, relativePath, index);
39
- }
40
- else if (entry.isFile()) {
41
- // Normalize separators to forward slash for consistency in keys
42
- const key = relativePath.split(path.sep).join("/");
43
- index.set(key, absolutePath);
44
- }
45
- }
46
- }
47
- // --- Public API ---
48
- /**
49
- * Collects all doctrine files, overlaying Flow doctrine over Base doctrine.
50
- * Returns a Map<relative, absolute>.
51
- */
52
- export function collectDoctrineIndex(root, activeFlowId) {
53
- const index = new Map();
54
- let overrides = 0;
55
- // 1. Base Doctrine
56
- const baseDoctrine = path.join(root, ".iris/aidlc");
57
- walkDoctrineDir(baseDoctrine, "", index); // Populates index
58
- // 2. Flow Doctrine (Overlay)
59
- if (activeFlowId) {
60
- try {
61
- const manifest = getManifestCached(root, activeFlowId);
62
- const flowDoctrine = getFlowDoctrineRoot(root, activeFlowId, manifest);
63
- if (fs.existsSync(flowDoctrine)) {
64
- // We walk flow doctrine and overwrite base keys
65
- const flowIndex = new Map();
66
- walkDoctrineDir(flowDoctrine, "", flowIndex);
67
- for (const [key, absPath] of flowIndex) {
68
- if (index.has(key))
69
- overrides++;
70
- index.set(key, absPath);
71
- }
72
- // Debug log (if verbose env var, or just console.debug if we had a logger)
73
- // console.debug(`[Doctrine] Active Flow: ${activeFlowId}. Overrides: ${overrides}`);
74
- }
75
- }
76
- catch (e) {
77
- // Strict error if flow is active but manifest fails
78
- console.error(kleur.red(`Failed to load manifest for active flow '${activeFlowId}': ${e.message}`));
79
- throw e;
80
- }
81
- }
82
- return index;
83
- }
84
- /**
85
- * Collect all effective doctrine files as ABSOLUTE paths.
86
- * Useful for tools that need to iterate all doctrine (like Packer).
87
- */
88
- export function collectDoctrineFiles(root, activeFlowId) {
89
- const index = collectDoctrineIndex(root, activeFlowId);
90
- return Array.from(index.values());
91
- }
92
- /**
93
- * Resolve a specific doctrine file by its DOCTRINE-RELATIVE path.
94
- *
95
- * @param root Repo root
96
- * @param doctrineRelPath Relative path within doctrine dir (e.g. "templates/foo.md")
97
- * @param activeFlowId Active flow ID (optional)
98
- * @returns Absolute path to the resolved file, or undefined if not found in either flow or base.
99
- */
100
- export function resolveDoctrinePath(root, doctrineRelPath, activeFlowId) {
101
- // 1. Check Flow Override
102
- if (activeFlowId) {
103
- try {
104
- const manifest = getManifestCached(root, activeFlowId);
105
- // Default doctrine dir is 'doctrine' if not specified
106
- const flowDoctrineDir = manifest.entrypoints?.doctrine_dir || "doctrine";
107
- // Construct absolute path to flow doctrine file
108
- const flowAbsPath = path.join(root, ".iris/flows", activeFlowId, flowDoctrineDir, doctrineRelPath);
109
- if (fs.existsSync(flowAbsPath)) {
110
- return flowAbsPath;
111
- }
112
- }
113
- catch (e) {
114
- // Let it throw to caller.
115
- throw e;
116
- }
117
- }
118
- // 2. Check Base Doctrine (.iris/aidlc)
119
- const baseAbsPath = path.join(root, ".iris/aidlc", doctrineRelPath);
120
- if (fs.existsSync(baseAbsPath)) {
121
- return baseAbsPath;
122
- }
123
- return undefined;
124
- }