@liangjie559567/ultrapower 5.5.1 → 5.5.5
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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/bridge/codex-server.cjs +15 -7
- package/bridge/gemini-server.cjs +25 -7
- package/bridge/mcp-server.cjs +9 -4
- package/bridge/team-bridge.cjs +5 -1
- package/commands/brainstorm.md +1 -1
- package/commands/execute-plan.md +1 -1
- package/commands/write-plan.md +1 -1
- package/dist/__tests__/delegation-enforcer-integration.test.d.ts +0 -4
- package/dist/__tests__/delegation-enforcer-integration.test.d.ts.map +1 -1
- package/dist/__tests__/delegation-enforcer-integration.test.js +1 -5
- package/dist/__tests__/delegation-enforcer-integration.test.js.map +1 -1
- package/dist/__tests__/job-management.test.js +43 -43
- package/dist/__tests__/job-management.test.js.map +1 -1
- package/dist/agents/definitions.d.ts +1 -1
- package/dist/agents/definitions.js +1 -1
- package/dist/features/delegation-enforcer.d.ts.map +1 -1
- package/dist/features/delegation-enforcer.js +51 -8
- package/dist/features/delegation-enforcer.js.map +1 -1
- package/dist/hooks/bridge.d.ts.map +1 -1
- package/dist/hooks/bridge.js +5 -0
- package/dist/hooks/bridge.js.map +1 -1
- package/dist/hooks/guards/pre-tool.d.ts.map +1 -1
- package/dist/hooks/guards/pre-tool.js +8 -2
- package/dist/hooks/guards/pre-tool.js.map +1 -1
- package/dist/hooks/recovery/session-recovery.js +1 -1
- package/dist/hooks/recovery/session-recovery.js.map +1 -1
- package/dist/hooks/rules-injector/constants.d.ts +2 -0
- package/dist/hooks/rules-injector/constants.d.ts.map +1 -1
- package/dist/hooks/rules-injector/constants.js +2 -0
- package/dist/hooks/rules-injector/constants.js.map +1 -1
- package/dist/hooks/rules-injector/finder.d.ts.map +1 -1
- package/dist/hooks/rules-injector/finder.js +12 -4
- package/dist/hooks/rules-injector/finder.js.map +1 -1
- package/dist/installer/__tests__/hooks.test.d.ts +6 -0
- package/dist/installer/__tests__/hooks.test.d.ts.map +1 -0
- package/dist/installer/__tests__/hooks.test.js +121 -0
- package/dist/installer/__tests__/hooks.test.js.map +1 -0
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +11 -10
- package/dist/installer/index.js.map +1 -1
- package/dist/lib/__tests__/atomic-write.test.js +3 -4
- package/dist/lib/__tests__/atomic-write.test.js.map +1 -1
- package/dist/lib/__tests__/version.test.d.ts +6 -0
- package/dist/lib/__tests__/version.test.d.ts.map +1 -0
- package/dist/lib/__tests__/version.test.js +37 -0
- package/dist/lib/__tests__/version.test.js.map +1 -0
- package/dist/lib/atomic-write.d.ts.map +1 -1
- package/dist/lib/atomic-write.js +6 -8
- package/dist/lib/atomic-write.js.map +1 -1
- package/dist/mcp/codex-core.d.ts.map +1 -1
- package/dist/mcp/codex-core.js +9 -4
- package/dist/mcp/codex-core.js.map +1 -1
- package/dist/mcp/gemini-core.d.ts.map +1 -1
- package/dist/mcp/gemini-core.js +16 -1
- package/dist/mcp/gemini-core.js.map +1 -1
- package/dist/mcp/job-management.js +2 -2
- package/dist/mcp/job-management.js.map +1 -1
- package/dist/mcp/prompt-persistence.d.ts +1 -1
- package/dist/mcp/prompt-persistence.js +3 -3
- package/dist/mcp/prompt-persistence.js.map +1 -1
- package/dist/tools/notepad-tools.d.ts.map +1 -1
- package/dist/tools/notepad-tools.js +6 -0
- package/dist/tools/notepad-tools.js.map +1 -1
- package/dist/tools/python-repl/bridge-manager.js +4 -4
- package/dist/tools/python-repl/bridge-manager.js.map +1 -1
- package/dist/tools/skills-tools.d.ts.map +1 -1
- package/dist/tools/skills-tools.js +5 -3
- package/dist/tools/skills-tools.js.map +1 -1
- package/docs/design/delegation-enforcer-integration.md +183 -0
- package/package.json +1 -1
- package/scripts/bump-version.mjs +1 -1
- package/scripts/release-steps.mjs +8 -2
- package/skills/ax-export/SKILL.md +7 -8
- package/skills/ax-status/SKILL.md +1 -1
- package/skills/executing-plans/SKILL.md +4 -4
- package/skills/requesting-code-review/SKILL.md +3 -3
- package/skills/subagent-driven-development/SKILL.md +8 -8
- package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +1 -1
- package/skills/systematic-debugging/SKILL.md +3 -3
- package/skills/writing-plans/SKILL.md +3 -3
- package/skills/writing-skills/SKILL.md +4 -4
- package/skills/writing-skills/testing-skills-with-subagents.md +1 -1
|
@@ -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.
|
|
11
|
+
"version": "5.5.5",
|
|
12
12
|
"source": {
|
|
13
13
|
"source": "npm",
|
|
14
14
|
"package": "@liangjie559567/ultrapower",
|
|
15
|
-
"version": "5.5.
|
|
15
|
+
"version": "5.5.5"
|
|
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.
|
|
4
|
+
"version": "5.5.5",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "liangjie559567"
|
|
7
7
|
},
|
package/bridge/codex-server.cjs
CHANGED
|
@@ -15074,7 +15074,7 @@ function slugify(text) {
|
|
|
15074
15074
|
return slug || "prompt";
|
|
15075
15075
|
}
|
|
15076
15076
|
function generatePromptId() {
|
|
15077
|
-
return (0, import_crypto.randomBytes)(
|
|
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,
|
|
16544
|
-
var RATE_LIMIT_RETRY_COUNT = Math.min(10, Math.max(1,
|
|
16545
|
-
var RATE_LIMIT_INITIAL_DELAY = Math.max(1e3,
|
|
16546
|
-
var RATE_LIMIT_MAX_DELAY = Math.max(5e3,
|
|
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,
|
|
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]{
|
|
17350
|
+
if (!/^[0-9a-f]{16}$/i.test(jobId)) {
|
|
17343
17351
|
return void 0;
|
|
17344
17352
|
}
|
|
17345
17353
|
const promptsDir = getPromptsDir(workingDirectory);
|
package/bridge/gemini-server.cjs
CHANGED
|
@@ -14917,7 +14917,7 @@ function slugify(text) {
|
|
|
14917
14917
|
return slug || "prompt";
|
|
14918
14918
|
}
|
|
14919
14919
|
function generatePromptId() {
|
|
14920
|
-
return (0, import_crypto.randomBytes)(
|
|
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,
|
|
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,
|
|
16968
|
-
var RATE_LIMIT_RETRY_COUNT = Math.min(10, Math.max(1,
|
|
16969
|
-
var RATE_LIMIT_INITIAL_DELAY = Math.max(1e3,
|
|
16970
|
-
var RATE_LIMIT_MAX_DELAY = Math.max(5e3,
|
|
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]{
|
|
17004
|
+
if (!/^[0-9a-f]{16}$/i.test(jobId)) {
|
|
16987
17005
|
return void 0;
|
|
16988
17006
|
}
|
|
16989
17007
|
const promptsDir = getPromptsDir(workingDirectory);
|
package/bridge/mcp-server.cjs
CHANGED
|
@@ -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
|
-
|
|
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)}`
|
package/bridge/team-bridge.cjs
CHANGED
|
@@ -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,
|
|
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;
|
package/commands/brainstorm.md
CHANGED
package/commands/execute-plan.md
CHANGED
package/commands/write-plan.md
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Integration tests for delegation enforcer
|
|
3
3
|
* Tests the entire flow from hook input to modified output
|
|
4
|
-
*
|
|
5
|
-
* NOTE: These tests are SKIPPED because the delegation enforcer is not yet wired
|
|
6
|
-
* into the hooks bridge. The enforcer module exists but processHook() doesn't
|
|
7
|
-
* call it. These tests will be enabled once the integration is implemented.
|
|
8
4
|
*/
|
|
9
5
|
export {};
|
|
10
6
|
//# sourceMappingURL=delegation-enforcer-integration.test.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delegation-enforcer-integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/delegation-enforcer-integration.test.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"delegation-enforcer-integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/delegation-enforcer-integration.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Integration tests for delegation enforcer
|
|
3
3
|
* Tests the entire flow from hook input to modified output
|
|
4
|
-
*
|
|
5
|
-
* NOTE: These tests are SKIPPED because the delegation enforcer is not yet wired
|
|
6
|
-
* into the hooks bridge. The enforcer module exists but processHook() doesn't
|
|
7
|
-
* call it. These tests will be enabled once the integration is implemented.
|
|
8
4
|
*/
|
|
9
5
|
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
10
6
|
import { processHook } from '../hooks/bridge.js';
|
|
11
|
-
describe
|
|
7
|
+
describe('delegation-enforcer integration', () => {
|
|
12
8
|
let originalDebugEnv;
|
|
13
9
|
beforeEach(() => {
|
|
14
10
|
originalDebugEnv = process.env.OMC_DEBUG;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delegation-enforcer-integration.test.js","sourceRoot":"","sources":["../../src/__tests__/delegation-enforcer-integration.test.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"delegation-enforcer-integration.test.js","sourceRoot":"","sources":["../../src/__tests__/delegation-enforcer-integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|
|
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
|
|
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-
|
|
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', '
|
|
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
|
|
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-
|
|
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', '
|
|
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: '
|
|
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-
|
|
109
|
+
fs.readdirSync.mockReturnValue(['codex-status-test-ab12cd34ef567890.json']);
|
|
110
110
|
fs.readFileSync.mockReturnValue(JSON.stringify(mockStatus));
|
|
111
|
-
const result = await handleKillJob('codex', '
|
|
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: '
|
|
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-
|
|
131
|
+
fs.readdirSync.mockReturnValue(['codex-status-test-ab12cd34ef567890.json']);
|
|
132
132
|
fs.readFileSync.mockReturnValue(JSON.stringify(mockStatus));
|
|
133
|
-
const result = await handleKillJob('codex', '
|
|
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', '
|
|
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', '
|
|
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', '
|
|
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: '
|
|
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-
|
|
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', '
|
|
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: '
|
|
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-
|
|
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', '
|
|
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: '
|
|
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-
|
|
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', '
|
|
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: '
|
|
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-
|
|
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', '
|
|
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: '
|
|
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-
|
|
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', '
|
|
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-
|
|
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', '
|
|
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-
|
|
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', '
|
|
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-
|
|
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: '
|
|
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', '
|
|
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', '
|
|
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-
|
|
389
|
+
fs.readdirSync.mockReturnValue(['codex-status-test-slug-ab12cd34ef567890.json']);
|
|
390
390
|
const mockStatus = {
|
|
391
391
|
provider: 'codex',
|
|
392
|
-
jobId: '
|
|
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', '
|
|
404
|
+
const result = await handleCheckJobStatus('codex', 'ab12cd34ef567890');
|
|
405
405
|
expect(result.isError).toBeFalsy();
|
|
406
|
-
expect(result.content[0].text).toContain('
|
|
406
|
+
expect(result.content[0].text).toContain('ab12cd34ef567890');
|
|
407
407
|
expect(getPromptsDir).toHaveBeenCalledWith('/other/project');
|
|
408
408
|
});
|
|
409
409
|
});
|