@liangjie559567/ultrapower 5.5.2 → 5.5.6

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 (94) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/bridge/codex-server.cjs +15 -7
  4. package/bridge/gemini-server.cjs +25 -7
  5. package/bridge/mcp-server.cjs +9 -4
  6. package/bridge/team-bridge.cjs +5 -1
  7. package/commands/brainstorm.md +1 -1
  8. package/commands/execute-plan.md +1 -1
  9. package/commands/write-plan.md +1 -1
  10. package/dist/__tests__/job-management.test.js +43 -43
  11. package/dist/__tests__/job-management.test.js.map +1 -1
  12. package/dist/agents/definitions.d.ts +1 -1
  13. package/dist/agents/definitions.js +1 -1
  14. package/dist/hooks/guards/pre-tool.d.ts.map +1 -1
  15. package/dist/hooks/guards/pre-tool.js +8 -2
  16. package/dist/hooks/guards/pre-tool.js.map +1 -1
  17. package/dist/hooks/recovery/session-recovery.js +1 -1
  18. package/dist/hooks/recovery/session-recovery.js.map +1 -1
  19. package/dist/hooks/rules-injector/constants.d.ts +2 -0
  20. package/dist/hooks/rules-injector/constants.d.ts.map +1 -1
  21. package/dist/hooks/rules-injector/constants.js +2 -0
  22. package/dist/hooks/rules-injector/constants.js.map +1 -1
  23. package/dist/hooks/rules-injector/finder.d.ts.map +1 -1
  24. package/dist/hooks/rules-injector/finder.js +12 -4
  25. package/dist/hooks/rules-injector/finder.js.map +1 -1
  26. package/dist/installer/__tests__/hooks.test.d.ts +6 -0
  27. package/dist/installer/__tests__/hooks.test.d.ts.map +1 -0
  28. package/dist/installer/__tests__/hooks.test.js +121 -0
  29. package/dist/installer/__tests__/hooks.test.js.map +1 -0
  30. package/dist/installer/index.d.ts.map +1 -1
  31. package/dist/installer/index.js +11 -10
  32. package/dist/installer/index.js.map +1 -1
  33. package/dist/lib/__tests__/atomic-write.test.js +3 -4
  34. package/dist/lib/__tests__/atomic-write.test.js.map +1 -1
  35. package/dist/lib/__tests__/version.test.d.ts +6 -0
  36. package/dist/lib/__tests__/version.test.d.ts.map +1 -0
  37. package/dist/lib/__tests__/version.test.js +37 -0
  38. package/dist/lib/__tests__/version.test.js.map +1 -0
  39. package/dist/lib/atomic-write.d.ts.map +1 -1
  40. package/dist/lib/atomic-write.js +6 -8
  41. package/dist/lib/atomic-write.js.map +1 -1
  42. package/dist/mcp/codex-core.d.ts.map +1 -1
  43. package/dist/mcp/codex-core.js +9 -4
  44. package/dist/mcp/codex-core.js.map +1 -1
  45. package/dist/mcp/gemini-core.d.ts.map +1 -1
  46. package/dist/mcp/gemini-core.js +16 -1
  47. package/dist/mcp/gemini-core.js.map +1 -1
  48. package/dist/mcp/job-management.js +2 -2
  49. package/dist/mcp/job-management.js.map +1 -1
  50. package/dist/mcp/prompt-persistence.d.ts +1 -1
  51. package/dist/mcp/prompt-persistence.js +3 -3
  52. package/dist/mcp/prompt-persistence.js.map +1 -1
  53. package/dist/tools/notepad-tools.d.ts.map +1 -1
  54. package/dist/tools/notepad-tools.js +6 -0
  55. package/dist/tools/notepad-tools.js.map +1 -1
  56. package/dist/tools/python-repl/bridge-manager.js +4 -4
  57. package/dist/tools/python-repl/bridge-manager.js.map +1 -1
  58. package/dist/tools/skills-tools.d.ts.map +1 -1
  59. package/dist/tools/skills-tools.js +5 -3
  60. package/dist/tools/skills-tools.js.map +1 -1
  61. package/docs/ARCHITECTURE.md +541 -162
  62. package/docs/CLAUDE.md +1 -1
  63. package/docs/FEATURES.md +1038 -420
  64. package/docs/REFERENCE.md +860 -787
  65. package/docs/plans/2026-03-02-docs-comprehensive-update-design.md +187 -0
  66. package/docs/plans/2026-03-02-docs-comprehensive-update.md +1395 -0
  67. package/docs/standards/AGENTS.md +1 -1
  68. package/docs/standards/README.md +3 -3
  69. package/docs/standards/agent-lifecycle.md +1 -1
  70. package/docs/standards/anti-patterns.md +1 -1
  71. package/docs/standards/audit-report.md +2 -2
  72. package/docs/standards/contribution-guide.md +1 -1
  73. package/docs/standards/hook-execution-order.md +1 -1
  74. package/docs/standards/runtime-protection.md +1 -1
  75. package/docs/standards/state-machine.md +1 -1
  76. package/docs/standards/user-guide.md +1 -1
  77. package/package.json +1 -1
  78. package/scripts/bump-version.mjs +1 -1
  79. package/scripts/release-steps.mjs +8 -2
  80. package/skills/ax-export/SKILL.md +7 -8
  81. package/skills/ax-status/SKILL.md +1 -1
  82. package/skills/executing-plans/SKILL.md +4 -4
  83. package/skills/requesting-code-review/SKILL.md +3 -3
  84. package/skills/subagent-driven-development/SKILL.md +8 -8
  85. package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +1 -1
  86. package/skills/systematic-debugging/SKILL.md +3 -3
  87. package/skills/writing-plans/SKILL.md +3 -3
  88. package/skills/writing-skills/SKILL.md +4 -4
  89. package/skills/writing-skills/testing-skills-with-subagents.md +1 -1
  90. package/docs/prd/ultrapower-standards-draft.md +0 -191
  91. package/docs/prd/ultrapower-standards-rough.md +0 -560
  92. package/docs/reviews/draft-prd-ultrapower-pain-fix/review_tech.md +0 -219
  93. package/docs/reviews/draft_prd_pain_points/review_domain.md +0 -215
  94. package/docs/reviews/ultrapower-full-bugfix-plan/review_product.md +0 -135
@@ -8,11 +8,11 @@
8
8
  {
9
9
  "name": "ultrapower",
10
10
  "description": "Disciplined multi-agent orchestration: workflow enforcement + parallel execution",
11
- "version": "5.5.1",
11
+ "version": "5.5.6",
12
12
  "source": {
13
13
  "source": "npm",
14
14
  "package": "@liangjie559567/ultrapower",
15
- "version": "5.5.1"
15
+ "version": "5.5.6"
16
16
  },
17
17
  "author": {
18
18
  "name": "liangjie559567"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ultrapower",
3
3
  "description": "Disciplined multi-agent orchestration: workflow enforcement + parallel execution. Combines superpowers' TDD/debugging discipline with OMC's multi-agent execution capabilities.",
4
- "version": "5.5.0",
4
+ "version": "5.5.6",
5
5
  "author": {
6
6
  "name": "liangjie559567"
7
7
  },
@@ -15074,7 +15074,7 @@ function slugify(text) {
15074
15074
  return slug || "prompt";
15075
15075
  }
15076
15076
  function generatePromptId() {
15077
- return (0, import_crypto.randomBytes)(4).toString("hex");
15077
+ return (0, import_crypto.randomBytes)(8).toString("hex");
15078
15078
  }
15079
15079
  function getPromptsDir(workingDirectory) {
15080
15080
  const root = getWorktreeRoot(workingDirectory) || workingDirectory || process.cwd();
@@ -16539,11 +16539,15 @@ function validateModelName(model) {
16539
16539
  throw new Error(`Invalid model name: "${model}". Model names must match pattern: alphanumeric start, followed by alphanumeric, dots, hyphens, or underscores (max 64 chars).`);
16540
16540
  }
16541
16541
  }
16542
+ function parseEnvInt(envVal, fallback) {
16543
+ const n = parseInt(envVal ?? "", 10);
16544
+ return isNaN(n) ? fallback : n;
16545
+ }
16542
16546
  var CODEX_DEFAULT_MODEL = process.env.OMC_CODEX_DEFAULT_MODEL || "gpt-5.3-codex";
16543
- var CODEX_TIMEOUT = Math.min(Math.max(5e3, parseInt(process.env.OMC_CODEX_TIMEOUT || "3600000", 10) || 36e5), 36e5);
16544
- var RATE_LIMIT_RETRY_COUNT = Math.min(10, Math.max(1, parseInt(process.env.OMC_CODEX_RATE_LIMIT_RETRY_COUNT || "3", 10) || 3));
16545
- var RATE_LIMIT_INITIAL_DELAY = Math.max(1e3, parseInt(process.env.OMC_CODEX_RATE_LIMIT_INITIAL_DELAY || "5000", 10) || 5e3);
16546
- var RATE_LIMIT_MAX_DELAY = Math.max(5e3, parseInt(process.env.OMC_CODEX_RATE_LIMIT_MAX_DELAY || "60000", 10) || 6e4);
16547
+ var CODEX_TIMEOUT = Math.min(Math.max(5e3, parseEnvInt(process.env.OMC_CODEX_TIMEOUT, 36e5)), 36e5);
16548
+ var RATE_LIMIT_RETRY_COUNT = Math.min(10, Math.max(1, parseEnvInt(process.env.OMC_CODEX_RATE_LIMIT_RETRY_COUNT, 3)));
16549
+ var RATE_LIMIT_INITIAL_DELAY = Math.max(1e3, parseEnvInt(process.env.OMC_CODEX_RATE_LIMIT_INITIAL_DELAY, 5e3));
16550
+ var RATE_LIMIT_MAX_DELAY = Math.max(5e3, parseEnvInt(process.env.OMC_CODEX_RATE_LIMIT_MAX_DELAY, 6e4));
16547
16551
  var CODEX_RECOMMENDED_ROLES = ["architect", "planner", "critic", "analyst", "code-reviewer", "security-reviewer", "tdd-guide"];
16548
16552
  var VALID_REASONING_EFFORTS = ["minimal", "low", "medium", "high", "xhigh"];
16549
16553
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
@@ -17321,8 +17325,12 @@ var spawnedPids2 = /* @__PURE__ */ new Set();
17321
17325
  function isSpawnedPid2(pid) {
17322
17326
  return spawnedPids2.has(pid);
17323
17327
  }
17328
+ function parseEnvInt2(envVal, fallback) {
17329
+ const n = parseInt(envVal ?? "", 10);
17330
+ return isNaN(n) ? fallback : n;
17331
+ }
17324
17332
  var GEMINI_DEFAULT_MODEL = process.env.OMC_GEMINI_DEFAULT_MODEL || "gemini-3-pro-preview";
17325
- var GEMINI_TIMEOUT = Math.min(Math.max(5e3, parseInt(process.env.OMC_GEMINI_TIMEOUT || "3600000", 10) || 36e5), 36e5);
17333
+ var GEMINI_TIMEOUT = Math.min(Math.max(5e3, parseEnvInt2(process.env.OMC_GEMINI_TIMEOUT, 36e5)), 36e5);
17326
17334
  var _yoloEnv = process.env.OMC_GEMINI_YOLO;
17327
17335
  var MAX_FILE_SIZE2 = 5 * 1024 * 1024;
17328
17336
  var MAX_STDOUT_BYTES2 = 10 * 1024 * 1024;
@@ -17339,7 +17347,7 @@ function textResult(text, isError = false) {
17339
17347
  };
17340
17348
  }
17341
17349
  function findJobStatusFile(provider, jobId, workingDirectory) {
17342
- if (!/^[0-9a-f]{8}$/i.test(jobId)) {
17350
+ if (!/^[0-9a-f]{16}$/i.test(jobId)) {
17343
17351
  return void 0;
17344
17352
  }
17345
17353
  const promptsDir = getPromptsDir(workingDirectory);
@@ -14917,7 +14917,7 @@ function slugify(text) {
14917
14917
  return slug || "prompt";
14918
14918
  }
14919
14919
  function generatePromptId() {
14920
- return (0, import_crypto.randomBytes)(4).toString("hex");
14920
+ return (0, import_crypto.randomBytes)(8).toString("hex");
14921
14921
  }
14922
14922
  function getPromptsDir(workingDirectory) {
14923
14923
  const root = getWorktreeRoot(workingDirectory) || workingDirectory || process.cwd();
@@ -16372,8 +16372,12 @@ function validateModelName(model) {
16372
16372
  throw new Error(`Invalid model name: "${model}". Model names must match pattern: alphanumeric start, followed by alphanumeric, dots, hyphens, or underscores (max 64 chars).`);
16373
16373
  }
16374
16374
  }
16375
+ function parseEnvInt(envVal, fallback) {
16376
+ const n = parseInt(envVal ?? "", 10);
16377
+ return isNaN(n) ? fallback : n;
16378
+ }
16375
16379
  var GEMINI_DEFAULT_MODEL = process.env.OMC_GEMINI_DEFAULT_MODEL || "gemini-3-pro-preview";
16376
- var GEMINI_TIMEOUT = Math.min(Math.max(5e3, parseInt(process.env.OMC_GEMINI_TIMEOUT || "3600000", 10) || 36e5), 36e5);
16380
+ var GEMINI_TIMEOUT = Math.min(Math.max(5e3, parseEnvInt(process.env.OMC_GEMINI_TIMEOUT, 36e5)), 36e5);
16377
16381
  var _yoloEnv = process.env.OMC_GEMINI_YOLO;
16378
16382
  var GEMINI_YOLO = _yoloEnv === "false" || _yoloEnv === "0" ? false : true;
16379
16383
  var GEMINI_RECOMMENDED_ROLES = ["designer", "writer", "vision"];
@@ -16395,6 +16399,11 @@ ${stderr}`;
16395
16399
  function executeGemini(prompt, model, cwd) {
16396
16400
  return new Promise((resolve7, reject) => {
16397
16401
  if (model) validateModelName(model);
16402
+ const MAX_PROMPT_BYTES = 4 * 1024 * 1024;
16403
+ const promptBytes = Buffer.byteLength(prompt, "utf-8");
16404
+ if (promptBytes > MAX_PROMPT_BYTES) {
16405
+ return reject(new Error(`Prompt size (${promptBytes} bytes) exceeds 4MB limit`));
16406
+ }
16398
16407
  let settled = false;
16399
16408
  const args = ["-p=.", ...GEMINI_YOLO ? ["--yolo"] : []];
16400
16409
  if (model) {
@@ -16466,6 +16475,11 @@ function executeGemini(prompt, model, cwd) {
16466
16475
  }
16467
16476
  function executeGeminiBackground(fullPrompt, modelInput, jobMeta, workingDirectory) {
16468
16477
  try {
16478
+ const MAX_PROMPT_BYTES = 4 * 1024 * 1024;
16479
+ const promptBytes = Buffer.byteLength(fullPrompt, "utf-8");
16480
+ if (promptBytes > MAX_PROMPT_BYTES) {
16481
+ return { error: `Prompt size (${promptBytes} bytes) exceeds 4MB limit` };
16482
+ }
16469
16483
  const modelExplicit = modelInput !== void 0 && modelInput !== null && modelInput !== "";
16470
16484
  const effectiveModel = modelInput || GEMINI_DEFAULT_MODEL;
16471
16485
  const modelsToTry = modelExplicit ? [effectiveModel] : GEMINI_MODEL_FALLBACKS.includes(effectiveModel) ? GEMINI_MODEL_FALLBACKS.slice(GEMINI_MODEL_FALLBACKS.indexOf(effectiveModel)) : [effectiveModel, ...GEMINI_MODEL_FALLBACKS];
@@ -16963,11 +16977,15 @@ var spawnedPids2 = /* @__PURE__ */ new Set();
16963
16977
  function isSpawnedPid2(pid) {
16964
16978
  return spawnedPids2.has(pid);
16965
16979
  }
16980
+ function parseEnvInt2(envVal, fallback) {
16981
+ const n = parseInt(envVal ?? "", 10);
16982
+ return isNaN(n) ? fallback : n;
16983
+ }
16966
16984
  var CODEX_DEFAULT_MODEL = process.env.OMC_CODEX_DEFAULT_MODEL || "gpt-5.3-codex";
16967
- var CODEX_TIMEOUT = Math.min(Math.max(5e3, parseInt(process.env.OMC_CODEX_TIMEOUT || "3600000", 10) || 36e5), 36e5);
16968
- var RATE_LIMIT_RETRY_COUNT = Math.min(10, Math.max(1, parseInt(process.env.OMC_CODEX_RATE_LIMIT_RETRY_COUNT || "3", 10) || 3));
16969
- var RATE_LIMIT_INITIAL_DELAY = Math.max(1e3, parseInt(process.env.OMC_CODEX_RATE_LIMIT_INITIAL_DELAY || "5000", 10) || 5e3);
16970
- var RATE_LIMIT_MAX_DELAY = Math.max(5e3, parseInt(process.env.OMC_CODEX_RATE_LIMIT_MAX_DELAY || "60000", 10) || 6e4);
16985
+ var CODEX_TIMEOUT = Math.min(Math.max(5e3, parseEnvInt2(process.env.OMC_CODEX_TIMEOUT, 36e5)), 36e5);
16986
+ var RATE_LIMIT_RETRY_COUNT = Math.min(10, Math.max(1, parseEnvInt2(process.env.OMC_CODEX_RATE_LIMIT_RETRY_COUNT, 3)));
16987
+ var RATE_LIMIT_INITIAL_DELAY = Math.max(1e3, parseEnvInt2(process.env.OMC_CODEX_RATE_LIMIT_INITIAL_DELAY, 5e3));
16988
+ var RATE_LIMIT_MAX_DELAY = Math.max(5e3, parseEnvInt2(process.env.OMC_CODEX_RATE_LIMIT_MAX_DELAY, 6e4));
16971
16989
  var MAX_FILE_SIZE2 = 5 * 1024 * 1024;
16972
16990
  var MAX_STDOUT_BYTES2 = 10 * 1024 * 1024;
16973
16991
 
@@ -16983,7 +17001,7 @@ function textResult(text, isError = false) {
16983
17001
  };
16984
17002
  }
16985
17003
  function findJobStatusFile(provider, jobId, workingDirectory) {
16986
- if (!/^[0-9a-f]{8}$/i.test(jobId)) {
17004
+ if (!/^[0-9a-f]{16}$/i.test(jobId)) {
16987
17005
  return void 0;
16988
17006
  }
16989
17007
  const promptsDir = getPromptsDir(workingDirectory);
@@ -19901,7 +19901,6 @@ function atomicWriteJsonSync(filePath, data) {
19901
19901
  }
19902
19902
  async function safeReadJson(filePath) {
19903
19903
  try {
19904
- await fs2.access(filePath);
19905
19904
  const content = await fs2.readFile(filePath, "utf-8");
19906
19905
  return JSON.parse(content);
19907
19906
  } catch (err) {
@@ -19909,7 +19908,7 @@ async function safeReadJson(filePath) {
19909
19908
  if (error2.code === "ENOENT") {
19910
19909
  return null;
19911
19910
  }
19912
- return null;
19911
+ throw err;
19913
19912
  }
19914
19913
  }
19915
19914
 
@@ -20612,7 +20611,7 @@ async function spawnBridgeServer(sessionId, projectDir) {
20612
20611
  async function ensureBridge(sessionId, projectDir) {
20613
20612
  const metaPath = getBridgeMetaPath(sessionId);
20614
20613
  const expectedSocketPath = getBridgeSocketPath(sessionId);
20615
- const meta = await safeReadJson(metaPath);
20614
+ const meta = await safeReadJson(metaPath).catch(() => null);
20616
20615
  if (meta && isValidBridgeMeta(meta)) {
20617
20616
  if (meta.sessionId !== sessionId) {
20618
20617
  await deleteBridgeMeta(sessionId);
@@ -20641,7 +20640,7 @@ async function killBridgeWithEscalation(sessionId, options) {
20641
20640
  const gracePeriod = options?.gracePeriodMs ?? DEFAULT_GRACE_PERIOD_MS;
20642
20641
  const startTime = Date.now();
20643
20642
  const metaPath = getBridgeMetaPath(sessionId);
20644
- const meta = await safeReadJson(metaPath);
20643
+ const meta = await safeReadJson(metaPath).catch(() => null);
20645
20644
  if (!meta || !isValidBridgeMeta(meta)) {
20646
20645
  return { terminated: true };
20647
20646
  }
@@ -22560,6 +22559,7 @@ ${sectionContent}`
22560
22559
  };
22561
22560
  } catch (error2) {
22562
22561
  return {
22562
+ isError: true,
22563
22563
  content: [{
22564
22564
  type: "text",
22565
22565
  text: `Error reading notepad: ${error2 instanceof Error ? error2.message : String(error2)}`
@@ -22603,6 +22603,7 @@ var notepadWritePriorityTool = {
22603
22603
  };
22604
22604
  } catch (error2) {
22605
22605
  return {
22606
+ isError: true,
22606
22607
  content: [{
22607
22608
  type: "text",
22608
22609
  text: `Error writing to Priority Context: ${error2 instanceof Error ? error2.message : String(error2)}`
@@ -22640,6 +22641,7 @@ var notepadWriteWorkingTool = {
22640
22641
  };
22641
22642
  } catch (error2) {
22642
22643
  return {
22644
+ isError: true,
22643
22645
  content: [{
22644
22646
  type: "text",
22645
22647
  text: `Error writing to Working Memory: ${error2 instanceof Error ? error2.message : String(error2)}`
@@ -22677,6 +22679,7 @@ var notepadWriteManualTool = {
22677
22679
  };
22678
22680
  } catch (error2) {
22679
22681
  return {
22682
+ isError: true,
22680
22683
  content: [{
22681
22684
  type: "text",
22682
22685
  text: `Error writing to MANUAL: ${error2 instanceof Error ? error2.message : String(error2)}`
@@ -22709,6 +22712,7 @@ var notepadPruneTool = {
22709
22712
  };
22710
22713
  } catch (error2) {
22711
22714
  return {
22715
+ isError: true,
22712
22716
  content: [{
22713
22717
  type: "text",
22714
22718
  text: `Error pruning notepad: ${error2 instanceof Error ? error2.message : String(error2)}`
@@ -22752,6 +22756,7 @@ var notepadStatsTool = {
22752
22756
  };
22753
22757
  } catch (error2) {
22754
22758
  return {
22759
+ isError: true,
22755
22760
  content: [{
22756
22761
  type: "text",
22757
22762
  text: `Error getting notepad stats: ${error2 instanceof Error ? error2.message : String(error2)}`
@@ -919,8 +919,12 @@ var DEFAULT_CONFIG = {
919
919
  };
920
920
 
921
921
  // src/mcp/gemini-core.ts
922
+ function parseEnvInt(envVal, fallback) {
923
+ const n = parseInt(envVal ?? "", 10);
924
+ return isNaN(n) ? fallback : n;
925
+ }
922
926
  var GEMINI_DEFAULT_MODEL = process.env.OMC_GEMINI_DEFAULT_MODEL || "gemini-3-pro-preview";
923
- var GEMINI_TIMEOUT = Math.min(Math.max(5e3, parseInt(process.env.OMC_GEMINI_TIMEOUT || "3600000", 10) || 36e5), 36e5);
927
+ var GEMINI_TIMEOUT = Math.min(Math.max(5e3, parseEnvInt(process.env.OMC_GEMINI_TIMEOUT, 36e5)), 36e5);
924
928
  var _yoloEnv = process.env.OMC_GEMINI_YOLO;
925
929
  var GEMINI_YOLO = _yoloEnv === "false" || _yoloEnv === "0" ? false : true;
926
930
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
@@ -2,4 +2,4 @@
2
2
  description: "在任何创意工作之前必须使用此命令——创建功能、构建组件、添加功能或修改行为。在实现之前探索需求和设计。"
3
3
  ---
4
4
 
5
- Invoke the superpowers:brainstorming skill and follow it exactly as presented to you
5
+ Invoke the ultrapower:brainstorming skill and follow it exactly as presented to you
@@ -2,4 +2,4 @@
2
2
  description: 分批执行计划并设置审查检查点
3
3
  ---
4
4
 
5
- Invoke the superpowers:executing-plans skill and follow it exactly as presented to you
5
+ Invoke the ultrapower:executing-plans skill and follow it exactly as presented to you
@@ -2,4 +2,4 @@
2
2
  description: 创建包含细粒度任务的详细实现计划
3
3
  ---
4
4
 
5
- Invoke the superpowers:writing-plans skill and follow it exactly as presented to you
5
+ Invoke the ultrapower:writing-plans skill and follow it exactly as presented to you
@@ -54,7 +54,7 @@ describe('job-management', () => {
54
54
  const result = findJobStatusFile('codex', 'abc123');
55
55
  expect(result).toBeUndefined();
56
56
  });
57
- it('returns undefined for too-long jobId', () => {
57
+ it('returns undefined for wrong-length jobId (12 chars)', () => {
58
58
  const result = findJobStatusFile('codex', 'abc123def456');
59
59
  expect(result).toBeUndefined();
60
60
  });
@@ -62,27 +62,27 @@ describe('job-management', () => {
62
62
  const result = findJobStatusFile('codex', '../etc/pa');
63
63
  expect(result).toBeUndefined();
64
64
  });
65
- it('proceeds for valid 8-char hex jobId (lowercase)', async () => {
65
+ it('proceeds for valid 16-char hex jobId (lowercase)', async () => {
66
66
  const fs = await import('fs');
67
67
  fs.existsSync.mockReturnValue(true);
68
- fs.readdirSync.mockReturnValue(['codex-status-test-slug-ab12cd34.json']);
68
+ fs.readdirSync.mockReturnValue(['codex-status-test-slug-ab12cd34ef567890.json']);
69
69
  fs.readFileSync.mockReturnValue(JSON.stringify({
70
70
  status: 'running',
71
71
  spawnedAt: new Date().toISOString()
72
72
  }));
73
- const result = findJobStatusFile('codex', 'ab12cd34');
73
+ const result = findJobStatusFile('codex', 'ab12cd34ef567890');
74
74
  expect(result).toBeDefined();
75
75
  expect(result?.slug).toBe('test-slug');
76
76
  });
77
- it('proceeds for valid 8-char hex jobId (uppercase)', async () => {
77
+ it('proceeds for valid 16-char hex jobId (uppercase)', async () => {
78
78
  const fs = await import('fs');
79
79
  fs.existsSync.mockReturnValue(true);
80
- fs.readdirSync.mockReturnValue(['codex-status-test-slug-AB12CD34.json']);
80
+ fs.readdirSync.mockReturnValue(['codex-status-test-slug-AB12CD34EF567890.json']);
81
81
  fs.readFileSync.mockReturnValue(JSON.stringify({
82
82
  status: 'running',
83
83
  spawnedAt: new Date().toISOString()
84
84
  }));
85
- const result = findJobStatusFile('codex', 'AB12CD34');
85
+ const result = findJobStatusFile('codex', 'AB12CD34EF567890');
86
86
  expect(result).toBeDefined();
87
87
  });
88
88
  });
@@ -92,7 +92,7 @@ describe('job-management', () => {
92
92
  it('allows SIGTERM', async () => {
93
93
  const mockStatus = {
94
94
  provider: 'codex',
95
- jobId: 'ab12cd34',
95
+ jobId: 'ab12cd34ef567890',
96
96
  slug: 'test',
97
97
  status: 'running',
98
98
  pid: 12345,
@@ -106,15 +106,15 @@ describe('job-management', () => {
106
106
  vi.spyOn(process, 'kill').mockImplementation(() => true);
107
107
  const fs = await import('fs');
108
108
  fs.existsSync.mockReturnValue(true);
109
- fs.readdirSync.mockReturnValue(['codex-status-test-ab12cd34.json']);
109
+ fs.readdirSync.mockReturnValue(['codex-status-test-ab12cd34ef567890.json']);
110
110
  fs.readFileSync.mockReturnValue(JSON.stringify(mockStatus));
111
- const result = await handleKillJob('codex', 'ab12cd34', 'SIGTERM');
111
+ const result = await handleKillJob('codex', 'ab12cd34ef567890', 'SIGTERM');
112
112
  expect(result.isError).toBeFalsy();
113
113
  });
114
114
  it('allows SIGINT', async () => {
115
115
  const mockStatus = {
116
116
  provider: 'codex',
117
- jobId: 'ab12cd34',
117
+ jobId: 'ab12cd34ef567890',
118
118
  slug: 'test',
119
119
  status: 'running',
120
120
  pid: 12345,
@@ -128,24 +128,24 @@ describe('job-management', () => {
128
128
  vi.spyOn(process, 'kill').mockImplementation(() => true);
129
129
  const fs = await import('fs');
130
130
  fs.existsSync.mockReturnValue(true);
131
- fs.readdirSync.mockReturnValue(['codex-status-test-ab12cd34.json']);
131
+ fs.readdirSync.mockReturnValue(['codex-status-test-ab12cd34ef567890.json']);
132
132
  fs.readFileSync.mockReturnValue(JSON.stringify(mockStatus));
133
- const result = await handleKillJob('codex', 'ab12cd34', 'SIGINT');
133
+ const result = await handleKillJob('codex', 'ab12cd34ef567890', 'SIGINT');
134
134
  expect(result.isError).toBeFalsy();
135
135
  });
136
136
  it('rejects SIGKILL', async () => {
137
- const result = await handleKillJob('codex', 'ab12cd34', 'SIGKILL');
137
+ const result = await handleKillJob('codex', 'ab12cd34ef567890', 'SIGKILL');
138
138
  expect(result.isError).toBe(true);
139
139
  expect(result.content[0].text).toContain('Invalid signal');
140
140
  expect(result.content[0].text).toContain('SIGKILL');
141
141
  });
142
142
  it('rejects arbitrary strings', async () => {
143
- const result = await handleKillJob('codex', 'ab12cd34', 'rm -rf /');
143
+ const result = await handleKillJob('codex', 'ab12cd34ef567890', 'rm -rf /');
144
144
  expect(result.isError).toBe(true);
145
145
  expect(result.content[0].text).toContain('Invalid signal');
146
146
  });
147
147
  it('rejects SIGUSR1', async () => {
148
- const result = await handleKillJob('codex', 'ab12cd34', 'SIGUSR1');
148
+ const result = await handleKillJob('codex', 'ab12cd34ef567890', 'SIGUSR1');
149
149
  expect(result.isError).toBe(true);
150
150
  expect(result.content[0].text).toContain('Invalid signal');
151
151
  });
@@ -154,7 +154,7 @@ describe('job-management', () => {
154
154
  it('preserves completed status when ESRCH', async () => {
155
155
  const mockStatus = {
156
156
  provider: 'codex',
157
- jobId: 'ab12cd34',
157
+ jobId: 'ab12cd34ef567890',
158
158
  slug: 'test',
159
159
  status: 'running',
160
160
  pid: 12345,
@@ -167,7 +167,7 @@ describe('job-management', () => {
167
167
  const completedStatus = { ...mockStatus, status: 'completed' };
168
168
  const fs = await import('fs');
169
169
  fs.existsSync.mockReturnValue(true);
170
- fs.readdirSync.mockReturnValue(['codex-status-test-ab12cd34.json']);
170
+ fs.readdirSync.mockReturnValue(['codex-status-test-ab12cd34ef567890.json']);
171
171
  fs.readFileSync.mockReturnValue(JSON.stringify(mockStatus));
172
172
  // First call returns running (for initial check), subsequent calls return completed
173
173
  let callCount = 0;
@@ -180,7 +180,7 @@ describe('job-management', () => {
180
180
  const esrchError = new Error('ESRCH');
181
181
  esrchError.code = 'ESRCH';
182
182
  vi.spyOn(process, 'kill').mockImplementation(() => { throw esrchError; });
183
- const result = await handleKillJob('codex', 'ab12cd34', 'SIGTERM');
183
+ const result = await handleKillJob('codex', 'ab12cd34ef567890', 'SIGTERM');
184
184
  // Should NOT overwrite to failed since job is completed
185
185
  const _failedWrites = writeJobStatusSpy.mock.calls.filter(call => call[0].status === 'failed');
186
186
  // The initial killedByUser write happens, but after ESRCH with completed status, no failed write
@@ -189,7 +189,7 @@ describe('job-management', () => {
189
189
  it('marks as failed when running and ESRCH', async () => {
190
190
  const mockStatus = {
191
191
  provider: 'codex',
192
- jobId: 'ab12cd34',
192
+ jobId: 'ab12cd34ef567890',
193
193
  slug: 'test',
194
194
  status: 'running',
195
195
  pid: 12345,
@@ -201,14 +201,14 @@ describe('job-management', () => {
201
201
  };
202
202
  const fs = await import('fs');
203
203
  fs.existsSync.mockReturnValue(true);
204
- fs.readdirSync.mockReturnValue(['codex-status-test-ab12cd34.json']);
204
+ fs.readdirSync.mockReturnValue(['codex-status-test-ab12cd34ef567890.json']);
205
205
  fs.readFileSync.mockReturnValue(JSON.stringify(mockStatus));
206
206
  vi.spyOn(promptPersistence, 'readJobStatus').mockReturnValue(mockStatus);
207
207
  const writeJobStatusSpy = vi.spyOn(promptPersistence, 'writeJobStatus');
208
208
  const esrchError = new Error('ESRCH');
209
209
  esrchError.code = 'ESRCH';
210
210
  vi.spyOn(process, 'kill').mockImplementation(() => { throw esrchError; });
211
- await handleKillJob('codex', 'ab12cd34', 'SIGTERM');
211
+ await handleKillJob('codex', 'ab12cd34ef567890', 'SIGTERM');
212
212
  // Should write failed status
213
213
  const failedWrites = writeJobStatusSpy.mock.calls.filter(call => call[0].status === 'failed');
214
214
  expect(failedWrites.length).toBeGreaterThan(0);
@@ -220,7 +220,7 @@ describe('job-management', () => {
220
220
  it('clamps negative to 1000ms minimum', async () => {
221
221
  const runningStatus = {
222
222
  provider: 'codex',
223
- jobId: 'ab12cd34',
223
+ jobId: 'ab12cd34ef567890',
224
224
  slug: 'test',
225
225
  status: 'running',
226
226
  pid: 12345,
@@ -232,12 +232,12 @@ describe('job-management', () => {
232
232
  };
233
233
  const fs = await import('fs');
234
234
  fs.existsSync.mockReturnValue(true);
235
- fs.readdirSync.mockReturnValue(['codex-status-test-ab12cd34.json']);
235
+ fs.readdirSync.mockReturnValue(['codex-status-test-ab12cd34ef567890.json']);
236
236
  fs.readFileSync.mockReturnValue(JSON.stringify(runningStatus));
237
237
  // Always return running status so it waits until timeout
238
238
  vi.spyOn(promptPersistence, 'readJobStatus').mockReturnValue(runningStatus);
239
239
  const start = Date.now();
240
- await handleWaitForJob('codex', 'ab12cd34', -1);
240
+ await handleWaitForJob('codex', 'ab12cd34ef567890', -1);
241
241
  const elapsed = Date.now() - start;
242
242
  // Should timeout after ~1000ms (the minimum clamped value), not immediately
243
243
  expect(elapsed).toBeGreaterThanOrEqual(900);
@@ -246,7 +246,7 @@ describe('job-management', () => {
246
246
  it('clamps zero to 1000ms minimum', async () => {
247
247
  const runningStatus = {
248
248
  provider: 'codex',
249
- jobId: 'ab12cd34',
249
+ jobId: 'ab12cd34ef567890',
250
250
  slug: 'test',
251
251
  status: 'running',
252
252
  pid: 12345,
@@ -258,11 +258,11 @@ describe('job-management', () => {
258
258
  };
259
259
  const fs = await import('fs');
260
260
  fs.existsSync.mockReturnValue(true);
261
- fs.readdirSync.mockReturnValue(['codex-status-test-ab12cd34.json']);
261
+ fs.readdirSync.mockReturnValue(['codex-status-test-ab12cd34ef567890.json']);
262
262
  fs.readFileSync.mockReturnValue(JSON.stringify(runningStatus));
263
263
  vi.spyOn(promptPersistence, 'readJobStatus').mockReturnValue(runningStatus);
264
264
  const start = Date.now();
265
- await handleWaitForJob('codex', 'ab12cd34', 0);
265
+ await handleWaitForJob('codex', 'ab12cd34ef567890', 0);
266
266
  const elapsed = Date.now() - start;
267
267
  expect(elapsed).toBeGreaterThanOrEqual(900);
268
268
  expect(elapsed).toBeLessThan(2000);
@@ -270,7 +270,7 @@ describe('job-management', () => {
270
270
  it('accepts normal timeout values', async () => {
271
271
  const completedStatus = {
272
272
  provider: 'codex',
273
- jobId: 'ab12cd34',
273
+ jobId: 'ab12cd34ef567890',
274
274
  slug: 'test',
275
275
  status: 'completed',
276
276
  promptFile: '/tmp/prompt.md',
@@ -281,14 +281,14 @@ describe('job-management', () => {
281
281
  };
282
282
  const fs = await import('fs');
283
283
  fs.existsSync.mockReturnValue(true);
284
- fs.readdirSync.mockReturnValue(['codex-status-test-ab12cd34.json']);
284
+ fs.readdirSync.mockReturnValue(['codex-status-test-ab12cd34ef567890.json']);
285
285
  fs.readFileSync.mockReturnValue(JSON.stringify(completedStatus));
286
286
  vi.spyOn(promptPersistence, 'readJobStatus').mockReturnValue(completedStatus);
287
287
  vi.spyOn(promptPersistence, 'readCompletedResponse').mockReturnValue({
288
288
  response: 'test response',
289
289
  status: completedStatus
290
290
  });
291
- const result = await handleWaitForJob('codex', 'ab12cd34', 5000);
291
+ const result = await handleWaitForJob('codex', 'ab12cd34ef567890', 5000);
292
292
  expect(result.isError).toBeFalsy();
293
293
  });
294
294
  });
@@ -300,12 +300,12 @@ describe('job-management', () => {
300
300
  // Mock getPromptsDir to return different paths based on workingDirectory
301
301
  getPromptsDir.mockImplementation((wd) => wd ? `${wd}/.omc/prompts` : '/tmp/test-prompts');
302
302
  fs.existsSync.mockReturnValue(true);
303
- fs.readdirSync.mockReturnValue(['codex-status-test-slug-ab12cd34.json']);
303
+ fs.readdirSync.mockReturnValue(['codex-status-test-slug-ab12cd34ef567890.json']);
304
304
  fs.readFileSync.mockReturnValue(JSON.stringify({
305
305
  status: 'running',
306
306
  spawnedAt: new Date().toISOString()
307
307
  }));
308
- const result = findJobStatusFile('codex', 'ab12cd34', '/other/project');
308
+ const result = findJobStatusFile('codex', 'ab12cd34ef567890', '/other/project');
309
309
  expect(result).toBeDefined();
310
310
  expect(getPromptsDir).toHaveBeenCalledWith('/other/project');
311
311
  });
@@ -314,12 +314,12 @@ describe('job-management', () => {
314
314
  const fs = await import('fs');
315
315
  getPromptsDir.mockReturnValue('/tmp/test-prompts');
316
316
  fs.existsSync.mockReturnValue(true);
317
- fs.readdirSync.mockReturnValue(['codex-status-test-slug-ab12cd34.json']);
317
+ fs.readdirSync.mockReturnValue(['codex-status-test-slug-ab12cd34ef567890.json']);
318
318
  fs.readFileSync.mockReturnValue(JSON.stringify({
319
319
  status: 'running',
320
320
  spawnedAt: new Date().toISOString()
321
321
  }));
322
- const result = findJobStatusFile('codex', 'ab12cd34');
322
+ const result = findJobStatusFile('codex', 'ab12cd34ef567890');
323
323
  expect(result).toBeDefined();
324
324
  expect(getPromptsDir).toHaveBeenCalledWith(undefined);
325
325
  });
@@ -334,7 +334,7 @@ describe('job-management', () => {
334
334
  callCount++;
335
335
  if (callCount <= 3)
336
336
  return []; // Not found for first 3 calls
337
- return ['codex-status-test-slug-ab12cd34.json'];
337
+ return ['codex-status-test-slug-ab12cd34ef567890.json'];
338
338
  });
339
339
  fs.readFileSync.mockReturnValue(JSON.stringify({
340
340
  status: 'completed',
@@ -343,7 +343,7 @@ describe('job-management', () => {
343
343
  }));
344
344
  const completedStatus = {
345
345
  provider: 'codex',
346
- jobId: 'ab12cd34',
346
+ jobId: 'ab12cd34ef567890',
347
347
  slug: 'test-slug',
348
348
  status: 'completed',
349
349
  promptFile: '/tmp/prompt.md',
@@ -358,7 +358,7 @@ describe('job-management', () => {
358
358
  response: 'test response',
359
359
  status: completedStatus,
360
360
  });
361
- const result = await handleWaitForJob('codex', 'ab12cd34', 30000);
361
+ const result = await handleWaitForJob('codex', 'ab12cd34ef567890', 30000);
362
362
  expect(result.isError).toBeFalsy();
363
363
  expect(result.content[0].text).toContain('completed');
364
364
  // Should have retried (callCount > 1)
@@ -370,7 +370,7 @@ describe('job-management', () => {
370
370
  fs.existsSync.mockReturnValue(true);
371
371
  fs.readdirSync.mockReturnValue([]);
372
372
  const start = Date.now();
373
- const result = await handleWaitForJob('codex', 'ab12cd34', 60000);
373
+ const result = await handleWaitForJob('codex', 'ab12cd34ef567890', 60000);
374
374
  const elapsed = Date.now() - start;
375
375
  expect(result.isError).toBe(true);
376
376
  expect(result.content[0].text).toContain('No job found');
@@ -386,10 +386,10 @@ describe('job-management', () => {
386
386
  getJobWd.mockReturnValue('/other/project');
387
387
  getPromptsDir.mockImplementation((wd) => wd ? `${wd}/.omc/prompts` : '/tmp/test-prompts');
388
388
  fs.existsSync.mockReturnValue(true);
389
- fs.readdirSync.mockReturnValue(['codex-status-test-slug-ab12cd34.json']);
389
+ fs.readdirSync.mockReturnValue(['codex-status-test-slug-ab12cd34ef567890.json']);
390
390
  const mockStatus = {
391
391
  provider: 'codex',
392
- jobId: 'ab12cd34',
392
+ jobId: 'ab12cd34ef567890',
393
393
  slug: 'test-slug',
394
394
  status: 'running',
395
395
  pid: 12345,
@@ -401,9 +401,9 @@ describe('job-management', () => {
401
401
  };
402
402
  fs.readFileSync.mockReturnValue(JSON.stringify(mockStatus));
403
403
  vi.spyOn(promptPersistence, 'readJobStatus').mockReturnValue(mockStatus);
404
- const result = await handleCheckJobStatus('codex', 'ab12cd34');
404
+ const result = await handleCheckJobStatus('codex', 'ab12cd34ef567890');
405
405
  expect(result.isError).toBeFalsy();
406
- expect(result.content[0].text).toContain('ab12cd34');
406
+ expect(result.content[0].text).toContain('ab12cd34ef567890');
407
407
  expect(getPromptsDir).toHaveBeenCalledWith('/other/project');
408
408
  });
409
409
  });