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,109 @@
1
+ /**
2
+ * Skill discovery, in the same three tiers as workflows: project → global → built-in.
3
+ *
4
+ * The engine deliberately knows almost nothing about skills. A workflow step's
5
+ * `do:` text just says "use the c-to-rust-plan skill"; the model reads that,
6
+ * finds the skill in its system prompt catalog, and loads it. That decoupling is
7
+ * inherited from both plugin versions and is why the 12 domain skills could move
8
+ * here as plain text.
9
+ *
10
+ * What changed from the plan: pi already ships this. `loadSkillsFromDir` parses
11
+ * SKILL.md frontmatter, and the default system prompt appends a catalog (name,
12
+ * description, ABSOLUTE location) plus the instruction to resolve a skill's
13
+ * relative references against its own directory — as long as the session has the
14
+ * `read` tool. So there is no `use_skill` tool here: writing one would have
15
+ * duplicated pi's mechanism and fought its prompt.
16
+ *
17
+ * All this file adds is the tier resolution pi doesn't do: same-named skills
18
+ * shadow, nearest tier wins, and only the winners are handed to the session.
19
+ */
20
+ import fs from "fs";
21
+ import path from "path";
22
+ import { fileURLToPath } from "url";
23
+ import { loadSkillsFromDir } from "../pi/adapter.js";
24
+ /** Skills shipped inside the package. */
25
+ export function getBuiltinSkillsDir() {
26
+ const __filename = fileURLToPath(import.meta.url);
27
+ // dist/engine/skills.js → package root → skills/
28
+ return path.join(path.dirname(__filename), "..", "..", "skills");
29
+ }
30
+ export function getProjectSkillsDir(ralphFlowDir) {
31
+ return path.join(ralphFlowDir, "skills");
32
+ }
33
+ export function getGlobalSkillsDir(globalConfigHome) {
34
+ return globalConfigHome ? path.join(globalConfigHome, "skills") : null;
35
+ }
36
+ /**
37
+ * Resolve the skills available to a DO session.
38
+ *
39
+ * @param ralphFlowDir the project's .ralph-flow dir
40
+ * @param globalConfigHome ~/.config/ralph-flow-pi, or null when there's no home
41
+ */
42
+ export function loadSkillIndex(ralphFlowDir, globalConfigHome) {
43
+ const globalDir = getGlobalSkillsDir(globalConfigHome);
44
+ const tiers = [
45
+ { source: "project", dir: getProjectSkillsDir(ralphFlowDir) },
46
+ ...(globalDir ? [{ source: "global", dir: globalDir }] : []),
47
+ { source: "builtin", dir: getBuiltinSkillsDir() },
48
+ ];
49
+ const byName = new Map();
50
+ const diagnostics = [];
51
+ for (const { source, dir } of tiers) {
52
+ if (!fs.existsSync(dir))
53
+ continue;
54
+ let result;
55
+ try {
56
+ result = loadSkillsFromDir({ dir, source });
57
+ }
58
+ catch (e) {
59
+ diagnostics.push(`扫描 skill 目录 ${dir} 失败:${e.message}`);
60
+ continue;
61
+ }
62
+ for (const d of result.diagnostics ?? []) {
63
+ if (d?.message)
64
+ diagnostics.push(`${d.message}(${source})`);
65
+ }
66
+ for (const skill of result.skills ?? []) {
67
+ const existing = byName.get(skill.name);
68
+ if (existing) {
69
+ // An earlier tier already won; record that this one is shadowed so
70
+ // doctor can explain why an edit to it had no effect.
71
+ existing.shadowed.push({ source, filePath: skill.filePath });
72
+ continue;
73
+ }
74
+ byName.set(skill.name, {
75
+ name: skill.name,
76
+ description: skill.description,
77
+ filePath: skill.filePath,
78
+ source,
79
+ shadowed: [],
80
+ });
81
+ }
82
+ }
83
+ const skills = [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
84
+ return { skills, paths: skills.map((s) => s.filePath), diagnostics };
85
+ }
86
+ /** Doctor section: which skills are available, and what shadows what. */
87
+ export function formatSkillReport(index) {
88
+ const lines = [];
89
+ const label = { project: "项目自定义", global: "全局用户", builtin: "内置" };
90
+ if (index.skills.length === 0) {
91
+ lines.push("没有找到任何 skill。");
92
+ }
93
+ else {
94
+ lines.push(`可用 skill:**${index.skills.length}** 个`, "");
95
+ for (const s of index.skills) {
96
+ lines.push(`- **${s.name}**(${label[s.source]}):${s.description || "(无描述)"}`);
97
+ for (const sh of s.shadowed) {
98
+ lines.push(` - ℹ️ 遮蔽了同名${label[sh.source]} skill:${sh.filePath}`);
99
+ }
100
+ }
101
+ }
102
+ if (index.diagnostics.length > 0) {
103
+ lines.push("", "问题:");
104
+ for (const d of index.diagnostics)
105
+ lines.push(`- ⚠️ ${d}`);
106
+ }
107
+ return lines.join("\n");
108
+ }
109
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/engine/skills.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Custom tools injected into every DO step session.
3
+ *
4
+ * `report_done` is the replacement for `<promise>done</promise>`. The plugin
5
+ * versions asked the model to end its message with that tag and then regex'd it
6
+ * back out — which needed rules for the last line, the last 100 characters, and
7
+ * stripping code fences, and still misfired when a model explained the tag
8
+ * instead of emitting it, or kept talking after it. A tool call is unambiguous:
9
+ * it either happened or it didn't, and prose can never look like one.
10
+ */
11
+ import type { Engine } from "./core.js";
12
+ import { type ToolDefinition } from "../pi/adapter.js";
13
+ /**
14
+ * The DO session's only way to end its step.
15
+ *
16
+ * Calling it writes the .done-reported marker; the runner's keep-alive loop
17
+ * watches for that and moves on to CHECK. Nothing here judges the work — that is
18
+ * the independent verifier's job, and keeping this tool dumb is what stops the
19
+ * worker from grading its own homework.
20
+ */
21
+ export declare function makeReportDoneTool(engine: Engine, instId: string): ToolDefinition;
22
+ //# sourceMappingURL=step-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-tools.d.ts","sourceRoot":"","sources":["../../src/engine/step-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEnE;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc,CAwBjF"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Custom tools injected into every DO step session.
3
+ *
4
+ * `report_done` is the replacement for `<promise>done</promise>`. The plugin
5
+ * versions asked the model to end its message with that tag and then regex'd it
6
+ * back out — which needed rules for the last line, the last 100 characters, and
7
+ * stripping code fences, and still misfired when a model explained the tag
8
+ * instead of emitting it, or kept talking after it. A tool call is unambiguous:
9
+ * it either happened or it didn't, and prose can never look like one.
10
+ */
11
+ import { Type } from "typebox";
12
+ import { defineTool } from "../pi/adapter.js";
13
+ /**
14
+ * The DO session's only way to end its step.
15
+ *
16
+ * Calling it writes the .done-reported marker; the runner's keep-alive loop
17
+ * watches for that and moves on to CHECK. Nothing here judges the work — that is
18
+ * the independent verifier's job, and keeping this tool dumb is what stops the
19
+ * worker from grading its own homework.
20
+ */
21
+ export function makeReportDoneTool(engine, instId) {
22
+ return defineTool({
23
+ name: "report_done",
24
+ label: "Report Done",
25
+ description: "在本步骤的所有任务要求和输出要求都满足后调用,声明 DO 阶段完成。这是结束本步骤的唯一方式。" +
26
+ "完成后会有一个独立的只读会话来验证你的工作,所以不要在工作未完成时调用。",
27
+ parameters: Type.Object({
28
+ summary: Type.Optional(Type.String({
29
+ description: "一句话说明你做了什么(可选,仅用于日志与报告;验证者不会看到它,只会看你的实际产出)。",
30
+ })),
31
+ }),
32
+ execute: async (_toolCallId, params) => {
33
+ const summary = typeof params.summary === "string" ? params.summary.trim() : "";
34
+ // writeDoneReported no-ops on a destroyed instance, so a cancel racing this
35
+ // call cannot resurrect the instance dir.
36
+ engine.writeDoneReported(instId);
37
+ engine.logEvent(instId, "info", "done_reported", { summary: summary.slice(0, 200) });
38
+ return {
39
+ content: [{ type: "text", text: "已记录:DO 阶段完成。接下来由独立的只读会话验证本步骤,你无需再做其他事。" }],
40
+ details: {},
41
+ };
42
+ },
43
+ });
44
+ }
45
+ //# sourceMappingURL=step-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-tools.js","sourceRoot":"","sources":["../../src/engine/step-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,OAAO,EAAE,UAAU,EAAuB,MAAM,kBAAkB,CAAC;AAEnE;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc,EAAE,MAAc;IAC/D,OAAO,UAAU,CAAC;QAChB,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,aAAa;QACpB,WAAW,EACT,iDAAiD;YACjD,sCAAsC;QACxC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC;YACtB,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;gBACjC,WAAW,EAAE,6CAA6C;aAC3D,CAAC,CAAC;SACJ,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,OAAO,GAAG,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChF,4EAA4E;YAC5E,0CAA0C;YAC1C,MAAM,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;YACjC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YACrF,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,wCAAwC,EAAE,CAAC;gBACpF,OAAO,EAAE,EAAE;aACZ,CAAC;QACJ,CAAC;KACF,CAA8B,CAAC;AAClC,CAAC"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Shared types for the ralph-flow-pi engine.
3
+ *
4
+ * The WORKFLOW SCHEMA (StepDef/WorkflowDef/AdversarialCheckConfig) is a verbatim
5
+ * mirror of the opencode plugin's engine.ts so existing user YAML runs unchanged;
6
+ * see SYNC.md. RalphFlowState is likewise mirrored — instance state files stay
7
+ * semantically identical.
8
+ */
9
+ export interface NormalStepDef {
10
+ id: string;
11
+ desc: string;
12
+ do: string;
13
+ input: string;
14
+ output: string;
15
+ check: string;
16
+ on_pass: string;
17
+ on_fail: string;
18
+ max_fail_count: number;
19
+ }
20
+ export interface SubWorkflowStepDef {
21
+ id: string;
22
+ desc: string;
23
+ workflow: string;
24
+ inputs?: Record<string, string>;
25
+ input: string;
26
+ output: string;
27
+ on_pass: string;
28
+ on_fail: string;
29
+ max_fail_count: number;
30
+ }
31
+ export type StepDef = NormalStepDef | SubWorkflowStepDef;
32
+ export interface AdversarialCheckConfig {
33
+ /**
34
+ * Accepted in both historical shapes. The string form ("provider/model" or
35
+ * "provider/model:thinking") is what pi-ai resolves natively; the object form
36
+ * is the opencode SDK's shape and is normalized to the string form at parse
37
+ * time so downstream code only ever sees a string.
38
+ */
39
+ model?: string;
40
+ /**
41
+ * Accepted for YAML compatibility. pi has no agent concept — the verifier's
42
+ * read-only sandbox is a tool-set preset instead, so this field only produces
43
+ * a doctor warning.
44
+ */
45
+ agent?: string;
46
+ system_prompt?: string;
47
+ timeout_ms?: number;
48
+ /**
49
+ * Extra glob patterns merged into the CHECK bash whitelist for THIS
50
+ * workflow only (same `*`-glob syntax as the built-in table in core.ts,
51
+ * e.g. "./scripts/check.sh *", "just test*", "my-cli verify *"). Exists
52
+ * because the built-in table is a fixed, hardcoded list that cannot know
53
+ * about a project's own build tooling — a custom CLI, `just`, `bazel`,
54
+ * `poetry run pytest`, etc. would otherwise have no way to run during
55
+ * CHECK at all. Patterns still pass through every shell-escape guard in
56
+ * check-bash.ts unchanged (command substitution, write redirection,
57
+ * script-embedded writes) — this only adds entries to the "is this command
58
+ * NAME allowed" table, nothing here weakens those checks. What it does NOT
59
+ * do: sandbox what the allowed command does once it runs — same trust
60
+ * boundary as the built-in `cargo test`/`npm test` entries (see
61
+ * check-bash.ts's file header). The workflow author is trusting their own
62
+ * project's script, same as running it locally.
63
+ */
64
+ extra_allowed_bash?: string[];
65
+ }
66
+ export interface WorkflowDef {
67
+ name: string;
68
+ description: string;
69
+ manual_step: string[];
70
+ steps: StepDef[];
71
+ adversarial_check?: AdversarialCheckConfig;
72
+ }
73
+ export interface RalphFlowState {
74
+ active: boolean;
75
+ workflow_name: string;
76
+ current_step: string;
77
+ current_phase: string;
78
+ fail_count: number;
79
+ user_task: string;
80
+ paused: boolean;
81
+ pause_reason?: string;
82
+ last_failure_reason?: string;
83
+ instance_id?: string;
84
+ /** The session that owns/drives this instance. Set by the tool that touches it. */
85
+ session_id?: string;
86
+ }
87
+ export interface StepExecutionRecord {
88
+ stepId: string;
89
+ phase: string;
90
+ status: "passed" | "failed";
91
+ failCount: number;
92
+ startTime: string;
93
+ endTime?: string;
94
+ reason?: string;
95
+ }
96
+ export interface CheckResult {
97
+ passed: boolean;
98
+ /** True when the check could not run at all (crash/timeout/no verdict) — not a work failure. */
99
+ infra?: boolean;
100
+ reason: string;
101
+ }
102
+ export interface InstanceInfo {
103
+ id: string;
104
+ state: RalphFlowState;
105
+ owner: string | null;
106
+ manualGate: boolean;
107
+ doneReported: boolean;
108
+ lastActivity: Date | null;
109
+ }
110
+ export interface TransitionResult {
111
+ text: string;
112
+ paused?: boolean;
113
+ completed?: boolean;
114
+ }
115
+ /**
116
+ * Platform seam — the little the engine needs from the host.
117
+ *
118
+ * The opencode version only needed abortActiveCheck (the DO phase ran in the
119
+ * host's own session, which the plugin could not abort). Here the engine owns
120
+ * every session, so destroyInstance must be able to abort the step session too.
121
+ */
122
+ export interface Platform {
123
+ /** Abort a still-running adversarial check (in-process handle). */
124
+ abortActiveCheck?(instId: string): void;
125
+ /** Abort a still-running DO step session (in-process handle). */
126
+ abortActiveStep?(instId: string): void;
127
+ }
128
+ export type PermissionAction = "allow" | "deny" | "ask";
129
+ export declare function isSubWorkflowStep(step: StepDef): step is SubWorkflowStepDef;
130
+ /**
131
+ * Strip UTF-8 BOM (Byte Order Mark) from file content.
132
+ * Windows Notepad and some editors add BOM to UTF-8 files.
133
+ * js-yaml and JSON.parse don't handle BOM, causing parse failures.
134
+ */
135
+ export declare function stripBom(text: string): string;
136
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/engine/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Shared types for the ralph-flow-pi engine.
3
+ *
4
+ * The WORKFLOW SCHEMA (StepDef/WorkflowDef/AdversarialCheckConfig) is a verbatim
5
+ * mirror of the opencode plugin's engine.ts so existing user YAML runs unchanged;
6
+ * see SYNC.md. RalphFlowState is likewise mirrored — instance state files stay
7
+ * semantically identical.
8
+ */
9
+ export function isSubWorkflowStep(step) {
10
+ return "workflow" in step && typeof step.workflow === "string";
11
+ }
12
+ /**
13
+ * Strip UTF-8 BOM (Byte Order Mark) from file content.
14
+ * Windows Notepad and some editors add BOM to UTF-8 files.
15
+ * js-yaml and JSON.parse don't handle BOM, causing parse failures.
16
+ */
17
+ export function stripBom(text) {
18
+ return text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;
19
+ }
20
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/engine/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAsIH,MAAM,UAAU,iBAAiB,CAAC,IAAa;IAC7C,OAAO,UAAU,IAAI,IAAI,IAAI,OAAQ,IAA2B,CAAC,QAAQ,KAAK,QAAQ,CAAC;AACzF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Non-interactive CLI verbs: `ralphflow status|list|doctor|cancel|continue`.
3
+ *
4
+ * These reach the same state machine as the ralphflow_* tools without
5
+ * starting the chat, so scripts and CI can inspect, unblock, and stop
6
+ * workflows. The formatting helpers are the engine's own, so headless output
7
+ * and the in-chat tool responses stay in sync. `continue` is the one verb
8
+ * that also drives the instance afterward (via a real runner, blocking until
9
+ * the next stopping point) rather than being a pure read/mutate-and-return —
10
+ * see its own doc comment for why that's still a bounded, one-shot operation
11
+ * and not a background daemon.
12
+ *
13
+ * There is no session id out here — every instance looks "owned by someone
14
+ * else", which is exactly right: a headless invocation is not a chat session.
15
+ */
16
+ import { type Engine } from "./engine/core.js";
17
+ import { type RunnerDeps } from "./engine/runner.js";
18
+ export interface HeadlessResult {
19
+ text: string;
20
+ /** Process exit code: 0 = fine, 1 = the user asked about something that isn't there. */
21
+ code: number;
22
+ }
23
+ export declare function runStatus(engine: Engine, explicit?: string): HeadlessResult;
24
+ export declare function runList(engine: Engine): HeadlessResult;
25
+ export declare function runDoctor(engine: Engine): HeadlessResult;
26
+ /**
27
+ * Cancel an instance. Takes the cross-process lock so a cancel can't interleave
28
+ * with a runner committing a check verdict in another process. The runner there
29
+ * notices the instance is gone on its next state read and discards its result.
30
+ */
31
+ export declare function runCancel(engine: Engine, explicit?: string): Promise<HeadlessResult>;
32
+ /**
33
+ * `ralphflow continue [实例ID]` — approve a manual review / resume a paused
34
+ * workflow / recover from a crash, without an interactive session. Reuses
35
+ * ralphflow_continue's exact state machine (`resolveContinueAction`,
36
+ * commands/tools.ts) — the only difference is what happens after: an
37
+ * interactive session hands off to the run view; this drives the instance
38
+ * with a real runner and blocks until it reaches its NEXT stopping point
39
+ * (another gate/pause, or completion) instead of returning immediately.
40
+ * That is a deliberate, bounded scope for "headless" — it does not turn this
41
+ * into a background daemon; the process exits once the instance stops moving
42
+ * on its own again, exactly as if a human were watching it.
43
+ *
44
+ * `attached: true` always — a one-shot CLI invocation has no standing session
45
+ * identity to already "be" the owner of anything, so the crash-recovery
46
+ * re-attach branch (resolveContinueAction's #5) is always reachable here,
47
+ * which is the right default for a headless caller.
48
+ *
49
+ * `runnerDeps` is a test seam (real callers never pass it) — same shape as
50
+ * `RunnerDeps` in engine/runner.ts, so a test can inject `createSession`/
51
+ * `checkDeps` fakes to drive the "runs to the next stop" behavior without
52
+ * API credentials, the same way runner.test.ts already does for the runner
53
+ * itself.
54
+ */
55
+ export declare function runContinue(engine: Engine, explicit?: string, runnerDeps?: RunnerDeps): Promise<HeadlessResult>;
56
+ export declare function runHeadless(verb: string, args: string[], cwd: string): Promise<HeadlessResult>;
57
+ //# sourceMappingURL=headless.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless.d.ts","sourceRoot":"","sources":["../src/headless.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,EAAoC,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAGjF,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAKnE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,cAAc,CAoF3E;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAUtD;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAKxD;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAuC1F;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,CA+DrH;AA2CD,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAYpG"}