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.
Files changed (57) hide show
  1. package/dist/bin/infernoflow.mjs +68 -0
  2. package/dist/lib/ai/ideDetection.mjs +1 -0
  3. package/dist/lib/ai/localProvider.mjs +1 -0
  4. package/dist/lib/ai/providerRouter.mjs +1 -0
  5. package/dist/lib/commands/adopt.mjs +20 -0
  6. package/dist/lib/commands/check.mjs +3 -0
  7. package/dist/lib/commands/context.mjs +20 -0
  8. package/dist/lib/commands/docGate.mjs +2 -0
  9. package/dist/lib/commands/implement.mjs +7 -0
  10. package/dist/lib/commands/init.mjs +17 -0
  11. package/dist/lib/commands/installCursorHooks.mjs +1 -0
  12. package/dist/lib/commands/installVsCodeCopilotHooks.mjs +1 -0
  13. package/dist/lib/commands/prImpact.mjs +2 -0
  14. package/dist/lib/commands/run.mjs +10 -0
  15. package/dist/lib/commands/status.mjs +4 -0
  16. package/dist/lib/commands/suggest.mjs +62 -0
  17. package/dist/lib/commands/syncAuto.mjs +1 -0
  18. package/dist/lib/cursorHooksInstall.mjs +1 -0
  19. package/dist/lib/draftToolingInstall.mjs +8 -0
  20. package/dist/lib/ui/output.mjs +6 -0
  21. package/dist/lib/ui/prompts.mjs +6 -0
  22. package/dist/lib/vsCodeCopilotHooksInstall.mjs +1 -0
  23. package/package.json +48 -44
  24. package/bin/infernoflow.mjs +0 -138
  25. package/lib/ai/ideDetection.mjs +0 -31
  26. package/lib/ai/localProvider.mjs +0 -88
  27. package/lib/ai/providerRouter.mjs +0 -73
  28. package/lib/commands/adopt.mjs +0 -768
  29. package/lib/commands/check.mjs +0 -179
  30. package/lib/commands/context.mjs +0 -164
  31. package/lib/commands/docGate.mjs +0 -81
  32. package/lib/commands/implement.mjs +0 -103
  33. package/lib/commands/init.mjs +0 -401
  34. package/lib/commands/installCursorHooks.mjs +0 -36
  35. package/lib/commands/installVsCodeCopilotHooks.mjs +0 -37
  36. package/lib/commands/prImpact.mjs +0 -157
  37. package/lib/commands/run.mjs +0 -338
  38. package/lib/commands/status.mjs +0 -172
  39. package/lib/commands/suggest.mjs +0 -501
  40. package/lib/commands/syncAuto.mjs +0 -96
  41. package/lib/cursorHooksInstall.mjs +0 -39
  42. package/lib/draftToolingInstall.mjs +0 -69
  43. package/lib/ui/output.mjs +0 -72
  44. package/lib/ui/prompts.mjs +0 -147
  45. package/lib/vsCodeCopilotHooksInstall.mjs +0 -42
  46. /package/{templates → dist/templates}/ci/github-inferno-check.yml +0 -0
  47. /package/{templates → dist/templates}/cursor/hooks/inferno-session-draft.mjs +0 -0
  48. /package/{templates → dist/templates}/cursor/hooks.json +0 -0
  49. /package/{templates → dist/templates}/github-hooks/infernoflow-drafts.json +0 -0
  50. /package/{templates → dist/templates}/inferno/CHANGELOG.md +0 -0
  51. /package/{templates → dist/templates}/inferno/capabilities.json +0 -0
  52. /package/{templates → dist/templates}/inferno/contract.json +0 -0
  53. /package/{templates → dist/templates}/inferno/scenarios/happy_path.json +0 -0
  54. /package/{templates → dist/templates}/scripts/inferno-doc-gate.mjs +0 -0
  55. /package/{templates → dist/templates}/scripts/inferno-install-hooks.mjs +0 -0
  56. /package/{templates → dist/templates}/scripts/inferno-promote-draft.mjs +0 -0
  57. /package/{templates → dist/templates}/scripts/inferno-vscode-copilot-hook.mjs +0 -0
@@ -1,138 +0,0 @@
1
- #!/usr/bin/env node
2
- import { readFileSync } from "node:fs";
3
- import { dirname, join } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { bold, gray, cyan, red } from "../lib/ui/output.mjs";
6
-
7
- const __dirname = dirname(fileURLToPath(import.meta.url));
8
- const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf8"));
9
- const VERSION = pkg.version || "0.0.0";
10
- const COMMAND_DESCRIPTIONS = {
11
- init: "Scaffold inferno/ in your project (or adopt existing project)",
12
- "install-cursor-hooks": "Install Cursor hooks: draft agent replies to inferno/CONTEXT.draft.md",
13
- "install-vscode-copilot-hooks":
14
- "Install VS Code + Copilot agent hooks (Preview): draft to inferno/CONTEXT.draft.md",
15
- check: "Validate contract, capabilities, scenarios, changelog",
16
- status: "Show contract health at a glance",
17
- "pr-impact": "Summarize PR impact on capabilities and docs",
18
- sync: "Run deterministic inferno sync flow",
19
- run: "One-command detect/propose/apply/validate flow",
20
- "doc-gate": "Fail if code changed but docs were not updated",
21
- suggest: "Generate AI prompt + apply capability updates",
22
- implement: "Generate code-agent implementation prompt(s)",
23
- context: "Generate AI-ready context for new sessions",
24
- };
25
-
26
- const COMMAND_HANDLERS = {
27
- init: async (args) => (await import("../lib/commands/init.mjs")).initCommand(args),
28
- "install-cursor-hooks": async (args) =>
29
- (await import("../lib/commands/installCursorHooks.mjs")).installCursorHooksCommand(args),
30
- "install-vscode-copilot-hooks": async (args) =>
31
- (await import("../lib/commands/installVsCodeCopilotHooks.mjs")).installVsCodeCopilotHooksCommand(args),
32
- check: async (args) => (await import("../lib/commands/check.mjs")).checkCommand(args),
33
- status: async (args) => (await import("../lib/commands/status.mjs")).statusCommand(args),
34
- "pr-impact": async (args) => (await import("../lib/commands/prImpact.mjs")).prImpactCommand(args),
35
- sync: async (args) => (await import("../lib/commands/syncAuto.mjs")).syncCommand(args),
36
- run: async (args) => (await import("../lib/commands/run.mjs")).runCommand(args),
37
- suggest: async (args) => (await import("../lib/commands/suggest.mjs")).suggestCommand(args),
38
- implement: async (args) => (await import("../lib/commands/implement.mjs")).implementCommand(args),
39
- context: async (args) => (await import("../lib/commands/context.mjs")).contextCommand(args),
40
- "doc-gate": async (args) => (await import("../lib/commands/docGate.mjs")).docGateCommand(args),
41
- };
42
-
43
- function formatCommandsHelp() {
44
- const names = Object.keys(COMMAND_DESCRIPTIONS);
45
- const w = Math.max(...names.map((n) => n.length), 8) + 1;
46
- return Object.entries(COMMAND_DESCRIPTIONS)
47
- .map(([name, desc]) => ` ${name.padEnd(w, " ")}${desc}`)
48
- .join("\n");
49
- }
50
-
51
- const HELP = `
52
- ${bold("🔥 infernoflow")} ${gray("v" + VERSION)}
53
- ${gray("The forge for liquid code — keep every AI session in sync")}
54
-
55
- ${bold("Usage:")}
56
- infernoflow <command> [options]
57
-
58
- ${bold("Commands:")}
59
- ${formatCommandsHelp()}
60
-
61
- ${bold("init options:")}
62
- --cursor-hooks Also install Cursor hooks (draft → inferno/CONTEXT.draft.md)
63
- --vscode-copilot-hooks Also install VS Code + Copilot hooks (.github/hooks — Preview)
64
- --adopt Infer capabilities from an existing codebase
65
- --lang <name> Override detected language (e.g. ts, js, py)
66
- --framework <name> Override detected framework (e.g. react, angular, express)
67
- --project-type <t> Override project type (frontend|backend|fullstack|cli|library)
68
- --report-json Print inferred adoption report as JSON
69
- --report-json-only Print JSON report only (no human-readable logs)
70
- --report-human-only Print only human-readable adoption report (no JSON block)
71
- --yes, -y Skip prompts and accept inferred/default values
72
- --force, -f Overwrite existing inferno/ files
73
-
74
- ${bold("install-cursor-hooks options:")}
75
- --force, -f Overwrite .cursor/hooks.json and hook scripts if they exist
76
-
77
- ${bold("install-vscode-copilot-hooks options:")}
78
- --force, -f Overwrite .github/hooks/infernoflow-drafts.json and scripts if they exist
79
-
80
- ${bold("context options:")}
81
- --intent "..." What you plan to build next
82
- --working "..." What you are building right now
83
- --decision "..." Record a decision or note
84
- --show Print context without writing file
85
- --copy, -c Copy context to clipboard instantly
86
- --reset Clear all stored state
87
-
88
- ${bold("implement options:")}
89
- --mode <type> cursor | generic | both (default: both)
90
- --copy, -c Copy generated prompt(s) to clipboard
91
-
92
- ${bold("run options:")}
93
- --dry-run Execute full flow without writing files
94
- --json Emit machine-readable events and result payload
95
- --no-rollback Keep changes even if validation fails
96
- --provider <type> auto | agent | local | prompt (default: auto)
97
- --ide <name> auto | cursor | vscode | windsurf (default: auto)
98
-
99
- ${bold("Typical workflow:")}
100
- ${gray('1. infernoflow context --intent "what I want to build"')}
101
- ${gray("2. [paste inferno/CONTEXT.md into Claude / Cursor / Copilot]")}
102
- ${gray("3. [build the feature]")}
103
- ${gray('4. infernoflow suggest "what I built"')}
104
- ${gray("5. infernoflow check")}
105
-
106
- ${bold("Machine output:")}
107
- ${gray("status --json")}
108
- ${gray("check --json")}
109
- ${gray("doc-gate --json")}
110
- ${gray("pr-impact --json")}
111
- ${gray("sync --auto --json")}
112
- ${gray('run "task" --json')}
113
- `;
114
-
115
- const [, , cmd, ...rest] = process.argv;
116
-
117
- if (!cmd || cmd === "--help" || cmd === "-h") {
118
- console.log(HELP);
119
- process.exit(0);
120
- }
121
- if (cmd === "--version" || cmd === "-v") {
122
- console.log(VERSION);
123
- process.exit(0);
124
- }
125
-
126
- const commands = Object.keys(COMMAND_HANDLERS);
127
-
128
- if (!commands.includes(cmd)) {
129
- console.error(red(`\nUnknown command: ${cmd}`));
130
- console.error(gray("Run: infernoflow --help\n"));
131
- process.exit(1);
132
- }
133
-
134
- const args = [cmd, ...rest];
135
- COMMAND_HANDLERS[cmd](args).catch((err) => {
136
- console.error(red("\nError: ") + err.message);
137
- process.exit(1);
138
- });
@@ -1,31 +0,0 @@
1
- export function detectIdeContext(preferredIde = "auto") {
2
- const env = process.env;
3
- const lowerPreferred = String(preferredIde || "auto").toLowerCase();
4
-
5
- const hasCursor = !!(env.CURSOR_TRACE_ID || env.CURSOR_AGENT || env.CURSOR_SESSION_ID || (env.VSCODE_GIT_ASKPASS_NODE || "").toLowerCase().includes("cursor") || (env.VSCODE_GIT_ASKPASS_MAIN || "").toLowerCase().includes("cursor"));
6
- const hasVscode = !!(env.VSCODE_PID || env.VSCODE_CWD || env.GITHUB_COPILOT_AGENT);
7
- const hasWindsurf = !!(env.WINDSURF || env.CODEIUM || env.WINDSURF_SESSION_ID);
8
-
9
- let ideDetected = "unknown";
10
- if (hasCursor) ideDetected = "cursor";
11
- else if (hasVscode) ideDetected = "vscode";
12
- else if (hasWindsurf) ideDetected = "windsurf";
13
-
14
- if (lowerPreferred !== "auto" && ["cursor", "vscode", "windsurf"].includes(lowerPreferred)) {
15
- ideDetected = lowerPreferred;
16
- }
17
-
18
- const explicitAgentAvailability = env.INFERNO_AGENT_AVAILABLE;
19
- const agentAvailable = explicitAgentAvailability != null
20
- ? explicitAgentAvailability === "1" || explicitAgentAvailability === "true"
21
- : ideDetected !== "unknown";
22
-
23
- const reasonCodes = [];
24
- if (ideDetected !== "unknown") reasonCodes.push(`IDE_${ideDetected.toUpperCase()}_DETECTED`);
25
- else reasonCodes.push("IDE_UNKNOWN");
26
- if (agentAvailable) reasonCodes.push("IDE_AGENT_AVAILABLE");
27
- else reasonCodes.push("IDE_AGENT_UNAVAILABLE");
28
-
29
- return { ideDetected, agentAvailable, reasonCodes };
30
- }
31
-
@@ -1,88 +0,0 @@
1
- const DEFAULT_TIMEOUT_MS = 45000;
2
-
3
- function withTimeout(ms) {
4
- const controller = new AbortController();
5
- const timer = setTimeout(() => controller.abort(), ms);
6
- return { controller, timer };
7
- }
8
-
9
- async function callOllama(prompt, timeoutMs) {
10
- const endpoint = process.env.INFERNO_LOCAL_ENDPOINT || "http://127.0.0.1:11434/api/generate";
11
- const model = process.env.INFERNO_LOCAL_MODEL || "llama3.1:8b";
12
- const { controller, timer } = withTimeout(timeoutMs);
13
- try {
14
- const res = await fetch(endpoint, {
15
- method: "POST",
16
- headers: { "Content-Type": "application/json" },
17
- signal: controller.signal,
18
- body: JSON.stringify({
19
- model,
20
- prompt,
21
- stream: false,
22
- }),
23
- });
24
- if (!res.ok) {
25
- const body = await res.text();
26
- throw new Error(`local_model_http_${res.status}: ${body.slice(0, 240)}`);
27
- }
28
- const data = await res.json();
29
- if (!data?.response || typeof data.response !== "string") {
30
- throw new Error("local_model_invalid_response");
31
- }
32
- return data.response.trim();
33
- } finally {
34
- clearTimeout(timer);
35
- }
36
- }
37
-
38
- async function callOpenAICompat(prompt, timeoutMs) {
39
- const endpoint = process.env.INFERNO_LOCAL_ENDPOINT || "http://127.0.0.1:1234/v1/chat/completions";
40
- const model = process.env.INFERNO_LOCAL_MODEL || "local-model";
41
- const apiKey = process.env.INFERNO_LOCAL_API_KEY || "local";
42
- const { controller, timer } = withTimeout(timeoutMs);
43
- try {
44
- const res = await fetch(endpoint, {
45
- method: "POST",
46
- headers: {
47
- "Content-Type": "application/json",
48
- Authorization: `Bearer ${apiKey}`,
49
- },
50
- signal: controller.signal,
51
- body: JSON.stringify({
52
- model,
53
- temperature: 0.1,
54
- messages: [
55
- { role: "system", content: "Return JSON only." },
56
- { role: "user", content: prompt },
57
- ],
58
- }),
59
- });
60
- if (!res.ok) {
61
- const body = await res.text();
62
- throw new Error(`local_model_http_${res.status}: ${body.slice(0, 240)}`);
63
- }
64
- const data = await res.json();
65
- const text = data?.choices?.[0]?.message?.content;
66
- if (!text || typeof text !== "string") {
67
- throw new Error("local_model_invalid_response");
68
- }
69
- return text.trim();
70
- } finally {
71
- clearTimeout(timer);
72
- }
73
- }
74
-
75
- export async function generateWithLocalModel(prompt, options = {}) {
76
- if (process.env.INFERNO_LOCAL_MOCK_RESPONSE) {
77
- return process.env.INFERNO_LOCAL_MOCK_RESPONSE;
78
- }
79
-
80
- const provider = (process.env.INFERNO_LOCAL_PROVIDER || "ollama").toLowerCase();
81
- const timeoutMs = Number(options.timeoutMs || process.env.INFERNO_LOCAL_TIMEOUT_MS || DEFAULT_TIMEOUT_MS);
82
-
83
- if (provider === "openai") {
84
- return callOpenAICompat(prompt, timeoutMs);
85
- }
86
- return callOllama(prompt, timeoutMs);
87
- }
88
-
@@ -1,73 +0,0 @@
1
- import { detectIdeContext } from "./ideDetection.mjs";
2
-
3
- export async function resolveProvider(requestedProvider = "auto", preferredIde = "auto") {
4
- const providerRequested = String(requestedProvider || "auto").toLowerCase();
5
- const ide = detectIdeContext(preferredIde);
6
- const reasonCodes = [...ide.reasonCodes];
7
-
8
- if (providerRequested === "local") {
9
- reasonCodes.push("LOCAL_PROVIDER_SELECTED");
10
- return {
11
- providerRequested,
12
- providerResolved: "local",
13
- ideDetected: ide.ideDetected,
14
- agentAvailable: ide.agentAvailable,
15
- reasonCodes,
16
- };
17
- }
18
-
19
- if (providerRequested === "prompt") {
20
- reasonCodes.push("PROMPT_PROVIDER_SELECTED");
21
- return {
22
- providerRequested,
23
- providerResolved: "prompt",
24
- ideDetected: ide.ideDetected,
25
- agentAvailable: ide.agentAvailable,
26
- reasonCodes,
27
- };
28
- }
29
-
30
- if (providerRequested === "agent") {
31
- if (!ide.agentAvailable) {
32
- reasonCodes.push("EXPLICIT_AGENT_REQUIRED");
33
- return {
34
- providerRequested,
35
- providerResolved: "none",
36
- ideDetected: ide.ideDetected,
37
- agentAvailable: ide.agentAvailable,
38
- reasonCodes,
39
- error: "agent_unavailable",
40
- };
41
- }
42
- reasonCodes.push("IDE_AGENT_SELECTED");
43
- return {
44
- providerRequested,
45
- providerResolved: "agent",
46
- ideDetected: ide.ideDetected,
47
- agentAvailable: ide.agentAvailable,
48
- reasonCodes,
49
- };
50
- }
51
-
52
- // auto
53
- if (ide.agentAvailable) {
54
- reasonCodes.push("IDE_AGENT_SELECTED");
55
- return {
56
- providerRequested: "auto",
57
- providerResolved: "agent",
58
- ideDetected: ide.ideDetected,
59
- agentAvailable: ide.agentAvailable,
60
- reasonCodes,
61
- };
62
- }
63
-
64
- reasonCodes.push("FALLBACK_PROMPT_MODE");
65
- return {
66
- providerRequested: "auto",
67
- providerResolved: "prompt",
68
- ideDetected: ide.ideDetected,
69
- agentAvailable: ide.agentAvailable,
70
- reasonCodes,
71
- };
72
- }
73
-