infernoflow 0.10.13 → 0.10.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/dist/bin/infernoflow.mjs +68 -0
- package/dist/lib/ai/ideDetection.mjs +1 -0
- package/dist/lib/ai/localProvider.mjs +1 -0
- package/dist/lib/ai/providerRouter.mjs +1 -0
- package/dist/lib/commands/adopt.mjs +20 -0
- package/dist/lib/commands/check.mjs +3 -0
- package/dist/lib/commands/context.mjs +20 -0
- package/dist/lib/commands/docGate.mjs +2 -0
- package/dist/lib/commands/implement.mjs +7 -0
- package/dist/lib/commands/init.mjs +17 -0
- package/dist/lib/commands/installCursorHooks.mjs +1 -0
- package/dist/lib/commands/installVsCodeCopilotHooks.mjs +1 -0
- package/dist/lib/commands/prImpact.mjs +2 -0
- package/dist/lib/commands/run.mjs +10 -0
- package/dist/lib/commands/status.mjs +4 -0
- package/dist/lib/commands/suggest.mjs +62 -0
- package/dist/lib/commands/syncAuto.mjs +1 -0
- package/dist/lib/cursorHooksInstall.mjs +1 -0
- package/dist/lib/draftToolingInstall.mjs +8 -0
- package/dist/lib/ui/output.mjs +6 -0
- package/dist/lib/ui/prompts.mjs +6 -0
- package/dist/lib/vsCodeCopilotHooksInstall.mjs +1 -0
- package/package.json +48 -44
- package/bin/infernoflow.mjs +0 -138
- package/lib/ai/ideDetection.mjs +0 -31
- package/lib/ai/localProvider.mjs +0 -88
- package/lib/ai/providerRouter.mjs +0 -73
- package/lib/commands/adopt.mjs +0 -768
- package/lib/commands/check.mjs +0 -179
- package/lib/commands/context.mjs +0 -164
- package/lib/commands/docGate.mjs +0 -81
- package/lib/commands/implement.mjs +0 -103
- package/lib/commands/init.mjs +0 -401
- package/lib/commands/installCursorHooks.mjs +0 -36
- package/lib/commands/installVsCodeCopilotHooks.mjs +0 -37
- package/lib/commands/prImpact.mjs +0 -157
- package/lib/commands/run.mjs +0 -338
- package/lib/commands/status.mjs +0 -172
- package/lib/commands/suggest.mjs +0 -501
- package/lib/commands/syncAuto.mjs +0 -96
- package/lib/cursorHooksInstall.mjs +0 -39
- package/lib/draftToolingInstall.mjs +0 -69
- package/lib/ui/output.mjs +0 -72
- package/lib/ui/prompts.mjs +0 -147
- package/lib/vsCodeCopilotHooksInstall.mjs +0 -42
- /package/{templates → dist/templates}/ci/github-inferno-check.yml +0 -0
- /package/{templates → dist/templates}/cursor/hooks/inferno-session-draft.mjs +0 -0
- /package/{templates → dist/templates}/cursor/hooks.json +0 -0
- /package/{templates → dist/templates}/github-hooks/infernoflow-drafts.json +0 -0
- /package/{templates → dist/templates}/inferno/CHANGELOG.md +0 -0
- /package/{templates → dist/templates}/inferno/capabilities.json +0 -0
- /package/{templates → dist/templates}/inferno/contract.json +0 -0
- /package/{templates → dist/templates}/inferno/scenarios/happy_path.json +0 -0
- /package/{templates → dist/templates}/scripts/inferno-doc-gate.mjs +0 -0
- /package/{templates → dist/templates}/scripts/inferno-install-hooks.mjs +0 -0
- /package/{templates → dist/templates}/scripts/inferno-promote-draft.mjs +0 -0
- /package/{templates → dist/templates}/scripts/inferno-vscode-copilot-hook.mjs +0 -0
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
|
|
4
|
-
const GITIGNORE_SNIPPET = `
|
|
5
|
-
# infernoflow: agent draft (IDE hooks — review before commit)
|
|
6
|
-
inferno/CONTEXT.draft.md
|
|
7
|
-
`.trimStart();
|
|
8
|
-
|
|
9
|
-
function upsertPromoteScript(cwd, silent, logOk) {
|
|
10
|
-
const pkgPath = path.join(cwd, "package.json");
|
|
11
|
-
if (!fs.existsSync(pkgPath)) {
|
|
12
|
-
if (!silent) logOk("No package.json — add script manually: inferno:promote-draft");
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
16
|
-
pkg.scripts = pkg.scripts || {};
|
|
17
|
-
if (!pkg.scripts["inferno:promote-draft"]) {
|
|
18
|
-
pkg.scripts["inferno:promote-draft"] = "node scripts/inferno-promote-draft.mjs";
|
|
19
|
-
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
20
|
-
if (!silent) logOk("Updated package.json script: inferno:promote-draft");
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* inferno/CONTEXT.draft.md gitignore + promote script (shared by Cursor and VS Code installers).
|
|
26
|
-
* @param {object} opts
|
|
27
|
-
* @param {string} opts.cwd
|
|
28
|
-
* @param {string} opts.templatesRoot
|
|
29
|
-
* @param {boolean} opts.force
|
|
30
|
-
* @param {boolean} opts.silent
|
|
31
|
-
* @param {(msg: string) => void} [opts.logOk]
|
|
32
|
-
* @param {(msg: string) => void} [opts.logWarn]
|
|
33
|
-
*/
|
|
34
|
-
export function installInfernoDraftTooling(opts) {
|
|
35
|
-
const { cwd, templatesRoot, force, silent } = opts;
|
|
36
|
-
const logOk = opts.logOk || (() => {});
|
|
37
|
-
const logWarn = opts.logWarn || (() => {});
|
|
38
|
-
|
|
39
|
-
function copyFile(src, dst) {
|
|
40
|
-
if (fs.existsSync(dst) && !force) {
|
|
41
|
-
if (!silent) logWarn("Skipped (exists): " + path.relative(cwd, dst));
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
fs.mkdirSync(path.dirname(dst), { recursive: true });
|
|
45
|
-
fs.copyFileSync(src, dst);
|
|
46
|
-
if (!silent) logOk("Created: " + path.relative(cwd, dst));
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const srcPromote = path.join(templatesRoot, "scripts", "inferno-promote-draft.mjs");
|
|
51
|
-
const dstPromote = path.join(cwd, "scripts", "inferno-promote-draft.mjs");
|
|
52
|
-
copyFile(srcPromote, dstPromote);
|
|
53
|
-
|
|
54
|
-
upsertPromoteScript(cwd, silent, logOk);
|
|
55
|
-
|
|
56
|
-
const gi = path.join(cwd, ".gitignore");
|
|
57
|
-
if (fs.existsSync(gi)) {
|
|
58
|
-
const cur = fs.readFileSync(gi, "utf8");
|
|
59
|
-
if (cur.includes("CONTEXT.draft.md")) {
|
|
60
|
-
if (!silent) logOk(".gitignore already mentions CONTEXT.draft.md");
|
|
61
|
-
} else {
|
|
62
|
-
fs.appendFileSync(gi, `\n${GITIGNORE_SNIPPET}\n`, "utf8");
|
|
63
|
-
if (!silent) logOk("Updated: " + path.relative(cwd, gi));
|
|
64
|
-
}
|
|
65
|
-
} else {
|
|
66
|
-
fs.writeFileSync(gi, `${GITIGNORE_SNIPPET}\n`, "utf8");
|
|
67
|
-
if (!silent) logOk("Created: " + path.relative(cwd, gi));
|
|
68
|
-
}
|
|
69
|
-
}
|
package/lib/ui/output.mjs
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
// Zero-dependency color/output utilities using ANSI codes
|
|
2
|
-
|
|
3
|
-
const c = {
|
|
4
|
-
reset: "\x1b[0m",
|
|
5
|
-
bold: "\x1b[1m",
|
|
6
|
-
red: "\x1b[31m",
|
|
7
|
-
green: "\x1b[32m",
|
|
8
|
-
yellow: "\x1b[33m",
|
|
9
|
-
blue: "\x1b[34m",
|
|
10
|
-
cyan: "\x1b[36m",
|
|
11
|
-
white: "\x1b[37m",
|
|
12
|
-
gray: "\x1b[90m",
|
|
13
|
-
orange: "\x1b[38;5;208m",
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const noColor = !process.stdout.isTTY || process.env.NO_COLOR;
|
|
17
|
-
|
|
18
|
-
function paint(code, text) {
|
|
19
|
-
if (noColor) return text;
|
|
20
|
-
return `${code}${text}${c.reset}`;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export const bold = t => paint(c.bold, t);
|
|
24
|
-
export const red = t => paint(c.red, t);
|
|
25
|
-
export const green = t => paint(c.green, t);
|
|
26
|
-
export const yellow = t => paint(c.yellow, t);
|
|
27
|
-
export const cyan = t => paint(c.cyan, t);
|
|
28
|
-
export const gray = t => paint(c.gray, t);
|
|
29
|
-
export const white = t => paint(c.white, t);
|
|
30
|
-
export const orange = t => paint(c.orange, t);
|
|
31
|
-
export const boldRed = t => paint(c.bold + c.red, t);
|
|
32
|
-
export const boldGreen = t => paint(c.bold + c.green, t);
|
|
33
|
-
export const boldYellow = t => paint(c.bold + c.yellow, t);
|
|
34
|
-
export const boldOrange = t => paint(c.bold + c.orange, t);
|
|
35
|
-
|
|
36
|
-
function strip(str) {
|
|
37
|
-
return str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function header(text) {
|
|
41
|
-
const title = boldOrange("🔥 infernoflow") + gray(" — " + text);
|
|
42
|
-
console.log("\n" + title);
|
|
43
|
-
console.log(gray("─".repeat(50)));
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function ok(msg) { console.log(" " + green("✔") + " " + msg); }
|
|
47
|
-
export function fail(msg, hint) {
|
|
48
|
-
console.log(" " + red("✘") + " " + red(msg));
|
|
49
|
-
if (hint) console.log(" " + gray("→ " + hint));
|
|
50
|
-
}
|
|
51
|
-
export function warn(msg) { console.log(" " + yellow("⚠") + " " + yellow(msg)); }
|
|
52
|
-
export function info(msg) { console.log(" " + cyan("ℹ") + " " + msg); }
|
|
53
|
-
export function section(title) { console.log("\n" + bold(white(title))); }
|
|
54
|
-
|
|
55
|
-
export function done(msg) {
|
|
56
|
-
console.log("\n" + boldGreen("✨ " + msg) + "\n");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function nextSteps(steps) {
|
|
60
|
-
console.log(bold("Next steps:"));
|
|
61
|
-
steps.forEach((s, i) => {
|
|
62
|
-
console.log(" " + gray((i + 1) + ".") + " " + s);
|
|
63
|
-
});
|
|
64
|
-
console.log();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function errorAndExit(msg, hint) {
|
|
68
|
-
console.error("\n" + boldRed("Error: ") + red(msg));
|
|
69
|
-
if (hint) console.error(gray(" → " + hint));
|
|
70
|
-
console.error();
|
|
71
|
-
process.exit(1);
|
|
72
|
-
}
|
package/lib/ui/prompts.mjs
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
// Zero-dependency interactive prompts using readline
|
|
2
|
-
|
|
3
|
-
import * as readline from "node:readline";
|
|
4
|
-
import * as fs from "node:fs";
|
|
5
|
-
import * as path from "node:path";
|
|
6
|
-
|
|
7
|
-
function ask(question, defaultVal = "") {
|
|
8
|
-
return new Promise(resolve => {
|
|
9
|
-
const hint = defaultVal ? ` (${defaultVal})` : "";
|
|
10
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
11
|
-
rl.question(` ${question}${hint}: `, answer => {
|
|
12
|
-
rl.close();
|
|
13
|
-
resolve(answer.trim() || defaultVal);
|
|
14
|
-
});
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export async function promptInit() {
|
|
19
|
-
const policyId = await ask("Project / policy name", process.env._INFERNO_DEFAULT_POLICY || "my-project");
|
|
20
|
-
const caps = await ask("Capabilities (comma-separated)", "CreateTask, ReadTasks, UpdateTask, DeleteTask");
|
|
21
|
-
return { policyId, capabilities: caps.split(",").map(c => c.trim()).filter(Boolean) };
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function readJson(filePath) {
|
|
25
|
-
try {
|
|
26
|
-
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
27
|
-
} catch {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function loadImplementContext(cwd) {
|
|
33
|
-
const infernoDir = path.join(cwd, "inferno");
|
|
34
|
-
const contract = readJson(path.join(infernoDir, "contract.json")) || {};
|
|
35
|
-
const caps = readJson(path.join(infernoDir, "capabilities.json")) || { capabilities: [] };
|
|
36
|
-
const state = readJson(path.join(infernoDir, "context-state.json")) || {};
|
|
37
|
-
const scenariosDir = path.join(infernoDir, "scenarios");
|
|
38
|
-
|
|
39
|
-
const scenarios = [];
|
|
40
|
-
if (fs.existsSync(scenariosDir)) {
|
|
41
|
-
for (const fileName of fs.readdirSync(scenariosDir).filter((f) => f.endsWith(".json"))) {
|
|
42
|
-
const scenario = readJson(path.join(scenariosDir, fileName));
|
|
43
|
-
if (scenario) scenarios.push({ file: fileName, scenario });
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return { contract, caps, state, scenarios };
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function renderCaps(capsRegistry) {
|
|
51
|
-
const list = capsRegistry?.capabilities || [];
|
|
52
|
-
if (list.length === 0) return "- none";
|
|
53
|
-
return list.map((c) => `- ${c.id}: ${c.title || c.id}`).join("\n");
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function renderScenarios(scenarios) {
|
|
57
|
-
if (!scenarios || scenarios.length === 0) return "- none";
|
|
58
|
-
return scenarios
|
|
59
|
-
.map(({ file, scenario }) => {
|
|
60
|
-
const covered = (scenario.capabilitiesCovered || []).join(", ") || "none";
|
|
61
|
-
return `- ${file}: covers [${covered}]`;
|
|
62
|
-
})
|
|
63
|
-
.join("\n");
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function baseContextBlock({ contract, caps, scenarios, state }) {
|
|
67
|
-
const policy = contract?.policyId || "unknown-policy";
|
|
68
|
-
const version = contract?.policyVersion ?? "unknown";
|
|
69
|
-
const declared = (contract?.capabilities || []).join(", ") || "none";
|
|
70
|
-
const working = state?.working || "not set";
|
|
71
|
-
const intent = state?.intent || "not set";
|
|
72
|
-
|
|
73
|
-
return [
|
|
74
|
-
`Project policyId: ${policy}`,
|
|
75
|
-
`Policy version: ${version}`,
|
|
76
|
-
`Declared capabilities: [${declared}]`,
|
|
77
|
-
`Working on: ${working}`,
|
|
78
|
-
`Intent: ${intent}`,
|
|
79
|
-
"",
|
|
80
|
-
"Capabilities registry:",
|
|
81
|
-
renderCaps(caps),
|
|
82
|
-
"",
|
|
83
|
-
"Scenarios:",
|
|
84
|
-
renderScenarios(scenarios),
|
|
85
|
-
].join("\n");
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function buildCursorImplementPrompt({ task, contract, caps, scenarios, state }) {
|
|
89
|
-
return [
|
|
90
|
-
"You are a Cursor coding agent working inside my repository.",
|
|
91
|
-
"Implement the task end-to-end with minimal reliable changes.",
|
|
92
|
-
"",
|
|
93
|
-
baseContextBlock({ contract, caps, scenarios, state }),
|
|
94
|
-
"",
|
|
95
|
-
`Task: ${task}`,
|
|
96
|
-
"",
|
|
97
|
-
"Requirements:",
|
|
98
|
-
"1) Propose smallest safe implementation.",
|
|
99
|
-
"2) Explain which files you changed and why.",
|
|
100
|
-
"3) Implement production-ready code.",
|
|
101
|
-
"4) Preserve backward compatibility unless explicitly requested.",
|
|
102
|
-
"5) Update tests or add smoke checks.",
|
|
103
|
-
"6) Provide run/verify commands.",
|
|
104
|
-
"7) If assumptions are needed, state briefly and proceed with sensible defaults.",
|
|
105
|
-
"",
|
|
106
|
-
"Output format:",
|
|
107
|
-
"- Plan (short)",
|
|
108
|
-
"- Code changes (by file)",
|
|
109
|
-
"- Tests updated/added",
|
|
110
|
-
"- Commands to run",
|
|
111
|
-
"- Acceptance checklist",
|
|
112
|
-
"",
|
|
113
|
-
"Quality bar:",
|
|
114
|
-
"- No TODO placeholders in final code",
|
|
115
|
-
"- Handle edge cases and errors",
|
|
116
|
-
"- Keep naming/style consistent",
|
|
117
|
-
"- Prefer simple maintainable solutions",
|
|
118
|
-
"",
|
|
119
|
-
"If model is overloaded (resource exhausted), retry with Auto/another model and continue deterministically.",
|
|
120
|
-
].join("\n");
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export function buildGenericImplementPrompt({ task, contract, caps, scenarios, state }) {
|
|
124
|
-
return [
|
|
125
|
-
"You are my senior software engineer pair.",
|
|
126
|
-
"Implement this task end-to-end in my project.",
|
|
127
|
-
"",
|
|
128
|
-
baseContextBlock({ contract, caps, scenarios, state }),
|
|
129
|
-
"",
|
|
130
|
-
`Goal: ${task}`,
|
|
131
|
-
"",
|
|
132
|
-
"Deliverables:",
|
|
133
|
-
"- Short implementation plan",
|
|
134
|
-
"- Exact file-level changes",
|
|
135
|
-
"- Test updates",
|
|
136
|
-
"- Verification commands",
|
|
137
|
-
"- Final acceptance checklist",
|
|
138
|
-
"",
|
|
139
|
-
"Constraints:",
|
|
140
|
-
"- Keep backward compatibility by default",
|
|
141
|
-
"- Make minimal reliable changes",
|
|
142
|
-
"- Handle edge cases and error states",
|
|
143
|
-
"- Keep output concise and actionable",
|
|
144
|
-
"",
|
|
145
|
-
"If you encounter temporary model high-load errors, retry and preserve the same output structure.",
|
|
146
|
-
].join("\n");
|
|
147
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import { installInfernoDraftTooling } from "./draftToolingInstall.mjs";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* VS Code + GitHub Copilot agent hooks (Preview). See:
|
|
7
|
-
* https://code.visualstudio.com/docs/copilot/customization/hooks
|
|
8
|
-
*
|
|
9
|
-
* @param {object} opts
|
|
10
|
-
* @param {string} opts.cwd
|
|
11
|
-
* @param {string} opts.templatesRoot
|
|
12
|
-
* @param {boolean} opts.force
|
|
13
|
-
* @param {boolean} opts.silent
|
|
14
|
-
* @param {(msg: string) => void} [opts.logOk]
|
|
15
|
-
* @param {(msg: string) => void} [opts.logWarn]
|
|
16
|
-
*/
|
|
17
|
-
export function installVsCodeCopilotHooksArtifacts(opts) {
|
|
18
|
-
const { cwd, templatesRoot, force, silent } = opts;
|
|
19
|
-
const logOk = opts.logOk || (() => {});
|
|
20
|
-
const logWarn = opts.logWarn || (() => {});
|
|
21
|
-
|
|
22
|
-
function copyFile(src, dst) {
|
|
23
|
-
if (fs.existsSync(dst) && !force) {
|
|
24
|
-
if (!silent) logWarn("Skipped (exists): " + path.relative(cwd, dst));
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
fs.mkdirSync(path.dirname(dst), { recursive: true });
|
|
28
|
-
fs.copyFileSync(src, dst);
|
|
29
|
-
if (!silent) logOk("Created: " + path.relative(cwd, dst));
|
|
30
|
-
return true;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
installInfernoDraftTooling({ cwd, templatesRoot, force, silent, logOk, logWarn });
|
|
34
|
-
|
|
35
|
-
const srcHooks = path.join(templatesRoot, "github-hooks", "infernoflow-drafts.json");
|
|
36
|
-
const dstHooks = path.join(cwd, ".github", "hooks", "infernoflow-drafts.json");
|
|
37
|
-
const srcHookScript = path.join(templatesRoot, "scripts", "inferno-vscode-copilot-hook.mjs");
|
|
38
|
-
const dstHookScript = path.join(cwd, "scripts", "inferno-vscode-copilot-hook.mjs");
|
|
39
|
-
|
|
40
|
-
copyFile(srcHooks, dstHooks);
|
|
41
|
-
copyFile(srcHookScript, dstHookScript);
|
|
42
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|