ralph-flow-pi 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 (131) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +428 -0
  3. package/dist/cli.d.ts +9 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +56 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/prompts.d.ts +25 -0
  8. package/dist/commands/prompts.d.ts.map +1 -0
  9. package/dist/commands/prompts.js +249 -0
  10. package/dist/commands/prompts.js.map +1 -0
  11. package/dist/commands/tools.d.ts +47 -0
  12. package/dist/commands/tools.d.ts.map +1 -0
  13. package/dist/commands/tools.js +633 -0
  14. package/dist/commands/tools.js.map +1 -0
  15. package/dist/engine/check-bash.d.ts +121 -0
  16. package/dist/engine/check-bash.d.ts.map +1 -0
  17. package/dist/engine/check-bash.js +373 -0
  18. package/dist/engine/check-bash.js.map +1 -0
  19. package/dist/engine/check.d.ts +47 -0
  20. package/dist/engine/check.d.ts.map +1 -0
  21. package/dist/engine/check.js +298 -0
  22. package/dist/engine/check.js.map +1 -0
  23. package/dist/engine/core.d.ts +153 -0
  24. package/dist/engine/core.d.ts.map +1 -0
  25. package/dist/engine/core.js +1984 -0
  26. package/dist/engine/core.js.map +1 -0
  27. package/dist/engine/lock.d.ts +27 -0
  28. package/dist/engine/lock.d.ts.map +1 -0
  29. package/dist/engine/lock.js +121 -0
  30. package/dist/engine/lock.js.map +1 -0
  31. package/dist/engine/runner.d.ts +108 -0
  32. package/dist/engine/runner.d.ts.map +1 -0
  33. package/dist/engine/runner.js +510 -0
  34. package/dist/engine/runner.js.map +1 -0
  35. package/dist/engine/skills.d.ts +53 -0
  36. package/dist/engine/skills.d.ts.map +1 -0
  37. package/dist/engine/skills.js +109 -0
  38. package/dist/engine/skills.js.map +1 -0
  39. package/dist/engine/step-tools.d.ts +22 -0
  40. package/dist/engine/step-tools.d.ts.map +1 -0
  41. package/dist/engine/step-tools.js +45 -0
  42. package/dist/engine/step-tools.js.map +1 -0
  43. package/dist/engine/types.d.ts +136 -0
  44. package/dist/engine/types.d.ts.map +1 -0
  45. package/dist/engine/types.js +20 -0
  46. package/dist/engine/types.js.map +1 -0
  47. package/dist/headless.d.ts +57 -0
  48. package/dist/headless.d.ts.map +1 -0
  49. package/dist/headless.js +318 -0
  50. package/dist/headless.js.map +1 -0
  51. package/dist/pi/adapter.d.ts +135 -0
  52. package/dist/pi/adapter.d.ts.map +1 -0
  53. package/dist/pi/adapter.js +231 -0
  54. package/dist/pi/adapter.js.map +1 -0
  55. package/dist/pi/interactive.d.ts +28 -0
  56. package/dist/pi/interactive.d.ts.map +1 -0
  57. package/dist/pi/interactive.js +58 -0
  58. package/dist/pi/interactive.js.map +1 -0
  59. package/dist/pi/tui.d.ts +12 -0
  60. package/dist/pi/tui.d.ts.map +1 -0
  61. package/dist/pi/tui.js +12 -0
  62. package/dist/pi/tui.js.map +1 -0
  63. package/dist/tui/app.d.ts +25 -0
  64. package/dist/tui/app.d.ts.map +1 -0
  65. package/dist/tui/app.js +47 -0
  66. package/dist/tui/app.js.map +1 -0
  67. package/dist/tui/embed.d.ts +42 -0
  68. package/dist/tui/embed.d.ts.map +1 -0
  69. package/dist/tui/embed.js +38 -0
  70. package/dist/tui/embed.js.map +1 -0
  71. package/dist/tui/extension.d.ts +88 -0
  72. package/dist/tui/extension.d.ts.map +1 -0
  73. package/dist/tui/extension.js +114 -0
  74. package/dist/tui/extension.js.map +1 -0
  75. package/dist/tui/history-editor.d.ts +38 -0
  76. package/dist/tui/history-editor.d.ts.map +1 -0
  77. package/dist/tui/history-editor.js +55 -0
  78. package/dist/tui/history-editor.js.map +1 -0
  79. package/dist/tui/launcher.d.ts +24 -0
  80. package/dist/tui/launcher.d.ts.map +1 -0
  81. package/dist/tui/launcher.js +97 -0
  82. package/dist/tui/launcher.js.map +1 -0
  83. package/dist/tui/render.d.ts +87 -0
  84. package/dist/tui/render.d.ts.map +1 -0
  85. package/dist/tui/render.js +266 -0
  86. package/dist/tui/render.js.map +1 -0
  87. package/dist/tui/run-app.d.ts +49 -0
  88. package/dist/tui/run-app.d.ts.map +1 -0
  89. package/dist/tui/run-app.js +317 -0
  90. package/dist/tui/run-app.js.map +1 -0
  91. package/dist/tui/run-model.d.ts +162 -0
  92. package/dist/tui/run-model.d.ts.map +1 -0
  93. package/dist/tui/run-model.js +280 -0
  94. package/dist/tui/run-model.js.map +1 -0
  95. package/dist/tui/run-view.d.ts +71 -0
  96. package/dist/tui/run-view.d.ts.map +1 -0
  97. package/dist/tui/run-view.js +167 -0
  98. package/dist/tui/run-view.js.map +1 -0
  99. package/dist/tui/welcome-header.d.ts +40 -0
  100. package/dist/tui/welcome-header.d.ts.map +1 -0
  101. package/dist/tui/welcome-header.js +90 -0
  102. package/dist/tui/welcome-header.js.map +1 -0
  103. package/package.json +55 -0
  104. package/skills/c-to-rust-audit/SKILL.md +67 -0
  105. package/skills/c-to-rust-implement/SKILL.md +151 -0
  106. package/skills/c-to-rust-implement/references/c-to-rust-patterns.md +86 -0
  107. package/skills/c-to-rust-implement/references/conditional-compilation.md +47 -0
  108. package/skills/c-to-rust-implement/references/crate-reference.md +15 -0
  109. package/skills/c-to-rust-implement/references/error-strategies.md +80 -0
  110. package/skills/c-to-rust-implement/references/inline-asm.md +37 -0
  111. package/skills/c-to-rust-plan/SKILL.md +166 -0
  112. package/skills/c-to-rust-plan/references/detection-commands.md +66 -0
  113. package/skills/c-to-rust-test-gen/SKILL.md +130 -0
  114. package/skills/c-to-rust-test-gen/references/proptest-patterns.md +81 -0
  115. package/skills/c-to-rust-test-gen/references/test-porting.md +56 -0
  116. package/skills/c-to-rust-validate/SKILL.md +121 -0
  117. package/skills/everything2rust-audit/SKILL.md +69 -0
  118. package/skills/everything2rust-design/SKILL.md +121 -0
  119. package/skills/everything2rust-design/references/domain-playbooks.md +68 -0
  120. package/skills/everything2rust-design/references/paradigm-map.md +99 -0
  121. package/skills/everything2rust-implement/SKILL.md +101 -0
  122. package/skills/everything2rust-spec/SKILL.md +86 -0
  123. package/skills/everything2rust-spec/references/oracle-strategies.md +96 -0
  124. package/skills/everything2rust-survey/SKILL.md +99 -0
  125. package/skills/everything2rust-test-gen/SKILL.md +68 -0
  126. package/skills/everything2rust-test-gen/references/harness-patterns.md +186 -0
  127. package/skills/everything2rust-validate/SKILL.md +85 -0
  128. package/workflows/c-to-rust.yaml +202 -0
  129. package/workflows/everything2rust.yaml +259 -0
  130. package/workflows/loop.yaml +68 -0
  131. package/workflows/spec.yaml +183 -0
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Anti-corruption layer over the Pi SDK.
3
+ *
4
+ * This is the ONLY file in the package allowed to import @earendil-works/*.
5
+ * Pi is on 0.x with a fast release cadence (244 releases by v0.80.7), so the
6
+ * blast radius of an API change has to stay inside these ~250 lines: everything
7
+ * else talks to the narrow interfaces below and to our own normalized event
8
+ * type, never to Pi's.
9
+ *
10
+ * Upgrade drill: bump the pinned version → fix this file → run the adapter
11
+ * contract tests → run the CHECK smoke (`ralph _check-once`).
12
+ */
13
+ import fs from "fs";
14
+ import path from "path";
15
+ import { createAgentSession, defineTool, DefaultResourceLoader, ModelRuntime, getAgentDir, resolveCliModel, SessionManager, SettingsManager, CURRENT_SESSION_VERSION, loadSkillsFromDir, VERSION as PI_VERSION, } from "@earendil-works/pi-coding-agent";
16
+ export { defineTool, loadSkillsFromDir, CURRENT_SESSION_VERSION };
17
+ /** Pi's read-only built-in tool set. Deliberately excludes bash: the verifier's
18
+ * only shell access is our whitelisted check_bash custom tool. This matches the
19
+ * Claude version's `--allowedTools "Read(*) Glob(*) Grep(*) …"` allow-list. */
20
+ export const READ_ONLY_TOOL_NAMES = ["read", "grep", "find", "ls"];
21
+ /** Full coding tool set for DO steps. */
22
+ export const CODING_TOOL_NAMES = ["read", "bash", "edit", "write", "grep", "find", "ls"];
23
+ function textOf(content) {
24
+ if (!Array.isArray(content))
25
+ return "";
26
+ return content
27
+ .filter((c) => c && c.type === "text" && typeof c.text === "string")
28
+ .map((c) => c.text)
29
+ .join("\n");
30
+ }
31
+ /** Translate one Pi event into zero or one of ours. */
32
+ function normalize(event) {
33
+ const e = event;
34
+ switch (e.type) {
35
+ case "message_update": {
36
+ const inner = e.assistantMessageEvent;
37
+ if (!inner)
38
+ return null;
39
+ if (inner.type === "text_delta" && typeof inner.delta === "string")
40
+ return { type: "text", delta: inner.delta };
41
+ if (inner.type === "thinking_delta" && typeof inner.delta === "string")
42
+ return { type: "reasoning", delta: inner.delta };
43
+ return null;
44
+ }
45
+ case "tool_execution_start":
46
+ return { type: "tool_start", toolCallId: String(e.toolCallId ?? ""), toolName: String(e.toolName ?? ""), args: e.args };
47
+ case "tool_execution_end":
48
+ return {
49
+ type: "tool_end",
50
+ toolCallId: String(e.toolCallId ?? ""),
51
+ toolName: String(e.toolName ?? ""),
52
+ isError: !!e.isError,
53
+ text: textOf(e.result?.content),
54
+ };
55
+ case "turn_end":
56
+ return { type: "turn_end" };
57
+ case "agent_end":
58
+ // willRetry means Pi is auto-retrying a provider error — the turn is not
59
+ // actually over, so don't wake the runner's keep-alive on it.
60
+ return e.willRetry ? null : { type: "agent_end" };
61
+ case "compaction_end":
62
+ return e.aborted ? null : { type: "compaction_end" };
63
+ default:
64
+ return null;
65
+ }
66
+ }
67
+ function wrap(session, jsonlPath) {
68
+ let disposed = false;
69
+ return {
70
+ jsonlPath,
71
+ async prompt(text) {
72
+ await session.prompt(text);
73
+ },
74
+ async followUp(text) {
75
+ await session.followUp(text);
76
+ },
77
+ async steer(text) {
78
+ await session.steer(text);
79
+ },
80
+ subscribe(listener) {
81
+ return session.subscribe((event) => {
82
+ const normalized = normalize(event);
83
+ if (normalized)
84
+ listener(normalized);
85
+ });
86
+ },
87
+ async abort() {
88
+ try {
89
+ await session.abort();
90
+ }
91
+ catch { }
92
+ },
93
+ dispose() {
94
+ if (disposed)
95
+ return;
96
+ disposed = true;
97
+ try {
98
+ session.dispose();
99
+ }
100
+ catch { }
101
+ },
102
+ };
103
+ }
104
+ let sharedRuntime = null;
105
+ async function getRuntime() {
106
+ if (!sharedRuntime) {
107
+ sharedRuntime = await ModelRuntime.create();
108
+ }
109
+ return sharedRuntime;
110
+ }
111
+ /**
112
+ * Resolve a "provider/model" or "provider/model:thinking" string.
113
+ *
114
+ * This is where adversarial_check.model gets its cross-provider superpower for
115
+ * free: pi-ai resolves any provider, so a workflow can verify Claude's work with
116
+ * GPT without the engine knowing anything about either.
117
+ *
118
+ * Returns `{ error }` rather than throwing — callers fall back to the session's
119
+ * default model, matching the plugin versions' "unresolvable model falls back"
120
+ * behavior.
121
+ */
122
+ export async function resolveModel(spec) {
123
+ const trimmed = String(spec || "").trim();
124
+ if (!trimmed)
125
+ return { model: undefined, error: "empty model spec" };
126
+ try {
127
+ const modelRuntime = await getRuntime();
128
+ const result = resolveCliModel({ cliModel: trimmed, modelRuntime });
129
+ return {
130
+ model: result.model,
131
+ thinkingLevel: result.thinkingLevel,
132
+ warning: result.warning ?? undefined,
133
+ error: result.error ?? undefined,
134
+ };
135
+ }
136
+ catch (e) {
137
+ return { model: undefined, error: e?.message || String(e) };
138
+ }
139
+ }
140
+ /** The existing transcript in a session dir, if any. */
141
+ export function findSessionFile(sessionDir) {
142
+ try {
143
+ const files = fs.readdirSync(sessionDir).filter((f) => f.endsWith(".jsonl")).sort();
144
+ // Newest wins if a dir somehow holds several (Pi's names sort chronologically).
145
+ return files.length > 0 ? path.join(sessionDir, files[files.length - 1]) : null;
146
+ }
147
+ catch {
148
+ return null;
149
+ }
150
+ }
151
+ async function build(options) {
152
+ const { cwd, model, thinkingLevel, tools, customTools, systemPrompt, appendSystemPrompt, sessionDir, disableCompaction, noExtensions, skillPaths, noSkills, } = options;
153
+ // Pi's `tools` option is an allowlist over ALL tools, custom ones included
154
+ // (sdk.js: `initialActiveToolNames = options.tools ? [...options.tools] : …`).
155
+ // Registering a custom tool without naming it here leaves it inactive — which
156
+ // for the check session would mean a verifier that can never submit a verdict,
157
+ // and would look like a permanent infra failure rather than a wiring bug.
158
+ const activeTools = [...tools, ...(customTools ?? []).map((t) => t.name)];
159
+ const resourceLoader = new DefaultResourceLoader({
160
+ cwd,
161
+ agentDir: getAgentDir(),
162
+ // The verifier must not inherit the user's pi extensions: an extension can
163
+ // register arbitrary tools, and a write tool smuggled into the check session
164
+ // would break the read-only guarantee this whole design rests on.
165
+ ...(noExtensions ? { noExtensions: true } : {}),
166
+ ...(noSkills ? { noSkills: true } : {}),
167
+ ...(skillPaths && skillPaths.length > 0 ? { additionalSkillPaths: skillPaths } : {}),
168
+ ...(systemPrompt !== undefined ? { systemPromptOverride: () => systemPrompt } : {}),
169
+ ...(appendSystemPrompt !== undefined
170
+ ? { appendSystemPromptOverride: (base) => [...base, appendSystemPrompt] }
171
+ : {}),
172
+ });
173
+ await resourceLoader.reload();
174
+ let sessionManager;
175
+ if (sessionDir) {
176
+ fs.mkdirSync(sessionDir, { recursive: true });
177
+ const existing = findSessionFile(sessionDir);
178
+ sessionManager = existing
179
+ ? SessionManager.open(existing, sessionDir, cwd)
180
+ : SessionManager.create(cwd, sessionDir);
181
+ }
182
+ else {
183
+ sessionManager = SessionManager.inMemory(cwd);
184
+ }
185
+ const settingsManager = disableCompaction
186
+ ? SettingsManager.inMemory({ compaction: { enabled: false } })
187
+ : undefined;
188
+ const { session } = await createAgentSession({
189
+ cwd,
190
+ agentDir: getAgentDir(),
191
+ ...(model ? { model: model } : {}),
192
+ ...(thinkingLevel ? { thinkingLevel: thinkingLevel } : {}),
193
+ tools: activeTools,
194
+ ...(customTools ? { customTools } : {}),
195
+ resourceLoader,
196
+ sessionManager,
197
+ ...(settingsManager ? { settingsManager } : {}),
198
+ });
199
+ // Resolved only after creation: Pi names the file lazily.
200
+ const resolvedPath = (() => {
201
+ try {
202
+ return sessionManager.getSessionFile() ?? null;
203
+ }
204
+ catch {
205
+ return null;
206
+ }
207
+ })();
208
+ return wrap(session, resolvedPath);
209
+ }
210
+ /** A DO step session: full coding tools, persisted, fresh context per step. */
211
+ export async function createStepSession(options) {
212
+ return build({ ...options, tools: options.tools ?? CODING_TOOL_NAMES });
213
+ }
214
+ /**
215
+ * A CHECK session: read-only built-ins only.
216
+ *
217
+ * The read-only guarantee is structural, not prompted — `edit`/`write`/`bash`
218
+ * are simply not in the tool set, so the verifier cannot mutate the workspace it
219
+ * is judging even if the model decides it wants to.
220
+ */
221
+ export async function createCheckSession(options) {
222
+ // noSkills: the verifier's job is to judge against the check criteria, not to
223
+ // follow a playbook. Skills describe how to BUILD things; handing them to the
224
+ // checker invites it to sympathize with the implementation it is grading.
225
+ return build({ ...options, tools: READ_ONLY_TOOL_NAMES, noExtensions: true, noSkills: true });
226
+ }
227
+ /** The pinned Pi version, surfaced for diagnostics. */
228
+ export function piVersion() {
229
+ return PI_VERSION;
230
+ }
231
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/pi/adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Booting pi's InteractiveMode, kept behind the anti-corruption layer with the
3
+ * rest of the SDK contact (see adapter.ts).
4
+ *
5
+ * The assembly mirrors what pi's own `main.ts` does, minus every CLI concern we
6
+ * don't have (flag parsing, --api-key, model scopes, print/rpc modes):
7
+ *
8
+ * services ← createAgentSessionServices, carrying our inline extension
9
+ * session ← createAgentSessionFromServices
10
+ * runtime ← createAgentSessionRuntime
11
+ * UI ← new InteractiveMode(runtime).run()
12
+ *
13
+ * The extension is passed as an `extensionFactories` entry, which is how pi
14
+ * loads in-process extensions — the same door its own bundled ones come through.
15
+ */
16
+ export interface BootInteractiveOptions {
17
+ cwd: string;
18
+ /** An inline extension: `{ name, factory(api) }`. */
19
+ extension: unknown;
20
+ /** If set, sent as the first message on startup (used to seed the create flow). */
21
+ initialMessage?: string;
22
+ /** Receives the main session's id once it exists. */
23
+ onSessionId(id: string): void;
24
+ /** Run on SIGINT / normal exit, before the process goes away. */
25
+ onShutdown(): void;
26
+ }
27
+ export declare function bootInteractive(options: BootInteractiveOptions): Promise<void>;
28
+ //# sourceMappingURL=interactive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../../src/pi/interactive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAWH,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,qDAAqD;IACrD,SAAS,EAAE,OAAO,CAAC;IACnB,mFAAmF;IACnF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qDAAqD;IACrD,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,iEAAiE;IACjE,UAAU,IAAI,IAAI,CAAC;CACpB;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0CpF"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Booting pi's InteractiveMode, kept behind the anti-corruption layer with the
3
+ * rest of the SDK contact (see adapter.ts).
4
+ *
5
+ * The assembly mirrors what pi's own `main.ts` does, minus every CLI concern we
6
+ * don't have (flag parsing, --api-key, model scopes, print/rpc modes):
7
+ *
8
+ * services ← createAgentSessionServices, carrying our inline extension
9
+ * session ← createAgentSessionFromServices
10
+ * runtime ← createAgentSessionRuntime
11
+ * UI ← new InteractiveMode(runtime).run()
12
+ *
13
+ * The extension is passed as an `extensionFactories` entry, which is how pi
14
+ * loads in-process extensions — the same door its own bundled ones come through.
15
+ */
16
+ import { createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, getAgentDir, InteractiveMode, SessionManager, } from "@earendil-works/pi-coding-agent";
17
+ export async function bootInteractive(options) {
18
+ const { cwd, extension, initialMessage, onSessionId, onShutdown } = options;
19
+ const agentDir = getAgentDir();
20
+ const sessionManager = SessionManager.create(cwd);
21
+ const runtime = await createAgentSessionRuntime(async ({ cwd: runtimeCwd, agentDir: runtimeAgentDir, sessionManager: sm, sessionStartEvent }) => {
22
+ const services = await createAgentSessionServices({
23
+ cwd: runtimeCwd,
24
+ agentDir: runtimeAgentDir,
25
+ resourceLoaderOptions: {
26
+ extensionFactories: [extension],
27
+ },
28
+ });
29
+ const created = await createAgentSessionFromServices({ services, sessionManager: sm, sessionStartEvent });
30
+ return { ...created, services, diagnostics: [...services.diagnostics] };
31
+ }, { cwd, agentDir, sessionManager });
32
+ onSessionId(sessionManager.getSessionId());
33
+ // Interrupted instances must be parked before we die, or their next run would
34
+ // see a live-looking state with a dead pid and have to guess. Registered
35
+ // before the UI starts so a crash during startup is still covered.
36
+ let shuttingDown = false;
37
+ const shutdown = () => {
38
+ if (shuttingDown)
39
+ return;
40
+ shuttingDown = true;
41
+ try {
42
+ onShutdown();
43
+ }
44
+ catch { }
45
+ };
46
+ process.on("exit", shutdown);
47
+ process.on("SIGINT", shutdown);
48
+ process.on("SIGTERM", shutdown);
49
+ const interactive = new InteractiveMode(runtime, initialMessage ? { initialMessage } : undefined);
50
+ try {
51
+ await interactive.init();
52
+ await interactive.run();
53
+ }
54
+ finally {
55
+ shutdown();
56
+ }
57
+ }
58
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../src/pi/interactive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EACL,8BAA8B,EAC9B,yBAAyB,EACzB,0BAA0B,EAC1B,WAAW,EACX,eAAe,EACf,cAAc,GACf,MAAM,iCAAiC,CAAC;AAczC,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAA+B;IACnE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IAC5E,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAC/B,MAAM,cAAc,GAAG,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAElD,MAAM,OAAO,GAAG,MAAM,yBAAyB,CAC7C,KAAK,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,eAAe,EAAE,cAAc,EAAE,EAAE,EAAE,iBAAiB,EAAE,EAAE,EAAE;QAC9F,MAAM,QAAQ,GAAG,MAAM,0BAA0B,CAAC;YAChD,GAAG,EAAE,UAAU;YACf,QAAQ,EAAE,eAAe;YACzB,qBAAqB,EAAE;gBACrB,kBAAkB,EAAE,CAAC,SAAgB,CAAC;aACvC;SACF,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,8BAA8B,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,iBAAiB,EAAE,CAAC,CAAC;QAC1G,OAAO,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,GAAG,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;IAC1E,CAAC,EACD,EAAE,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,CAClC,CAAC;IAEF,WAAW,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC,CAAC;IAE3C,8EAA8E;IAC9E,yEAAyE;IACzE,mEAAmE;IACnE,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,IAAI,YAAY;YAAE,OAAO;QACzB,YAAY,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC;YAAC,UAAU,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IAChC,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAEhC,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAClG,IAAI,CAAC;QACH,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC;QACzB,MAAM,WAAW,CAAC,GAAG,EAAE,CAAC;IAC1B,CAAC;YAAS,CAAC;QACT,QAAQ,EAAE,CAAC;IACb,CAAC;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The single point of contact with pi-tui and pi's theme module.
3
+ *
4
+ * Same anti-corruption discipline as adapter.ts: pi-tui is on the same fast 0.x
5
+ * cadence as the SDK, so every `@earendil-works/pi-tui` and theme import lives
6
+ * here and the run view talks only to these re-exports. A pi-tui API change is a
7
+ * one-file fix.
8
+ */
9
+ export { TUI, Container, Text, Markdown, SelectList, Input, ProcessTerminal, matchesKey, parseKey, Key, type Component, type SelectItem, type SelectListTheme, type Terminal, type EditorTheme, } from "@earendil-works/pi-tui";
10
+ export { visibleWidth, wrapTextWithAnsi, truncateToWidth, } from "@earendil-works/pi-tui";
11
+ export { initTheme, getSelectListTheme, getMarkdownTheme, CustomEditor, Theme, type KeybindingsManager, type ThemeColor, } from "@earendil-works/pi-coding-agent";
12
+ //# sourceMappingURL=tui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../../src/pi/tui.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,GAAG,EACH,SAAS,EACT,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,KAAK,EACL,eAAe,EACf,UAAU,EACV,QAAQ,EACR,GAAG,EACH,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,QAAQ,EACb,KAAK,WAAW,GACjB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,EACZ,KAAK,EACL,KAAK,kBAAkB,EACvB,KAAK,UAAU,GAChB,MAAM,iCAAiC,CAAC"}
package/dist/pi/tui.js ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The single point of contact with pi-tui and pi's theme module.
3
+ *
4
+ * Same anti-corruption discipline as adapter.ts: pi-tui is on the same fast 0.x
5
+ * cadence as the SDK, so every `@earendil-works/pi-tui` and theme import lives
6
+ * here and the run view talks only to these re-exports. A pi-tui API change is a
7
+ * one-file fix.
8
+ */
9
+ export { TUI, Container, Text, Markdown, SelectList, Input, ProcessTerminal, matchesKey, parseKey, Key, } from "@earendil-works/pi-tui";
10
+ export { visibleWidth, wrapTextWithAnsi, truncateToWidth, } from "@earendil-works/pi-tui";
11
+ export { initTheme, getSelectListTheme, getMarkdownTheme, CustomEditor, Theme, } from "@earendil-works/pi-coding-agent";
12
+ //# sourceMappingURL=tui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui.js","sourceRoot":"","sources":["../../src/pi/tui.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,GAAG,EACH,SAAS,EACT,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,KAAK,EACL,eAAe,EACf,UAAU,EACV,QAAQ,EACR,GAAG,GAMJ,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,EACZ,KAAK,GAGN,MAAM,iCAAiC,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The chat surface — `ralphflow`'s default entry point.
3
+ *
4
+ * A general chat, same as talking to Claude Code: starting/watching a workflow
5
+ * is one of the things you can ask it to do (natural language or a
6
+ * /ralphflow-* command), not a separate forced-first mode. When a workflow is
7
+ * actually running, ralphflow_start/continue/watch (commands/tools.ts) borrow
8
+ * this SAME chat session's TUI via Pi's `ctx.ui.custom()` and hand it to the
9
+ * dedicated run view (tui/run-app.ts's runInstanceInTui) for the duration of
10
+ * the run — see tui/embed.ts. Detaching (Esc) hands the terminal straight
11
+ * back to this chat, mid-conversation, workflow still running in the
12
+ * background. Designing a NEW workflow (/ralphflow-create) is also just a
13
+ * conversation in this same surface, seeded with a different opening message.
14
+ *
15
+ * It reuses pi's InteractiveMode with our inline extension (the seven
16
+ * ralphflow_* tools + eight slash commands).
17
+ */
18
+ /** Launch the chat surface. `seed`, if given, is sent as the first message. */
19
+ export declare function runChat(cwd: string, seed?: string): Promise<void>;
20
+ /**
21
+ * `ralphflow create [描述]` — drop into the chat already pointed at the
22
+ * create flow, so the user lands in a workflow-design conversation.
23
+ */
24
+ export declare function runCreateMode(cwd: string, description: string): Promise<void>;
25
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/tui/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAOH,+EAA+E;AAC/E,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBvE;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGnF"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * The chat surface — `ralphflow`'s default entry point.
3
+ *
4
+ * A general chat, same as talking to Claude Code: starting/watching a workflow
5
+ * is one of the things you can ask it to do (natural language or a
6
+ * /ralphflow-* command), not a separate forced-first mode. When a workflow is
7
+ * actually running, ralphflow_start/continue/watch (commands/tools.ts) borrow
8
+ * this SAME chat session's TUI via Pi's `ctx.ui.custom()` and hand it to the
9
+ * dedicated run view (tui/run-app.ts's runInstanceInTui) for the duration of
10
+ * the run — see tui/embed.ts. Detaching (Esc) hands the terminal straight
11
+ * back to this chat, mid-conversation, workflow still running in the
12
+ * background. Designing a NEW workflow (/ralphflow-create) is also just a
13
+ * conversation in this same surface, seeded with a different opening message.
14
+ *
15
+ * It reuses pi's InteractiveMode with our inline extension (the seven
16
+ * ralphflow_* tools + eight slash commands).
17
+ */
18
+ import { createEngine } from "../engine/core.js";
19
+ import { abortActiveCheck } from "../engine/check.js";
20
+ import { createRalphExtension } from "./extension.js";
21
+ import { bootInteractive } from "../pi/interactive.js";
22
+ /** Launch the chat surface. `seed`, if given, is sent as the first message. */
23
+ export async function runChat(cwd, seed) {
24
+ const engine = createEngine(cwd, { abortActiveCheck });
25
+ engine.ensureProjectWorkflows();
26
+ // The main session's id is the ownership token in every instance's state.json.
27
+ // It only exists once pi has built the session, so the extension reads it
28
+ // lazily rather than capturing it at construction.
29
+ let sessionId = "";
30
+ const ralph = createRalphExtension(engine, () => sessionId);
31
+ await bootInteractive({
32
+ cwd,
33
+ extension: ralph.extension,
34
+ initialMessage: seed,
35
+ onSessionId: (id) => { sessionId = id; },
36
+ onShutdown: () => ralph.shutdown(),
37
+ });
38
+ }
39
+ /**
40
+ * `ralphflow create [描述]` — drop into the chat already pointed at the
41
+ * create flow, so the user lands in a workflow-design conversation.
42
+ */
43
+ export async function runCreateMode(cwd, description) {
44
+ const seed = `我想创建一个新的工作流。${description ? `需求:${description}` : ""}\n\n请用 /ralphflow-create 的流程带我设计:先了解要自动化的流程和人工审查点,再设计步骤图给我看,然后写 YAML 并用 ralphflow_doctor 校验到干净。`;
45
+ await runChat(cwd, seed);
46
+ }
47
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/tui/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,GAAW,EAAE,IAAa;IACtD,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,EAAE,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACvD,MAAM,CAAC,sBAAsB,EAAE,CAAC;IAEhC,+EAA+E;IAC/E,0EAA0E;IAC1E,mDAAmD;IACnD,IAAI,SAAS,GAAG,EAAE,CAAC;IACnB,MAAM,KAAK,GAAG,oBAAoB,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAE5D,MAAM,eAAe,CAAC;QACpB,GAAG;QACH,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,cAAc,EAAE,IAAI;QACpB,WAAW,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC;QACxC,UAAU,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE;KACnC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW,EAAE,WAAmB;IAClE,MAAM,IAAI,GAAG,eAAe,WAAW,CAAC,CAAC,CAAC,MAAM,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,iGAAiG,CAAC;IACpK,MAAM,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The chat session's "take over the terminal to run a workflow" seam.
3
+ *
4
+ * `ralphflow_start`/`ralphflow_continue`/`ralphflow_watch` (commands/tools.ts)
5
+ * call `attachRunView` once an instance is actively running. It borrows the
6
+ * SAME `TUI` the chat session already owns (via Pi's `ctx.ui.custom()`) rather
7
+ * than spawning a second one — save the chat's current root components,
8
+ * clear, mount the run view, run it to completion/cancellation/detach,
9
+ * restore the saved components, hand back.
10
+ *
11
+ * Verified against a real terminal + real model (see fancy-purring-sparkle.md
12
+ * step 3): the chat's header/transcript/editor survive a takeover-and-restore
13
+ * cycle intact, and the model resumes exactly where it left off. The one
14
+ * subtlety that mattered in that spike: the factory passed to `ui.custom`
15
+ * must not resolve until AFTER `done()` has been called. `showExtensionCustom`
16
+ * does `Promise.resolve(factory(...)).then(c => { if (!closed) { editor
17
+ * Container.clear(); editorContainer.addChild(c); ... } })` the moment the
18
+ * factory's returned promise settles — if that happened while we're still
19
+ * mid-takeover, it would clobber the chat's real editor with `undefined`.
20
+ * Keeping the factory itself pending until we call `done()` (which flips
21
+ * `closed` to true) makes that branch a no-op.
22
+ */
23
+ import type { Engine } from "../engine/core.js";
24
+ import type { Runner } from "../engine/runner.js";
25
+ import { type RunInstanceOutcome } from "./run-app.js";
26
+ import type { TUI } from "../pi/tui.js";
27
+ /**
28
+ * The slice of Pi's extension context this file touches. `custom`'s result is
29
+ * `T | undefined` to match Pi's real signature (`done` takes an optional
30
+ * result) — we always call `done(result)` with a real value below, so
31
+ * `attachRunView` narrows it back to a guaranteed `RunInstanceOutcome` for
32
+ * its own callers.
33
+ */
34
+ export interface UiCustomHost {
35
+ ui: {
36
+ custom<T>(factory: (tui: TUI, theme: unknown, keybindings: unknown, done: (result?: T) => void) => unknown): Promise<T | undefined>;
37
+ };
38
+ /** ExtensionContext.abort — see tools.ts's attachResult for why this, not just `terminate`, is called on detach. */
39
+ abort?(): void;
40
+ }
41
+ export declare function attachRunView(ctx: UiCustomHost, engine: Engine, runner: Runner, sessionId: string, instId: string): Promise<RunInstanceOutcome>;
42
+ //# sourceMappingURL=embed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.d.ts","sourceRoot":"","sources":["../../src/tui/embed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAoB,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAExC;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE;QAAE,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,IAAI,KAAK,OAAO,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAA;KAAE,CAAC;IAC5I,oHAAoH;IACpH,KAAK,CAAC,IAAI,IAAI,CAAC;CAChB;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,YAAY,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,kBAAkB,CAAC,CAY7B"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The chat session's "take over the terminal to run a workflow" seam.
3
+ *
4
+ * `ralphflow_start`/`ralphflow_continue`/`ralphflow_watch` (commands/tools.ts)
5
+ * call `attachRunView` once an instance is actively running. It borrows the
6
+ * SAME `TUI` the chat session already owns (via Pi's `ctx.ui.custom()`) rather
7
+ * than spawning a second one — save the chat's current root components,
8
+ * clear, mount the run view, run it to completion/cancellation/detach,
9
+ * restore the saved components, hand back.
10
+ *
11
+ * Verified against a real terminal + real model (see fancy-purring-sparkle.md
12
+ * step 3): the chat's header/transcript/editor survive a takeover-and-restore
13
+ * cycle intact, and the model resumes exactly where it left off. The one
14
+ * subtlety that mattered in that spike: the factory passed to `ui.custom`
15
+ * must not resolve until AFTER `done()` has been called. `showExtensionCustom`
16
+ * does `Promise.resolve(factory(...)).then(c => { if (!closed) { editor
17
+ * Container.clear(); editorContainer.addChild(c); ... } })` the moment the
18
+ * factory's returned promise settles — if that happened while we're still
19
+ * mid-takeover, it would clobber the chat's real editor with `undefined`.
20
+ * Keeping the factory itself pending until we call `done()` (which flips
21
+ * `closed` to true) makes that branch a no-op.
22
+ */
23
+ import { runInstanceInTui } from "./run-app.js";
24
+ export async function attachRunView(ctx, engine, runner, sessionId, instId) {
25
+ const result = await ctx.ui.custom(async (tui, _theme, _keybindings, done) => {
26
+ const saved = [...tui.children];
27
+ tui.clear();
28
+ const outcome = await runInstanceInTui({ engine, tui, sessionId, instId, runner });
29
+ tui.clear();
30
+ for (const c of saved)
31
+ tui.addChild(c);
32
+ tui.requestRender(true);
33
+ done(outcome);
34
+ return undefined; // ignored: `done()` already closed the custom UI
35
+ });
36
+ return result ?? { outcome: "detached" };
37
+ }
38
+ //# sourceMappingURL=embed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.js","sourceRoot":"","sources":["../../src/tui/embed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,EAAE,gBAAgB,EAA2B,MAAM,cAAc,CAAC;AAgBzE,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAiB,EACjB,MAAc,EACd,MAAc,EACd,SAAiB,EACjB,MAAc;IAEd,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAqB,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE;QAC/F,MAAM,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;QAChC,GAAG,CAAC,KAAK,EAAE,CAAC;QACZ,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QACnF,GAAG,CAAC,KAAK,EAAE,CAAC;QACZ,KAAK,MAAM,CAAC,IAAI,KAAK;YAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QACvC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QACxB,IAAI,CAAC,OAAO,CAAC,CAAC;QACd,OAAO,SAAS,CAAC,CAAC,iDAAiD;IACrE,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * The ralph-flow extension for the main chat session.
3
+ *
4
+ * This is the whole TUI. The plan budgeted ~870 lines for a hand-built one
5
+ * (transcript pane, streaming renderer, slash dispatcher, status bar) — none of
6
+ * that got written, because pi's InteractiveMode already IS a Claude-Code-style
7
+ * TUI and its extension API exposes exactly the three seams we need:
8
+ *
9
+ * registerTool → the six ralphflow_* tools, so the model can drive them
10
+ * from plain language ("start the spec workflow on X")
11
+ * registerCommand → the eight /ralphflow-* slash commands, verbatim
12
+ * sendMessage → the runner's output, rendered into the same transcript
13
+ *
14
+ * The important thing this does NOT do: hand pi the workflow. Step sessions are
15
+ * still created and driven by our runner, one fresh context per step. The main
16
+ * chat session is a control surface and a viewport — if it were the DO session
17
+ * we would have rebuilt the opencode plugin's central flaw on a new stack.
18
+ */
19
+ import type { Engine } from "../engine/core.js";
20
+ import { type Runner } from "../engine/runner.js";
21
+ /**
22
+ * Pi's extension surface, narrowed to what this file touches.
23
+ *
24
+ * Two different objects, easy to conflate (a real crash the first time
25
+ * around): `ExtensionAPI` — this file's `api`, from `factory(api)` — has
26
+ * `registerTool`/`registerCommand`/`sendMessage`/`sendUserMessage`/`on`, and
27
+ * NO `ui`. `ExtensionContext` — a *different* type, handed to every `on(...)`
28
+ * handler and command/tool `execute()` as a context argument — is where `ui`
29
+ * (`.custom`, `.setEditorComponent`, …) actually lives. `ui.custom` (used in
30
+ * tools.ts's attachRunView) is only ever reached via a tool's own `execute()`
31
+ * receiving that context, never via this top-level `api`.
32
+ */
33
+ interface PiExtensionApi {
34
+ registerTool(tool: any): void;
35
+ registerCommand(name: string, options: {
36
+ description?: string;
37
+ handler: (args: string, ctx: any) => Promise<void>;
38
+ }): void;
39
+ sendMessage(message: {
40
+ customType: string;
41
+ content: string;
42
+ display?: string;
43
+ details?: unknown;
44
+ }, options?: {
45
+ triggerTurn?: boolean;
46
+ deliverAs?: "steer" | "followUp" | "nextTurn";
47
+ }): void;
48
+ sendUserMessage(content: string, options?: {
49
+ deliverAs?: "steer" | "followUp";
50
+ }): void;
51
+ on(event: string, handler: (event: any, ctx: ExtensionContextLike) => void): void;
52
+ }
53
+ /** Just the corner of ExtensionContext (extensions/types.ts) this file needs. */
54
+ interface ExtensionContextLike {
55
+ mode: string;
56
+ ui: {
57
+ setEditorComponent(factory: ((tui: any, theme: any, keybindings: any) => unknown) | undefined): void;
58
+ setHeader(factory: ((tui: any, theme: any) => unknown) | undefined): void;
59
+ };
60
+ }
61
+ export interface RalphExtensionResult {
62
+ runner: Runner;
63
+ /** Called on SIGINT/exit so interrupted instances resume cleanly. */
64
+ shutdown(): void;
65
+ }
66
+ /**
67
+ * Build the inline extension. `getSessionId` must return the main session's id
68
+ * — it is the ownership token written into every instance's state.json.
69
+ */
70
+ export declare function createRalphExtension(engine: Engine, getSessionId: () => string): {
71
+ extension: {
72
+ name: string;
73
+ factory(a: PiExtensionApi): void;
74
+ };
75
+ readonly runner: {
76
+ ensureRunning: (instId: string) => void;
77
+ reviseGate: (instId: string, instruction: string) => void;
78
+ sendUserMessage: (instId: string, text: string) => boolean;
79
+ addEventListener: (l: import("../engine/runner.js").RunnerEvents) => () => void;
80
+ abortActiveStep: (instId: string) => void;
81
+ isRunning: (instId: string) => boolean;
82
+ idle: () => Promise<void>;
83
+ pauseAllForShutdown: () => void;
84
+ };
85
+ shutdown: () => void;
86
+ };
87
+ export {};
88
+ //# sourceMappingURL=extension.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../src/tui/extension.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAOhE;;;;;;;;;;;GAWG;AACH,UAAU,cAAc;IACtB,YAAY,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,CAAC;IAC9B,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3H,WAAW,CAAC,OAAO,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,CAAA;KAAE,GAAG,IAAI,CAAC;IAC7L,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,GAAG,UAAU,CAAA;KAAE,GAAG,IAAI,CAAC;IACvF,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,oBAAoB,KAAK,IAAI,GAAG,IAAI,CAAC;CACnF;AAED,iFAAiF;AACjF,UAAU,oBAAoB;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE;QACF,kBAAkB,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;QACrG,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;KAC3E,CAAC;CACH;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,QAAQ,IAAI,IAAI,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,MAAM;;;mBAahE,cAAc;;;;;;;;;;;;;EA6E5B"}