alanbox 0.1.1

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 (41) hide show
  1. package/0commondflowv1/AGENTS.md +51 -0
  2. package/0commondflowv1/res/three-lens-review.js +124 -0
  3. package/0commondflowv1/src/AGENTS.md +26 -0
  4. package/0commondflowv1/src/args.js +75 -0
  5. package/0commondflowv1/src/cli.js +121 -0
  6. package/0commondflowv1/src/commands/AGENTS.md +29 -0
  7. package/0commondflowv1/src/commands/doctor.js +17 -0
  8. package/0commondflowv1/src/commands/info.js +33 -0
  9. package/0commondflowv1/src/commands/install.js +247 -0
  10. package/0commondflowv1/src/commands/swarm/auto.js +270 -0
  11. package/0commondflowv1/src/commands/swarm/custom.js +60 -0
  12. package/0commondflowv1/src/commands/swarm/index.js +20 -0
  13. package/0commondflowv1/src/core/AGENTS.md +31 -0
  14. package/0commondflowv1/src/core/handoff.js +100 -0
  15. package/0commondflowv1/src/core/prompt-builder.js +93 -0
  16. package/0commondflowv1/src/core/prompt-templates.js +92 -0
  17. package/0commondflowv1/src/core/storage.js +98 -0
  18. package/0commondflowv1/src/core/swarm-executor.js +167 -0
  19. package/0commondflowv1/src/core/workers.js +172 -0
  20. package/0commondflowv1/src/core/workflow-planner.js +366 -0
  21. package/0commondflowv1/src/core/workflow-storage.js +123 -0
  22. package/0commondflowv1/src/prompt/AGENTS.md +16 -0
  23. package/0commondflowv1/src/prompt/default.md +30 -0
  24. package/0commondflowv1/src/prompt/reviewer.md +59 -0
  25. package/0commondflowv1/src/prompt/synthesizer.md +31 -0
  26. package/0commondflowv1/src/prompt/verifier.md +31 -0
  27. package/0commondflowv1/src/runner/AGENTS.md +24 -0
  28. package/0commondflowv1/src/runner/codex-runner.js +519 -0
  29. package/0commondflowv1/src/runner/config.json +16 -0
  30. package/README.md +31 -0
  31. package/bin/multirunagent.js +15 -0
  32. package/hooks/hooks.json +18 -0
  33. package/mcp/README.md +5 -0
  34. package/package.json +45 -0
  35. package/plugin/AGENTS.md +14 -0
  36. package/plugin/plugin.json +36 -0
  37. package/scripts/sub-codex-hook.ps1 +15 -0
  38. package/skills/AGENTS.md +17 -0
  39. package/skills/aibox-swam/SKILL.md +77 -0
  40. package/skills/sub-codex-doctor/SKILL.md +27 -0
  41. package/skills/sub-codex-swarm/SKILL.md +56 -0
@@ -0,0 +1,172 @@
1
+ /**
2
+ * worker 规划辅助函数。
3
+ * 解析 worker 规格、匹配配置 worker,并生成依赖层级。
4
+ */
5
+
6
+ function parseWorkerSpecs(specs, parallel, config) {
7
+ const usedIds = new Set();
8
+ const stages = specs.map((spec) => parseWorkerStageSpec(spec));
9
+ let taskIndex = 0;
10
+
11
+ const tasksByStage = stages.map((stageSpecs) => stageSpecs.map((stageSpec) => {
12
+ const task = parseTaskSpec(stageSpec, taskIndex, config);
13
+ taskIndex += 1;
14
+ const idBase = task.role.replace(/\s+/g, '-');
15
+ let id = idBase;
16
+ let suffix = 2;
17
+ while (usedIds.has(id)) {
18
+ id = `${idBase}-${suffix++}`;
19
+ }
20
+ usedIds.add(id);
21
+ return { ...task, id };
22
+ }));
23
+
24
+ if (parallel) {
25
+ return tasksByStage.flat();
26
+ }
27
+
28
+ return tasksByStage.flatMap((stage, stageIndex) => {
29
+ if (stageIndex === 0) return stage;
30
+ const dependsOn = tasksByStage[stageIndex - 1].map((task) => task.id);
31
+ return stage.map((task) => ({ ...task, dependsOn }));
32
+ });
33
+ }
34
+
35
+ function parseWorkerStageSpec(spec) {
36
+ const text = String(spec || '').trim();
37
+ if (!text.startsWith('[')) return [text];
38
+ if (!text.endsWith(']')) {
39
+ throw new Error(`invalid grouped --worker "${spec}". Expected "[<worker>:<role>:<prompt>,<worker>:<role>:<prompt>]".`);
40
+ }
41
+
42
+ const inner = text.slice(1, -1).trim();
43
+ if (!inner) {
44
+ throw new Error('empty grouped --worker. Expected at least one worker spec inside [].');
45
+ }
46
+
47
+ const parts = splitGroupedWorkerSpecs(inner);
48
+ if (parts.length === 0) {
49
+ throw new Error('empty grouped --worker. Expected at least one worker spec inside [].');
50
+ }
51
+ return parts;
52
+ }
53
+
54
+ function splitGroupedWorkerSpecs(text) {
55
+ const parts = [];
56
+ let current = '';
57
+ let escaping = false;
58
+
59
+ for (const char of text) {
60
+ if (escaping) {
61
+ current += char;
62
+ escaping = false;
63
+ continue;
64
+ }
65
+ if (char === '\\') {
66
+ escaping = true;
67
+ continue;
68
+ }
69
+ if (char === ',') {
70
+ const part = current.trim();
71
+ if (part) parts.push(part);
72
+ current = '';
73
+ continue;
74
+ }
75
+ current += char;
76
+ }
77
+
78
+ if (escaping) current += '\\';
79
+ const tail = current.trim();
80
+ if (tail) parts.push(tail);
81
+ return parts;
82
+ }
83
+
84
+ function parseTaskSpec(spec, index, config) {
85
+ const firstColon = spec.indexOf(':');
86
+ const secondColon = firstColon >= 0 ? spec.indexOf(':', firstColon + 1) : -1;
87
+ if (firstColon < 0 || secondColon < 0) {
88
+ throw new Error(`invalid --worker "${spec}". Expected "<platform-or-worker>:<role>:<prompt>".`);
89
+ }
90
+
91
+ const platformOrWorker = spec.slice(0, firstColon).trim();
92
+ const { provider, worker } = resolveWorkerFromPlatform(platformOrWorker, index, config);
93
+ const isDynamicWorker = worker.startsWith('worker-');
94
+ if (!isDynamicWorker && !config.workers?.[worker]) {
95
+ throw new Error(`unknown worker "${platformOrWorker}". Allowed: codex, worker-<n>, or configured workers: ${Object.keys(config.workers || {}).join(', ')}`);
96
+ }
97
+
98
+ const role = spec.slice(firstColon + 1, secondColon).trim() || `worker-${index + 1}`;
99
+ const prompt = spec.slice(secondColon + 1).trim();
100
+ if (!prompt) {
101
+ throw new Error(`missing prompt in --task "${spec}"`);
102
+ }
103
+
104
+ return { platform: provider, provider, worker, role, prompt };
105
+ }
106
+
107
+ function resolveWorkerFromPlatform(value, index, config) {
108
+ const text = String(value || '').trim().toLowerCase();
109
+ if (text === 'codex') {
110
+ return {
111
+ provider: 'codex',
112
+ worker: index === 0 && config.primaryWorker ? config.primaryWorker : `worker-${index + 1}`,
113
+ };
114
+ }
115
+ if (text === 'claude') {
116
+ return {
117
+ provider: 'claude',
118
+ worker: `worker-${index + 1}`,
119
+ };
120
+ }
121
+ const worker = normalizeWorkerName(text);
122
+ const workerProvider = config.workers?.[worker]?.provider || config.defaultProvider || 'codex';
123
+ return { provider: workerProvider, worker };
124
+ }
125
+
126
+ function normalizeWorkerName(value) {
127
+ const text = String(value || '').trim();
128
+ if (/^codex-\d+$/.test(text)) return text.replace(/^codex-/, 'worker-');
129
+ if (/^\d+$/.test(text)) return `worker-${text}`;
130
+ return text;
131
+ }
132
+
133
+ function buildDependencyLevels(tasks) {
134
+ const levels = [];
135
+ const placed = new Set();
136
+
137
+ while (placed.size < tasks.length) {
138
+ const level = [];
139
+ for (const task of tasks) {
140
+ if (placed.has(task.id)) continue;
141
+ const depsReady = !task.dependsOn || task.dependsOn.every((dep) => placed.has(dep));
142
+ if (depsReady) {
143
+ level.push(task);
144
+ }
145
+ }
146
+
147
+ if (level.length === 0) {
148
+ for (const task of tasks) {
149
+ if (!placed.has(task.id)) level.push(task);
150
+ }
151
+ }
152
+
153
+ for (const task of level) {
154
+ placed.add(task.id);
155
+ }
156
+ levels.push(level);
157
+ }
158
+
159
+ return levels;
160
+ }
161
+
162
+ module.exports = {
163
+ parseWorkerSpecs,
164
+ parseWorkerStageSpec,
165
+ splitGroupedWorkerSpecs,
166
+ parseTaskSpec,
167
+ resolveWorkerFromPlatform,
168
+ normalizeWorkerName,
169
+ buildDependencyLevels,
170
+ };
171
+
172
+
@@ -0,0 +1,366 @@
1
+ /**
2
+ * 最小 GOAP workflow planner。
3
+ * 只实现本地 CLI 需要的 Goal / WorldState / Action 抽象,不引入 daemon、Redis 或 Ruflo 大架构。
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const crypto = require('crypto');
9
+ const { renderRoleTemplate } = require('./prompt-templates');
10
+ const { sanitizePathPart } = require('./storage');
11
+
12
+ const DEFAULT_EXCLUDES = new Set(['.git', 'node_modules', 'dist', 'build', '.next', 'coverage', '.cache', '.sub-codex']);
13
+ const MAX_AUTO_DIR_AGENTS = 12;
14
+
15
+ function planWorkflow({ goal, cwd, namespace, agentSpecs = [], planHint = '', config, previousFailures = [] }) {
16
+ const worldState = buildInitialWorldState({ goal, cwd, namespace, agentSpecs, planHint, previousFailures });
17
+ const agents = normalizeAgentSpecs(agentSpecs, config);
18
+ const reviewTargets = chooseReviewTargets({ cwd, planHint, agents });
19
+ const reviewAgents = buildReviewActions({ goal, cwd, planHint, agents, reviewTargets, previousFailures });
20
+ const synthAction = buildSyntheticAction({
21
+ id: 'synthesize',
22
+ type: 'synthesize',
23
+ role: 'synthesizer',
24
+ provider: 'codex',
25
+ prompt: '汇总所有 reviewer 的结果,去重问题,给出最终判断和建议执行顺序。',
26
+ dependsOn: reviewAgents.map((action) => action.id),
27
+ goal,
28
+ cwd,
29
+ planHint,
30
+ expectedState: 'reviewFindings 已汇总,形成可读报告。',
31
+ });
32
+ const verifyAction = buildSyntheticAction({
33
+ id: 'verify',
34
+ type: 'verify',
35
+ role: 'verifier',
36
+ provider: 'codex',
37
+ prompt: '验证目标是否已经达成;如果没有达成,请在 HANDOFF_JSON.status 中返回 failed 或 blocked,并说明原因。',
38
+ dependsOn: [synthAction.id],
39
+ goal,
40
+ cwd,
41
+ planHint,
42
+ expectedState: 'goalVerified 为 true,或者给出需要重规划的失败原因。',
43
+ });
44
+ const actions = [...reviewAgents, synthAction, verifyAction];
45
+ const workflow = {
46
+ schemaVersion: 1,
47
+ mode: 'auto-swarm',
48
+ namespace,
49
+ goal,
50
+ cwd,
51
+ planHint,
52
+ worldState,
53
+ phases: buildPhases(actions),
54
+ actions,
55
+ expectedWorldStateChanges: [
56
+ 'goalCaptured: false -> true',
57
+ 'workflowRecommended: false -> true',
58
+ 'reviewFindings: [] -> reviewer handoff summaries',
59
+ 'goalVerified: false -> verifier judgement',
60
+ ],
61
+ risks: buildRisks({ reviewTargets, previousFailures }),
62
+ };
63
+ workflow.planHash = hashPlan(workflow);
64
+ return workflow;
65
+ }
66
+
67
+ function buildInitialWorldState({ goal, cwd, namespace, agentSpecs, planHint, previousFailures }) {
68
+ return {
69
+ goalCaptured: Boolean(goal),
70
+ workflowRecommended: false,
71
+ approved: false,
72
+ executedActions: [],
73
+ failedActions: previousFailures.map((item) => item.id || item.actionId || '').filter(Boolean),
74
+ goalVerified: false,
75
+ cwd,
76
+ namespace,
77
+ agentCount: agentSpecs.length,
78
+ hasPlanHint: Boolean(planHint),
79
+ };
80
+ }
81
+
82
+ function normalizeAgentSpecs(agentSpecs, config) {
83
+ const specs = Array.isArray(agentSpecs) ? agentSpecs.filter(Boolean) : [];
84
+ if (specs.length === 0) {
85
+ return [{ provider: 'codex', worker: 'worker-1', role: 'reviewer', prompt: '复核当前项目代码。' }];
86
+ }
87
+ return specs.map((spec, index) => parseAutoAgentSpec(spec, index, config));
88
+ }
89
+
90
+ function parseAutoAgentSpec(spec, index, config) {
91
+ const text = String(spec || '').trim();
92
+ const firstColon = text.indexOf(':');
93
+ if (firstColon < 0) {
94
+ return { provider: 'codex', worker: `worker-${index + 1}`, role: `agent-${index + 1}`, prompt: text };
95
+ }
96
+
97
+ const first = text.slice(0, firstColon).trim();
98
+ const rest = text.slice(firstColon + 1);
99
+ const secondColon = rest.indexOf(':');
100
+ const knownProvider = ['codex', 'claude'].includes(first.toLowerCase());
101
+ const knownWorker = isWorkerName(first) || Boolean(config.workers?.[first]);
102
+
103
+ if ((knownProvider || knownWorker) && secondColon >= 0) {
104
+ const role = rest.slice(0, secondColon).trim() || `agent-${index + 1}`;
105
+ const prompt = rest.slice(secondColon + 1).trim();
106
+ const provider = knownProvider ? first.toLowerCase() : (config.workers?.[first]?.provider || config.defaultProvider || 'codex');
107
+ const worker = knownProvider ? `worker-${index + 1}` : first;
108
+ return { provider, worker, role, prompt };
109
+ }
110
+
111
+ return {
112
+ provider: 'codex',
113
+ worker: `worker-${index + 1}`,
114
+ role: first || `agent-${index + 1}`,
115
+ prompt: rest.trim(),
116
+ };
117
+ }
118
+
119
+ function isWorkerName(value) {
120
+ return /^worker-[A-Za-z0-9_.-]+$/i.test(value) || /^codex-\d+$/i.test(value) || /^\d+$/.test(value);
121
+ }
122
+
123
+ function chooseReviewTargets({ cwd, planHint, agents }) {
124
+ if (!shouldFanOutBySubdir(planHint)) {
125
+ return [];
126
+ }
127
+
128
+ let entries = [];
129
+ try {
130
+ entries = fs.readdirSync(cwd, { withFileTypes: true });
131
+ } catch {
132
+ return [];
133
+ }
134
+
135
+ const dirs = entries
136
+ .filter((entry) => entry.isDirectory())
137
+ .map((entry) => entry.name)
138
+ .filter((name) => !DEFAULT_EXCLUDES.has(name))
139
+ .slice(0, MAX_AUTO_DIR_AGENTS)
140
+ .map((name) => path.join(cwd, name));
141
+
142
+ if (dirs.length === 0 && agents.length > 0) return [];
143
+ return dirs;
144
+ }
145
+
146
+ function shouldFanOutBySubdir(planHint) {
147
+ return /子文件夹|子目录|每个.*(目录|文件夹)|parallel|并行/i.test(String(planHint || ''));
148
+ }
149
+
150
+ function buildReviewActions({ goal, cwd, planHint, agents, reviewTargets, previousFailures }) {
151
+ const baseAgents = agents.length ? agents : [{ provider: 'codex', worker: 'worker-1', role: 'reviewer', prompt: goal }];
152
+ const targets = reviewTargets.length ? reviewTargets : baseAgents.map((agent) => agent.target || '');
153
+
154
+ if (reviewTargets.length > 0) {
155
+ const base = baseAgents[0] || { provider: 'codex', role: 'reviewer', prompt: goal };
156
+ return reviewTargets.map((target, index) => buildReviewAction({
157
+ goal,
158
+ cwd,
159
+ planHint,
160
+ previousFailures,
161
+ agent: {
162
+ ...base,
163
+ worker: `worker-${index + 1}`,
164
+ role: base.role || 'reviewer',
165
+ prompt: `${base.prompt || goal}\n重点路径:${target}`,
166
+ },
167
+ index,
168
+ target,
169
+ }));
170
+ }
171
+
172
+ return baseAgents.map((agent, index) => buildReviewAction({
173
+ goal,
174
+ cwd,
175
+ planHint,
176
+ previousFailures,
177
+ agent,
178
+ index,
179
+ target: '',
180
+ }));
181
+ }
182
+
183
+ function buildReviewAction({ goal, cwd, planHint, previousFailures, agent, index, target }) {
184
+ const idBase = `${agent.role || 'review'}-${target ? path.basename(target) : index + 1}`;
185
+ const id = uniqueActionId('review', idBase, index);
186
+ const retryContext = previousFailures.length
187
+ ? `\n上次失败信息:${previousFailures.map((item) => item.error || item.summary || item.id).join(';')}`
188
+ : '';
189
+ const task = [agent.prompt || goal, retryContext].filter(Boolean).join('\n');
190
+ const expectedState = target
191
+ ? `完成 ${target} 的复核,输出问题、证据和 HANDOFF_JSON。`
192
+ : '完成指定范围复核,输出问题、证据和 HANDOFF_JSON。';
193
+ const rendered = renderRoleTemplate({
194
+ role: agent.role || 'reviewer',
195
+ goal,
196
+ task,
197
+ cwd,
198
+ constraints: planHint,
199
+ expectedState,
200
+ });
201
+
202
+ return {
203
+ id,
204
+ type: 'review',
205
+ provider: agent.provider || 'codex',
206
+ worker: agent.worker || `worker-${index + 1}`,
207
+ role: agent.role || 'reviewer',
208
+ prompt: rendered.text,
209
+ dependsOn: [],
210
+ target,
211
+ expectedEffects: ['reviewFindings += handoff.findings', expectedState],
212
+ template: summarizeTemplate(rendered.resolution),
213
+ };
214
+ }
215
+
216
+ function buildSyntheticAction({ id, type, role, provider, prompt, dependsOn, goal, cwd, planHint, expectedState }) {
217
+ const rendered = renderRoleTemplate({
218
+ role,
219
+ goal,
220
+ task: prompt,
221
+ cwd,
222
+ constraints: planHint,
223
+ expectedState,
224
+ });
225
+ return {
226
+ id,
227
+ type,
228
+ provider,
229
+ worker: `worker-${role}`,
230
+ role,
231
+ prompt: rendered.text,
232
+ dependsOn,
233
+ target: '',
234
+ expectedEffects: [expectedState],
235
+ template: summarizeTemplate(rendered.resolution),
236
+ };
237
+ }
238
+
239
+ function summarizeTemplate(resolution) {
240
+ return {
241
+ name: resolution.template,
242
+ path: resolution.path,
243
+ fallback: resolution.fallback,
244
+ inline: resolution.inline,
245
+ };
246
+ }
247
+
248
+ function uniqueActionId(prefix, value, index) {
249
+ return `${prefix}-${sanitizePathPart(value || index + 1).toLowerCase()}`;
250
+ }
251
+
252
+ function buildPhases(actions) {
253
+ const reviewIds = actions.filter((action) => action.type === 'review').map((action) => action.id);
254
+ const synthesizeIds = actions.filter((action) => action.type === 'synthesize').map((action) => action.id);
255
+ const verifyIds = actions.filter((action) => action.type === 'verify').map((action) => action.id);
256
+ return [
257
+ { id: 'review', title: '并行复核', actionIds: reviewIds, parallel: true },
258
+ { id: 'synthesize', title: '汇总结果', actionIds: synthesizeIds, parallel: false },
259
+ { id: 'verify', title: '验证目标', actionIds: verifyIds, parallel: false },
260
+ ].filter((phase) => phase.actionIds.length > 0);
261
+ }
262
+
263
+ function buildRisks({ reviewTargets, previousFailures }) {
264
+ const risks = [
265
+ 'auto workflow 会调用真实 provider;执行前请先使用 --dry-run 查看计划。',
266
+ '如果 workflow 新增 action、扩大目录或改变 provider,应重新确认后再执行。',
267
+ ];
268
+ if (reviewTargets.length >= MAX_AUTO_DIR_AGENTS) {
269
+ risks.push(`子目录 fan-out 已限制为前 ${MAX_AUTO_DIR_AGENTS} 个目录,避免一次启动过多 worker。`);
270
+ }
271
+ if (previousFailures.length) {
272
+ risks.push('这是基于失败信息生成的重规划,需重点检查失败 action 的范围是否扩大。');
273
+ }
274
+ return risks;
275
+ }
276
+
277
+ function workflowToTasks(workflow, namespace) {
278
+ return workflow.actions.map((action, index) => ({
279
+ id: action.id,
280
+ worker: action.worker || `worker-${index + 1}`,
281
+ provider: action.provider || 'codex',
282
+ platform: action.provider || 'codex',
283
+ role: action.role,
284
+ prompt: action.prompt,
285
+ dependsOn: action.dependsOn || [],
286
+ namespace,
287
+ workflowAction: {
288
+ type: action.type,
289
+ target: action.target,
290
+ expectedEffects: action.expectedEffects,
291
+ template: action.template,
292
+ },
293
+ }));
294
+ }
295
+
296
+ function replanWorkflow({ workflow, failures, cwd, namespace, config, planHint }) {
297
+ const failedIds = new Set(failures.map((item) => item.id).filter(Boolean));
298
+ const retryableActions = workflow.actions.filter((action) => failedIds.has(action.id) && action.type !== 'verify');
299
+ if (retryableActions.length === 0) {
300
+ return planWorkflow({
301
+ goal: workflow.goal,
302
+ cwd,
303
+ namespace,
304
+ agentSpecs: [],
305
+ planHint,
306
+ config,
307
+ previousFailures: failures,
308
+ });
309
+ }
310
+
311
+ const retryActions = retryableActions.map((action, index) => ({
312
+ ...action,
313
+ id: `${action.id}-retry-${index + 1}`,
314
+ dependsOn: [],
315
+ prompt: `${action.prompt}\n\n这是失败后的重试。请先阅读上次失败信息,并只在原范围内修复/复核:${JSON.stringify(failures)}`,
316
+ expectedEffects: [...(action.expectedEffects || []), 'retryFailureResolved: false -> true'],
317
+ }));
318
+ const synthAction = buildSyntheticAction({
319
+ id: 'synthesize-retry',
320
+ type: 'synthesize',
321
+ role: 'synthesizer',
322
+ provider: 'codex',
323
+ prompt: '汇总重试 action 的结果,并说明是否已经解决失败原因。',
324
+ dependsOn: retryActions.map((action) => action.id),
325
+ goal: workflow.goal,
326
+ cwd,
327
+ planHint,
328
+ expectedState: '重试结果已汇总。',
329
+ });
330
+ const verifyAction = buildSyntheticAction({
331
+ id: 'verify-retry',
332
+ type: 'verify',
333
+ role: 'verifier',
334
+ provider: 'codex',
335
+ prompt: '验证重试后目标是否达成;未达成则返回 failed 或 blocked。',
336
+ dependsOn: [synthAction.id],
337
+ goal: workflow.goal,
338
+ cwd,
339
+ planHint,
340
+ expectedState: '重试后的 goalVerified 为 true。',
341
+ });
342
+ const actions = [...retryActions, synthAction, verifyAction];
343
+ const next = {
344
+ ...workflow,
345
+ replannedFrom: workflow.planHash,
346
+ actions,
347
+ phases: buildPhases(actions),
348
+ risks: buildRisks({ reviewTargets: [], previousFailures: failures }),
349
+ };
350
+ next.planHash = hashPlan(next);
351
+ return next;
352
+ }
353
+
354
+ function hashPlan(workflow) {
355
+ const copy = JSON.parse(JSON.stringify(workflow));
356
+ delete copy.planHash;
357
+ return crypto.createHash('sha256').update(JSON.stringify(copy)).digest('hex');
358
+ }
359
+
360
+ module.exports = {
361
+ planWorkflow,
362
+ workflowToTasks,
363
+ replanWorkflow,
364
+ parseAutoAgentSpec,
365
+ hashPlan,
366
+ };
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Auto workflow 的本地 AgentDB-lite 存储。
3
+ * 只负责 workflow run 级状态;旧 swarm 的 results/memory 路径仍由 storage.js 维护。
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const { resolveRunDir, sanitizePathPart } = require('./storage');
9
+
10
+ function createRunId() {
11
+ const stamp = new Date().toISOString().replace(/[-:TZ.]/g, '').slice(0, 14);
12
+ const suffix = Math.random().toString(36).slice(2, 8);
13
+ return `run-${stamp}-${suffix}`;
14
+ }
15
+
16
+ function resolveWorkflowRunDir(namespace, runId) {
17
+ return path.join(resolveRunDir(namespace), 'runs', sanitizePathPart(runId));
18
+ }
19
+
20
+ function createWorkflowRun({ namespace, runId = createRunId(), goal, cwd }) {
21
+ const runDir = resolveWorkflowRunDir(namespace, runId);
22
+ return {
23
+ namespace,
24
+ runId,
25
+ goal,
26
+ cwd,
27
+ runDir,
28
+ resultDir: path.join(runDir, 'results'),
29
+ memoryDir: path.join(runDir, 'memory'),
30
+ statePath: path.join(runDir, 'state.json'),
31
+ planPath: path.join(runDir, 'plan.json'),
32
+ runPath: path.join(runDir, 'run.json'),
33
+ stepsPath: path.join(runDir, 'steps.jsonl'),
34
+ };
35
+ }
36
+
37
+ function loadWorkflowRun(namespace, runId) {
38
+ const runDir = resolveWorkflowRunDir(namespace, runId);
39
+ const runPath = path.join(runDir, 'run.json');
40
+ if (!fs.existsSync(runPath)) {
41
+ throw new Error(`workflow run not found: ${runId}`);
42
+ }
43
+ const run = readJson(runPath);
44
+ return createWorkflowRun({
45
+ namespace: run.namespace || namespace,
46
+ runId: run.runId || runId,
47
+ goal: run.goal || '',
48
+ cwd: run.cwd || process.cwd(),
49
+ });
50
+ }
51
+
52
+ function saveRunMetadata(run, data) {
53
+ writeJson(run.runPath, {
54
+ schemaVersion: 1,
55
+ namespace: run.namespace,
56
+ runId: run.runId,
57
+ goal: run.goal,
58
+ cwd: run.cwd,
59
+ createdAt: data.createdAt || new Date().toISOString(),
60
+ updatedAt: new Date().toISOString(),
61
+ status: data.status,
62
+ planHash: data.planHash,
63
+ });
64
+ }
65
+
66
+ function savePlan(run, workflow) {
67
+ writeJson(run.planPath, workflow);
68
+ }
69
+
70
+ function saveState(run, state) {
71
+ writeJson(run.statePath, {
72
+ schemaVersion: 1,
73
+ namespace: run.namespace,
74
+ runId: run.runId,
75
+ updatedAt: new Date().toISOString(),
76
+ ...state,
77
+ });
78
+ }
79
+
80
+ function appendStep(run, event) {
81
+ fs.mkdirSync(path.dirname(run.stepsPath), { recursive: true });
82
+ fs.appendFileSync(run.stepsPath, `${JSON.stringify({
83
+ at: new Date().toISOString(),
84
+ ...event,
85
+ })}\n`, 'utf8');
86
+ }
87
+
88
+ function readPlan(run) {
89
+ return readJson(run.planPath);
90
+ }
91
+
92
+ function readState(run) {
93
+ return readJson(run.statePath);
94
+ }
95
+
96
+ function writeJson(filePath, value) {
97
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
98
+ const tempPath = `${filePath}.tmp`;
99
+ fs.writeFileSync(tempPath, JSON.stringify(value, null, 2), 'utf8');
100
+ fs.renameSync(tempPath, filePath);
101
+ }
102
+
103
+ function readJson(filePath) {
104
+ try {
105
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
106
+ } catch (error) {
107
+ throw new Error(`failed to read JSON ${filePath}: ${error.message}`);
108
+ }
109
+ }
110
+
111
+ module.exports = {
112
+ createRunId,
113
+ resolveWorkflowRunDir,
114
+ createWorkflowRun,
115
+ loadWorkflowRun,
116
+ saveRunMetadata,
117
+ savePlan,
118
+ saveState,
119
+ appendStep,
120
+ readPlan,
121
+ readState,
122
+ writeJson,
123
+ };
@@ -0,0 +1,16 @@
1
+ ## prompt
2
+
3
+ `0commondflowv1/src/prompt` 存放随源码维护的可复用提示词模板
4
+
5
+ ### Important files
6
+
7
+ - `reviewer.md` — 代码审查提示词模板,指导 reviewer 输出阻塞问题、非阻塞建议、检查范围和结论。
8
+ - `default.md` — auto workflow role 模板 fallback。
9
+ - `synthesizer.md` — 汇总多个 reviewer handoff 的模板。
10
+ - `verifier.md` — 验证目标是否达成、失败原因和是否需要重规划的模板。
11
+
12
+ ### Implementation notes
13
+
14
+ - 新增提示词时优先使用小写短文件名,例如 `review.md`。
15
+ - 提示词应说明角色、目标、工作方式、输出格式和约束;不要写入一次性排查结论。
16
+ - 如果提示词被 CLI 参数、README、skills 或默认配置引用,修改时同步检查对应说明。
@@ -0,0 +1,30 @@
1
+ # Default Agent Prompt
2
+
3
+ 你是 multirunagent auto workflow 中的 {{role}} agent。
4
+
5
+ ## 目标
6
+
7
+ {{goal}}
8
+
9
+ ## 当前任务
10
+
11
+ {{task}}
12
+
13
+ ## 工作目录
14
+
15
+ {{cwd}}
16
+
17
+ ## 补充约束
18
+
19
+ {{constraints}}
20
+
21
+ ## 预期状态变化
22
+
23
+ {{expectedState}}
24
+
25
+ ## 输出要求
26
+
27
+ - 用中文输出。
28
+ - 只处理当前任务,不扩展范围。
29
+ - 给出可复核的证据、文件路径或命令结果。
30
+ - 最后输出 `HANDOFF_JSON` fenced JSON,字段包含 status、summary、files、findings、nextSteps、artifacts,可选 verification。