project-iris 0.0.13 → 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 +261 -94
- 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,345 +0,0 @@
|
|
|
1
|
-
import kleur from "kleur";
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import { writeJsonAtomic } from "../fs/atomic.js";
|
|
4
|
-
import { InquirerIO } from "./interview-io.js";
|
|
5
|
-
import { ensureDir } from "../../lib.js";
|
|
6
|
-
import { getInboxPath, getHistoryDraftPath, getLatestDraftPath, getLegacyDraftPath } from "../paths.js";
|
|
7
|
-
import { createEmptyDraft, validateDraft } from "./intent-schema.js";
|
|
8
|
-
// --- Rubric Logic Moved to Schema/Shared or kept here? ---
|
|
9
|
-
// The prompt asked for logic in schema.ts? No, prompt asked for SCHEMA definition in schema.ts.
|
|
10
|
-
// Let's keep logic in schema.ts or here.
|
|
11
|
-
// Actually, `calculateConfidence` is better in `intent-schema.ts` if we want to test it easily without inquirer deps.
|
|
12
|
-
// But my previous `intent-schema.ts` didn't have `calculateConfidence`.
|
|
13
|
-
// I should probably move `calculateConfidence` into `intent-schema.ts` OR just import the type and keep logic here.
|
|
14
|
-
// To minimize changes to `intent-schema.ts` which I already wrote, I will keep `calculateConfidence` here
|
|
15
|
-
// BUT I need to make sure I use the types correctly.
|
|
16
|
-
// WAIT, I ALREADY WROTE `intent-schema.ts` WITHOUT `calculateConfidence`.
|
|
17
|
-
// So I will implement `calculateConfidence` here in this file, extending the one in schema if needed or just standalone.
|
|
18
|
-
// Re-defining locally to match the file I tried to write before
|
|
19
|
-
// ACTUALLY, checking `intent-schema.ts` content from Step 193... it does NOT have calculateConfidence.
|
|
20
|
-
// So I must implement it here.
|
|
21
|
-
export function formatIntentDraft(draft) {
|
|
22
|
-
return `
|
|
23
|
-
# Intent: ${draft.goal}
|
|
24
|
-
|
|
25
|
-
## Context
|
|
26
|
-
- **Target User:** ${draft.userType}
|
|
27
|
-
- **Project Phase:** ${draft.projectPhase}
|
|
28
|
-
- **Confidence:** ${draft.confidence.score}
|
|
29
|
-
|
|
30
|
-
## Success Criteria
|
|
31
|
-
${draft.successCriteria.length > 0 ? draft.successCriteria.map(c => `- ${c}`).join("\n") : "(None provided)"}
|
|
32
|
-
|
|
33
|
-
## Technical Constraints
|
|
34
|
-
${draft.constraints.map(c => `- ${c}`).join("\n")}
|
|
35
|
-
|
|
36
|
-
## Tooling Stack
|
|
37
|
-
${draft.tools.map(t => `- ${t}`).join("\n")}
|
|
38
|
-
|
|
39
|
-
## Additional Details
|
|
40
|
-
${draft.nonGoals.length > 0 ? `\n### Non-Goals\n${draft.nonGoals.map(x => `- ${x}`).join("\n")}` : ""}
|
|
41
|
-
${draft.acceptanceTests.length > 0 ? `\n### Acceptance Tests\n${draft.acceptanceTests.map(x => `- ${x}`).join("\n")}` : ""}
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
*Generated via IRIS Interactive Interview*
|
|
45
|
-
`.trim();
|
|
46
|
-
}
|
|
47
|
-
function calcConfidenceScore(draft) {
|
|
48
|
-
let score = 0;
|
|
49
|
-
const explanation = [];
|
|
50
|
-
// 1. Goal Clarity
|
|
51
|
-
if (draft.goal && draft.goal.split(" ").length > 3) {
|
|
52
|
-
score += 0.2;
|
|
53
|
-
explanation.push("+0.2 for clear goal statement");
|
|
54
|
-
}
|
|
55
|
-
else if (draft.goal) {
|
|
56
|
-
score += 0.1;
|
|
57
|
-
explanation.push("+0.1 for goal presence");
|
|
58
|
-
}
|
|
59
|
-
const successLen = draft.successCriteria?.length || 0;
|
|
60
|
-
if (successLen > 0) {
|
|
61
|
-
score += 0.2;
|
|
62
|
-
explanation.push(`+0.2 for ${successLen} success criteria`);
|
|
63
|
-
}
|
|
64
|
-
const acceptLen = draft.acceptanceTests?.length || 0;
|
|
65
|
-
if (acceptLen > 0) {
|
|
66
|
-
score += 0.1;
|
|
67
|
-
explanation.push(`+0.1 for ${acceptLen} acceptance tests`);
|
|
68
|
-
}
|
|
69
|
-
if (draft.constraints && draft.constraints.length > 0) {
|
|
70
|
-
score += 0.1;
|
|
71
|
-
explanation.push("+0.1 for identified constraints");
|
|
72
|
-
}
|
|
73
|
-
if (draft.tools && draft.tools.length > 0) {
|
|
74
|
-
score += 0.1;
|
|
75
|
-
explanation.push("+0.1 for tool selection");
|
|
76
|
-
}
|
|
77
|
-
if (draft.nonGoals && draft.nonGoals.length > 0) {
|
|
78
|
-
score += 0.1;
|
|
79
|
-
explanation.push("+0.1 for explicit non-goals");
|
|
80
|
-
}
|
|
81
|
-
if (draft.userType && draft.projectPhase) {
|
|
82
|
-
score += 0.1;
|
|
83
|
-
explanation.push("+0.1 for user context & phase");
|
|
84
|
-
}
|
|
85
|
-
score = Math.min(1.0, Math.max(0, Math.round(score * 10) / 10));
|
|
86
|
-
return { score, explanation };
|
|
87
|
-
}
|
|
88
|
-
// Export for tests if needed, but the main export is runIntentInterview
|
|
89
|
-
export { calcConfidenceScore as calculateConfidence };
|
|
90
|
-
// --- Interview Logic ---
|
|
91
|
-
export async function runIntentInterview(initialIntent, config, existingDraft, io = new InquirerIO()) {
|
|
92
|
-
io.header("\n🎤 Interactive Intent Interview");
|
|
93
|
-
if (config?.guidance?.systemNotes) {
|
|
94
|
-
io.print(kleur.dim(config.guidance.systemNotes));
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
97
|
-
io.print(kleur.dim("Let's clarify your goals before we start building.\n"));
|
|
98
|
-
}
|
|
99
|
-
const draftPartial = existingDraft ? { ...existingDraft } : createEmptyDraft();
|
|
100
|
-
// If we have an existing draft, we assume we are resuming/refining, so we don't overwrite unless intent is new?
|
|
101
|
-
// Actually if initialIntent is provided on resume, it might be the "follow up prompt" context, which isn't a draft field.
|
|
102
|
-
// But draftPartial.goal is the high level goal.
|
|
103
|
-
if (!existingDraft && initialIntent) {
|
|
104
|
-
draftPartial.goal = initialIntent;
|
|
105
|
-
}
|
|
106
|
-
// 1. Goal (Skip if exists)
|
|
107
|
-
if (!draftPartial.goal) {
|
|
108
|
-
const { goal } = await io.ask([
|
|
109
|
-
{
|
|
110
|
-
type: "input",
|
|
111
|
-
name: "goal",
|
|
112
|
-
message: config?.guidance?.starterQuestions?.[0] || "What are you trying to build?",
|
|
113
|
-
validate: (input) => input.trim().length > 0 || "Please provide a goal."
|
|
114
|
-
}
|
|
115
|
-
]);
|
|
116
|
-
draftPartial.goal = goal;
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
// If resuming or passed in arg
|
|
120
|
-
io.print(`${kleur.cyan("? ")}Goal: ${kleur.cyan(draftPartial.goal || "")}`);
|
|
121
|
-
}
|
|
122
|
-
// 2. User & Phase
|
|
123
|
-
const context = await io.ask([
|
|
124
|
-
{
|
|
125
|
-
type: "list",
|
|
126
|
-
name: "userType",
|
|
127
|
-
message: "Who is the primary user?",
|
|
128
|
-
choices: [
|
|
129
|
-
"Individual Developer",
|
|
130
|
-
"Team / Connectors",
|
|
131
|
-
"Enterprise / Organization",
|
|
132
|
-
"End Consumers"
|
|
133
|
-
]
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
type: "list",
|
|
137
|
-
name: "projectPhase",
|
|
138
|
-
message: "What phase is this project in?",
|
|
139
|
-
choices: [
|
|
140
|
-
{ name: "Inception (New Idea)", value: "Inception" },
|
|
141
|
-
{ name: "Construction (Active Dev)", value: "Construction" },
|
|
142
|
-
{ name: "Operations (Maintenance)", value: "Operations" }
|
|
143
|
-
]
|
|
144
|
-
}
|
|
145
|
-
]);
|
|
146
|
-
Object.assign(draftPartial, context);
|
|
147
|
-
// 3. Success Criteria (Required)
|
|
148
|
-
io.print("\n" + kleur.bold("Success Criteria"));
|
|
149
|
-
// Loop until we have at least one criteria (Enforcement)
|
|
150
|
-
while (true) {
|
|
151
|
-
io.print(kleur.dim("What must be true for this to be considered done? (Enter empty line to finish)"));
|
|
152
|
-
const criteria = [];
|
|
153
|
-
if (draftPartial.successCriteria)
|
|
154
|
-
criteria.push(...draftPartial.successCriteria);
|
|
155
|
-
while (true) {
|
|
156
|
-
const { item } = await io.ask([{
|
|
157
|
-
type: "input",
|
|
158
|
-
name: "item",
|
|
159
|
-
message: `Criterion ${criteria.length + 1}:`
|
|
160
|
-
}]);
|
|
161
|
-
if (!item.trim())
|
|
162
|
-
break;
|
|
163
|
-
criteria.push(item.trim());
|
|
164
|
-
}
|
|
165
|
-
draftPartial.successCriteria = criteria;
|
|
166
|
-
if (criteria.length === 0) {
|
|
167
|
-
io.warn("⚠ At least one Success Criterion is required.");
|
|
168
|
-
const { retry } = await io.ask([{
|
|
169
|
-
type: "confirm",
|
|
170
|
-
name: "retry",
|
|
171
|
-
message: "Try adding criteria again?",
|
|
172
|
-
default: true
|
|
173
|
-
}]);
|
|
174
|
-
if (!retry) {
|
|
175
|
-
io.warn("Cannot proceed without success criteria. Interview cancelled.");
|
|
176
|
-
return null;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
else {
|
|
180
|
-
break;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
// 4. Constraints (Multi-select)
|
|
184
|
-
const { constraints } = await io.ask([
|
|
185
|
-
{
|
|
186
|
-
type: "checkbox",
|
|
187
|
-
name: "constraints",
|
|
188
|
-
message: "What constraints matter most?",
|
|
189
|
-
choices: [
|
|
190
|
-
"Time (Speed to Market)",
|
|
191
|
-
"Quality (Robustness)",
|
|
192
|
-
"Compliance / Security",
|
|
193
|
-
"Performance",
|
|
194
|
-
"Cost / Budget",
|
|
195
|
-
"Simplicity"
|
|
196
|
-
]
|
|
197
|
-
}
|
|
198
|
-
]);
|
|
199
|
-
draftPartial.constraints = constraints;
|
|
200
|
-
// 5. Tools
|
|
201
|
-
const { tools } = await io.ask([
|
|
202
|
-
{
|
|
203
|
-
type: "checkbox",
|
|
204
|
-
name: "tools",
|
|
205
|
-
message: "Which tools/platforms are involved?",
|
|
206
|
-
choices: [
|
|
207
|
-
{ name: "Node.js / TypeScript", checked: true },
|
|
208
|
-
"Python",
|
|
209
|
-
"React / Frontend",
|
|
210
|
-
"Docker / K8s",
|
|
211
|
-
"AWS / Cloud",
|
|
212
|
-
"Database (SQL/NoSQL)"
|
|
213
|
-
]
|
|
214
|
-
}
|
|
215
|
-
]);
|
|
216
|
-
draftPartial.tools = tools;
|
|
217
|
-
// 6. Optional Fields
|
|
218
|
-
const { addMore } = await io.ask([{
|
|
219
|
-
type: "confirm",
|
|
220
|
-
name: "addMore",
|
|
221
|
-
message: "Add non-goals, risks, or acceptance tests? (Optional)",
|
|
222
|
-
default: false
|
|
223
|
-
}]);
|
|
224
|
-
if (addMore) {
|
|
225
|
-
// Non Goals
|
|
226
|
-
io.print("\n" + kleur.bold("Non-Goals (What are we NOT doing?)"));
|
|
227
|
-
while (true) {
|
|
228
|
-
const { item } = await io.ask([{ type: "input", name: "item", message: ">" }]);
|
|
229
|
-
if (!item.trim())
|
|
230
|
-
break;
|
|
231
|
-
if (!draftPartial.nonGoals)
|
|
232
|
-
draftPartial.nonGoals = [];
|
|
233
|
-
draftPartial.nonGoals.push(item.trim());
|
|
234
|
-
}
|
|
235
|
-
// Acceptance Tests
|
|
236
|
-
io.print("\n" + kleur.bold("Acceptance Tests (How will we verify?)"));
|
|
237
|
-
while (true) {
|
|
238
|
-
const { item } = await io.ask([{ type: "input", name: "item", message: ">" }]);
|
|
239
|
-
if (!item.trim())
|
|
240
|
-
break;
|
|
241
|
-
if (!draftPartial.acceptanceTests)
|
|
242
|
-
draftPartial.acceptanceTests = [];
|
|
243
|
-
draftPartial.acceptanceTests.push(item.trim());
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
// Calculate Confidence
|
|
247
|
-
const rubric = calcConfidenceScore(draftPartial);
|
|
248
|
-
// Assemble final draft
|
|
249
|
-
const draft = {
|
|
250
|
-
...createEmptyDraft(),
|
|
251
|
-
...draftPartial,
|
|
252
|
-
confidence: rubric,
|
|
253
|
-
// Ensure successCriteria is array
|
|
254
|
-
successCriteria: draftPartial.successCriteria || [],
|
|
255
|
-
createdAt: new Date().toISOString()
|
|
256
|
-
};
|
|
257
|
-
// Summary
|
|
258
|
-
io.divider();
|
|
259
|
-
io.header("📋 Intent Summary");
|
|
260
|
-
io.print(`Goal: ${draft.goal}`);
|
|
261
|
-
io.print(`Context: ${draft.userType} / ${draft.projectPhase}`);
|
|
262
|
-
io.print(`Criteria: ${draft.successCriteria.length} items`);
|
|
263
|
-
io.print(`Tools: ${draft.tools.join(", ")}`);
|
|
264
|
-
io.print("");
|
|
265
|
-
const scoreColor = draft.confidence.score > 0.7 ? kleur.green : draft.confidence.score > 0.4 ? kleur.yellow : kleur.red;
|
|
266
|
-
io.print(`Confidence Score: ${scoreColor(draft.confidence.score.toFixed(2) + " / 1.0")}`);
|
|
267
|
-
draft.confidence.explanation.forEach(exp => io.print(kleur.dim(` ${exp}`)));
|
|
268
|
-
io.divider();
|
|
269
|
-
// Validation check
|
|
270
|
-
const val = validateDraft(draft);
|
|
271
|
-
if (!val.valid) {
|
|
272
|
-
io.warn(kleur.red("Draft validation failed:"));
|
|
273
|
-
val.errors.forEach(e => io.print(`- ${e}`));
|
|
274
|
-
io.print("Please restart or fix inputs.");
|
|
275
|
-
return null;
|
|
276
|
-
}
|
|
277
|
-
const { confirm } = await io.ask([
|
|
278
|
-
{
|
|
279
|
-
type: "confirm",
|
|
280
|
-
name: "confirm",
|
|
281
|
-
message: "Do you want to generate intent artifacts now?",
|
|
282
|
-
default: true
|
|
283
|
-
}
|
|
284
|
-
]);
|
|
285
|
-
if (!confirm) {
|
|
286
|
-
io.warn("Interview cancelled. No artifacts generated.");
|
|
287
|
-
return null;
|
|
288
|
-
}
|
|
289
|
-
return draft;
|
|
290
|
-
}
|
|
291
|
-
/**
|
|
292
|
-
* Saves intent draft enforcing schema.
|
|
293
|
-
* @param writeLegacy If true, also writes .iris/inbox/intent-draft.json (deprecated)
|
|
294
|
-
*/
|
|
295
|
-
export function saveIntentDraft(root, draft, writeLegacy = false) {
|
|
296
|
-
const inboxDir = getInboxPath(root);
|
|
297
|
-
ensureDir(inboxDir);
|
|
298
|
-
// Enforce Schema Defaults & Versioning
|
|
299
|
-
const fullDraft = {
|
|
300
|
-
...createEmptyDraft(),
|
|
301
|
-
...draft,
|
|
302
|
-
createdAt: draft.createdAt || new Date().toISOString()
|
|
303
|
-
};
|
|
304
|
-
// Recalculate confidence if missing
|
|
305
|
-
if (!draft.confidence) {
|
|
306
|
-
fullDraft.confidence = calcConfidenceScore(fullDraft);
|
|
307
|
-
}
|
|
308
|
-
// 1. Save History
|
|
309
|
-
const historyFile = getHistoryDraftPath(root, new Date(fullDraft.createdAt));
|
|
310
|
-
// 2. Save Latest (Canonical)
|
|
311
|
-
const latestFile = getLatestDraftPath(root);
|
|
312
|
-
writeJsonAtomic(historyFile, fullDraft);
|
|
313
|
-
writeJsonAtomic(latestFile, fullDraft);
|
|
314
|
-
// 3. Optional Legacy
|
|
315
|
-
if (writeLegacy) {
|
|
316
|
-
const legacyFile = getLegacyDraftPath(root);
|
|
317
|
-
writeJsonAtomic(legacyFile, fullDraft);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Migrates legacy intent-draft.json to intent-draft.latest.json.
|
|
322
|
-
*/
|
|
323
|
-
export function migrateLegacyDraft(root) {
|
|
324
|
-
const legacyFile = getLegacyDraftPath(root);
|
|
325
|
-
const latestFile = getLatestDraftPath(root);
|
|
326
|
-
if (fs.existsSync(legacyFile) && !fs.existsSync(latestFile)) {
|
|
327
|
-
try {
|
|
328
|
-
const content = JSON.parse(fs.readFileSync(legacyFile, "utf-8"));
|
|
329
|
-
// Enforce schema by saving via normalized function
|
|
330
|
-
// Treat content as partial
|
|
331
|
-
if (!content.successCriteria) {
|
|
332
|
-
content.successCriteria = ["(Migrated from legacy draft)"];
|
|
333
|
-
}
|
|
334
|
-
// Re-save (generates latest + history)
|
|
335
|
-
// Do NOT write legacy again (avoid loop), so writeLegacy=false
|
|
336
|
-
saveIntentDraft(root, content, false);
|
|
337
|
-
return true;
|
|
338
|
-
}
|
|
339
|
-
catch (e) {
|
|
340
|
-
console.error(kleur.red(`Failed to migrate legacy draft: ${e}`));
|
|
341
|
-
return false;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
return false;
|
|
345
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
export const CURRENT_SCHEMA_VERSION = "1";
|
|
2
|
-
export function createEmptyDraft() {
|
|
3
|
-
return {
|
|
4
|
-
version: CURRENT_SCHEMA_VERSION,
|
|
5
|
-
createdAt: new Date().toISOString(),
|
|
6
|
-
goal: "",
|
|
7
|
-
userType: "",
|
|
8
|
-
projectPhase: "",
|
|
9
|
-
constraints: [],
|
|
10
|
-
tools: [],
|
|
11
|
-
successCriteria: [],
|
|
12
|
-
nonGoals: [],
|
|
13
|
-
assumptions: [],
|
|
14
|
-
risks: [],
|
|
15
|
-
acceptanceTests: [],
|
|
16
|
-
confidence: { score: 0, explanation: [] }
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
export function validateDraft(draft) {
|
|
20
|
-
const errors = [];
|
|
21
|
-
if (!draft.goal)
|
|
22
|
-
errors.push("Goal is required");
|
|
23
|
-
if (!draft.successCriteria || draft.successCriteria.length === 0) {
|
|
24
|
-
errors.push("At least one Success Criterion is required");
|
|
25
|
-
}
|
|
26
|
-
// We can add more strict checks here if needed
|
|
27
|
-
return { valid: errors.length === 0, errors };
|
|
28
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import inquirer from "inquirer";
|
|
2
|
-
import kleur from "kleur";
|
|
3
|
-
export class InquirerIO {
|
|
4
|
-
async ask(questions) {
|
|
5
|
-
// map Question interface to inquirer question
|
|
6
|
-
// Inquirer types are slightly different, but compatible enough for pass-through usually
|
|
7
|
-
const answers = await inquirer.prompt(questions);
|
|
8
|
-
return answers;
|
|
9
|
-
}
|
|
10
|
-
print(message) {
|
|
11
|
-
console.log(message);
|
|
12
|
-
}
|
|
13
|
-
header(text) {
|
|
14
|
-
console.log(kleur.bold(text));
|
|
15
|
-
}
|
|
16
|
-
divider() {
|
|
17
|
-
console.log(kleur.dim("=========================================="));
|
|
18
|
-
}
|
|
19
|
-
warn(message) {
|
|
20
|
-
console.log(kleur.yellow(message));
|
|
21
|
-
}
|
|
22
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import yaml from "js-yaml";
|
|
3
|
-
import kleur from "kleur";
|
|
4
|
-
import { KNOWN_INTENT_FIELDS } from "./types.js";
|
|
5
|
-
export const DEFAULT_INTERVIEW_CONFIG = {
|
|
6
|
-
schemaVersion: 1,
|
|
7
|
-
required: ["successCriteria", "user", "problem"],
|
|
8
|
-
optional: ["nonGoals", "risks", "acceptanceTests"],
|
|
9
|
-
guidance: {
|
|
10
|
-
systemNotes: "You are a Product Manager / Business Analyst. Ask clarifying questions.",
|
|
11
|
-
starterQuestions: [
|
|
12
|
-
"Who is the user and what problem are we solving?",
|
|
13
|
-
"What does success look like (measurable)?",
|
|
14
|
-
"What are the constraints (time, budget, tech, legal)?"
|
|
15
|
-
],
|
|
16
|
-
redFlags: ["Ambiguous scope", "No success metric"]
|
|
17
|
-
},
|
|
18
|
-
weights: {
|
|
19
|
-
successCriteria: 3,
|
|
20
|
-
risks: 2
|
|
21
|
-
},
|
|
22
|
-
fieldPrompts: {
|
|
23
|
-
successCriteria: "What does success look like? How will we measure it?",
|
|
24
|
-
user: "Who is the specific user for this feature?",
|
|
25
|
-
problem: "What core problem are we solving?",
|
|
26
|
-
risks: "Are there any risks or non-goals we should state?",
|
|
27
|
-
constraints: "Are there any technical or budget constraints?"
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
export function loadEffectiveInterviewConfig(framework) {
|
|
31
|
-
if (!framework || !framework.files.interview || !fs.existsSync(framework.files.interview)) {
|
|
32
|
-
return DEFAULT_INTERVIEW_CONFIG;
|
|
33
|
-
}
|
|
34
|
-
try {
|
|
35
|
-
const content = fs.readFileSync(framework.files.interview, "utf8");
|
|
36
|
-
const raw = yaml.load(content);
|
|
37
|
-
// 1. Schema Version Check
|
|
38
|
-
if (raw.schemaVersion !== 1) {
|
|
39
|
-
console.error(kleur.yellow(`IRIS_WARNING: Unsupported interview schema version ${raw.schemaVersion}. Using default.`));
|
|
40
|
-
return DEFAULT_INTERVIEW_CONFIG;
|
|
41
|
-
}
|
|
42
|
-
// 2. Strict Field Validation
|
|
43
|
-
const allFields = [...(raw.required || []), ...(raw.optional || [])];
|
|
44
|
-
const unknownFields = allFields.filter(f => !KNOWN_INTENT_FIELDS.has(f));
|
|
45
|
-
if (unknownFields.length > 0) {
|
|
46
|
-
console.error(kleur.yellow(`IRIS_WARNING: Invalid interview configuration. Unknown fields: ${unknownFields.join(", ")}. Using default.`));
|
|
47
|
-
return DEFAULT_INTERVIEW_CONFIG;
|
|
48
|
-
}
|
|
49
|
-
// 3. Merge with minimal defaults (or just return raw if we trust it completely?)
|
|
50
|
-
// The plan says "If invalid/missing return DEFAULT".
|
|
51
|
-
// But if valid, we return the parsed object.
|
|
52
|
-
// Should we merge fieldPrompts if missing?
|
|
53
|
-
// Best to provide safety defaults for prompts if not overridden.
|
|
54
|
-
return {
|
|
55
|
-
schemaVersion: raw.schemaVersion,
|
|
56
|
-
required: raw.required || [],
|
|
57
|
-
optional: raw.optional || [],
|
|
58
|
-
guidance: {
|
|
59
|
-
systemNotes: raw.guidance?.systemNotes || DEFAULT_INTERVIEW_CONFIG.guidance.systemNotes,
|
|
60
|
-
starterQuestions: raw.guidance?.starterQuestions || DEFAULT_INTERVIEW_CONFIG.guidance.starterQuestions,
|
|
61
|
-
redFlags: raw.guidance?.redFlags || DEFAULT_INTERVIEW_CONFIG.guidance.redFlags
|
|
62
|
-
},
|
|
63
|
-
weights: raw.weights || {},
|
|
64
|
-
fieldPrompts: { ...DEFAULT_INTERVIEW_CONFIG.fieldPrompts, ...raw.fieldPrompts }
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
catch (e) {
|
|
68
|
-
console.error(kleur.yellow(`IRIS_WARNING: Failed to parse interview.yaml: ${e.message}. Using default.`));
|
|
69
|
-
return DEFAULT_INTERVIEW_CONFIG;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export const KNOWN_INTENT_FIELDS = new Set([
|
|
2
|
-
'successCriteria',
|
|
3
|
-
'user',
|
|
4
|
-
'problem',
|
|
5
|
-
'constraints',
|
|
6
|
-
'nonGoals',
|
|
7
|
-
'risks',
|
|
8
|
-
'acceptanceTests',
|
|
9
|
-
'context',
|
|
10
|
-
'context.user',
|
|
11
|
-
'context.phase',
|
|
12
|
-
'visuals',
|
|
13
|
-
'name', // Sometimes inferred, but valid
|
|
14
|
-
'description', // Basic
|
|
15
|
-
'features', // High level
|
|
16
|
-
]);
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Access a value in an object via dot-notation.
|
|
3
|
-
* Safe traversal: returns undefined if path breaks.
|
|
4
|
-
*/
|
|
5
|
-
export function getByPath(obj, path) {
|
|
6
|
-
if (!obj)
|
|
7
|
-
return undefined;
|
|
8
|
-
const parts = path.split('.');
|
|
9
|
-
let current = obj;
|
|
10
|
-
for (const part of parts) {
|
|
11
|
-
if (current === null || current === undefined)
|
|
12
|
-
return undefined;
|
|
13
|
-
current = current[part];
|
|
14
|
-
}
|
|
15
|
-
return current;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Checks if a value is "missing" according to strict interview rules.
|
|
19
|
-
* Missing = null, undefined, empty string "", whitespace-only string, or empty array [].
|
|
20
|
-
*/
|
|
21
|
-
export function isMissing(value) {
|
|
22
|
-
if (value === null || value === undefined)
|
|
23
|
-
return true;
|
|
24
|
-
if (typeof value === 'string')
|
|
25
|
-
return value.trim().length === 0;
|
|
26
|
-
if (Array.isArray(value))
|
|
27
|
-
return value.length === 0;
|
|
28
|
-
// Objects? We typically check leaf nodes, but an empty object {} usually counts as present for 'context'
|
|
29
|
-
// UNLESS the requirement is specifically context.user.
|
|
30
|
-
// So for generic objects, existence is enough.
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Returns a list of required fields that are missing in the draft.
|
|
35
|
-
*/
|
|
36
|
-
export function getMissingFields(draft, requiredFields) {
|
|
37
|
-
return requiredFields.filter(field => isMissing(getByPath(draft, field)));
|
|
38
|
-
}
|
package/dist/iris/manifest.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import yaml from "js-yaml";
|
|
4
|
-
import { writeFile } from "../lib.js";
|
|
5
|
-
const MANIFEST_PATH = path.join(process.cwd(), ".iris/manifest.yaml");
|
|
6
|
-
export function loadManifest() {
|
|
7
|
-
if (!fs.existsSync(MANIFEST_PATH))
|
|
8
|
-
return null;
|
|
9
|
-
try {
|
|
10
|
-
const doc = yaml.load(fs.readFileSync(MANIFEST_PATH, "utf8"));
|
|
11
|
-
// Basic migration/defaulting if needed
|
|
12
|
-
return {
|
|
13
|
-
version: 1,
|
|
14
|
-
installed_at: new Date().toISOString(),
|
|
15
|
-
tools_selected: [],
|
|
16
|
-
paths_installed: [],
|
|
17
|
-
created_dirs: [],
|
|
18
|
-
...doc
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
catch (e) {
|
|
22
|
-
console.error("Failed to parse manifest:", e);
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
export function saveManifest(manifest) {
|
|
27
|
-
writeFile(MANIFEST_PATH, yaml.dump(manifest));
|
|
28
|
-
}
|
|
29
|
-
export function updateManifest(updates) {
|
|
30
|
-
const current = loadManifest() || {
|
|
31
|
-
version: 1,
|
|
32
|
-
installed_at: new Date().toISOString(),
|
|
33
|
-
tools_selected: [],
|
|
34
|
-
paths_installed: [],
|
|
35
|
-
created_dirs: [],
|
|
36
|
-
};
|
|
37
|
-
const updated = {
|
|
38
|
-
...current,
|
|
39
|
-
...updates,
|
|
40
|
-
installed_at: new Date().toISOString(), // Always update timestamp
|
|
41
|
-
tools_selected: Array.from(new Set([...current.tools_selected, ...(updates.tools_selected || [])])),
|
|
42
|
-
paths_installed: mergePaths(current.paths_installed, updates.paths_installed || []),
|
|
43
|
-
created_dirs: Array.from(new Set([...current.created_dirs, ...(updates.created_dirs || [])])),
|
|
44
|
-
};
|
|
45
|
-
saveManifest(updated);
|
|
46
|
-
}
|
|
47
|
-
function mergePaths(current, updates) {
|
|
48
|
-
// Map current paths by path string for easy update
|
|
49
|
-
const map = new Map();
|
|
50
|
-
current.forEach(p => map.set(p.path, p));
|
|
51
|
-
// Apply updates
|
|
52
|
-
updates.forEach(p => map.set(p.path, p));
|
|
53
|
-
return Array.from(map.values());
|
|
54
|
-
}
|