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.
- package/README.md +214 -323
- package/bin/cli.js +21 -0
- package/flows/aidlc/README.md +372 -0
- package/flows/aidlc/agents/construction-agent.md +79 -0
- package/flows/aidlc/agents/inception-agent.md +97 -0
- package/flows/aidlc/agents/master-agent.md +61 -0
- package/flows/aidlc/agents/operations-agent.md +89 -0
- package/flows/aidlc/commands/construction-agent.md +63 -0
- package/flows/aidlc/commands/inception-agent.md +55 -0
- package/flows/aidlc/commands/master-agent.md +47 -0
- package/flows/aidlc/commands/operations-agent.md +77 -0
- package/flows/aidlc/context-config.yaml +67 -0
- package/flows/aidlc/memory-bank.yaml +104 -0
- package/flows/aidlc/quick-start.md +322 -0
- package/flows/aidlc/skills/construction/bolt-list.md +163 -0
- package/flows/aidlc/skills/construction/bolt-replan.md +345 -0
- package/flows/aidlc/skills/construction/bolt-start.md +442 -0
- package/flows/aidlc/skills/construction/bolt-status.md +185 -0
- package/flows/aidlc/skills/construction/navigator.md +196 -0
- package/flows/aidlc/skills/inception/bolt-plan.md +372 -0
- package/flows/aidlc/skills/inception/context.md +171 -0
- package/flows/aidlc/skills/inception/intent-create.md +211 -0
- package/flows/aidlc/skills/inception/intent-list.md +124 -0
- package/flows/aidlc/skills/inception/navigator.md +207 -0
- package/flows/aidlc/skills/inception/requirements.md +227 -0
- package/flows/aidlc/skills/inception/review.md +248 -0
- package/flows/aidlc/skills/inception/story-create.md +304 -0
- package/flows/aidlc/skills/inception/units.md +278 -0
- package/flows/aidlc/skills/master/analyze-context.md +239 -0
- package/flows/aidlc/skills/master/answer-question.md +141 -0
- package/flows/aidlc/skills/master/explain-flow.md +158 -0
- package/flows/aidlc/skills/master/project-init.md +281 -0
- package/flows/aidlc/skills/master/route-request.md +126 -0
- package/flows/aidlc/skills/operations/build.md +237 -0
- package/flows/aidlc/skills/operations/deploy.md +259 -0
- package/flows/aidlc/skills/operations/monitor.md +265 -0
- package/flows/aidlc/skills/operations/navigator.md +209 -0
- package/flows/aidlc/skills/operations/verify.md +224 -0
- package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/construction/bolt-types/ddd-construction-bolt.md +3 -3
- package/{dist → flows/aidlc}/templates/construction/bolt-types/spike-bolt.md +2 -2
- package/flows/aidlc/templates/construction/construction-log-template.md +129 -0
- package/flows/aidlc/templates/construction/standards/coding-standards.md +29 -0
- package/flows/aidlc/templates/construction/standards/system-architecture.md +22 -0
- package/flows/aidlc/templates/construction/standards/tech-stack.md +19 -0
- package/flows/aidlc/templates/inception/inception-log-template.md +134 -0
- package/flows/aidlc/templates/inception/project/README.md +55 -0
- package/flows/aidlc/templates/standards/catalog.yaml +345 -0
- package/flows/aidlc/templates/standards/coding-standards.guide.md +553 -0
- package/flows/aidlc/templates/standards/data-stack.guide.md +162 -0
- package/flows/aidlc/templates/standards/tech-stack.guide.md +280 -0
- package/lib/InstallerFactory.js +36 -0
- package/lib/analytics/env-detector.js +92 -0
- package/lib/analytics/index.js +22 -0
- package/lib/analytics/machine-id.js +33 -0
- package/lib/analytics/tracker.js +232 -0
- package/lib/cli-utils.js +342 -0
- package/lib/constants.js +32 -0
- package/lib/installer.js +402 -0
- package/lib/installers/AntigravityInstaller.js +22 -0
- package/lib/installers/ClaudeInstaller.js +85 -0
- package/lib/installers/ClineInstaller.js +21 -0
- package/lib/installers/CodexInstaller.js +21 -0
- package/lib/installers/CopilotInstaller.js +113 -0
- package/lib/installers/CursorInstaller.js +63 -0
- package/lib/installers/GeminiInstaller.js +75 -0
- package/lib/installers/KiroInstaller.js +22 -0
- package/lib/installers/OpenCodeInstaller.js +22 -0
- package/lib/installers/RooInstaller.js +22 -0
- package/lib/installers/ToolInstaller.js +73 -0
- package/lib/installers/WindsurfInstaller.js +22 -0
- package/lib/markdown-validator.ts +175 -0
- package/lib/yaml-validator.ts +99 -0
- package/package.json +105 -32
- package/scripts/artifact-validator.js +594 -0
- package/scripts/bolt-complete.js +606 -0
- package/scripts/status-integrity.js +598 -0
- package/dist/bridge/agent-runner.js +0 -190
- package/dist/bridge/connector-factory.js +0 -31
- package/dist/bridge/connectors/antigravity-connector.js +0 -18
- package/dist/bridge/connectors/cursor-connector.js +0 -31
- package/dist/bridge/connectors/in-process-connector.js +0 -29
- package/dist/bridge/connectors/vscode-connector.js +0 -31
- package/dist/bridge/connectors/windsurf-connector.js +0 -23
- package/dist/bridge/filesystem-connector.js +0 -110
- package/dist/bridge/helper.js +0 -203
- package/dist/bridge/types.js +0 -10
- package/dist/cli.js +0 -40
- package/dist/commands/ask.js +0 -259
- package/dist/commands/bridge.js +0 -88
- package/dist/commands/create.js +0 -25
- package/dist/commands/develop.js +0 -141
- package/dist/commands/doctor.js +0 -102
- package/dist/commands/flow.js +0 -301
- package/dist/commands/framework.js +0 -273
- package/dist/commands/generate.js +0 -59
- package/dist/commands/install.js +0 -100
- package/dist/commands/pack.js +0 -33
- package/dist/commands/phase.js +0 -38
- package/dist/commands/run.js +0 -199
- package/dist/commands/status.js +0 -114
- package/dist/commands/uninstall.js +0 -14
- package/dist/commands/use.js +0 -20
- package/dist/commands/validate.js +0 -102
- package/dist/framework/framework-loader.js +0 -97
- package/dist/framework/framework-paths.js +0 -48
- package/dist/framework/framework-types.js +0 -15
- package/dist/iris/artifact-checker.js +0 -78
- package/dist/iris/artifacts/config.js +0 -68
- package/dist/iris/artifacts/generator.js +0 -88
- package/dist/iris/artifacts/types.js +0 -1
- package/dist/iris/bundle.js +0 -44
- package/dist/iris/doctrine/collector.js +0 -124
- package/dist/iris/fixer.js +0 -149
- package/dist/iris/flows/manifest.js +0 -124
- package/dist/iris/framework-context.js +0 -49
- package/dist/iris/framework-manager.js +0 -215
- package/dist/iris/fs/atomic.js +0 -22
- package/dist/iris/guard.js +0 -38
- package/dist/iris/importers/index.js +0 -9
- package/dist/iris/importers/types.js +0 -8
- package/dist/iris/importers/writer.js +0 -139
- package/dist/iris/include.js +0 -49
- package/dist/iris/installer.js +0 -334
- package/dist/iris/interactive/env.js +0 -21
- package/dist/iris/interactive/intent-interview.js +0 -345
- package/dist/iris/interactive/intent-schema.js +0 -28
- package/dist/iris/interactive/interview-io.js +0 -22
- package/dist/iris/interview/config.js +0 -71
- package/dist/iris/interview/types.js +0 -16
- package/dist/iris/interview/utils.js +0 -38
- package/dist/iris/manifest.js +0 -54
- package/dist/iris/packer.js +0 -325
- package/dist/iris/parsers/unit-parser.js +0 -43
- package/dist/iris/paths.js +0 -18
- package/dist/iris/policy.js +0 -133
- package/dist/iris/proc.js +0 -56
- package/dist/iris/report.js +0 -53
- package/dist/iris/resolver.js +0 -66
- package/dist/iris/router.js +0 -114
- package/dist/iris/routes.js +0 -189
- package/dist/iris/run-state.js +0 -146
- package/dist/iris/state.js +0 -113
- package/dist/iris/templates.js +0 -70
- package/dist/iris/tmp.js +0 -24
- package/dist/iris/uninstaller.js +0 -181
- package/dist/iris/utils/interpolate.js +0 -42
- package/dist/iris/validator.js +0 -391
- package/dist/iris/workflow/config.js +0 -51
- package/dist/iris/workflow/engine.js +0 -129
- package/dist/iris/workflow/steps.js +0 -448
- package/dist/iris/workflow/types.js +0 -1
- package/dist/iris_bundle/frameworks/iris-core/framework.yaml +0 -9
- package/dist/iris_bundle/frameworks/iris-core/memory/memory-bank.yaml +0 -1
- package/dist/iris_bundle/frameworks/iris-core/policy.yaml +0 -7
- package/dist/iris_bundle/frameworks/iris-core/templates/config/memory-bank.yaml +0 -1
- package/dist/iris_bundle/frameworks/iris-core/templates/construction/bolt-types/spike-bolt.md +0 -240
- package/dist/lib.js +0 -96
- package/dist/templates/construction/bolt-template.md +0 -226
- package/dist/templates/construction/bolt-types/ddd-construction-bolt/adr-template.md +0 -49
- package/dist/templates/construction/bolt-types/ddd-construction-bolt/ddd-01-domain-model-template.md +0 -55
- package/dist/templates/construction/bolt-types/ddd-construction-bolt/ddd-02-technical-design-template.md +0 -67
- package/dist/templates/construction/bolt-types/ddd-construction-bolt/ddd-03-test-report-template.md +0 -62
- package/dist/templates/construction/bolt-types/ddd-construction-bolt.md +0 -528
- package/dist/templates/construction/bolt-types/simple-construction-bolt.md +0 -347
- package/dist/templates/inception/requirements-template.md +0 -144
- package/dist/templates/inception/stories-template.md +0 -38
- package/dist/templates/inception/story-template.md +0 -147
- package/dist/templates/inception/system-context-template.md +0 -29
- package/dist/templates/inception/unit-brief-template.md +0 -177
- package/dist/templates/inception/units-template.md +0 -52
- package/dist/utils/exit-codes.js +0 -7
- package/dist/utils/logo.js +0 -17
- package/dist/workflows/bolt-execution.js +0 -238
- package/dist/workflows/bolt-plan.js +0 -221
- package/dist/workflows/intent-inception.js +0 -285
- package/dist/workflows/memory-bank-generator.js +0 -180
- package/dist/workflows/reporting.js +0 -74
- /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/construction/bolt-template.md +0 -0
- /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/construction/bolt-types/ddd-construction-bolt/adr-template.md +0 -0
- /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/construction/bolt-types/ddd-construction-bolt/ddd-01-domain-model-template.md +0 -0
- /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/construction/bolt-types/ddd-construction-bolt/ddd-02-technical-design-template.md +0 -0
- /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/construction/bolt-types/ddd-construction-bolt/ddd-03-test-report-template.md +0 -0
- /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/construction/bolt-types/simple-construction-bolt.md +0 -0
- /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/inception/requirements-template.md +0 -0
- /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/inception/stories-template.md +0 -0
- /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/inception/story-template.md +0 -0
- /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/inception/system-context-template.md +0 -0
- /package/{dist/iris_bundle/frameworks/iris-core → flows/aidlc}/templates/inception/unit-brief-template.md +0 -0
- /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 {};
|
package/dist/iris/bundle.js
DELETED
|
@@ -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
|
-
}
|