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
package/dist/iris/fixer.js
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import kleur from "kleur";
|
|
4
|
-
import { repoRoot, ensureDir } from "../lib.js";
|
|
5
|
-
import { resolveDoctrinePath } from "./doctrine/collector.js";
|
|
6
|
-
import { loadState } from "./state.js";
|
|
7
|
-
function toDoctrineRelativeTemplatePath(t) {
|
|
8
|
-
const prefix = ".iris/aidlc/";
|
|
9
|
-
if (t.startsWith(prefix))
|
|
10
|
-
return t.substring(prefix.length);
|
|
11
|
-
// If someone already passed doctrine-relative, allow it (but ensure no leading slash if needed, usually robust)
|
|
12
|
-
if (!t.startsWith(".iris/"))
|
|
13
|
-
return t;
|
|
14
|
-
return t; // Unknown path type, return as-is
|
|
15
|
-
}
|
|
16
|
-
export function collectFixPlan(result) {
|
|
17
|
-
const plan = {
|
|
18
|
-
actions: [],
|
|
19
|
-
skipped: []
|
|
20
|
-
};
|
|
21
|
-
const root = repoRoot();
|
|
22
|
-
const state = loadState();
|
|
23
|
-
const activeFlowId = state.active.flow;
|
|
24
|
-
for (const error of result.errors) {
|
|
25
|
-
if (error.code !== "MISSING_ARTIFACT") {
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
if (!error.path)
|
|
29
|
-
continue;
|
|
30
|
-
// Fix: Create Directory
|
|
31
|
-
if (error.artifactType === "dir") {
|
|
32
|
-
// Check if already in plan
|
|
33
|
-
const exists = plan.actions.find(a => a.path === error.path && a.kind === "mkdir");
|
|
34
|
-
if (!exists) {
|
|
35
|
-
plan.actions.push({
|
|
36
|
-
kind: "mkdir",
|
|
37
|
-
path: error.path
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
// Fix: Create File from Template
|
|
43
|
-
if (error.artifactType === "file") {
|
|
44
|
-
if (error.template) {
|
|
45
|
-
// Normalize template path before resolving
|
|
46
|
-
const templateRel = toDoctrineRelativeTemplatePath(error.template);
|
|
47
|
-
// Verify template exists (resolving override)
|
|
48
|
-
const templatePath = resolveDoctrinePath(root, templateRel, activeFlowId);
|
|
49
|
-
if (templatePath && fs.existsSync(templatePath)) {
|
|
50
|
-
plan.actions.push({
|
|
51
|
-
kind: "createFileFromTemplate",
|
|
52
|
-
path: error.path,
|
|
53
|
-
template: templateRel // Store NORMALIZED path
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
plan.skipped.push({
|
|
58
|
-
reason: `Template missing: ${error.template}`,
|
|
59
|
-
path: error.path
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
plan.skipped.push({
|
|
65
|
-
reason: "No template defined",
|
|
66
|
-
path: error.path
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
// Sort actions: mkdir first, then files
|
|
73
|
-
plan.actions.sort((a, b) => {
|
|
74
|
-
if (a.kind === "mkdir" && b.kind !== "mkdir")
|
|
75
|
-
return -1;
|
|
76
|
-
if (a.kind !== "mkdir" && b.kind === "mkdir")
|
|
77
|
-
return 1;
|
|
78
|
-
return a.path.localeCompare(b.path);
|
|
79
|
-
});
|
|
80
|
-
return plan;
|
|
81
|
-
}
|
|
82
|
-
export async function applyFixPlan(plan, options) {
|
|
83
|
-
const result = {
|
|
84
|
-
createdDirs: 0,
|
|
85
|
-
createdFiles: 0,
|
|
86
|
-
paths: []
|
|
87
|
-
};
|
|
88
|
-
const root = repoRoot();
|
|
89
|
-
const state = loadState();
|
|
90
|
-
const activeFlowId = state.active.flow;
|
|
91
|
-
if (options.dryRun) {
|
|
92
|
-
console.log(kleur.bold().blue("Dry Run Fix Plan:"));
|
|
93
|
-
}
|
|
94
|
-
for (const action of plan.actions) {
|
|
95
|
-
const fullPath = path.join(root, action.path);
|
|
96
|
-
if (action.kind === "mkdir") {
|
|
97
|
-
if (options.dryRun) {
|
|
98
|
-
console.log(` [MKDIR] ${action.path}`);
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
try {
|
|
102
|
-
if (!fs.existsSync(fullPath)) {
|
|
103
|
-
ensureDir(fullPath);
|
|
104
|
-
result.createdDirs++;
|
|
105
|
-
result.paths.push(action.path);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
catch (e) {
|
|
109
|
-
console.error(kleur.red(`Failed to create dir ${action.path}: ${e}`));
|
|
110
|
-
}
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
if (action.kind === "createFileFromTemplate" && action.template) {
|
|
114
|
-
// Re-resolve to get absolute path (base or flow)
|
|
115
|
-
// Template should already be normalized in collectFixPlan
|
|
116
|
-
const templatePath = resolveDoctrinePath(root, action.template, activeFlowId);
|
|
117
|
-
if (options.dryRun) {
|
|
118
|
-
console.log(` [COPY] ${action.path} (from ${action.template})`);
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
// Check existence logic (safe overwrite)
|
|
122
|
-
if (fs.existsSync(fullPath)) {
|
|
123
|
-
if (options.yes) {
|
|
124
|
-
console.log(kleur.yellow(`Skipping ${action.path}: File exists.`));
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
if (!templatePath || !fs.existsSync(templatePath)) {
|
|
132
|
-
console.error(kleur.red(`Template not found: ${action.template}`));
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
try {
|
|
136
|
-
// Read template
|
|
137
|
-
const content = fs.readFileSync(templatePath, "utf-8");
|
|
138
|
-
ensureDir(path.dirname(fullPath));
|
|
139
|
-
fs.writeFileSync(fullPath, content);
|
|
140
|
-
result.createdFiles++;
|
|
141
|
-
result.paths.push(action.path);
|
|
142
|
-
}
|
|
143
|
-
catch (e) {
|
|
144
|
-
console.error(kleur.red(`Failed to create file ${action.path}: ${e}`));
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return result;
|
|
149
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import yaml from "js-yaml";
|
|
4
|
-
// --- Errors ---
|
|
5
|
-
export class FlowNotFoundError extends Error {
|
|
6
|
-
flowId;
|
|
7
|
-
path;
|
|
8
|
-
constructor(flowId, path) {
|
|
9
|
-
super(`Flow '${flowId}' not found at ${path}`);
|
|
10
|
-
this.flowId = flowId;
|
|
11
|
-
this.path = path;
|
|
12
|
-
this.name = "FlowNotFoundError";
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
export class FlowManifestValidationError extends Error {
|
|
16
|
-
flowId;
|
|
17
|
-
constructor(flowId, message) {
|
|
18
|
-
super(`Invalid manifest for flow '${flowId}': ${message}`);
|
|
19
|
-
this.flowId = flowId;
|
|
20
|
-
this.name = "FlowManifestValidationError";
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
// --- Constants & Defaults ---
|
|
24
|
-
const DEFAULT_ENTRYPOINTS = {
|
|
25
|
-
doctrine_dir: "doctrine",
|
|
26
|
-
policy_overlay: "policy.overlay.yaml",
|
|
27
|
-
routes_overlay: "routes.overlay.yaml"
|
|
28
|
-
};
|
|
29
|
-
// --- Helpers ---
|
|
30
|
-
export function getFlowsDir(root) {
|
|
31
|
-
return path.join(root, ".iris/flows");
|
|
32
|
-
}
|
|
33
|
-
export function getFlowDir(root, flowId) {
|
|
34
|
-
return path.join(getFlowsDir(root), flowId);
|
|
35
|
-
}
|
|
36
|
-
export function getFlowDoctrineRoot(root, flowId, manifest) {
|
|
37
|
-
return path.join(getFlowDir(root, flowId), manifest.entrypoints.doctrine_dir);
|
|
38
|
-
}
|
|
39
|
-
export function getFlowPolicyOverlayPath(root, flowId, manifest) {
|
|
40
|
-
return path.join(getFlowDir(root, flowId), manifest.entrypoints.policy_overlay);
|
|
41
|
-
}
|
|
42
|
-
export function getFlowRoutesOverlayPath(root, flowId, manifest) {
|
|
43
|
-
return path.join(getFlowDir(root, flowId), manifest.entrypoints.routes_overlay);
|
|
44
|
-
}
|
|
45
|
-
// --- Loader ---
|
|
46
|
-
export function loadFlowManifest(root, flowId) {
|
|
47
|
-
const flowDir = getFlowDir(root, flowId);
|
|
48
|
-
const manifestPath = path.join(flowDir, "flow.yaml");
|
|
49
|
-
if (!fs.existsSync(manifestPath)) {
|
|
50
|
-
throw new FlowNotFoundError(flowId, manifestPath);
|
|
51
|
-
}
|
|
52
|
-
let raw;
|
|
53
|
-
try {
|
|
54
|
-
raw = yaml.load(fs.readFileSync(manifestPath, "utf8"));
|
|
55
|
-
}
|
|
56
|
-
catch (e) {
|
|
57
|
-
throw new FlowManifestValidationError(flowId, `Failed to parse YAML: ${e.message}`);
|
|
58
|
-
}
|
|
59
|
-
if (!raw || typeof raw !== "object") {
|
|
60
|
-
throw new FlowManifestValidationError(flowId, "Manifest is not a valid object");
|
|
61
|
-
}
|
|
62
|
-
// Validation: Required Fields
|
|
63
|
-
if (!raw.id || typeof raw.id !== "string" || !raw.id.trim()) {
|
|
64
|
-
throw new FlowManifestValidationError(flowId, "Missing or empty 'id'");
|
|
65
|
-
}
|
|
66
|
-
if (!raw.name || typeof raw.name !== "string" || !raw.name.trim()) {
|
|
67
|
-
throw new FlowManifestValidationError(flowId, "Missing or empty 'name'");
|
|
68
|
-
}
|
|
69
|
-
if (!raw.version || typeof raw.version !== "string" || !raw.version.trim()) {
|
|
70
|
-
throw new FlowManifestValidationError(flowId, "Missing or empty 'version'");
|
|
71
|
-
}
|
|
72
|
-
// Validation: ID Match
|
|
73
|
-
if (raw.id !== flowId) {
|
|
74
|
-
throw new FlowManifestValidationError(flowId, `Manifest ID '${raw.id}' does not match flow ID '${flowId}'`);
|
|
75
|
-
}
|
|
76
|
-
// Defaults & Entrypoint Validation
|
|
77
|
-
const entrypoints = { ...DEFAULT_ENTRYPOINTS, ...(raw.entrypoints || {}) };
|
|
78
|
-
// Validate Paths
|
|
79
|
-
validateRelativePath(flowId, "doctrine_dir", entrypoints.doctrine_dir);
|
|
80
|
-
validateRelativePath(flowId, "policy_overlay", entrypoints.policy_overlay);
|
|
81
|
-
validateRelativePath(flowId, "routes_overlay", entrypoints.routes_overlay);
|
|
82
|
-
return {
|
|
83
|
-
id: raw.id,
|
|
84
|
-
name: raw.name,
|
|
85
|
-
version: raw.version,
|
|
86
|
-
description: raw.description,
|
|
87
|
-
entrypoints
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
function validateRelativePath(flowId, field, p) {
|
|
91
|
-
if (!p || typeof p !== "string" || !p.trim()) {
|
|
92
|
-
throw new FlowManifestValidationError(flowId, `Entrypoint '${field}' must be a non-empty string`);
|
|
93
|
-
}
|
|
94
|
-
if (path.isAbsolute(p)) {
|
|
95
|
-
throw new FlowManifestValidationError(flowId, `Entrypoint '${field}' must be relative`);
|
|
96
|
-
}
|
|
97
|
-
const normalized = path.normalize(p);
|
|
98
|
-
if (normalized.startsWith("..") || normalized === ".." || normalized.includes(path.sep + "..")) {
|
|
99
|
-
throw new FlowManifestValidationError(flowId, `Entrypoint '${field}' cannot traverse upwards`);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
export function listInstalledFlows(root) {
|
|
103
|
-
const flowsDir = getFlowsDir(root);
|
|
104
|
-
if (!fs.existsSync(flowsDir))
|
|
105
|
-
return [];
|
|
106
|
-
const results = [];
|
|
107
|
-
const entries = fs.readdirSync(flowsDir, { withFileTypes: true });
|
|
108
|
-
for (const entry of entries) {
|
|
109
|
-
if (!entry.isDirectory())
|
|
110
|
-
continue;
|
|
111
|
-
const flowId = entry.name;
|
|
112
|
-
try {
|
|
113
|
-
// This will validate schema and ID match
|
|
114
|
-
const manifest = loadFlowManifest(root, flowId);
|
|
115
|
-
results.push(manifest);
|
|
116
|
-
}
|
|
117
|
-
catch (e) {
|
|
118
|
-
// Ignore invalid/partial flows during listing unless specific debug needed?
|
|
119
|
-
// User requested: "don't crash on partial folders"
|
|
120
|
-
// We sip it.
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
return results;
|
|
124
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import kleur from "kleur";
|
|
2
|
-
import { loadState, getActiveFramework } from "./state.js";
|
|
3
|
-
import { loadFramework } from "../framework/framework-loader.js";
|
|
4
|
-
import { FrameworkError } from "../framework/framework-types.js";
|
|
5
|
-
import { repoRoot } from "../lib.js";
|
|
6
|
-
/**
|
|
7
|
-
* Resolves the currently active framework from state.
|
|
8
|
-
* Centralizes logic for commands to obtain the framework context.
|
|
9
|
-
*
|
|
10
|
-
* Rules:
|
|
11
|
-
* 1. Reads .iris/state.yaml for active ID.
|
|
12
|
-
* 2. Attempts to load framework.
|
|
13
|
-
* 3. Returns structured context (success or failure).
|
|
14
|
-
* 4. Prints warning to stderr if load fails (but returns context so caller can decide fallback).
|
|
15
|
-
*/
|
|
16
|
-
export async function resolveActiveFramework(root) {
|
|
17
|
-
const r = root || repoRoot();
|
|
18
|
-
const state = loadState(); // loadState() takes no args currently
|
|
19
|
-
const activeFw = getActiveFramework(state);
|
|
20
|
-
try {
|
|
21
|
-
const resolution = await loadFramework(activeFw.current, { repoRoot: r });
|
|
22
|
-
return {
|
|
23
|
-
activeId: activeFw.current,
|
|
24
|
-
activeVersion: activeFw.version,
|
|
25
|
-
resolution,
|
|
26
|
-
error: null
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
catch (err) {
|
|
30
|
-
// If it's a known FrameworkError, return it.
|
|
31
|
-
// If generic error, wrap it? loadFramework usually throws FrameworkError or Error.
|
|
32
|
-
let fwError;
|
|
33
|
-
if (err instanceof FrameworkError) {
|
|
34
|
-
fwError = err;
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
// Generic error wrapper
|
|
38
|
-
fwError = new FrameworkError("INVALID_YAML", activeFw.current, `Failed to load framework '${activeFw.current}': ${err instanceof Error ? err.message : String(err)}`);
|
|
39
|
-
}
|
|
40
|
-
// Emit Warning as requested
|
|
41
|
-
console.error(kleur.yellow(`IRIS_WARNING IRIS_FRAMEWORK_LOAD_FAILED: Could not load active framework '${activeFw.current}'. Reason: ${fwError.message}`));
|
|
42
|
-
return {
|
|
43
|
-
activeId: activeFw.current,
|
|
44
|
-
activeVersion: activeFw.version,
|
|
45
|
-
resolution: null,
|
|
46
|
-
error: fwError
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
}
|
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { FrameworkError } from "../framework/framework-types.js";
|
|
4
|
-
import { loadFramework } from "../framework/framework-loader.js";
|
|
5
|
-
import { getBundledFrameworksDir } from "./bundle.js";
|
|
6
|
-
import { copyDir, ensureDir } from "../lib.js";
|
|
7
|
-
import { loadState, getActiveFramework } from "./state.js";
|
|
8
|
-
// --- Validation ---
|
|
9
|
-
/**
|
|
10
|
-
* Validates a framework ID.
|
|
11
|
-
* Defaults to strict mode: ^[a-z0-9][a-z0-9-_]*$
|
|
12
|
-
* Future: allowScoped option.
|
|
13
|
-
*/
|
|
14
|
-
export function validateFrameworkId(id, options = {}) {
|
|
15
|
-
const { allowScoped = false } = options;
|
|
16
|
-
if (!id || typeof id !== 'string')
|
|
17
|
-
return false;
|
|
18
|
-
// Strict mode (current default)
|
|
19
|
-
// Starts with alphanumeric, followed by alphanumeric, -, _
|
|
20
|
-
// TODO: Support scoped IDs (e.g. @scope/pkg) in future version.
|
|
21
|
-
// Suggestion: Store scoped IDs under .iris/frameworks/@scope__pkg (encoded) to keep flat structure.
|
|
22
|
-
const strictRegex = /^[a-z0-9][a-z0-9-_]*$/;
|
|
23
|
-
return strictRegex.test(id);
|
|
24
|
-
}
|
|
25
|
-
// --- Listing ---
|
|
26
|
-
export async function listInstalledFrameworks(root) {
|
|
27
|
-
const frameworksDir = path.join(root, ".iris/frameworks");
|
|
28
|
-
const state = loadState();
|
|
29
|
-
const activeFw = getActiveFramework(state);
|
|
30
|
-
if (!fs.existsSync(frameworksDir)) {
|
|
31
|
-
return [];
|
|
32
|
-
}
|
|
33
|
-
const entries = fs.readdirSync(frameworksDir, { withFileTypes: true });
|
|
34
|
-
const results = [];
|
|
35
|
-
for (const entry of entries) {
|
|
36
|
-
if (!entry.isDirectory())
|
|
37
|
-
continue;
|
|
38
|
-
// Ignore temp directories from failed atomic installs
|
|
39
|
-
if (entry.name.startsWith('.tmp-'))
|
|
40
|
-
continue;
|
|
41
|
-
const fwPath = path.join(frameworksDir, entry.name);
|
|
42
|
-
// Ensure active checking uses the folder name derived ID if logical ID is missing?
|
|
43
|
-
// Actually framework state uses the ID.
|
|
44
|
-
const isActive = activeFw.current === entry.name;
|
|
45
|
-
try {
|
|
46
|
-
const resolution = await loadFramework(entry.name, { repoRoot: root });
|
|
47
|
-
results.push({
|
|
48
|
-
id: resolution.manifest.id || entry.name, // Source of truth fallback
|
|
49
|
-
version: resolution.manifest.version,
|
|
50
|
-
path: fwPath,
|
|
51
|
-
valid: true,
|
|
52
|
-
active: isActive,
|
|
53
|
-
manifest: resolution.manifest
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
catch (error) {
|
|
57
|
-
results.push({
|
|
58
|
-
id: entry.name, // Fallback to folder name
|
|
59
|
-
version: null,
|
|
60
|
-
path: fwPath,
|
|
61
|
-
valid: false,
|
|
62
|
-
active: isActive,
|
|
63
|
-
error: {
|
|
64
|
-
code: error.code || 'UNKNOWN',
|
|
65
|
-
message: error.message || String(error)
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return results;
|
|
71
|
-
}
|
|
72
|
-
export async function listBundledFrameworks() {
|
|
73
|
-
const bundleDir = getBundledFrameworksDir();
|
|
74
|
-
if (!fs.existsSync(bundleDir)) {
|
|
75
|
-
return [];
|
|
76
|
-
}
|
|
77
|
-
const entries = fs.readdirSync(bundleDir, { withFileTypes: true });
|
|
78
|
-
const results = [];
|
|
79
|
-
for (const entry of entries) {
|
|
80
|
-
if (!entry.isDirectory())
|
|
81
|
-
continue;
|
|
82
|
-
const fwPath = path.join(bundleDir, entry.name);
|
|
83
|
-
try {
|
|
84
|
-
// Load explicitly from path
|
|
85
|
-
const resolution = await loadFramework(fwPath, { repoRoot: "/" });
|
|
86
|
-
results.push({
|
|
87
|
-
id: resolution.manifest.id || entry.name,
|
|
88
|
-
path: fwPath,
|
|
89
|
-
version: resolution.manifest.version,
|
|
90
|
-
valid: true
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
catch (e) {
|
|
94
|
-
results.push({
|
|
95
|
-
id: entry.name,
|
|
96
|
-
path: fwPath,
|
|
97
|
-
valid: false,
|
|
98
|
-
error: e.message
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return results;
|
|
103
|
-
}
|
|
104
|
-
// --- Installation ---
|
|
105
|
-
export async function installFrameworkFromPath(root, sourcePath, options = {}) {
|
|
106
|
-
const frameworksDir = path.join(root, ".iris/frameworks");
|
|
107
|
-
ensureDir(frameworksDir);
|
|
108
|
-
// 1. Validate Source & Get ID
|
|
109
|
-
// We load it to ensure it's a valid framework AND to get the canonical ID
|
|
110
|
-
let resolution;
|
|
111
|
-
try {
|
|
112
|
-
resolution = await loadFramework(sourcePath, { repoRoot: root });
|
|
113
|
-
}
|
|
114
|
-
catch (e) {
|
|
115
|
-
throw new FrameworkError('INSTALL_FAILED', sourcePath, `Failed to load source framework: ${e.message}`, e.hint);
|
|
116
|
-
}
|
|
117
|
-
// Ensure ID is present
|
|
118
|
-
const id = resolution.manifest.id;
|
|
119
|
-
if (!id) {
|
|
120
|
-
throw new FrameworkError('INVALID_SCHEMA', sourcePath, `Framework manifest missing required 'id' field.`);
|
|
121
|
-
}
|
|
122
|
-
// 2. Validate ID (Strict)
|
|
123
|
-
if (!validateFrameworkId(id)) {
|
|
124
|
-
throw new FrameworkError('INVALID_ID', id, `Framework ID '${id}' is invalid.`, "IDs must match ^[a-z0-9][a-z0-9-_]*$");
|
|
125
|
-
}
|
|
126
|
-
// 3. Resolve Target Path & Safety Guard
|
|
127
|
-
const targetPath = path.resolve(frameworksDir, id);
|
|
128
|
-
// Guard: Path Traversal
|
|
129
|
-
if (!targetPath.startsWith(path.resolve(frameworksDir) + path.sep)) {
|
|
130
|
-
throw new FrameworkError('SECURITY_VIOLATION', id, `Invalid framework ID '${id}': Resulting path traverses outside frameworks directory.`);
|
|
131
|
-
}
|
|
132
|
-
// 4. Check Existence
|
|
133
|
-
if (fs.existsSync(targetPath)) {
|
|
134
|
-
if (!options.force) {
|
|
135
|
-
throw new FrameworkError('ALREADY_EXISTS', targetPath, `Framework '${id}' is already installed.`, "Use --force to overwrite.");
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
// 5. Atomic Install
|
|
139
|
-
// Copy to .tmp-<id>-<random>
|
|
140
|
-
const tempName = `.tmp-${id}-${Math.random().toString(36).substring(7)}`;
|
|
141
|
-
const tempPath = path.join(frameworksDir, tempName);
|
|
142
|
-
try {
|
|
143
|
-
// Copy recursive
|
|
144
|
-
copyDir(resolution.rootDir, tempPath);
|
|
145
|
-
// 6. Rename / Swap
|
|
146
|
-
if (fs.existsSync(targetPath)) {
|
|
147
|
-
// Remove old (Safe because verified inside frameworksDir)
|
|
148
|
-
fs.rmSync(targetPath, { recursive: true, force: true });
|
|
149
|
-
}
|
|
150
|
-
fs.renameSync(tempPath, targetPath);
|
|
151
|
-
return {
|
|
152
|
-
id,
|
|
153
|
-
version: resolution.manifest.version,
|
|
154
|
-
path: targetPath,
|
|
155
|
-
valid: true,
|
|
156
|
-
active: false,
|
|
157
|
-
manifest: resolution.manifest
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
catch (e) {
|
|
161
|
-
// Cleanup temp
|
|
162
|
-
if (fs.existsSync(tempPath)) {
|
|
163
|
-
fs.rmSync(tempPath, { recursive: true, force: true });
|
|
164
|
-
}
|
|
165
|
-
throw new FrameworkError('INSTALL_FAILED', targetPath, `Failed to install framework: ${e.message}`);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
export async function installBundledFramework(root, id, options = {}) {
|
|
169
|
-
const bundleDir = getBundledFrameworksDir();
|
|
170
|
-
// Fallback logic to find bundled framework
|
|
171
|
-
let sourcePath = path.join(bundleDir, id);
|
|
172
|
-
if (!fs.existsSync(sourcePath)) {
|
|
173
|
-
const allBundled = await listBundledFrameworks();
|
|
174
|
-
const found = allBundled.find(b => b.id === id && b.valid);
|
|
175
|
-
if (found) {
|
|
176
|
-
sourcePath = found.path;
|
|
177
|
-
}
|
|
178
|
-
else {
|
|
179
|
-
throw new FrameworkError('NOT_FOUND', id, `Bundled framework '${id}' not found.`);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return installFrameworkFromPath(root, sourcePath, options);
|
|
183
|
-
}
|
|
184
|
-
// --- Removal ---
|
|
185
|
-
export function removeFramework(root, id) {
|
|
186
|
-
const frameworksDir = path.join(root, ".iris/frameworks");
|
|
187
|
-
// 1. Guard: Frameworks dir exists?
|
|
188
|
-
if (!fs.existsSync(frameworksDir)) {
|
|
189
|
-
throw new FrameworkError('NOT_FOUND', frameworksDir, "No frameworks installed.");
|
|
190
|
-
}
|
|
191
|
-
// 2. Resolve Target & Safety
|
|
192
|
-
// Use regex first
|
|
193
|
-
if (!validateFrameworkId(id)) {
|
|
194
|
-
throw new FrameworkError('INVALID_ID', id, `Invalid framework ID format.`);
|
|
195
|
-
}
|
|
196
|
-
const targetPath = path.resolve(frameworksDir, id);
|
|
197
|
-
if (!targetPath.startsWith(path.resolve(frameworksDir) + path.sep)) {
|
|
198
|
-
throw new FrameworkError('SECURITY_VIOLATION', id, `Path traversal detected.`);
|
|
199
|
-
}
|
|
200
|
-
if (!fs.existsSync(targetPath)) {
|
|
201
|
-
throw new FrameworkError('NOT_FOUND', targetPath, `Framework '${id}' is not installed.`);
|
|
202
|
-
}
|
|
203
|
-
// 3. Guard: Active
|
|
204
|
-
const state = loadState();
|
|
205
|
-
if (state.framework.current === id) {
|
|
206
|
-
throw new FrameworkError('ACTIVE_FRAMEWORK', id, `Cannot remove active framework '${id}'.`, "Switch to another framework first (e.g. 'iris framework use iris-core').");
|
|
207
|
-
}
|
|
208
|
-
// 4. Delete
|
|
209
|
-
fs.rmSync(targetPath, { recursive: true, force: true });
|
|
210
|
-
}
|
|
211
|
-
// --- Validation Wrapper ---
|
|
212
|
-
export async function validateFrameworkParams(input, root) {
|
|
213
|
-
// Just a wrapper for loadFramework but enables consistent error handling for CLI
|
|
214
|
-
return loadFramework(input, { repoRoot: root });
|
|
215
|
-
}
|
package/dist/iris/fs/atomic.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
export function writeJsonAtomic(filePath, data) {
|
|
4
|
-
const tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
5
|
-
const dir = path.dirname(filePath);
|
|
6
|
-
if (!fs.existsSync(dir)) {
|
|
7
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
8
|
-
}
|
|
9
|
-
try {
|
|
10
|
-
fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
|
|
11
|
-
fs.renameSync(tmpPath, filePath);
|
|
12
|
-
}
|
|
13
|
-
catch (error) {
|
|
14
|
-
// Attempt cleanup
|
|
15
|
-
try {
|
|
16
|
-
if (fs.existsSync(tmpPath))
|
|
17
|
-
fs.unlinkSync(tmpPath);
|
|
18
|
-
}
|
|
19
|
-
catch { }
|
|
20
|
-
throw error;
|
|
21
|
-
}
|
|
22
|
-
}
|
package/dist/iris/guard.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import kleur from "kleur";
|
|
2
|
-
import { validate } from "./validator.js";
|
|
3
|
-
import { EXIT_CODES } from "../utils/exit-codes.js";
|
|
4
|
-
export async function requireValidRepoOrExit(options = {}) {
|
|
5
|
-
// Run validation in read-only mode first?
|
|
6
|
-
// Should we write back validation results for 'run'?
|
|
7
|
-
// Specs: "Runs the same core validator used by iris validate"
|
|
8
|
-
// If we run 'iris run', it probably SHOULD update the last_validation timestamp to show we checked.
|
|
9
|
-
// So writeBack: true (default) is appropriate here.
|
|
10
|
-
const result = await validate({
|
|
11
|
-
apply: false,
|
|
12
|
-
strict: options.strict || false,
|
|
13
|
-
writeBack: true
|
|
14
|
-
});
|
|
15
|
-
if (!result.valid) {
|
|
16
|
-
console.log("");
|
|
17
|
-
console.log(kleur.red().bold("⛔ Repo invalid; run iris validate for details"));
|
|
18
|
-
console.log("");
|
|
19
|
-
// List 1-3 most important issues
|
|
20
|
-
const topErrors = result.errors.slice(0, 3);
|
|
21
|
-
topErrors.forEach((err) => {
|
|
22
|
-
console.log(kleur.red(` [${err.code}] ${err.path || ""}`));
|
|
23
|
-
});
|
|
24
|
-
if (result.errors.length > 3) {
|
|
25
|
-
console.log(kleur.dim(` ... and ${result.errors.length - 3} more.`));
|
|
26
|
-
}
|
|
27
|
-
console.log("");
|
|
28
|
-
process.exit(EXIT_CODES.INVALID);
|
|
29
|
-
}
|
|
30
|
-
// If validated with warnings, we usually proceed unless strict is on.
|
|
31
|
-
// Validator handles strict check internally?
|
|
32
|
-
// No, validate() returns warnings=true. command/validate.ts handled exit.
|
|
33
|
-
if (result.warnings && options.strict) {
|
|
34
|
-
console.log("");
|
|
35
|
-
console.log(kleur.red().bold("⛔ Repo has warnings (strict mode enabled)"));
|
|
36
|
-
process.exit(EXIT_CODES.INVALID);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
const REGISTRY = {};
|
|
2
|
-
export function registerImporter(importer) {
|
|
3
|
-
REGISTRY[importer.id] = importer;
|
|
4
|
-
}
|
|
5
|
-
// No importers registered - IRIS ships only iris-core
|
|
6
|
-
export function getImporter(id) {
|
|
7
|
-
return REGISTRY[id] || null;
|
|
8
|
-
}
|
|
9
|
-
export const IMPORTERS = REGISTRY;
|