rax-flow 0.1.0

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 (83) hide show
  1. package/dashboard/index.html +420 -0
  2. package/dist/benchmark.d.ts +10 -0
  3. package/dist/benchmark.d.ts.map +1 -0
  4. package/dist/benchmark.js +123 -0
  5. package/dist/benchmark.js.map +1 -0
  6. package/dist/bin.d.ts +3 -0
  7. package/dist/bin.d.ts.map +1 -0
  8. package/dist/bin.js +115 -0
  9. package/dist/bin.js.map +1 -0
  10. package/dist/bootstrap.d.ts +8 -0
  11. package/dist/bootstrap.d.ts.map +1 -0
  12. package/dist/bootstrap.js +22 -0
  13. package/dist/bootstrap.js.map +1 -0
  14. package/dist/bridge-adapter-templates.d.ts +4 -0
  15. package/dist/bridge-adapter-templates.d.ts.map +1 -0
  16. package/dist/bridge-adapter-templates.js +185 -0
  17. package/dist/bridge-adapter-templates.js.map +1 -0
  18. package/dist/bridge-test.d.ts +7 -0
  19. package/dist/bridge-test.d.ts.map +1 -0
  20. package/dist/bridge-test.js +89 -0
  21. package/dist/bridge-test.js.map +1 -0
  22. package/dist/dashboard.d.ts +4 -0
  23. package/dist/dashboard.d.ts.map +1 -0
  24. package/dist/dashboard.js +49 -0
  25. package/dist/dashboard.js.map +1 -0
  26. package/dist/doctor.d.ts +6 -0
  27. package/dist/doctor.d.ts.map +1 -0
  28. package/dist/doctor.js +70 -0
  29. package/dist/doctor.js.map +1 -0
  30. package/dist/evolve.d.ts +7 -0
  31. package/dist/evolve.d.ts.map +1 -0
  32. package/dist/evolve.js +48 -0
  33. package/dist/evolve.js.map +1 -0
  34. package/dist/host-init-templates.d.ts +16 -0
  35. package/dist/host-init-templates.d.ts.map +1 -0
  36. package/dist/host-init-templates.js +119 -0
  37. package/dist/host-init-templates.js.map +1 -0
  38. package/dist/index.d.ts +11 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +11 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/init-host.d.ts +10 -0
  43. package/dist/init-host.d.ts.map +1 -0
  44. package/dist/init-host.js +232 -0
  45. package/dist/init-host.js.map +1 -0
  46. package/dist/install.d.ts +8 -0
  47. package/dist/install.d.ts.map +1 -0
  48. package/dist/install.js +99 -0
  49. package/dist/install.js.map +1 -0
  50. package/dist/run.d.ts +16 -0
  51. package/dist/run.d.ts.map +1 -0
  52. package/dist/run.js +238 -0
  53. package/dist/run.js.map +1 -0
  54. package/dist/styles.d.ts +12 -0
  55. package/dist/styles.d.ts.map +1 -0
  56. package/dist/styles.js +12 -0
  57. package/dist/styles.js.map +1 -0
  58. package/dist/vendor-manifests.d.ts +22 -0
  59. package/dist/vendor-manifests.d.ts.map +1 -0
  60. package/dist/vendor-manifests.js +94 -0
  61. package/dist/vendor-manifests.js.map +1 -0
  62. package/dist/ws-relay.d.ts +12 -0
  63. package/dist/ws-relay.d.ts.map +1 -0
  64. package/dist/ws-relay.js +148 -0
  65. package/dist/ws-relay.js.map +1 -0
  66. package/package.json +28 -0
  67. package/src/benchmark.ts +156 -0
  68. package/src/bin.ts +127 -0
  69. package/src/bootstrap.ts +36 -0
  70. package/src/bridge-adapter-templates.ts +181 -0
  71. package/src/bridge-test.ts +107 -0
  72. package/src/dashboard.ts +51 -0
  73. package/src/doctor.ts +92 -0
  74. package/src/evolve.ts +74 -0
  75. package/src/host-init-templates.ts +134 -0
  76. package/src/index.ts +10 -0
  77. package/src/init-host.ts +285 -0
  78. package/src/install.ts +118 -0
  79. package/src/run.ts +317 -0
  80. package/src/styles.ts +12 -0
  81. package/src/vendor-manifests.ts +113 -0
  82. package/src/ws-relay.ts +156 -0
  83. package/tsconfig.json +12 -0
package/src/doctor.ts ADDED
@@ -0,0 +1,92 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { HostBridgeAdapter } from "@rax-flow/providers";
4
+ import { c } from "./styles.js";
5
+
6
+ interface DoctorOptions {
7
+ cwd: string;
8
+ }
9
+
10
+ interface RaxConfig {
11
+ defaultProvider?: string;
12
+ strongProvider?: string;
13
+ providers?: {
14
+ host?: { model?: string; mode?: "auto" | "bridge-only" | "mock"; bridgeCommandEnv?: string; timeoutMs?: number };
15
+ };
16
+ }
17
+
18
+ async function loadConfig(cwd: string): Promise<RaxConfig | null> {
19
+ const file = path.join(cwd, ".raxrc");
20
+ try {
21
+ const raw = await readFile(file, "utf8");
22
+ return JSON.parse(raw) as RaxConfig;
23
+ } catch {
24
+ return null;
25
+ }
26
+ }
27
+
28
+ function printLine(ok: boolean, label: string, details?: string) {
29
+ const icon = ok ? c.green("[ok]") : c.red("[fail]");
30
+ console.log(`${icon} ${label}${details ? ` - ${details}` : ""}`);
31
+ }
32
+
33
+ export async function runDoctor(options: DoctorOptions): Promise<number> {
34
+ console.log(c.blue("RAX-FLOW Doctor"));
35
+
36
+ const config = await loadConfig(options.cwd);
37
+ if (!config) {
38
+ printLine(false, "Missing .raxrc", "run `rax-flow install` first");
39
+ return 1;
40
+ }
41
+ printLine(true, "Found .raxrc");
42
+
43
+ const hostCfg = config.providers?.host;
44
+ const bridgeCommandEnv = hostCfg?.bridgeCommandEnv ?? "RAX_HOST_BRIDGE_COMMAND";
45
+ const bridgeCommand = process.env[bridgeCommandEnv];
46
+ const provider = new HostBridgeAdapter({
47
+ model: hostCfg?.model ?? "host-managed",
48
+ mode: hostCfg?.mode ?? "auto",
49
+ command: bridgeCommand,
50
+ timeoutMs: hostCfg?.timeoutMs ?? 10000
51
+ });
52
+
53
+ const health = await provider.healthCheck();
54
+ printLine(health, "Host provider health", `mode=${hostCfg?.mode ?? "auto"}`);
55
+
56
+ const hasBridgeFn = typeof (globalThis as Record<string, unknown>).__RAX_HOST_BRIDGE__ === "function";
57
+ printLine(hasBridgeFn || Boolean(bridgeCommand), "Bridge source", hasBridgeFn ? "global bridge function" : bridgeCommand ? `command via ${bridgeCommandEnv}` : "auto/mock fallback");
58
+
59
+ try {
60
+ const ping = await provider.callModel("doctor ping", { model: hostCfg?.model ?? "host-managed", maxTokens: 32, temperature: 0 });
61
+ printLine(true, "callModel test", `provider=${ping.provider} model=${ping.model}`);
62
+ } catch (error) {
63
+ printLine(false, "callModel test", String(error));
64
+ return 1;
65
+ }
66
+
67
+ try {
68
+ const structured = await provider.callStructured(
69
+ "doctor structured ping",
70
+ {
71
+ type: "object",
72
+ required: ["agent", "success", "confidence", "risks", "logs", "data"],
73
+ properties: {
74
+ agent: { type: "string" },
75
+ success: { type: "boolean" },
76
+ confidence: { type: "number" },
77
+ risks: { type: "array" },
78
+ logs: { type: "array" },
79
+ data: { type: "object" }
80
+ }
81
+ },
82
+ { model: hostCfg?.model ?? "host-managed", maxTokens: 128, temperature: 0 }
83
+ );
84
+ printLine(true, "callStructured test", `model=${structured.model}`);
85
+ } catch (error) {
86
+ printLine(false, "callStructured test", String(error));
87
+ return 1;
88
+ }
89
+
90
+ console.log(c.green("Doctor checks passed."));
91
+ return 0;
92
+ }
package/src/evolve.ts ADDED
@@ -0,0 +1,74 @@
1
+ import { readFile, readdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { c } from "./styles.js";
4
+
5
+ interface EvolveOptions {
6
+ cwd: string;
7
+ history?: boolean;
8
+ }
9
+
10
+ interface Blueprint {
11
+ id: string;
12
+ version: string;
13
+ createdAt: string;
14
+ fitnessScore: number;
15
+ mutationType: string;
16
+ metadata?: {
17
+ message?: string;
18
+ reason?: string;
19
+ };
20
+ }
21
+
22
+ export async function showEvolution(options: EvolveOptions): Promise<number> {
23
+ const evolutionDir = path.join(options.cwd, ".rax-flow", "evolutions");
24
+
25
+ try {
26
+ const files = await readdir(evolutionDir);
27
+ const blueprintFiles = files.filter(f => f.startsWith("blueprint_") && f.endsWith(".json"));
28
+
29
+ if (blueprintFiles.length === 0) {
30
+ console.log(c.yellow("\nNo evolutions recorded yet. Run more tasks to trigger Darwinian mutations."));
31
+ return 0;
32
+ }
33
+
34
+ const blueprints: Blueprint[] = [];
35
+ for (const file of blueprintFiles) {
36
+ const raw = await readFile(path.join(evolutionDir, file), "utf8");
37
+ blueprints.push(JSON.parse(raw) as Blueprint);
38
+ }
39
+
40
+ // Sort by creation date
41
+ blueprints.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
42
+
43
+ console.log(c.bold(c.magenta(`\n\n--- [GENETIC LINEAGE: RAX-FLOW] ---`)));
44
+ console.log(c.gray(`Found ${blueprints.length} evolutionary jumps.\n`));
45
+
46
+ blueprints.forEach((bp, i) => {
47
+ const connector = i === blueprints.length - 1 ? "└" : "├";
48
+ const branch = i === 0 ? "" : ` ${connector}── `;
49
+
50
+ const scoreColor = bp.fitnessScore >= 0.8 ? c.green : (bp.fitnessScore >= 0.6 ? c.yellow : c.red);
51
+
52
+ console.log(`${branch}${c.bold(bp.id)} ${c.gray(`v${bp.version}`)}`);
53
+ console.log(` ${c.gray("Type:")} ${c.cyan(bp.mutationType)}`);
54
+ console.log(` ${c.gray("Fitness:")} ${scoreColor(bp.fitnessScore.toFixed(2))}`);
55
+ if (bp.metadata?.reason || bp.metadata?.message) {
56
+ console.log(` ${c.gray("Note:")} ${c.white(bp.metadata.reason || bp.metadata.message || "")}`);
57
+ }
58
+ if (i < blueprints.length - 1) {
59
+ console.log(` ${c.gray("│")}`);
60
+ }
61
+ });
62
+
63
+ console.log(c.bold(c.cyan(`\nSurvival of the fittest: Blueprint ${blueprints[blueprints.length - 1]?.id} is currently dominant.`)));
64
+
65
+ return 0;
66
+ } catch (error) {
67
+ if ((error as any).code === "ENOENT") {
68
+ console.log(c.yellow("\nNo evolutions directory found. Run tasks first."));
69
+ return 0;
70
+ }
71
+ console.error(c.red(`Failed to read evolution history: ${error}`));
72
+ return 1;
73
+ }
74
+ }
@@ -0,0 +1,134 @@
1
+ export type HostTarget = "claude-code" | "codex" | "opencode" | "kilo" | "generic";
2
+
3
+ export interface HostTemplate {
4
+ id: HostTarget;
5
+ title: string;
6
+ envHint: string;
7
+ chatHint: string;
8
+ bootstrapPromptBase: string[];
9
+ quickCommands: string[];
10
+ autoInjectMode: "native" | "scripted" | "manual";
11
+ sessionEntryExamples: string[];
12
+ }
13
+
14
+ export const HOST_TEMPLATES: Record<HostTarget, HostTemplate> = {
15
+ "claude-code": {
16
+ id: "claude-code",
17
+ title: "Claude Code",
18
+ envHint: "Export RAX_HOST_BRIDGE_COMMAND before starting Claude Code session.",
19
+ chatHint: "Paste BOOTSTRAP_PROMPT.txt at the beginning of the chat.",
20
+ bootstrapPromptBase: [
21
+ "RAX-FLOW bootstrap (Claude Code)",
22
+ "- Enable host-native orchestration.",
23
+ "- Route generation through the configured host bridge.",
24
+ "- Keep structured JSON outputs for orchestration steps.",
25
+ "- Execute Verify -> Fix loop when schema validation fails.",
26
+ "- Report confidence, risk flags, and logs for each step."
27
+ ],
28
+ quickCommands: ["npx rax-flow doctor", "npx rax-flow run --prompt \"Build feature X\" --stream"],
29
+ autoInjectMode: "scripted",
30
+ sessionEntryExamples: [
31
+ "claude-code chat --message-file .rax-flow/host-init/claude-code/BOOTSTRAP_PROMPT.txt",
32
+ "claude-code (open session, then paste BOOTSTRAP_PROMPT.txt)"
33
+ ]
34
+ },
35
+ codex: {
36
+ id: "codex",
37
+ title: "Codex",
38
+ envHint: "Set RAX_HOST_BRIDGE_COMMAND in the shell running Codex.",
39
+ chatHint: "Send BOOTSTRAP_PROMPT.txt as first instruction in session.",
40
+ bootstrapPromptBase: [
41
+ "RAX-FLOW bootstrap (Codex)",
42
+ "- Use host-native model execution through the host bridge.",
43
+ "- Produce strict structured outputs for all agent steps.",
44
+ "- Apply Verify -> Fix until valid schema or retry cap.",
45
+ "- Include confidence and risks in every final step."
46
+ ],
47
+ quickCommands: ["npx rax-flow doctor", "npx rax-flow run --prompt \"Build feature X\" --stream"],
48
+ autoInjectMode: "scripted",
49
+ sessionEntryExamples: [
50
+ "codex chat --message-file .rax-flow/host-init/codex/BOOTSTRAP_PROMPT.txt",
51
+ "codex (open session, then paste BOOTSTRAP_PROMPT.txt)"
52
+ ]
53
+ },
54
+ opencode: {
55
+ id: "opencode",
56
+ title: "OpenCode",
57
+ envHint: "Configure RAX_HOST_BRIDGE_COMMAND in OpenCode terminal/runtime env.",
58
+ chatHint: "Paste BOOTSTRAP_PROMPT.txt before requesting implementation.",
59
+ bootstrapPromptBase: [
60
+ "RAX-FLOW bootstrap (OpenCode)",
61
+ "- Activate host bridge orchestration mode.",
62
+ "- Keep responses compact but structured for agent pipeline.",
63
+ "- Trigger fix cycles on validation failures automatically.",
64
+ "- Emit step logs and confidence scores."
65
+ ],
66
+ quickCommands: ["npx rax-flow doctor", "npx rax-flow run --prompt \"Build feature X\" --stream"],
67
+ autoInjectMode: "manual",
68
+ sessionEntryExamples: [
69
+ "opencode chat --message-file .rax-flow/host-init/opencode/BOOTSTRAP_PROMPT.txt",
70
+ "opencode (open session, then paste BOOTSTRAP_PROMPT.txt)"
71
+ ]
72
+ },
73
+ kilo: {
74
+ id: "kilo",
75
+ title: "Kilo Code",
76
+ envHint: "Set RAX_HOST_BRIDGE_COMMAND in Kilo launch environment.",
77
+ chatHint: "Paste BOOTSTRAP_PROMPT.txt as initialization message.",
78
+ bootstrapPromptBase: [
79
+ "RAX-FLOW bootstrap (Kilo)",
80
+ "- Run in host-native orchestration mode.",
81
+ "- Enforce structured output contract for each stage.",
82
+ "- Apply Verify -> Fix and escalate when confidence is low.",
83
+ "- Return actionable logs and risk flags."
84
+ ],
85
+ quickCommands: ["npx rax-flow doctor", "npx rax-flow run --prompt \"Build feature X\" --stream"],
86
+ autoInjectMode: "manual",
87
+ sessionEntryExamples: [
88
+ "kilo chat --message-file .rax-flow/host-init/kilo/BOOTSTRAP_PROMPT.txt",
89
+ "kilo (open session, then paste BOOTSTRAP_PROMPT.txt)"
90
+ ]
91
+ },
92
+ generic: {
93
+ id: "generic",
94
+ title: "Generic Host",
95
+ envHint: "Provide a bridge command through RAX_HOST_BRIDGE_COMMAND.",
96
+ chatHint: "Paste BOOTSTRAP_PROMPT.txt at session start.",
97
+ bootstrapPromptBase: [
98
+ "RAX-FLOW bootstrap (Generic)",
99
+ "- Enable orchestration through host bridge.",
100
+ "- Return strict JSON for each orchestration step.",
101
+ "- Retry/fix invalid outputs automatically.",
102
+ "- Report confidence, risks, and logs."
103
+ ],
104
+ quickCommands: ["npx rax-flow doctor", "npx rax-flow run --prompt \"Build feature X\" --stream"],
105
+ autoInjectMode: "manual",
106
+ sessionEntryExamples: [
107
+ "your-host-cli chat --message-file .rax-flow/host-init/generic/BOOTSTRAP_PROMPT.txt",
108
+ "open session, then paste BOOTSTRAP_PROMPT.txt"
109
+ ]
110
+ }
111
+ };
112
+
113
+ export function parseHostTarget(value: string | undefined): HostTarget {
114
+ if (!value) return "generic";
115
+ if (value in HOST_TEMPLATES) return value as HostTarget;
116
+ return "generic";
117
+ }
118
+
119
+ export function listHostTargets(): HostTarget[] {
120
+ return Object.keys(HOST_TEMPLATES) as HostTarget[];
121
+ }
122
+
123
+ export function buildBootstrapPrompt(target: HostTarget, task?: string): string {
124
+ const template = HOST_TEMPLATES[target];
125
+ const lines = [...template.bootstrapPromptBase];
126
+
127
+ if (task && task.trim().length > 0) {
128
+ lines.push(`- Task context: ${task.trim()}`);
129
+ lines.push("- Keep orchestration aligned with this task context unless user changes scope.");
130
+ }
131
+
132
+ lines.push("- If bridge call fails, report issue clearly and keep orchestration state.");
133
+ return lines.join("\n");
134
+ }
package/src/index.ts ADDED
@@ -0,0 +1,10 @@
1
+ export * from "./install.js";
2
+ export * from "./run.js";
3
+ export * from "./benchmark.js";
4
+ export * from "./doctor.js";
5
+ export * from "./bridge-test.js";
6
+ export * from "./init-host.js";
7
+ export * from "./bootstrap.js";
8
+ export * from "./host-init-templates.js";
9
+ export * from "./bridge-adapter-templates.js";
10
+ export * from "./vendor-manifests.js";
@@ -0,0 +1,285 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { c } from "./styles.js";
4
+ import { HOST_TEMPLATES, HostTarget, buildBootstrapPrompt, listHostTargets, parseHostTarget } from "./host-init-templates.js";
5
+ import { generateVendorManifest, vendorManifestFilename, type HostManifestModel } from "./vendor-manifests.js";
6
+ import { bridgeAdapterFilename, renderBridgeAdapter } from "./bridge-adapter-templates.js";
7
+
8
+ interface InitHostOptions {
9
+ cwd: string;
10
+ target?: string;
11
+ printOnly?: boolean;
12
+ all?: boolean;
13
+ task?: string;
14
+ }
15
+
16
+ function bridgeCommand(adapterFile: string): string {
17
+ return `node ${adapterFile}`;
18
+ }
19
+
20
+ function renderSetupScript(command: string): string {
21
+ return [
22
+ "#!/usr/bin/env bash",
23
+ "set -e",
24
+ `export RAX_HOST_BRIDGE_COMMAND=\"${command}\"`,
25
+ 'echo "RAX_HOST_BRIDGE_COMMAND configured"',
26
+ "echo \"Run: npx rax-flow doctor\"",
27
+ "echo \"Run: npx rax-flow run --prompt 'Build feature X' --stream\""
28
+ ].join("\n");
29
+ }
30
+
31
+ function renderInstructions(params: {
32
+ title: string;
33
+ envHint: string;
34
+ chatHint: string;
35
+ command: string;
36
+ adapterFile: string;
37
+ quickCommands: string[];
38
+ sessionEntryExamples: string[];
39
+ autoInjectMode: "native" | "scripted" | "manual";
40
+ task?: string;
41
+ }): string {
42
+ const taskSection = params.task?.trim()
43
+ ? ["", "## Task context", `- ${params.task.trim()}`, "- Embedded into BOOTSTRAP_PROMPT.txt"]
44
+ : [];
45
+
46
+ return [
47
+ `# ${params.title} - Non-UI Initialization`,
48
+ "",
49
+ "## 1) Configure bridge command",
50
+ `- ${params.envHint}`,
51
+ `- Command: \`${params.command}\``,
52
+ `- Bridge adapter scaffold: \`${params.adapterFile}\``,
53
+ "- Replace callHostModel() with your editor runtime model call implementation.",
54
+ "- Configure bridge runtime values in `bridge-runtime-config.json`.",
55
+ "- Use `bridge-smoke-test.json` to validate structured response mapping.",
56
+ "",
57
+ "## 2) Chat bootstrap",
58
+ `- ${params.chatHint}`,
59
+ "- Use BOOTSTRAP_PROMPT.txt content.",
60
+ ...taskSection,
61
+ "",
62
+ "## 3) Session launch patterns",
63
+ `- Auto inject mode: \`${params.autoInjectMode}\``,
64
+ ...params.sessionEntryExamples.map((line) => `- \`${line}\``),
65
+ "",
66
+ "## 4) Validate",
67
+ ...params.quickCommands.map((cmd) => `- \`${cmd}\``)
68
+ ].join("\n");
69
+ }
70
+
71
+ function renderSessionStartScript(target: HostTarget, sessionEntryExamples: string[]): string {
72
+ const lines = [
73
+ "#!/usr/bin/env bash",
74
+ "set -e",
75
+ `echo \"RAX-FLOW session starter (${target})\"`,
76
+ "echo \"Use one of these commands (adapt to your local CLI):\""
77
+ ];
78
+
79
+ for (const entry of sessionEntryExamples) {
80
+ lines.push(`echo \"- ${entry}\"`);
81
+ }
82
+
83
+ lines.push("echo \"If unsupported, copy/paste BOOTSTRAP_PROMPT.txt manually.\"");
84
+ return lines.join("\n");
85
+ }
86
+
87
+ function renderRuntimeConfig(target: HostTarget, task?: string): string {
88
+ const payload = {
89
+ version: 1,
90
+ vendor: target,
91
+ model: "host-managed",
92
+ endpoint: null,
93
+ authEnv: null,
94
+ structuredMode: "json",
95
+ timeoutMs: 20000,
96
+ taskContext: task?.trim() || null,
97
+ notes: [
98
+ "Fill endpoint/auth fields if your host runtime requires external transport.",
99
+ "If host runtime is in-process, keep endpoint null and call runtime SDK directly in bridge adapter."
100
+ ]
101
+ };
102
+ return JSON.stringify(payload, null, 2);
103
+ }
104
+
105
+ function renderBridgeSmokeTest(target: HostTarget): string {
106
+ const payload = {
107
+ version: 1,
108
+ action: "callStructured",
109
+ prompt: "Smoke test structured output",
110
+ schema: {
111
+ type: "object",
112
+ required: ["agent", "success", "confidence", "risks", "logs", "data"],
113
+ properties: {
114
+ agent: { type: "string" },
115
+ success: { type: "boolean" },
116
+ confidence: { type: "number" },
117
+ risks: { type: "array" },
118
+ logs: { type: "array" },
119
+ data: { type: "object" }
120
+ }
121
+ },
122
+ options: { model: "host-managed", temperature: 0, maxTokens: 256 },
123
+ meta: { target }
124
+ };
125
+ return JSON.stringify(payload, null, 2);
126
+ }
127
+
128
+ function renderManifest(params: {
129
+ target: HostTarget;
130
+ title: string;
131
+ autoInjectMode: "native" | "scripted" | "manual";
132
+ bridgeCommand: string;
133
+ quickCommands: string[];
134
+ sessionEntryExamples: string[];
135
+ bootstrapPromptFile: string;
136
+ instructionsFile: string;
137
+ adapterFile: string;
138
+ runtimeConfigFile: string;
139
+ smokeTestFile: string;
140
+ vendorFile: string;
141
+ task?: string;
142
+ }): HostManifestModel {
143
+ return {
144
+ version: 2,
145
+ target: params.target,
146
+ title: params.title,
147
+ autoInjectMode: params.autoInjectMode,
148
+ bridgeCommand: params.bridgeCommand,
149
+ quickCommands: params.quickCommands,
150
+ sessionEntryExamples: params.sessionEntryExamples,
151
+ task: params.task ?? null,
152
+ files: {
153
+ bootstrapPrompt: params.bootstrapPromptFile,
154
+ instructions: params.instructionsFile,
155
+ bridgeAdapter: params.adapterFile,
156
+ bridgeRuntimeConfig: params.runtimeConfigFile,
157
+ bridgeSmokeTest: params.smokeTestFile,
158
+ vendorManifest: params.vendorFile
159
+ }
160
+ };
161
+ }
162
+
163
+ async function generateForTarget(cwd: string, target: HostTarget, task?: string): Promise<{ dir: string; bootstrapPrompt: string; quickCommands: string[] }> {
164
+ const template = HOST_TEMPLATES[target];
165
+ const baseDir = path.join(cwd, ".rax-flow", "host-init", target);
166
+ const adapterFile = path.join(baseDir, bridgeAdapterFilename(target));
167
+ const command = bridgeCommand(adapterFile);
168
+
169
+ await mkdir(baseDir, { recursive: true });
170
+
171
+ const setupSh = renderSetupScript(command);
172
+ const sessionStartSh = renderSessionStartScript(target, template.sessionEntryExamples);
173
+ const bootstrapPrompt = buildBootstrapPrompt(target, task);
174
+ const bridgeAdapter = renderBridgeAdapter(target);
175
+ const instructions = renderInstructions({
176
+ title: template.title,
177
+ envHint: template.envHint,
178
+ chatHint: template.chatHint,
179
+ command,
180
+ adapterFile,
181
+ quickCommands: template.quickCommands,
182
+ sessionEntryExamples: template.sessionEntryExamples,
183
+ autoInjectMode: template.autoInjectMode,
184
+ task
185
+ });
186
+
187
+ const bootstrapPromptFile = path.join(baseDir, "BOOTSTRAP_PROMPT.txt");
188
+ const instructionsFile = path.join(baseDir, "INSTRUCTIONS.md");
189
+ const runtimeConfigFile = path.join(baseDir, "bridge-runtime-config.json");
190
+ const smokeTestFile = path.join(baseDir, "bridge-smoke-test.json");
191
+ const vendorFile = vendorManifestFilename(target);
192
+ const manifestObj = renderManifest({
193
+ target,
194
+ title: template.title,
195
+ autoInjectMode: template.autoInjectMode,
196
+ bridgeCommand: command,
197
+ quickCommands: template.quickCommands,
198
+ sessionEntryExamples: template.sessionEntryExamples,
199
+ bootstrapPromptFile,
200
+ instructionsFile,
201
+ adapterFile,
202
+ runtimeConfigFile,
203
+ smokeTestFile,
204
+ vendorFile: path.join(baseDir, vendorFile),
205
+ task
206
+ });
207
+ const manifest = JSON.stringify(manifestObj, null, 2);
208
+ const vendorManifest = generateVendorManifest(target, baseDir, manifestObj);
209
+
210
+ await writeFile(path.join(baseDir, "setup-bridge.sh"), `${setupSh}\n`, "utf8");
211
+ await writeFile(path.join(baseDir, "start-session.sh"), `${sessionStartSh}\n`, "utf8");
212
+ await writeFile(adapterFile, `${bridgeAdapter}\n`, "utf8");
213
+ await writeFile(runtimeConfigFile, `${renderRuntimeConfig(target, task)}\n`, "utf8");
214
+ await writeFile(smokeTestFile, `${renderBridgeSmokeTest(target)}\n`, "utf8");
215
+ await writeFile(bootstrapPromptFile, `${bootstrapPrompt}\n`, "utf8");
216
+ await writeFile(instructionsFile, `${instructions}\n`, "utf8");
217
+ await writeFile(path.join(baseDir, "host-manifest.json"), `${manifest}\n`, "utf8");
218
+ await writeFile(path.join(baseDir, vendorFile), `${JSON.stringify(vendorManifest, null, 2)}\n`, "utf8");
219
+
220
+ return { dir: baseDir, bootstrapPrompt, quickCommands: template.quickCommands };
221
+ }
222
+
223
+ async function generateSummary(cwd: string, generated: Array<{ target: HostTarget; dir: string }>, task?: string): Promise<string> {
224
+ const summaryFile = path.join(cwd, ".rax-flow", "host-init", "INIT_SUMMARY.md");
225
+ const body = [
226
+ "# RAX-FLOW Host Init Summary",
227
+ "",
228
+ ...(task?.trim() ? ["Task context:", `- ${task.trim()}`, ""] : []),
229
+ "Generated targets:",
230
+ ...generated.map((item) => `- ${item.target}: \`${item.dir}\``),
231
+ "",
232
+ "Recommended sequence:",
233
+ "1. Review bridge-adapter-*.mjs and wire host runtime in callHostModel",
234
+ "2. Source setup-bridge.sh for your target",
235
+ "3. Run start-session.sh for launch hints",
236
+ "4. Paste BOOTSTRAP_PROMPT.txt into chat start",
237
+ "5. Run `npx rax-flow doctor`",
238
+ "6. Run `npx rax-flow run --prompt \"Build feature X\" --stream`"
239
+ ].join("\n");
240
+ await writeFile(summaryFile, `${body}\n`, "utf8");
241
+ return summaryFile;
242
+ }
243
+
244
+ export async function runInitHost(options: InitHostOptions): Promise<number> {
245
+ const targets = options.all ? listHostTargets() : [parseHostTarget(options.target)];
246
+
247
+ if (options.printOnly) {
248
+ for (const target of targets) {
249
+ const template = HOST_TEMPLATES[target];
250
+ const bootstrapPrompt = buildBootstrapPrompt(target, options.task);
251
+ console.log(c.blue(`RAX-FLOW Host Init (print) - ${target}`));
252
+ console.log(bootstrapPrompt);
253
+ console.log("quick commands:");
254
+ template.quickCommands.forEach((cmd) => console.log(`- ${cmd}`));
255
+ console.log("session launch patterns:");
256
+ template.sessionEntryExamples.forEach((line) => console.log(`- ${line}`));
257
+ }
258
+ return 0;
259
+ }
260
+
261
+ const generated: Array<{ target: HostTarget; dir: string }> = [];
262
+
263
+ for (const target of targets) {
264
+ const out = await generateForTarget(options.cwd, target, options.task);
265
+ generated.push({ target, dir: out.dir });
266
+ console.log(c.blue("RAX-FLOW Host Init"));
267
+ console.log(`target: ${target}`);
268
+ if (options.task?.trim()) {
269
+ console.log(`task context: ${options.task.trim()}`);
270
+ }
271
+ console.log(c.green(`Generated ${path.join(out.dir, "INSTRUCTIONS.md")}`));
272
+ console.log(c.green(`Generated ${path.join(out.dir, "BOOTSTRAP_PROMPT.txt")}`));
273
+ console.log(c.green(`Generated ${path.join(out.dir, "setup-bridge.sh")}`));
274
+ console.log(c.green(`Generated ${path.join(out.dir, "start-session.sh")}`));
275
+ console.log(c.green(`Generated ${path.join(out.dir, bridgeAdapterFilename(target))}`));
276
+ console.log(c.green(`Generated ${path.join(out.dir, "bridge-runtime-config.json")}`));
277
+ console.log(c.green(`Generated ${path.join(out.dir, "bridge-smoke-test.json")}`));
278
+ console.log(c.green(`Generated ${path.join(out.dir, "host-manifest.json")}`));
279
+ console.log(c.green(`Generated ${path.join(out.dir, vendorManifestFilename(target))}`));
280
+ }
281
+
282
+ const summary = await generateSummary(options.cwd, generated, options.task);
283
+ console.log(c.green(`Generated ${summary}`));
284
+ return 0;
285
+ }