pi-firecode 1.0.0 → 1.0.2

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 (93) hide show
  1. package/README.md +59 -41
  2. package/README.zh-CN.md +78 -0
  3. package/config.example.jsonc +21 -22
  4. package/dist/config.example.jsonc +90 -0
  5. package/dist/index.js +11443 -0
  6. package/dist/master/prompts/master.en.md +22 -0
  7. package/{master → dist/master}/prompts/master.zh.md +3 -3
  8. package/dist/master/prompts/worker.en.md +1 -0
  9. package/dist/watcher/prompts/watch.en.md +43 -0
  10. package/package.json +10 -27
  11. package/activity.ts +0 -92
  12. package/busy.ts +0 -188
  13. package/config.ts +0 -500
  14. package/deliver.ts +0 -119
  15. package/flame.ts +0 -149
  16. package/format.ts +0 -133
  17. package/header.ts +0 -218
  18. package/herdr-client.ts +0 -60
  19. package/index.ts +0 -68
  20. package/jsonc.ts +0 -34
  21. package/master/actions.ts +0 -293
  22. package/master/activity-list.ts +0 -281
  23. package/master/event-card.ts +0 -87
  24. package/master/event-format.ts +0 -83
  25. package/master/guard.ts +0 -46
  26. package/master/index.ts +0 -252
  27. package/master/list-view.ts +0 -129
  28. package/master/outbox.ts +0 -188
  29. package/master/prompt.ts +0 -26
  30. package/master/role.ts +0 -18
  31. package/master/run.ts +0 -315
  32. package/master/runtime.ts +0 -259
  33. package/master/spawn.ts +0 -234
  34. package/master/state.ts +0 -225
  35. package/master/worker-view.ts +0 -517
  36. package/provider/claude-sub.ts +0 -151
  37. package/provider/openai-native/index.ts +0 -8
  38. package/provider/openai-native/src/compact-client.ts +0 -350
  39. package/provider/openai-native/src/config.ts +0 -297
  40. package/provider/openai-native/src/extension.ts +0 -93
  41. package/provider/openai-native/src/native-compaction.ts +0 -151
  42. package/provider/openai-native/src/native-details.ts +0 -157
  43. package/provider/openai-native/src/native-replay.ts +0 -253
  44. package/provider/openai-native/src/native-runtime.ts +0 -144
  45. package/provider/openai-native/src/options.ts +0 -87
  46. package/provider/openai-native/src/request-pipeline.ts +0 -21
  47. package/provider/openai-native/src/responses-input.ts +0 -433
  48. package/review/advisor.ts +0 -110
  49. package/review/card.ts +0 -398
  50. package/review/checkpoint.ts +0 -378
  51. package/review/evidence.ts +0 -230
  52. package/review/index.ts +0 -992
  53. package/review/occupancy.ts +0 -25
  54. package/review/outcome.ts +0 -98
  55. package/review/prompt.ts +0 -209
  56. package/review/reviewer.ts +0 -353
  57. package/review/session.ts +0 -110
  58. package/review/state.ts +0 -877
  59. package/review/ui.ts +0 -89
  60. package/round-recorder.ts +0 -18
  61. package/session/herdr-display.ts +0 -87
  62. package/session/presets.ts +0 -300
  63. package/session/quota.ts +0 -123
  64. package/session/rename.ts +0 -46
  65. package/session/stats.ts +0 -313
  66. package/statusbar/index.ts +0 -256
  67. package/statusbar/render.ts +0 -113
  68. package/theme.ts +0 -45
  69. package/tools/actions.ts +0 -53
  70. package/tools/assistant-view.ts +0 -64
  71. package/tools/click-anchor.ts +0 -56
  72. package/tools/group-view.ts +0 -420
  73. package/tools/grouping.ts +0 -158
  74. package/tools/host.ts +0 -369
  75. package/tools/index.ts +0 -186
  76. package/tools/line.ts +0 -231
  77. package/tools/machine.ts +0 -78
  78. package/tools/parts.ts +0 -143
  79. package/tools/round.ts +0 -95
  80. package/tools/timing.ts +0 -22
  81. package/tools/turn-clock.ts +0 -41
  82. package/tools/turn-summary.ts +0 -109
  83. package/truncated-write.ts +0 -18
  84. package/watcher/card.ts +0 -91
  85. package/watcher/index.ts +0 -176
  86. package/watcher/observer.ts +0 -75
  87. package/watcher/transcript.ts +0 -56
  88. /package/{master → dist/master}/prompts/worker.zh.md +0 -0
  89. /package/{review → dist/review}/prompts/advisor.en.md +0 -0
  90. /package/{review → dist/review}/prompts/advisor.zh.md +0 -0
  91. /package/{review → dist/review}/prompts/review.en.md +0 -0
  92. /package/{review → dist/review}/prompts/review.zh.md +0 -0
  93. /package/{watcher → dist/watcher}/prompts/watch.zh.md +0 -0
package/master/state.ts DELETED
@@ -1,225 +0,0 @@
1
- import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
2
- import { dirname, join } from "node:path";
3
-
4
- const STATE_VERSION = 9;
5
-
6
- export const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"] as const;
7
- export type WorkerThinking = (typeof THINKING_LEVELS)[number];
8
- export type WorkerStatus = "working" | "idle" | "reviewing";
9
- export type WorkerDisposition = "pending" | "reminded";
10
-
11
- export interface WorkerRef {
12
- name: string;
13
- role: string;
14
- model: string;
15
- thinking: WorkerThinking;
16
- status: WorkerStatus;
17
- sessionPath: string;
18
- cwd?: string;
19
- interruptedAt?: number;
20
- /**
21
- * 启动序:start 在同步段按到达先后取的单调序号,活动列表与全过程视图按它排。必须持久化:并行 start 越过
22
- * await 后落盘的先后(以及任何落盘时刻)与到达先后不一致,恢复后若靠别的字段排会换序。
23
- */
24
- launch: number;
25
- reviewNeeded?: boolean;
26
- disposition?: WorkerDisposition;
27
- }
28
-
29
- export interface MasterState {
30
- version: typeof STATE_VERSION;
31
- workers: WorkerRef[];
32
- }
33
-
34
- export type MasterEvent =
35
- | { type: "UPSERT_WORKER"; worker: WorkerRef }
36
- | { type: "REMOVE_WORKER"; name: string }
37
- | { type: "CLEAR" };
38
-
39
- export function initialMasterState(): MasterState {
40
- return { version: STATE_VERSION, workers: [] };
41
- }
42
-
43
- export function reduceMaster(state: MasterState, event: MasterEvent): MasterState {
44
- switch (event.type) {
45
- case "UPSERT_WORKER":
46
- return { ...state, workers: upsertWorker(state.workers, event.worker) };
47
- case "REMOVE_WORKER": {
48
- const workers = state.workers.filter((worker) => worker.name !== event.name);
49
- return workers.length === state.workers.length ? state : { ...state, workers };
50
- }
51
- case "CLEAR":
52
- return initialMasterState();
53
- }
54
- }
55
-
56
- export function recoverMasterState(state: MasterState, interruptedAt = Date.now()): MasterState {
57
- let changed = false;
58
- const workers = state.workers.map((worker) => {
59
- if (worker.status === "idle") return worker;
60
- changed = true;
61
- return { ...worker, status: "idle" as const, interruptedAt };
62
- });
63
- return changed ? { ...state, workers } : state;
64
- }
65
-
66
- export function restoreMasterState(data: unknown): MasterState | undefined {
67
- if (!data || typeof data !== "object" || Array.isArray(data)) return undefined;
68
- const record = data as Record<string, unknown>;
69
- if (record.version !== STATE_VERSION || !Array.isArray(record.workers) || !record.workers.every(isWorker))
70
- return undefined;
71
- const workers = record.workers as WorkerRef[];
72
- if (new Set(workers.map((worker) => worker.name)).size !== workers.length) return undefined;
73
- if (new Set(workers.map((worker) => worker.sessionPath)).size !== workers.length) return undefined;
74
- return { version: STATE_VERSION, workers };
75
- }
76
-
77
- export class LegacyMasterStateError extends Error {
78
- constructor(readonly version: number) {
79
- super(
80
- `Master Worker Pool 状态是旧版 v${version}(当前 v${STATE_VERSION}),不再读取;`
81
- + "重新启动指挥官模式会从空池重建,旧运行时进程不会纳入新池,需要手动清理",
82
- );
83
- }
84
- }
85
-
86
- /** 子代理池档案:与运行配置同一个 Pi Agent 目录(含 PI_CODING_AGENT_DIR 覆写),按主会话 id 分文件。 */
87
- export function masterStatePath(agentDir: string, sessionId: string): string {
88
- const safeId = sessionId.replace(/[^a-zA-Z0-9_-]/gu, "-");
89
- return join(agentDir, "tmp", `firecode-master-${safeId}.json`);
90
- }
91
-
92
- export function loadMasterState(path: string): MasterState | undefined {
93
- let raw: string;
94
- try {
95
- raw = readFileSync(path, "utf8");
96
- } catch (error) {
97
- if ((error as NodeJS.ErrnoException).code === "ENOENT") return undefined;
98
- throw error;
99
- }
100
- let data: unknown;
101
- try {
102
- data = JSON.parse(raw);
103
- } catch {
104
- throw new Error(`Master Worker Pool 状态不是合法 JSON:${path}`);
105
- }
106
- const version = (data as { version?: unknown } | null)?.version;
107
- if (typeof version === "number" && version !== STATE_VERSION && version !== 8) throw new LegacyMasterStateError(version);
108
- const state = restoreMasterState(version === 8 ? migrateFromV8(data as { workers?: unknown }) : data);
109
- if (!state) throw new Error(`Master Worker Pool 状态结构无效:${path}`);
110
- return state;
111
- }
112
-
113
- export class MasterStore {
114
- private stateValue: MasterState;
115
- private readonly path: string;
116
- private readonly onChange?: () => void;
117
- readonly discardedLegacyVersion?: number;
118
-
119
- constructor(path: string, restored?: MasterState, onChange?: () => void) {
120
- this.path = path;
121
- this.onChange = onChange;
122
- if (restored) this.stateValue = restored;
123
- else {
124
- const loaded = this.loadOwnedState();
125
- this.stateValue = loaded.state;
126
- this.discardedLegacyVersion = loaded.discardedLegacyVersion;
127
- }
128
- }
129
-
130
- get state(): MasterState {
131
- return this.stateValue;
132
- }
133
-
134
- dispatch(event: MasterEvent): MasterState {
135
- const next = reduceMaster(this.stateValue, event);
136
- if (next === this.stateValue) return next;
137
- if (event.type === "CLEAR") rmSync(this.path, { force: true });
138
- else writeState(this.path, next);
139
- this.stateValue = next;
140
- this.onChange?.();
141
- return next;
142
- }
143
-
144
- private loadOwnedState(): { state: MasterState; discardedLegacyVersion?: number } {
145
- try {
146
- return { state: loadMasterState(this.path) ?? initialMasterState() };
147
- } catch (error) {
148
- if (!(error instanceof LegacyMasterStateError)) throw error;
149
- rmSync(this.path, { force: true });
150
- return { state: initialMasterState(), discardedLegacyVersion: error.version };
151
- }
152
- }
153
- }
154
-
155
- /**
156
- * v8 → v9 只差启动序:v8 的创建时间是同一先后的近似(并行 start 下可能有出入,从此以 launch 为准),没有创建时间的
157
- * 是更早版本恢复来的、排最前。升级不丢池:池里是用户仍在用的子代理,丢弃会让指挥官失去它们的会话与审查义务。
158
- */
159
- function migrateFromV8(data: { workers?: unknown }): unknown {
160
- if (!Array.isArray(data.workers)) return data;
161
- const workers = data.workers as Record<string, unknown>[];
162
- const created = (index: number) => (typeof workers[index]?.createdAt === "number" ? workers[index].createdAt as number : -Infinity);
163
- const order = workers.map((_, index) => index).sort((a, b) => created(a) - created(b) || a - b);
164
- return {
165
- version: STATE_VERSION,
166
- workers: workers.map((worker, index) => {
167
- const { createdAt: _createdAt, ...rest } = worker ?? {};
168
- return { ...rest, launch: order.indexOf(index) + 1 };
169
- }),
170
- };
171
- }
172
-
173
- export function requireWorker(state: MasterState, name: string): WorkerRef {
174
- const worker = state.workers.find((candidate) => candidate.name === name);
175
- if (!worker) throw new Error(`子代理不存在:${name}`);
176
- return worker;
177
- }
178
-
179
- function writeState(path: string, state: MasterState): void {
180
- mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
181
- const temporary = `${path}.${process.pid}.${crypto.randomUUID()}.tmp`;
182
- try {
183
- writeFileSync(temporary, `${JSON.stringify(state)}\n`, { encoding: "utf8", mode: 0o600 });
184
- renameSync(temporary, path);
185
- } catch (error) {
186
- rmSync(temporary, { force: true });
187
- throw error;
188
- }
189
- }
190
-
191
- function upsertWorker(workers: WorkerRef[], worker: WorkerRef): WorkerRef[] {
192
- const index = workers.findIndex((candidate) => candidate.name === worker.name);
193
- const sessionOwner = workers.find((candidate) => candidate.sessionPath === worker.sessionPath);
194
- if (sessionOwner && sessionOwner.name !== worker.name)
195
- throw new Error(`sessionPath 已被占用:${worker.sessionPath}`);
196
- if (index < 0) return [...workers, worker];
197
- if (workers[index].sessionPath !== worker.sessionPath)
198
- throw new Error(`子代理 ${worker.name} 不能更换 sessionPath`);
199
- return workers.map((candidate, position) => (position === index ? worker : candidate));
200
- }
201
-
202
- function isWorker(value: unknown): value is WorkerRef {
203
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
204
- const record = value as Record<string, unknown>;
205
- if (
206
- typeof record.name !== "string" || !/^[a-z][a-z0-9_-]{0,31}$/u.test(record.name) ||
207
- typeof record.role !== "string" || !record.role ||
208
- typeof record.model !== "string" || !record.model ||
209
- typeof record.thinking !== "string" || !THINKING_LEVELS.includes(record.thinking as WorkerThinking) ||
210
- typeof record.status !== "string" || !isStatus(record.status) ||
211
- typeof record.sessionPath !== "string" || !record.sessionPath
212
- ) return false;
213
- if (record.cwd !== undefined && (typeof record.cwd !== "string" || !record.cwd)) return false;
214
- if (record.interruptedAt !== undefined && (typeof record.interruptedAt !== "number" || record.interruptedAt <= 0))
215
- return false;
216
- if (record.reviewNeeded !== undefined && typeof record.reviewNeeded !== "boolean") return false;
217
- if (typeof record.launch !== "number" || !Number.isInteger(record.launch) || record.launch <= 0) return false;
218
- if (record.disposition !== undefined && record.disposition !== "pending" && record.disposition !== "reminded")
219
- return false;
220
- return true;
221
- }
222
-
223
- function isStatus(value: string): value is WorkerStatus {
224
- return value === "working" || value === "idle" || value === "reviewing";
225
- }