project-iris 0.0.8 → 0.0.11
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 +294 -264
- package/dist/bridge/agent-runner.js +190 -0
- package/dist/bridge/connector-factory.js +4 -0
- package/dist/bridge/connectors/in-process-connector.js +29 -0
- package/dist/bridge/filesystem-connector.js +5 -0
- package/dist/cli.js +10 -2
- package/dist/commands/ask.js +150 -23
- package/dist/commands/bridge.js +8 -0
- package/dist/commands/flow.js +301 -0
- package/dist/commands/framework.js +273 -0
- package/dist/commands/generate.js +59 -0
- package/dist/commands/install.js +72 -29
- package/dist/commands/pack.js +7 -1
- package/dist/commands/run.js +195 -13
- package/dist/commands/status.js +9 -0
- package/dist/commands/uninstall.js +3 -1
- package/dist/commands/use.js +20 -0
- package/dist/commands/validate.js +80 -65
- package/dist/framework/framework-loader.js +97 -0
- package/dist/framework/framework-paths.js +48 -0
- package/dist/framework/framework-types.js +15 -0
- package/dist/iris/artifacts/config.js +68 -0
- package/dist/iris/artifacts/generator.js +88 -0
- package/dist/iris/artifacts/types.js +1 -0
- package/dist/iris/bundle.js +44 -0
- package/dist/iris/doctrine/collector.js +124 -0
- package/dist/iris/fixer.js +28 -22
- package/dist/iris/flows/manifest.js +124 -0
- package/dist/iris/framework-context.js +49 -0
- package/dist/iris/framework-manager.js +215 -0
- package/dist/iris/fs/atomic.js +22 -0
- package/dist/iris/importers/index.js +9 -0
- package/dist/iris/importers/types.js +8 -0
- package/dist/iris/importers/writer.js +139 -0
- package/dist/iris/installer.js +105 -40
- package/dist/iris/interactive/env.js +21 -0
- package/dist/iris/interactive/intent-interview.js +345 -0
- package/dist/iris/interactive/intent-schema.js +28 -0
- package/dist/iris/interactive/interview-io.js +22 -0
- package/dist/iris/interview/config.js +71 -0
- package/dist/iris/interview/types.js +16 -0
- package/dist/iris/interview/utils.js +38 -0
- package/dist/iris/packer.js +69 -47
- package/dist/iris/parsers/unit-parser.js +43 -0
- package/dist/iris/paths.js +18 -0
- package/dist/iris/policy.js +122 -17
- package/dist/iris/proc.js +56 -0
- package/dist/iris/resolver.js +3 -0
- package/dist/iris/routes.js +180 -11
- package/dist/iris/run-state.js +3 -0
- package/dist/iris/state.js +37 -9
- package/dist/iris/templates.js +70 -0
- package/dist/iris/tmp.js +24 -0
- package/dist/iris/uninstaller.js +24 -9
- package/dist/iris/utils/interpolate.js +42 -0
- package/dist/iris/validator.js +72 -10
- package/dist/iris/workflow/config.js +51 -0
- package/dist/iris/workflow/engine.js +129 -0
- package/dist/iris/workflow/steps.js +448 -0
- package/dist/iris/workflow/types.js +1 -0
- package/dist/utils/logo.js +17 -0
- package/dist/workflows/intent-inception.js +87 -65
- package/package.json +8 -6
- package/src/iris_bundle/.iris/aidlc/README.md +0 -16
- package/src/iris_bundle/.iris/aidlc/agents/iris-construction-agent.md +0 -35
- package/src/iris_bundle/.iris/aidlc/agents/iris-inception-agent.md +0 -30
- package/src/iris_bundle/.iris/aidlc/agents/iris-master-agent.md +0 -35
- package/src/iris_bundle/.iris/aidlc/agents/iris-operations-agent.md +0 -29
- package/src/iris_bundle/.iris/aidlc/commands/iris-construction-agent.md +0 -18
- package/src/iris_bundle/.iris/aidlc/commands/iris-inception-agent.md +0 -18
- package/src/iris_bundle/.iris/aidlc/commands/iris-master-agent.md +0 -18
- package/src/iris_bundle/.iris/aidlc/commands/iris-operations-agent.md +0 -18
- package/src/iris_bundle/.iris/aidlc/context/context-map.md +0 -25
- package/src/iris_bundle/.iris/aidlc/context/exclusion-rules.md +0 -13
- package/src/iris_bundle/.iris/aidlc/context/load-order.md +0 -25
- package/src/iris_bundle/.iris/aidlc/memory/intent-rules.md +0 -9
- package/src/iris_bundle/.iris/aidlc/memory/log-rules.md +0 -5
- package/src/iris_bundle/.iris/aidlc/memory/memory-bank.yaml +0 -39
- package/src/iris_bundle/.iris/aidlc/memory/unit-rules.md +0 -9
- package/src/iris_bundle/.iris/aidlc/quick-start.md +0 -24
- package/src/iris_bundle/.iris/aidlc/skills/execution/implementation.md +0 -14
- package/src/iris_bundle/.iris/aidlc/skills/execution/refactoring.md +0 -13
- package/src/iris_bundle/.iris/aidlc/skills/execution/scaffold-generation.md +0 -15
- package/src/iris_bundle/.iris/aidlc/skills/governance/escalation.md +0 -13
- package/src/iris_bundle/.iris/aidlc/skills/governance/quality-gates.md +0 -14
- package/src/iris_bundle/.iris/aidlc/skills/governance/stop-conditions.md +0 -11
- package/src/iris_bundle/.iris/aidlc/skills/reasoning/decomposition.md +0 -23
- package/src/iris_bundle/.iris/aidlc/skills/reasoning/risk-analysis.md +0 -14
- package/src/iris_bundle/.iris/aidlc/skills/reasoning/verification.md +0 -21
- package/src/iris_bundle/.iris/aidlc/standards/artifacts-registry.md +0 -38
- package/src/iris_bundle/.iris/aidlc/standards/decision-logging.md +0 -16
- package/src/iris_bundle/.iris/aidlc/standards/doctrine-structure.md +0 -31
- package/src/iris_bundle/.iris/aidlc/standards/documentation-rules.md +0 -15
- package/src/iris_bundle/.iris/aidlc/standards/file-structure.md +0 -21
- package/src/iris_bundle/.iris/aidlc/standards/naming-conventions.md +0 -18
- package/src/iris_bundle/.iris/aidlc/standards/phases-and-gates.md +0 -25
- package/src/iris_bundle/.iris/aidlc/standards/routes-and-routing.md +0 -35
- package/src/iris_bundle/.iris/aidlc/standards/tool-wrappers.md +0 -32
- package/src/iris_bundle/.iris/aidlc/templates/bolt.md +0 -23
- package/src/iris_bundle/.iris/aidlc/templates/doctrine-doc-template.md +0 -33
- package/src/iris_bundle/.iris/aidlc/templates/intent.md +0 -23
- package/src/iris_bundle/.iris/aidlc/templates/log.md +0 -24
- package/src/iris_bundle/.iris/aidlc/templates/review.md +0 -21
- package/src/iris_bundle/.iris/aidlc/templates/unit.md +0 -31
- package/src/iris_bundle/.iris/aidlc/validation/failure-modes.md +0 -16
- package/src/iris_bundle/.iris/aidlc/validation/phase-preconditions.md +0 -21
- package/src/iris_bundle/.iris/aidlc/validation/quality-checklist.md +0 -20
- package/src/iris_bundle/.iris/policy.yaml +0 -27
- package/src/iris_bundle/.iris/routes.yaml +0 -98
- package/src/iris_bundle/.iris/state.yaml +0 -7
- package/src/iris_bundle/.iris/tools/claude/.claude/claude.md +0 -9
- package/src/iris_bundle/.iris/tools/claude/.claude/commands/compare-specs.md +0 -203
- package/src/iris_bundle/.iris/tools/claude/.claude/commands/iris-construction-agent.md +0 -25
- package/src/iris_bundle/.iris/tools/claude/.claude/commands/iris-inception-agent.md +0 -25
- package/src/iris_bundle/.iris/tools/claude/.claude/commands/iris-master-agent.md +0 -25
- package/src/iris_bundle/.iris/tools/claude/.claude/commands/iris-operations-agent.md +0 -25
- package/src/iris_bundle/.iris/tools/codex/AGENTS.md +0 -15
- package/src/iris_bundle/.iris/tools/cursor/.cursor/commands/iris-construction-agent.md +0 -25
- package/src/iris_bundle/.iris/tools/cursor/.cursor/commands/iris-inception-agent.md +0 -25
- package/src/iris_bundle/.iris/tools/cursor/.cursor/commands/iris-master-agent.md +0 -25
- package/src/iris_bundle/.iris/tools/cursor/.cursor/commands/iris-operations-agent.md +0 -25
- package/src/iris_bundle/.iris/tools/gemini/.gemini/commands/iris-construction-agent.toml +0 -29
- package/src/iris_bundle/.iris/tools/gemini/.gemini/commands/iris-inception-agent.toml +0 -29
- package/src/iris_bundle/.iris/tools/gemini/.gemini/commands/iris-master-agent.toml +0 -29
- package/src/iris_bundle/.iris/tools/gemini/.gemini/commands/iris-operations-agent.toml +0 -29
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import kleur from "kleur";
|
|
4
|
+
import { INBOX_DIR, OUTBOX_DIR } from "./helper.js";
|
|
5
|
+
export async function startAgentRunner(options = {}) {
|
|
6
|
+
const pollInterval = options.pollInterval || 2000;
|
|
7
|
+
const verbose = options.verbose !== false;
|
|
8
|
+
console.log(kleur.bold("🤖 IRIS Automated Agent Started"));
|
|
9
|
+
console.log(kleur.dim(` Watching: ${INBOX_DIR}`));
|
|
10
|
+
console.log(kleur.dim(` Answering to: ${OUTBOX_DIR}\n`));
|
|
11
|
+
// Ensure directories
|
|
12
|
+
fs.mkdirSync(INBOX_DIR, { recursive: true });
|
|
13
|
+
fs.mkdirSync(OUTBOX_DIR, { recursive: true });
|
|
14
|
+
const processed = new Set();
|
|
15
|
+
// Polling Loop
|
|
16
|
+
setInterval(async () => {
|
|
17
|
+
try {
|
|
18
|
+
const files = fs.readdirSync(INBOX_DIR).filter(f => f.endsWith(".json"));
|
|
19
|
+
for (const file of files) {
|
|
20
|
+
if (processed.has(file))
|
|
21
|
+
continue;
|
|
22
|
+
const filePath = path.join(INBOX_DIR, file);
|
|
23
|
+
try {
|
|
24
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
25
|
+
const task = JSON.parse(content);
|
|
26
|
+
processed.add(file);
|
|
27
|
+
const outPath = path.join(OUTBOX_DIR, file);
|
|
28
|
+
if (fs.existsSync(outPath)) {
|
|
29
|
+
processed.add(file);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (verbose) {
|
|
33
|
+
console.log(kleur.cyan(`\n[Active] Processing task: ${task.taskId}`));
|
|
34
|
+
console.log(kleur.dim(` Stage: ${task.stage}`));
|
|
35
|
+
console.log(kleur.dim(` Intent: ${task.intent}`));
|
|
36
|
+
}
|
|
37
|
+
// Think...
|
|
38
|
+
await new Promise(r => setTimeout(r, 1000)); // Simulate latency
|
|
39
|
+
// Handle
|
|
40
|
+
const result = await handleTask(task);
|
|
41
|
+
// Respond
|
|
42
|
+
fs.writeFileSync(outPath, JSON.stringify(result, null, 2));
|
|
43
|
+
console.log(kleur.green(` ✓ Responded to ${task.taskId}`));
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
console.error(kleur.red(` ✗ Failed to process ${file}: ${err.message}`));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
// Ignore read errors
|
|
52
|
+
}
|
|
53
|
+
}, pollInterval);
|
|
54
|
+
}
|
|
55
|
+
// Heuristic Intelligence
|
|
56
|
+
export async function handleTask(task) {
|
|
57
|
+
// 1. Intent Inception (Ping-Pong)
|
|
58
|
+
if (task.stage === "INTENT_INCEPTION" && task.metadata?.step === "clarify_turn") {
|
|
59
|
+
return handleClarification(task);
|
|
60
|
+
}
|
|
61
|
+
// 2. Artifact Generation
|
|
62
|
+
if (task.stage === "INTENT_INCEPTION" && task.metadata?.step === "generate_artifacts") {
|
|
63
|
+
return handleArtifactGeneration(task);
|
|
64
|
+
}
|
|
65
|
+
// 3. Bolt Plan
|
|
66
|
+
if (task.stage === "BOLT_PLAN" && task.metadata?.step === "generate_bolt_plan") {
|
|
67
|
+
return handleBoltPlan(task);
|
|
68
|
+
}
|
|
69
|
+
// Default fallback
|
|
70
|
+
return {
|
|
71
|
+
taskId: task.taskId,
|
|
72
|
+
status: "ok",
|
|
73
|
+
message: "DONE",
|
|
74
|
+
filesChanged: []
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function handleClarification(task) {
|
|
78
|
+
const instructions = task.instructions || "";
|
|
79
|
+
const historyLines = instructions.split("\n").filter(l => l.trim().startsWith("Q:"));
|
|
80
|
+
const turnCount = historyLines.length;
|
|
81
|
+
let message = "DONE";
|
|
82
|
+
// Simple Script
|
|
83
|
+
if (turnCount === 0) {
|
|
84
|
+
message = "\"Who is the primary user for this application?\"";
|
|
85
|
+
}
|
|
86
|
+
else if (turnCount === 1) {
|
|
87
|
+
message = "\"What are the key technical constraints (Language, DB)?\"";
|
|
88
|
+
}
|
|
89
|
+
else if (turnCount === 2) {
|
|
90
|
+
message = "\"What are the success criteria for this project?\"";
|
|
91
|
+
}
|
|
92
|
+
else if (turnCount === 3) {
|
|
93
|
+
message = "\"What are the non-goals (what should we NOT build)?\"";
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
message = "\"DONE\"";
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
taskId: task.taskId,
|
|
100
|
+
status: "ok",
|
|
101
|
+
message,
|
|
102
|
+
filesChanged: []
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function handleArtifactGeneration(task) {
|
|
106
|
+
const intentSlug = task.metadata?.intentSlug || "default";
|
|
107
|
+
const prompt = task.instructions || "";
|
|
108
|
+
// 1. Parse Inputs (Poor man's extraction from "User Answers" section of prompt)
|
|
109
|
+
let targetUser = "Unknown User";
|
|
110
|
+
let techStack = "Node.js (Default)";
|
|
111
|
+
let successCriteria = "- Standard success criteria";
|
|
112
|
+
let nonGoals = "- None specified";
|
|
113
|
+
// Extract Answers
|
|
114
|
+
const qaRegex = /Q: (.*?)\nA: (.*?)(?=\nQ:|\n$)/gs;
|
|
115
|
+
const matches = [...prompt.matchAll(qaRegex)];
|
|
116
|
+
matches.forEach(([, q, a]) => {
|
|
117
|
+
const qLower = q.toLowerCase();
|
|
118
|
+
if (qLower.includes("primary user"))
|
|
119
|
+
targetUser = a.trim();
|
|
120
|
+
else if (qLower.includes("technical constraints"))
|
|
121
|
+
techStack = a.trim();
|
|
122
|
+
else if (qLower.includes("success criteria"))
|
|
123
|
+
successCriteria = a.trim().split('.').map(s => s.trim()).filter(Boolean).map(s => `- ${s}`).join("\n");
|
|
124
|
+
else if (qLower.includes("non-goals"))
|
|
125
|
+
nonGoals = a.trim().split('.').map(s => s.trim()).filter(Boolean).map(s => `- ${s}`).join("\n");
|
|
126
|
+
});
|
|
127
|
+
// 2. Generate Requirements
|
|
128
|
+
const reqContent = `# Requirements: ${task.intent}
|
|
129
|
+
|
|
130
|
+
## Goal
|
|
131
|
+
${task.intent}
|
|
132
|
+
|
|
133
|
+
## Target User
|
|
134
|
+
${targetUser}
|
|
135
|
+
|
|
136
|
+
## Success Criteria
|
|
137
|
+
${successCriteria}
|
|
138
|
+
|
|
139
|
+
## Non-Goals
|
|
140
|
+
${nonGoals}
|
|
141
|
+
|
|
142
|
+
## Functional Requirements (Inferred)
|
|
143
|
+
- User should be able to complete the core workflows described in criteria.
|
|
144
|
+
- System should be performant and reliable.
|
|
145
|
+
`;
|
|
146
|
+
// 3. Generate System Context
|
|
147
|
+
const sysContent = `# System Context
|
|
148
|
+
|
|
149
|
+
## Tech Stack
|
|
150
|
+
${techStack}
|
|
151
|
+
|
|
152
|
+
## Architecture Decisions
|
|
153
|
+
- **Frontend / Backend Split**: as implied by tech stack.
|
|
154
|
+
- **Data Persistence**: ${techStack.includes("firebase") ? "Firebase" : "Local/File-based (Default)"}.
|
|
155
|
+
|
|
156
|
+
## Constraints
|
|
157
|
+
- ${techStack}
|
|
158
|
+
`;
|
|
159
|
+
const root = process.cwd();
|
|
160
|
+
const reqPath = `memory-bank/intents/${intentSlug}/requirements.md`;
|
|
161
|
+
const sysPath = `memory-bank/intents/${intentSlug}/system-context.md`;
|
|
162
|
+
ensureFile(path.join(root, reqPath), reqContent);
|
|
163
|
+
ensureFile(path.join(root, sysPath), sysContent);
|
|
164
|
+
return {
|
|
165
|
+
taskId: task.taskId,
|
|
166
|
+
status: "ok",
|
|
167
|
+
message: "Artifacts generated.",
|
|
168
|
+
filesChanged: [reqPath, sysPath]
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function handleBoltPlan(task) {
|
|
172
|
+
const root = process.cwd();
|
|
173
|
+
const planPath = "memory-bank/operations/bolts/plan.md";
|
|
174
|
+
const boltPath = "memory-bank/operations/bolts/b001-bootstrap.md";
|
|
175
|
+
const planContent = `# Bolt Plan\n\n- [ ] [B001] [Bootstrap Project](./b001-bootstrap.md)\n`;
|
|
176
|
+
const boltContent = `# Bolt: Bootstrap\n\n## Tasks\n- [ ] Init project\n\n## Acceptance\n- runs\n`;
|
|
177
|
+
ensureFile(path.join(root, planPath), planContent);
|
|
178
|
+
ensureFile(path.join(root, boltPath), boltContent);
|
|
179
|
+
return {
|
|
180
|
+
taskId: task.taskId,
|
|
181
|
+
status: "ok",
|
|
182
|
+
message: "Plan generated.",
|
|
183
|
+
filesChanged: [planPath, boltPath]
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function ensureFile(p, content) {
|
|
187
|
+
const dir = path.dirname(p);
|
|
188
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
189
|
+
fs.writeFileSync(p, content);
|
|
190
|
+
}
|
|
@@ -3,6 +3,7 @@ import { CursorConnector } from "./connectors/cursor-connector.js";
|
|
|
3
3
|
import { VSCodeConnector } from "./connectors/vscode-connector.js";
|
|
4
4
|
import { AntigravityConnector } from "./connectors/antigravity-connector.js";
|
|
5
5
|
import { WindsurfConnector } from "./connectors/windsurf-connector.js";
|
|
6
|
+
import { InProcessBridgeConnector } from "./connectors/in-process-connector.js";
|
|
6
7
|
/**
|
|
7
8
|
* Create a bridge connector based on IDE id
|
|
8
9
|
*/
|
|
@@ -18,6 +19,9 @@ export function createConnector(ideId) {
|
|
|
18
19
|
return new AntigravityConnector();
|
|
19
20
|
case "windsurf":
|
|
20
21
|
return new WindsurfConnector();
|
|
22
|
+
case "auto":
|
|
23
|
+
case "internal":
|
|
24
|
+
return new InProcessBridgeConnector();
|
|
21
25
|
case "claude":
|
|
22
26
|
case "codex":
|
|
23
27
|
default:
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { handleTask } from "../agent-runner.js";
|
|
2
|
+
export class InProcessBridgeConnector {
|
|
3
|
+
id = "in-process";
|
|
4
|
+
displayName = "Internal Agent";
|
|
5
|
+
pendingTasks = new Map();
|
|
6
|
+
async isAvailable() {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
async ensureRunning() {
|
|
10
|
+
// No-op
|
|
11
|
+
}
|
|
12
|
+
async sendTask(packet) {
|
|
13
|
+
this.pendingTasks.set(packet.taskId, packet);
|
|
14
|
+
return { taskId: packet.taskId };
|
|
15
|
+
}
|
|
16
|
+
async waitResult(taskId, opts) {
|
|
17
|
+
const packet = this.pendingTasks.get(taskId);
|
|
18
|
+
if (!packet) {
|
|
19
|
+
throw new Error(`Task ${taskId} not found in process memory`);
|
|
20
|
+
}
|
|
21
|
+
// Simulate async processing (think time)
|
|
22
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
23
|
+
// Execute logic directly
|
|
24
|
+
const result = await handleTask(packet);
|
|
25
|
+
// Cleanup
|
|
26
|
+
this.pendingTasks.delete(taskId);
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -2,6 +2,7 @@ import fs from "fs";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { processInboxTasks } from "./helper.js";
|
|
4
4
|
import { getSelectedIde } from "../iris/state.js";
|
|
5
|
+
import kleur from "kleur";
|
|
5
6
|
const BRIDGE_DIR = path.join(process.cwd(), ".iris/bridge");
|
|
6
7
|
const INBOX_DIR = path.join(BRIDGE_DIR, "inbox");
|
|
7
8
|
const OUTBOX_DIR = path.join(BRIDGE_DIR, "outbox");
|
|
@@ -40,6 +41,7 @@ export class FilesystemBridgeConnector {
|
|
|
40
41
|
while (Date.now() - startTime < timeoutMs) {
|
|
41
42
|
// Check for result logic...
|
|
42
43
|
if (fs.existsSync(outboxPath)) {
|
|
44
|
+
console.log(kleur.dim(` [Debug] Found result at: ${outboxPath}`));
|
|
43
45
|
const content = fs.readFileSync(outboxPath, "utf8");
|
|
44
46
|
const result = JSON.parse(content);
|
|
45
47
|
// Clean up
|
|
@@ -50,6 +52,9 @@ export class FilesystemBridgeConnector {
|
|
|
50
52
|
}
|
|
51
53
|
return result;
|
|
52
54
|
}
|
|
55
|
+
else {
|
|
56
|
+
// console.log(kleur.dim(` [Debug] Waiting... Checked: ${outboxPath}`));
|
|
57
|
+
}
|
|
53
58
|
// AUTO-BRIDGE: Act as the bridge while waiting
|
|
54
59
|
const ideId = getSelectedIde();
|
|
55
60
|
if (ideId) {
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import { installCommand } from "./commands/install.js";
|
|
4
|
+
import { flowCommand } from "./commands/flow.js";
|
|
4
5
|
import { uninstallCommand } from "./commands/uninstall.js";
|
|
5
6
|
import { phaseCommand } from "./commands/phase.js";
|
|
6
7
|
import { validateCommand } from "./commands/validate.js";
|
|
@@ -11,13 +12,19 @@ import { askCommand } from "./commands/ask.js";
|
|
|
11
12
|
import { doctorCommand } from "./commands/doctor.js";
|
|
12
13
|
import { developCommand } from "./commands/develop.js";
|
|
13
14
|
import { bridgeCommand } from "./commands/bridge.js";
|
|
15
|
+
import { frameworkCommand } from "./commands/framework.js";
|
|
16
|
+
import { generateCommand } from "./commands/generate.js";
|
|
17
|
+
import { useCommand } from "./commands/use.js";
|
|
14
18
|
const program = new Command();
|
|
15
19
|
program
|
|
16
20
|
.name("iris")
|
|
17
21
|
.description("IRIS CLI - Intelligent Repository for Intent-driven Systems")
|
|
18
|
-
.version("0.0.
|
|
22
|
+
.version("0.0.11")
|
|
19
23
|
.addCommand(installCommand)
|
|
20
24
|
.addCommand(uninstallCommand)
|
|
25
|
+
.addCommand(frameworkCommand)
|
|
26
|
+
.addCommand(generateCommand)
|
|
27
|
+
.addCommand(flowCommand)
|
|
21
28
|
.addCommand(phaseCommand)
|
|
22
29
|
.addCommand(validateCommand)
|
|
23
30
|
.addCommand(statusCommand)
|
|
@@ -26,5 +33,6 @@ program
|
|
|
26
33
|
.addCommand(askCommand)
|
|
27
34
|
.addCommand(doctorCommand)
|
|
28
35
|
.addCommand(developCommand)
|
|
29
|
-
.addCommand(bridgeCommand)
|
|
36
|
+
.addCommand(bridgeCommand)
|
|
37
|
+
.addCommand(useCommand);
|
|
30
38
|
program.parseAsync(process.argv);
|
package/dist/commands/ask.js
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import inquirer from "inquirer";
|
|
3
3
|
import kleur from "kleur";
|
|
4
|
+
import path from "path";
|
|
4
5
|
import fs from "fs";
|
|
5
6
|
import { repoRoot } from "../lib.js";
|
|
6
|
-
import { getIrisDebugInfo } from "../iris/resolver.js";
|
|
7
|
-
import {
|
|
7
|
+
import { resolveArtifactPath, getIrisDebugInfo } from "../iris/resolver.js";
|
|
8
|
+
import { loadEffectiveRoutes } from "../iris/routes.js";
|
|
8
9
|
import { routeIntent } from "../iris/router.js";
|
|
9
10
|
import { checkArtifact } from "../iris/artifact-checker.js";
|
|
10
11
|
import { loadPolicy } from "../iris/policy.js";
|
|
11
12
|
import { loadState } from "../iris/state.js";
|
|
12
13
|
import { EXIT_CODES } from "../utils/exit-codes.js";
|
|
13
14
|
import { createConnector } from "../bridge/connector-factory.js";
|
|
14
|
-
import { getSelectedIde } from "../iris/state.js";
|
|
15
15
|
import { executeIntentInception } from "../workflows/intent-inception.js";
|
|
16
16
|
import { executeBoltPlan } from "../workflows/bolt-plan.js";
|
|
17
17
|
import { createRun } from "../iris/run-state.js";
|
|
18
|
+
import { migrateLegacyDraft } from "../iris/interactive/intent-interview.js";
|
|
19
|
+
import { checkInteractiveMode } from "../iris/interactive/env.js";
|
|
20
|
+
import { resolveActiveFramework } from "../iris/framework-context.js";
|
|
21
|
+
import { loadEffectiveInterviewConfig } from "../iris/interview/config.js";
|
|
18
22
|
export const askCommand = new Command("ask")
|
|
19
23
|
.description("Route intent to an agent and generate context pack")
|
|
20
24
|
.argument("[intent...]", "Natural language request intent")
|
|
@@ -25,8 +29,12 @@ export const askCommand = new Command("ask")
|
|
|
25
29
|
.option("--json", "Output structured JSON result", false)
|
|
26
30
|
.option("--dry-run", "Simulate routing without writing files", false)
|
|
27
31
|
.option("--debug", "Show IRIS authority and artifact resolution info", false)
|
|
32
|
+
.option("--non-interactive", "Skip interactive interview", false)
|
|
33
|
+
.option("--force-interactive", "Force interactive mode even in CI/Pipe", false)
|
|
34
|
+
.option("--save-draft-only", "Run interview and save draft, but do not execute workflow", false)
|
|
28
35
|
.action(async (intentParts, opts) => {
|
|
29
36
|
const root = repoRoot();
|
|
37
|
+
const { resolution } = await resolveActiveFramework(root);
|
|
30
38
|
if (opts.debug) {
|
|
31
39
|
const debug = getIrisDebugInfo(root);
|
|
32
40
|
console.log(kleur.bold("IRIS Authority Debug"));
|
|
@@ -36,7 +44,7 @@ export const askCommand = new Command("ask")
|
|
|
36
44
|
console.log(`- Bundled Path:${debug.bundledPath}`);
|
|
37
45
|
console.log("");
|
|
38
46
|
// Show artifact validation details
|
|
39
|
-
const policy = loadPolicy();
|
|
47
|
+
const policy = loadPolicy(root);
|
|
40
48
|
const state = loadState();
|
|
41
49
|
const phase = state.phase.current;
|
|
42
50
|
const requirements = policy.phases[phase]?.requires || [];
|
|
@@ -60,39 +68,143 @@ export const askCommand = new Command("ask")
|
|
|
60
68
|
console.log("");
|
|
61
69
|
}
|
|
62
70
|
}
|
|
71
|
+
// Migration Check
|
|
72
|
+
const migrated = migrateLegacyDraft(root);
|
|
73
|
+
if (migrated) {
|
|
74
|
+
console.log(kleur.dim("Migrated old intent-draft.json to intent-draft.latest.json"));
|
|
75
|
+
}
|
|
63
76
|
// 1. Get Intent
|
|
64
77
|
let intent = intentParts.join(" ");
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
78
|
+
// Environment Check
|
|
79
|
+
const envCheck = checkInteractiveMode({
|
|
80
|
+
nonInteractive: opts.nonInteractive,
|
|
81
|
+
forceInteractive: opts.forceInteractive
|
|
82
|
+
});
|
|
83
|
+
if (envCheck.isInteractive) {
|
|
84
|
+
// 1.5 Load Interview Config
|
|
85
|
+
// Skipped Legacy Interview - proceeding directly to Ping-Pong Flow
|
|
86
|
+
// If no intent provided yet, ask for just the one-liner intent
|
|
87
|
+
if (!intent) {
|
|
88
|
+
const { initialIntent } = await inquirer.prompt([
|
|
89
|
+
{
|
|
90
|
+
type: "input",
|
|
91
|
+
name: "initialIntent",
|
|
92
|
+
message: "What are you trying to build?",
|
|
93
|
+
validate: (val) => val.trim().length > 0 || "Please provide a goal."
|
|
94
|
+
}
|
|
69
95
|
]);
|
|
70
|
-
intent =
|
|
96
|
+
intent = initialIntent;
|
|
71
97
|
}
|
|
72
|
-
|
|
73
|
-
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
// NON-INTERACTIVE MODE
|
|
101
|
+
if (!opts.nonInteractive && !opts.forceInteractive) {
|
|
102
|
+
// Warn if we fell back automatically (reason exists)
|
|
103
|
+
if (envCheck.reason) {
|
|
104
|
+
console.warn(kleur.yellow(`⚠ Interactive mode disabled: ${envCheck.reason}`));
|
|
105
|
+
console.warn(kleur.dim(" Use --force-interactive to override if safe."));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Fallback input reading
|
|
109
|
+
if (!intent) {
|
|
110
|
+
if (process.stdin.isTTY) {
|
|
111
|
+
console.error(kleur.red("Error: Intent argument required in non-interactive mode."));
|
|
112
|
+
process.exit(EXIT_CODES.INVALID);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
try {
|
|
117
|
+
intent = fs.readFileSync(0, "utf-8").trim();
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
// Ignore read error
|
|
121
|
+
}
|
|
122
|
+
}
|
|
74
123
|
}
|
|
75
124
|
}
|
|
76
125
|
if (!intent) {
|
|
77
126
|
console.error(kleur.red("No intent provided."));
|
|
78
127
|
process.exit(EXIT_CODES.INVALID);
|
|
128
|
+
return; // TS Guard
|
|
79
129
|
}
|
|
80
130
|
// 2. Load Routes
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
131
|
+
let routesConfig;
|
|
132
|
+
try {
|
|
133
|
+
const state = loadState();
|
|
134
|
+
// Load Base or Effective
|
|
135
|
+
routesConfig = loadEffectiveRoutes(resolution, root, state.active.flow);
|
|
136
|
+
}
|
|
137
|
+
catch (e) {
|
|
138
|
+
if (e.name === "RoutesOverlayMissingError") {
|
|
139
|
+
console.error(kleur.red(`\n[Policy Error] ${e.message}`));
|
|
140
|
+
process.exit(EXIT_CODES.POLICY_ERROR);
|
|
141
|
+
}
|
|
142
|
+
if (e.name === "RoutesLoadError") {
|
|
143
|
+
console.error(kleur.red(`\n[Routes Error] ${e.message}`));
|
|
144
|
+
if (e.cause)
|
|
145
|
+
console.error(kleur.gray(e.cause));
|
|
146
|
+
process.exit(EXIT_CODES.POLICY_ERROR);
|
|
147
|
+
}
|
|
148
|
+
// Fallback for unexpected
|
|
149
|
+
console.error(kleur.red(`Failed to load routes: ${e.message}`));
|
|
84
150
|
process.exit(EXIT_CODES.POLICY_ERROR);
|
|
85
151
|
}
|
|
86
152
|
// 3. Route
|
|
87
153
|
const routing = routeIntent(intent, routesConfig);
|
|
88
154
|
const routeId = routing.route === "default" ? "default" : routing.route.route_id;
|
|
155
|
+
const source = routing.route !== "default" ? routing.route._source : "default";
|
|
156
|
+
if (opts.debug) {
|
|
157
|
+
console.log(kleur.bold(`Matched route_id: ${routeId} ${source ? `(source: ${source})` : ""}`));
|
|
158
|
+
}
|
|
89
159
|
// 4. Execution Workflow (Inception + Planning)
|
|
160
|
+
if (opts.dryRun) {
|
|
161
|
+
// DRY RUN: Simulate pack generation
|
|
162
|
+
// We know intent, route, agent.
|
|
163
|
+
// We can create a Plan object.
|
|
164
|
+
const plan = {
|
|
165
|
+
schemaVersion: 1,
|
|
166
|
+
intent: intent,
|
|
167
|
+
framework: resolution ? resolution.manifest.id : "legacy-fallback",
|
|
168
|
+
route: {
|
|
169
|
+
id: routeId,
|
|
170
|
+
target: routing.route === "default" ? "default" : routing.route.agent,
|
|
171
|
+
score: routing.route === "default" ? 0 : routing.route.score
|
|
172
|
+
},
|
|
173
|
+
routesSource: {
|
|
174
|
+
kind: routesConfig?._meta?.sourceKind || (resolution ? 'framework' : 'legacy'),
|
|
175
|
+
path: routesConfig?._meta?.sourcePath || (resolution ? resolution.files.routes : resolveArtifactPath(root, ".iris/routes.yaml"))
|
|
176
|
+
},
|
|
177
|
+
interviewSource: (() => {
|
|
178
|
+
// We need to load it here for dry run to show source
|
|
179
|
+
const interviewConfig = loadEffectiveInterviewConfig(resolution);
|
|
180
|
+
const isFramework = !!(resolution?.files.interview);
|
|
181
|
+
return {
|
|
182
|
+
kind: isFramework ? 'framework' : 'default',
|
|
183
|
+
path: isFramework ? resolution?.files.interview : null,
|
|
184
|
+
activeFrameworkId: resolution?.manifest.id || null
|
|
185
|
+
};
|
|
186
|
+
})(),
|
|
187
|
+
pack: {
|
|
188
|
+
planned: true,
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
if (opts.json) {
|
|
192
|
+
console.log(JSON.stringify(plan, null, 2));
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
console.log(kleur.yellow("[Dry Run] Routing Result:"));
|
|
196
|
+
console.log(JSON.stringify(plan, null, 2));
|
|
197
|
+
}
|
|
198
|
+
process.exit(0);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
90
201
|
console.log(kleur.bold("Starting IRIS Inception & Planning"));
|
|
91
202
|
console.log(kleur.dim("This process will clarify your intent and generate an implementation plan.\n"));
|
|
92
203
|
// Initialize Bridge/IDE
|
|
93
|
-
|
|
94
|
-
//
|
|
95
|
-
//
|
|
204
|
+
// Default to 'auto' (In-Process Agent) for seamless UX, ignoring detected IDE unless explicitly bridged?
|
|
205
|
+
// For now, satisfy user request: "Check user intent first".
|
|
206
|
+
// We will use "auto" as the default connector.
|
|
207
|
+
const ideId = "auto";
|
|
96
208
|
// Create new run
|
|
97
209
|
const runState = createRun(intent, ideId, "manual");
|
|
98
210
|
const connector = createConnector(ideId);
|
|
@@ -107,14 +219,29 @@ export const askCommand = new Command("ask")
|
|
|
107
219
|
gate: "manual",
|
|
108
220
|
noBridge: false
|
|
109
221
|
});
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
222
|
+
const result = {
|
|
223
|
+
runId: runState.runId,
|
|
224
|
+
status: "plan_created",
|
|
225
|
+
planPath: path.join(root, ".iris/runs", runState.runId, "implementation_plan.md")
|
|
226
|
+
};
|
|
227
|
+
if (opts.json) {
|
|
228
|
+
console.log(JSON.stringify(result, null, 2));
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
console.log("");
|
|
232
|
+
console.log(kleur.bold(kleur.green("✓ Plan Created Successfully!")));
|
|
233
|
+
console.log("To start execution, run:");
|
|
234
|
+
console.log(kleur.cyan(` iris develop --resume ${runState.runId}`));
|
|
235
|
+
console.log("");
|
|
236
|
+
}
|
|
115
237
|
}
|
|
116
238
|
catch (error) {
|
|
117
|
-
|
|
239
|
+
if (opts.json) {
|
|
240
|
+
console.log(JSON.stringify({ error: error.message }, null, 2));
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
console.error(kleur.red(`\n✗ Planning Failed: ${error.message}`));
|
|
244
|
+
}
|
|
118
245
|
process.exit(1);
|
|
119
246
|
}
|
|
120
247
|
});
|
package/dist/commands/bridge.js
CHANGED
|
@@ -18,6 +18,14 @@ bridgeCommand
|
|
|
18
18
|
verbose: true
|
|
19
19
|
});
|
|
20
20
|
});
|
|
21
|
+
// iris bridge serve
|
|
22
|
+
bridgeCommand
|
|
23
|
+
.command("serve")
|
|
24
|
+
.description("Start automated agent (Simulates AI response)")
|
|
25
|
+
.action(async () => {
|
|
26
|
+
const { startAgentRunner } = await import("../bridge/agent-runner.js");
|
|
27
|
+
await startAgentRunner({ verbose: true });
|
|
28
|
+
});
|
|
21
29
|
// iris bridge status
|
|
22
30
|
bridgeCommand
|
|
23
31
|
.command("status")
|