oh-my-copilot 4.13.45 → 4.13.55

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 (43) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/bridge/cli.cjs +254 -9
  4. package/bridge/mcp-server.cjs +6 -2
  5. package/dist/__tests__/auto-slash-aliases.test.js +6 -6
  6. package/dist/__tests__/auto-slash-aliases.test.js.map +1 -1
  7. package/dist/__tests__/auto-update.test.js +132 -2
  8. package/dist/__tests__/auto-update.test.js.map +1 -1
  9. package/dist/__tests__/pre-tool-enforcer.test.js +253 -0
  10. package/dist/__tests__/pre-tool-enforcer.test.js.map +1 -1
  11. package/dist/__tests__/skills.test.js +77 -7
  12. package/dist/__tests__/skills.test.js.map +1 -1
  13. package/dist/__tests__/wiki-hook-output-format.test.d.ts +2 -0
  14. package/dist/__tests__/wiki-hook-output-format.test.d.ts.map +1 -0
  15. package/dist/__tests__/wiki-hook-output-format.test.js +59 -0
  16. package/dist/__tests__/wiki-hook-output-format.test.js.map +1 -0
  17. package/dist/features/auto-update.d.ts.map +1 -1
  18. package/dist/features/auto-update.js +53 -5
  19. package/dist/features/auto-update.js.map +1 -1
  20. package/dist/hooks/bridge.d.ts.map +1 -1
  21. package/dist/hooks/bridge.js +109 -0
  22. package/dist/hooks/bridge.js.map +1 -1
  23. package/dist/hooks/persistent-mode/index.d.ts +6 -0
  24. package/dist/hooks/persistent-mode/index.d.ts.map +1 -1
  25. package/dist/hooks/persistent-mode/index.js +96 -0
  26. package/dist/hooks/persistent-mode/index.js.map +1 -1
  27. package/dist/hooks/persistent-mode/stop-hook-blocking.test.js +115 -22
  28. package/dist/hooks/persistent-mode/stop-hook-blocking.test.js.map +1 -1
  29. package/dist/mcp/tool-registry.d.ts.map +1 -1
  30. package/dist/mcp/tool-registry.js +6 -2
  31. package/dist/mcp/tool-registry.js.map +1 -1
  32. package/docs/REFERENCE.md +5 -5
  33. package/docs/copilot-instructions.md +1 -1
  34. package/package.json +1 -1
  35. package/scripts/persistent-mode.cjs +71 -0
  36. package/scripts/persistent-mode.mjs +66 -0
  37. package/scripts/pre-tool-enforcer.mjs +105 -4
  38. package/scripts/wiki-pre-compact.mjs +1 -4
  39. package/skills/deep-dive/SKILL.md +52 -4
  40. package/skills/deep-interview/SKILL.md +109 -15
  41. package/skills/plan/SKILL.md +1 -1
  42. package/skills/ralplan/SKILL.md +2 -2
  43. package/templates/hooks/persistent-mode.mjs +66 -0
@@ -10,7 +10,7 @@
10
10
  {
11
11
  "name": "oh-my-copilot",
12
12
  "description": "Copilot CLI native multi-agent orchestration with intelligent model routing, 18 agent variants, and 32 powerful skills. Zero learning curve. Maximum power.",
13
- "version": "4.13.45",
13
+ "version": "4.13.55",
14
14
  "author": {
15
15
  "name": "Robin Norberg",
16
16
  "email": "github@platypus.se"
@@ -27,5 +27,5 @@
27
27
  ]
28
28
  }
29
29
  ],
30
- "version": "4.13.45"
30
+ "version": "4.13.55"
31
31
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-copilot",
3
- "version": "4.13.45",
3
+ "version": "4.13.55",
4
4
  "description": "Multi-agent orchestration system for Copilot CLI",
5
5
  "author": {
6
6
  "name": "Robin Norberg and oh-my-copilot contributors"
package/bridge/cli.cjs CHANGED
@@ -17581,12 +17581,56 @@ function updateLastCheckTime() {
17581
17581
  saveVersionMetadata(current);
17582
17582
  }
17583
17583
  }
17584
+ function getGitHubUpdateToken() {
17585
+ const token = process.env.GH_TOKEN?.trim() || process.env.GITHUB_TOKEN?.trim();
17586
+ return token || null;
17587
+ }
17588
+ function getGitHubReleaseHeaders() {
17589
+ const headers = {
17590
+ "Accept": "application/vnd.github.v3+json",
17591
+ "User-Agent": "oh-my-copilot-updater"
17592
+ };
17593
+ const token = getGitHubUpdateToken();
17594
+ if (token) {
17595
+ headers.Authorization = `Bearer ${token}`;
17596
+ }
17597
+ return headers;
17598
+ }
17599
+ function getHeader(response, name) {
17600
+ return response.headers?.get(name) ?? response.headers?.get(name.toLowerCase()) ?? null;
17601
+ }
17602
+ function formatRateLimitReset(resetHeader) {
17603
+ if (!resetHeader) {
17604
+ return null;
17605
+ }
17606
+ const resetSeconds = Number.parseInt(resetHeader, 10);
17607
+ if (!Number.isFinite(resetSeconds) || resetSeconds <= 0) {
17608
+ return null;
17609
+ }
17610
+ return new Date(resetSeconds * 1e3).toISOString();
17611
+ }
17612
+ async function formatGitHubReleaseFetchError(response, usedToken) {
17613
+ let body = "";
17614
+ try {
17615
+ body = await response.text();
17616
+ } catch {
17617
+ body = "";
17618
+ }
17619
+ const remaining = getHeader(response, "x-ratelimit-remaining");
17620
+ const resetAt = formatRateLimitReset(getHeader(response, "x-ratelimit-reset"));
17621
+ const bodyLooksRateLimited = /rate limit|api rate limit|secondary rate/i.test(body);
17622
+ const isRateLimited = response.status === 429 || response.status === 403 && (remaining === "0" || bodyLooksRateLimited);
17623
+ if (!isRateLimited) {
17624
+ return `Failed to fetch release info: ${response.status} ${response.statusText}`;
17625
+ }
17626
+ const retrySuffix = resetAt ? ` Try again after ${resetAt}.` : "";
17627
+ const authHint = usedToken ? "The configured GitHub token appears to be rate limited; verify the token or try again later." : "Set GH_TOKEN or GITHUB_TOKEN to use authenticated GitHub API requests and increase rate limits.";
17628
+ return `Failed to fetch release info: GitHub API rate limit exceeded (${response.status} ${response.statusText}). ${authHint}${retrySuffix}`;
17629
+ }
17584
17630
  async function fetchLatestRelease() {
17631
+ const usedToken = getGitHubUpdateToken() !== null;
17585
17632
  const response = await fetch(`${GITHUB_API_URL}/releases/latest`, {
17586
- headers: {
17587
- "Accept": "application/vnd.github.v3+json",
17588
- "User-Agent": "oh-my-copilot-updater"
17589
- }
17633
+ headers: getGitHubReleaseHeaders()
17590
17634
  });
17591
17635
  if (response.status === 404) {
17592
17636
  const pkgResponse = await fetch(`${GITHUB_RAW_URL}/main/package.json`, {
@@ -17609,7 +17653,7 @@ async function fetchLatestRelease() {
17609
17653
  throw new Error("No releases found and could not fetch package.json");
17610
17654
  }
17611
17655
  if (!response.ok) {
17612
- throw new Error(`Failed to fetch release info: ${response.status} ${response.statusText}`);
17656
+ throw new Error(await formatGitHubReleaseFetchError(response, usedToken));
17613
17657
  }
17614
17658
  return await response.json();
17615
17659
  }
@@ -24647,6 +24691,7 @@ __export(persistent_mode_exports, {
24647
24691
  createHookOutput: () => createHookOutput,
24648
24692
  getIdleNotificationCooldownSeconds: () => getIdleNotificationCooldownSeconds,
24649
24693
  getToolErrorRetryGuidance: () => getToolErrorRetryGuidance,
24694
+ hasPendingOwnedAsyncWork: () => hasPendingOwnedAsyncWork,
24650
24695
  readLastToolError: () => readLastToolError,
24651
24696
  recordIdleNotificationSent: () => recordIdleNotificationSent,
24652
24697
  resetTodoContinuationAttempts: () => resetTodoContinuationAttempts,
@@ -24702,6 +24747,78 @@ function isStaleState(state) {
24702
24747
  }
24703
24748
  return Date.now() - mostRecent > STALE_STATE_THRESHOLD_MS;
24704
24749
  }
24750
+ function parseTimestamp(value) {
24751
+ if (typeof value !== "string" || value.length === 0) {
24752
+ return null;
24753
+ }
24754
+ const parsed = new Date(value).getTime();
24755
+ return Number.isFinite(parsed) ? parsed : null;
24756
+ }
24757
+ function isFreshTimestamp(value, ttlMs = PENDING_ASYNC_STATE_STALE_MS) {
24758
+ const parsed = parseTimestamp(value);
24759
+ return parsed !== null && Date.now() - parsed <= ttlMs;
24760
+ }
24761
+ function hasPendingBackgroundTask(directory, sessionId) {
24762
+ try {
24763
+ const stateRoot2 = (0, import_path56.join)(getOmcRoot(directory), "state");
24764
+ const hudPath = sessionId ? (0, import_path56.join)(stateRoot2, "sessions", sessionId, "hud-state.json") : (0, import_path56.join)(stateRoot2, "hud-state.json");
24765
+ if (!(0, import_fs49.existsSync)(hudPath)) return false;
24766
+ const hudState = JSON.parse((0, import_fs49.readFileSync)(hudPath, "utf-8"));
24767
+ return Boolean(hudState?.backgroundTasks?.some((task) => {
24768
+ if (task.status !== "running") return false;
24769
+ return isFreshTimestamp(task.startedAt ?? task.startTime);
24770
+ }));
24771
+ } catch {
24772
+ return false;
24773
+ }
24774
+ }
24775
+ function readPendingWakeupState(directory, sessionId) {
24776
+ const stateRoot2 = (0, import_path56.join)(getOmcRoot(directory), "state");
24777
+ const dirs = sessionId ? [(0, import_path56.join)(stateRoot2, "sessions", sessionId), stateRoot2] : [stateRoot2];
24778
+ const fileNames = [
24779
+ "scheduled-wakeup-state.json",
24780
+ "schedule-wakeup-state.json",
24781
+ "wakeup-state.json"
24782
+ ];
24783
+ const states = [];
24784
+ for (const dir of dirs) {
24785
+ for (const fileName of fileNames) {
24786
+ const filePath = (0, import_path56.join)(dir, fileName);
24787
+ try {
24788
+ if (!(0, import_fs49.existsSync)(filePath)) continue;
24789
+ const parsed = JSON.parse((0, import_fs49.readFileSync)(filePath, "utf-8"));
24790
+ if (parsed && typeof parsed === "object") {
24791
+ states.push(parsed);
24792
+ }
24793
+ } catch {
24794
+ continue;
24795
+ }
24796
+ }
24797
+ }
24798
+ return states;
24799
+ }
24800
+ function hasPendingScheduledWakeup(directory, sessionId) {
24801
+ const now = Date.now();
24802
+ return readPendingWakeupState(directory, sessionId).some((state) => {
24803
+ const status = typeof state.status === "string" ? state.status.toLowerCase() : "";
24804
+ if (["completed", "complete", "cancelled", "canceled", "failed", "expired"].includes(status)) {
24805
+ return false;
24806
+ }
24807
+ const dueAt = parseTimestamp(
24808
+ state.due_at ?? state.wakeup_at ?? state.scheduled_for ?? state.deadline_at ?? state.expires_at
24809
+ );
24810
+ if (dueAt !== null) {
24811
+ return dueAt > now;
24812
+ }
24813
+ if (state.active === true || state.pending === true) {
24814
+ return isFreshTimestamp(state.created_at ?? state.updated_at ?? state.started_at);
24815
+ }
24816
+ return false;
24817
+ });
24818
+ }
24819
+ function hasPendingOwnedAsyncWork(directory, sessionId) {
24820
+ return hasPendingBackgroundTask(directory, sessionId) || hasPendingScheduledWakeup(directory, sessionId);
24821
+ }
24705
24822
  function readLastToolError(directory) {
24706
24823
  const stateDir = (0, import_path56.join)(getOmcRoot(directory), "state");
24707
24824
  const errorPath = (0, import_path56.join)(stateDir, "last-tool-error.json");
@@ -25717,6 +25834,13 @@ async function checkPersistentModes(sessionId, directory, stopContext) {
25717
25834
  if (skipHooks.includes("persistent-mode") || skipHooks.includes("stop-continuation")) {
25718
25835
  return { shouldBlock: false, message: "", mode: "none" };
25719
25836
  }
25837
+ if (hasPendingOwnedAsyncWork(workingDir, sessionId)) {
25838
+ return {
25839
+ shouldBlock: false,
25840
+ message: "",
25841
+ mode: "none"
25842
+ };
25843
+ }
25720
25844
  try {
25721
25845
  const { readSkillActiveStateNormalized: readSkillActiveStateNormalized2, pruneExpiredWorkflowSkillTombstones: pruneExpiredWorkflowSkillTombstones2, writeSkillActiveStateCopies: writeSkillActiveStateCopies2 } = await Promise.resolve().then(() => (init_skill_state(), skill_state_exports));
25722
25846
  const current = readSkillActiveStateNormalized2(workingDir, sessionId);
@@ -25826,7 +25950,7 @@ function createHookOutput(result) {
25826
25950
  message: result.message || void 0
25827
25951
  };
25828
25952
  }
25829
- var import_fs49, import_path56, CANCEL_SIGNAL_TTL_MS2, STALE_STATE_THRESHOLD_MS, todoContinuationAttempts, TRANSCRIPT_TAIL_BYTES, CRITICAL_CONTEXT_STOP_PERCENT, RALPLAN_TERMINAL_PHASES, REVIEWER_TASK_TOOL_NAMES, REVIEWER_COMMAND_TOOL_NAMES, AWAITING_CONFIRMATION_TTL_MS, TEAM_PIPELINE_STOP_BLOCKER_MAX, TEAM_PIPELINE_STOP_BLOCKER_TTL_MS, RALPLAN_STOP_BLOCKER_MAX, RALPLAN_STOP_BLOCKER_TTL_MS, RALPLAN_ACTIVE_AGENT_RECENCY_WINDOW_MS;
25953
+ var import_fs49, import_path56, CANCEL_SIGNAL_TTL_MS2, STALE_STATE_THRESHOLD_MS, PENDING_ASYNC_STATE_STALE_MS, todoContinuationAttempts, TRANSCRIPT_TAIL_BYTES, CRITICAL_CONTEXT_STOP_PERCENT, RALPLAN_TERMINAL_PHASES, REVIEWER_TASK_TOOL_NAMES, REVIEWER_COMMAND_TOOL_NAMES, AWAITING_CONFIRMATION_TTL_MS, TEAM_PIPELINE_STOP_BLOCKER_MAX, TEAM_PIPELINE_STOP_BLOCKER_TTL_MS, RALPLAN_STOP_BLOCKER_MAX, RALPLAN_STOP_BLOCKER_TTL_MS, RALPLAN_ACTIVE_AGENT_RECENCY_WINDOW_MS;
25830
25954
  var init_persistent_mode = __esm({
25831
25955
  "src/hooks/persistent-mode/index.ts"() {
25832
25956
  "use strict";
@@ -25850,6 +25974,7 @@ var init_persistent_mode = __esm({
25850
25974
  init_mode_registry();
25851
25975
  CANCEL_SIGNAL_TTL_MS2 = 3e4;
25852
25976
  STALE_STATE_THRESHOLD_MS = 2 * 60 * 60 * 1e3;
25977
+ PENDING_ASYNC_STATE_STALE_MS = 24 * 60 * 60 * 1e3;
25853
25978
  todoContinuationAttempts = /* @__PURE__ */ new Map();
25854
25979
  TRANSCRIPT_TAIL_BYTES = 32 * 1024;
25855
25980
  CRITICAL_CONTEXT_STOP_PERCENT = 95;
@@ -39058,7 +39183,7 @@ async function captureWorkerPane(paneId) {
39058
39183
  return "";
39059
39184
  }
39060
39185
  }
39061
- function isFreshTimestamp(value, maxAgeMs = MONITOR_SIGNAL_STALE_MS) {
39186
+ function isFreshTimestamp2(value, maxAgeMs = MONITOR_SIGNAL_STALE_MS) {
39062
39187
  if (!value) return false;
39063
39188
  const parsed = Date.parse(value);
39064
39189
  if (!Number.isFinite(parsed)) return false;
@@ -40067,8 +40192,8 @@ async function monitorTeamV2(teamName, cwd) {
40067
40192
  }
40068
40193
  }
40069
40194
  const paneSuggestsIdle = alive && paneLooksReady(paneCapture) && !paneHasActiveTask(paneCapture);
40070
- const statusFresh = isFreshTimestamp(status.updated_at);
40071
- const heartbeatFresh = isFreshTimestamp(heartbeat?.last_turn_at);
40195
+ const statusFresh = isFreshTimestamp2(status.updated_at);
40196
+ const heartbeatFresh = isFreshTimestamp2(heartbeat?.last_turn_at);
40072
40197
  const hasWorkStartEvidence = expectedTaskId !== "" && hasWorkerStatusProgress(status, expectedTaskId);
40073
40198
  const missingDependencyIds = outstandingTask ? getMissingDependencyIds(outstandingTask, taskById) : [];
40074
40199
  let stallReason = null;
@@ -84028,6 +84153,7 @@ var TEAM_STAGE_ALIASES = {
84028
84153
  fixing: "team-fix"
84029
84154
  };
84030
84155
  var BACKGROUND_AGENT_ID_PATTERN = /agentId:\s*([a-zA-Z0-9_-]+)/;
84156
+ var BACKGROUND_BASH_ID_PATTERN = /(?:background (?:bash )?(?:command|process|task).*?(?:id|ID)|bash_id|task_id)[:=]\s*([a-zA-Z0-9_-]+)/i;
84031
84157
  var TASK_OUTPUT_ID_PATTERN = /<task_id>([^<]+)<\/task_id>/i;
84032
84158
  var TASK_OUTPUT_STATUS_PATTERN = /<status>([^<]+)<\/status>/i;
84033
84159
  var SAFE_SESSION_ID_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,255}$/;
@@ -84236,6 +84362,19 @@ function extractAsyncAgentId(toolOutput) {
84236
84362
  }
84237
84363
  return toolOutput.match(BACKGROUND_AGENT_ID_PATTERN)?.[1];
84238
84364
  }
84365
+ function extractBackgroundBashId(toolOutput) {
84366
+ if (typeof toolOutput !== "string") {
84367
+ return void 0;
84368
+ }
84369
+ return toolOutput.match(BACKGROUND_BASH_ID_PATTERN)?.[1];
84370
+ }
84371
+ function bashLaunchIsBackgroundPending(toolOutput) {
84372
+ if (typeof toolOutput !== "string") {
84373
+ return false;
84374
+ }
84375
+ const normalized = toolOutput.toLowerCase();
84376
+ return normalized.includes("running in the background") || normalized.includes("started in the background") || normalized.includes("background command") || normalized.includes("background process") || Boolean(extractBackgroundBashId(toolOutput));
84377
+ }
84239
84378
  function parseTaskOutputLifecycle(toolOutput) {
84240
84379
  if (typeof toolOutput !== "string") {
84241
84380
  return null;
@@ -84257,6 +84396,62 @@ function taskLaunchDidFail(toolOutput) {
84257
84396
  const normalized = toolOutput.toLowerCase();
84258
84397
  return normalized.includes("error") || normalized.includes("failed");
84259
84398
  }
84399
+ function getSessionStateDir2(directory, sessionId) {
84400
+ const stateDir = (0, import_path90.join)(getOmcRoot(directory), "state");
84401
+ if (sessionId && SAFE_SESSION_ID_PATTERN.test(sessionId)) {
84402
+ return (0, import_path90.join)(stateDir, "sessions", sessionId);
84403
+ }
84404
+ return stateDir;
84405
+ }
84406
+ function getScheduledWakeupStatePath(directory, sessionId) {
84407
+ return (0, import_path90.join)(getSessionStateDir2(directory, sessionId), "scheduled-wakeup-state.json");
84408
+ }
84409
+ function parseWakeupDueAt(toolInput) {
84410
+ if (!toolInput || typeof toolInput !== "object") {
84411
+ return void 0;
84412
+ }
84413
+ const input = toolInput;
84414
+ const absolute = input.due_at ?? input.wakeup_at ?? input.scheduled_for ?? input.deadline_at ?? input.at;
84415
+ if (typeof absolute === "string") {
84416
+ const parsed = new Date(absolute).getTime();
84417
+ if (Number.isFinite(parsed)) return new Date(parsed).toISOString();
84418
+ }
84419
+ const delaySeconds = input.seconds ?? input.delay_seconds ?? input.delaySeconds;
84420
+ if (typeof delaySeconds === "number" && Number.isFinite(delaySeconds)) {
84421
+ return new Date(Date.now() + Math.max(0, delaySeconds) * 1e3).toISOString();
84422
+ }
84423
+ const delayMs = input.milliseconds ?? input.delay_ms ?? input.delayMs;
84424
+ if (typeof delayMs === "number" && Number.isFinite(delayMs)) {
84425
+ return new Date(Date.now() + Math.max(0, delayMs)).toISOString();
84426
+ }
84427
+ const delayMinutes = input.minutes ?? input.delay_minutes ?? input.delayMinutes;
84428
+ if (typeof delayMinutes === "number" && Number.isFinite(delayMinutes)) {
84429
+ return new Date(Date.now() + Math.max(0, delayMinutes) * 6e4).toISOString();
84430
+ }
84431
+ return void 0;
84432
+ }
84433
+ function recordScheduledWakeup(directory, sessionId, toolInput) {
84434
+ try {
84435
+ const statePath = getScheduledWakeupStatePath(directory, sessionId);
84436
+ (0, import_fs75.mkdirSync)((0, import_path90.dirname)(statePath), { recursive: true });
84437
+ (0, import_fs75.writeFileSync)(
84438
+ statePath,
84439
+ JSON.stringify(
84440
+ {
84441
+ active: true,
84442
+ pending: true,
84443
+ status: "pending",
84444
+ session_id: sessionId,
84445
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
84446
+ due_at: parseWakeupDueAt(toolInput)
84447
+ },
84448
+ null,
84449
+ 2
84450
+ )
84451
+ );
84452
+ } catch {
84453
+ }
84454
+ }
84260
84455
  function getModeStatePaths(directory, modeName, sessionId) {
84261
84456
  const stateDir = (0, import_path90.join)(getOmcRoot(directory), "state");
84262
84457
  const safeSessionId = typeof sessionId === "string" && SAFE_SESSION_ID_PATTERN.test(sessionId) ? sessionId : void 0;
@@ -85586,6 +85781,22 @@ Command blocked: ${command}`
85586
85781
  );
85587
85782
  }
85588
85783
  }
85784
+ if (input.toolName === "Bash") {
85785
+ const toolInput = modifiedToolInput ?? input.toolInput;
85786
+ if (toolInput?.run_in_background === true && toolInput.command) {
85787
+ const taskId = getHookToolUseId(input) ?? `bash-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
85788
+ addBackgroundTask(
85789
+ taskId,
85790
+ toolInput.command,
85791
+ "bash",
85792
+ directory,
85793
+ input.sessionId
85794
+ );
85795
+ }
85796
+ }
85797
+ if ((input.toolName || "").toLowerCase() === "schedulewakeup") {
85798
+ recordScheduledWakeup(directory, input.sessionId, input.toolInput);
85799
+ }
85589
85800
  if (input.toolName === "Edit" || input.toolName === "Write") {
85590
85801
  const toolInput = input.toolInput;
85591
85802
  if (toolInput?.file_path && input.sessionId) {
@@ -85726,6 +85937,40 @@ async function processPostToolUse(input) {
85726
85937
  }
85727
85938
  }
85728
85939
  }
85940
+ if (input.toolName === "Bash") {
85941
+ const toolInput = input.toolInput;
85942
+ if (toolInput?.run_in_background === true) {
85943
+ const toolUseId = getHookToolUseId(input);
85944
+ const backgroundBashId = extractBackgroundBashId(input.toolOutput);
85945
+ const command = toolInput.command;
85946
+ if (backgroundBashId) {
85947
+ if (toolUseId) {
85948
+ remapBackgroundTaskId(toolUseId, backgroundBashId, directory, input.sessionId);
85949
+ } else if (command) {
85950
+ remapMostRecentMatchingBackgroundTaskId(
85951
+ command,
85952
+ backgroundBashId,
85953
+ directory,
85954
+ "bash",
85955
+ input.sessionId
85956
+ );
85957
+ }
85958
+ } else if (!bashLaunchIsBackgroundPending(input.toolOutput)) {
85959
+ const failed = taskLaunchDidFail(input.toolOutput);
85960
+ if (toolUseId) {
85961
+ completeBackgroundTask(toolUseId, directory, failed, input.sessionId);
85962
+ } else if (command) {
85963
+ completeMostRecentMatchingBackgroundTask(
85964
+ command,
85965
+ directory,
85966
+ failed,
85967
+ "bash",
85968
+ input.sessionId
85969
+ );
85970
+ }
85971
+ }
85972
+ }
85973
+ }
85729
85974
  if (isDelegationToolName2(input.toolName)) {
85730
85975
  const dashboard = getAgentDashboard(directory);
85731
85976
  if (dashboard) {
@@ -37873,7 +37873,10 @@ function zodTypeToJsonSchema(zodType) {
37873
37873
  }
37874
37874
  if (zodType instanceof external_exports3.ZodDefault) {
37875
37875
  const inner = zodTypeToJsonSchema(zodType._def.innerType);
37876
- inner.default = zodType._def.defaultValue();
37876
+ const def = zodType._def.defaultValue;
37877
+ if (def !== void 0) {
37878
+ inner.default = typeof def === "function" ? def() : def;
37879
+ }
37877
37880
  return inner;
37878
37881
  }
37879
37882
  const description = zodType._def?.description;
@@ -37888,7 +37891,8 @@ function zodTypeToJsonSchema(zodType) {
37888
37891
  result.type = "boolean";
37889
37892
  } else if (zodType instanceof external_exports3.ZodArray) {
37890
37893
  result.type = "array";
37891
- result.items = zodType._def?.type ? zodTypeToJsonSchema(zodType._def.type) : { type: "string" };
37894
+ const elem = zodType._def?.element ?? zodType._def?.type;
37895
+ result.items = elem ? zodTypeToJsonSchema(elem) : { type: "string" };
37892
37896
  } else if (zodType instanceof external_exports3.ZodEnum) {
37893
37897
  result.type = "string";
37894
37898
  result.enum = zodType._def?.values;
@@ -119,8 +119,8 @@ Advanced: ambiguity ≤ 20%
119
119
  writeFileSync(join(tempConfigDir, 'skills', 'deep-interview', 'SKILL.md'), `---
120
120
  name: deep-interview
121
121
  description: Deep interview
122
- pipeline: [deep-interview, omc-plan, autopilot]
123
- next-skill: omc-plan
122
+ pipeline: [deep-interview, plan, autopilot]
123
+ next-skill: plan
124
124
  next-skill-args: --consensus --direct
125
125
  handoff: .omcp/specs/deep-interview-{slug}.md
126
126
  ---
@@ -134,9 +134,9 @@ Deep interview body`);
134
134
  });
135
135
  expect(result.success).toBe(true);
136
136
  expect(result.replacementText).toContain('## Skill Pipeline');
137
- expect(result.replacementText).toContain('Pipeline: `deep-interview → omc-plan → autopilot`');
137
+ expect(result.replacementText).toContain('Pipeline: `deep-interview → plan → autopilot`');
138
138
  expect(result.replacementText).toContain('Next skill arguments: `--consensus --direct`');
139
- expect(result.replacementText).toContain('Skill("oh-my-copilot:omc-plan")');
139
+ expect(result.replacementText).toContain('Skill("oh-my-copilot:plan")');
140
140
  expect(result.replacementText).toContain('`.omcp/specs/deep-interview-{slug}.md`');
141
141
  });
142
142
  it.skip('discovers project-local compatibility skills from .agents/skills', async () => {
@@ -166,8 +166,8 @@ Compatibility body`);
166
166
  writeFileSync(join(tempConfigDir, 'skills', 'deep-interview', 'SKILL.md'), `---
167
167
  name: deep-interview
168
168
  description: Deep interview
169
- pipeline: [deep-interview, omc-plan, autopilot]
170
- next-skill: omc-plan
169
+ pipeline: [deep-interview, plan, autopilot]
170
+ next-skill: plan
171
171
  next-skill-args: --consensus --direct
172
172
  handoff: .omcp/specs/deep-interview-{slug}.md
173
173
  ---
@@ -1 +1 @@
1
- {"version":3,"file":"auto-slash-aliases.test.js","sourceRoot":"","sources":["../../src/__tests__/auto-slash-aliases.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auto-slash-aliases.test.js","sourceRoot":"","sources":["../../src/__tests__/auto-slash-aliases.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACnE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAE5B,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAChD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAClC,MAAM,uBAAuB,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAE/D,IAAI,QAAgB,CAAC;IACrB,IAAI,aAAqB,CAAC;IAC1B,IAAI,cAAsB,CAAC;IAE3B,KAAK,UAAU,YAAY;QACzB,EAAE,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,MAAM,CAAC,yCAAyC,CAAC,CAAC;IAC3D,CAAC;IAED,UAAU,CAAC,GAAG,EAAE;QACd,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,yBAAyB,CAAC,CAAC,CAAC;QAClE,aAAa,GAAG,IAAI,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;QACjD,cAAc,GAAG,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAE3C,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtE,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,yBAAyB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzF,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtE,SAAS,CAAC,IAAI,CAAC,cAAc,EAAE,UAAU,EAAE,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE7E,aAAa,CACX,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EACjD;;;;;UAKI,CACL,CAAC;QAEF,aAAa,CACX,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,yBAAyB,EAAE,UAAU,CAAC,EACpE;;;;;SAKG,CACJ,CAAC;QAEF,aAAa,CACX,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EACjD;;;;;;;;;;sBAUgB,CACjB,CAAC;QAEF,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,aAAa,CAAC;QAC/C,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAC3B,IAAI,uBAAuB,KAAK,SAAS,EAAE,CAAC;YAC1C,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;QACxC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,uBAAuB,CAAC;QAC3D,CAAC;QACD,EAAE,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;QAE5E,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAEtD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB;QAC/D,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,uCAAuC;QAE3E,MAAM,WAAW,GAAG,qBAAqB,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC3E,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACtC,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;QACzD,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iFAAiF,EAAE,KAAK,IAAI,EAAE;QAC/F,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChF,aAAa,CACX,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,gBAAgB,EAAE,UAAU,CAAC,EAC3D;;;;;;;;;;;;;;;CAeL,CACI,CAAC;QACF,aAAa,CACX,IAAI,CAAC,aAAa,EAAE,eAAe,CAAC,EACpC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,EAAE,aAAa,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CACzE,CAAC;QAEF,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,mBAAmB,CAAC;YACjC,OAAO,EAAE,gBAAgB;YACzB,IAAI,EAAE,oBAAoB;YAC1B,GAAG,EAAE,oCAAoC;SAC1C,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAC;QACtE,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAC3D,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC5D,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;QAC/D,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;QAC7D,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC;QACjE,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QAC9D,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC5D,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;QACxE,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAC/D,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QAC9D,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QAClE,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;QACjE,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC;QACrE,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QAClE,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAChE,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC,+EAA+E,EAAE,KAAK,IAAI,EAAE;QAClG,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChF,aAAa,CACX,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,gBAAgB,EAAE,UAAU,CAAC,EAC3D;;;;;;;;;oBASc,CACf,CAAC;QAEF,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,mBAAmB,CAAC;YACjC,OAAO,EAAE,gBAAgB;YACzB,IAAI,EAAE,oBAAoB;YAC1B,GAAG,EAAE,oCAAoC;SAC1C,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QAC9D,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,+CAA+C,CAAC,CAAC;QAC1F,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,8CAA8C,CAAC,CAAC;QACzF,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;QACxE,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,wCAAwC,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;QACrF,SAAS,CAAC,IAAI,CAAC,cAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvG,aAAa,CACX,IAAI,CAAC,cAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,UAAU,CAAC,EACrE;;;;;mBAKa,CACd,CAAC;QACF,aAAa,CACX,IAAI,CAAC,cAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,WAAW,EAAE,aAAa,CAAC,EACrF,SAAS,CACV,CAAC;QAEF,MAAM,EAAE,WAAW,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;QAEzF,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzD,MAAM,CAAC,qBAAqB,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE9F,MAAM,MAAM,GAAG,mBAAmB,CAAC;YACjC,OAAO,EAAE,cAAc;YACvB,IAAI,EAAE,EAAE;YACR,GAAG,EAAE,eAAe;SACrB,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;QAC/D,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;QACxE,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC,yFAAyF,EAAE,KAAK,IAAI,EAAE;QAC5G,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChF,aAAa,CACX,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,gBAAgB,EAAE,UAAU,CAAC,EAC3D;;;;;;;;;oBASc,CACf,CAAC;QAEF,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,mBAAmB,CAAC;YACjC,OAAO,EAAE,gBAAgB;YACzB,IAAI,EAAE,4CAA4C;YAClD,GAAG,EAAE,4DAA4D;SAClE,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC;QACvE,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,qCAAqC,CAAC,CAAC;QAChF,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,6DAA6D,CAAC,CAAC;QACxG,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC,kFAAkF,EAAE,KAAK,IAAI,EAAE;QACrG,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,cAAc,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;QAEtB,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChF,aAAa,CACX,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,gBAAgB,EAAE,UAAU,CAAC,EAC3D;;;;;oBAKc,CACf,CAAC;QAEF,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,mBAAmB,CAAC;YACjC,OAAO,EAAE,gBAAgB;YACzB,IAAI,EAAE,4CAA4C;YAClD,GAAG,EAAE,4DAA4D;SAClE,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC;aAC3B,SAAS,CAAC,qCAAqC,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oHAAoH,EAAE,KAAK,IAAI,EAAE;QAClI,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,cAAc,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,aAAa,CAAC;QAE9C,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,mBAAmB,CAAC;YACjC,OAAO,EAAE,MAAM;YACf,IAAI,EAAE,uBAAuB;YAC7B,GAAG,EAAE,6BAA6B;SACnC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,wEAAwE,CAAC,CAAC;QACnH,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,CAAC,0EAA0E,CAAC,CAAC;QACrH,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,mCAAmC,CAAC,CAAC;QAClF,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,qCAAqC,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -21,6 +21,7 @@ vi.mock('fs', async () => {
21
21
  const actual = await vi.importActual('fs');
22
22
  return {
23
23
  ...actual,
24
+ cpSync: vi.fn(),
24
25
  existsSync: vi.fn(),
25
26
  mkdirSync: vi.fn(),
26
27
  readFileSync: vi.fn(),
@@ -28,12 +29,13 @@ vi.mock('fs', async () => {
28
29
  };
29
30
  });
30
31
  import { execSync } from 'child_process';
31
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
32
+ import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
32
33
  import { homedir } from 'os';
33
34
  import { join } from 'path';
34
35
  import { install, isProjectScopedPlugin, isRunningAsPlugin, checkNodeVersion } from '../installer/index.js';
35
- import { reconcileUpdateRuntime, performUpdate, } from '../features/auto-update.js';
36
+ import { reconcileUpdateRuntime, performUpdate, fetchLatestRelease, } from '../features/auto-update.js';
36
37
  const mockedExecSync = vi.mocked(execSync);
38
+ const mockedCpSync = vi.mocked(cpSync);
37
39
  const mockedExistsSync = vi.mocked(existsSync);
38
40
  const mockedMkdirSync = vi.mocked(mkdirSync);
39
41
  const mockedReadFileSync = vi.mocked(readFileSync);
@@ -42,9 +44,21 @@ const mockedInstall = vi.mocked(install);
42
44
  const mockedIsProjectScopedPlugin = vi.mocked(isProjectScopedPlugin);
43
45
  const mockedIsRunningAsPlugin = vi.mocked(isRunningAsPlugin);
44
46
  const mockedCheckNodeVersion = vi.mocked(checkNodeVersion);
47
+ const originalPlatformDescriptor = Object.getOwnPropertyDescriptor(process, 'platform');
48
+ const originalGhToken = process.env.GH_TOKEN;
49
+ const originalGithubToken = process.env.GITHUB_TOKEN;
50
+ function mockPlatform(platform) {
51
+ Object.defineProperty(process, 'platform', {
52
+ configurable: true,
53
+ value: platform,
54
+ });
55
+ }
45
56
  describe('auto-update reconciliation', () => {
46
57
  beforeEach(() => {
47
58
  vi.clearAllMocks();
59
+ delete process.env.GH_TOKEN;
60
+ delete process.env.GITHUB_TOKEN;
61
+ mockedCpSync.mockImplementation(() => undefined);
48
62
  mockedExistsSync.mockReturnValue(true);
49
63
  mockedIsProjectScopedPlugin.mockReturnValue(false);
50
64
  // Default: running as plugin so forceHooks/refreshHooksInPlugin logic works
@@ -78,6 +92,122 @@ describe('auto-update reconciliation', () => {
78
92
  afterEach(() => {
79
93
  vi.unstubAllGlobals();
80
94
  delete process.env.CLAUDE_PLUGIN_ROOT;
95
+ if (originalGhToken === undefined) {
96
+ delete process.env.GH_TOKEN;
97
+ }
98
+ else {
99
+ process.env.GH_TOKEN = originalGhToken;
100
+ }
101
+ if (originalGithubToken === undefined) {
102
+ delete process.env.GITHUB_TOKEN;
103
+ }
104
+ else {
105
+ process.env.GITHUB_TOKEN = originalGithubToken;
106
+ }
107
+ if (originalPlatformDescriptor) {
108
+ Object.defineProperty(process, 'platform', originalPlatformDescriptor);
109
+ }
110
+ });
111
+ it('fetches latest release without Authorization when no GitHub token is configured', async () => {
112
+ const release = {
113
+ tag_name: 'v4.1.5',
114
+ name: '4.1.5',
115
+ published_at: '2026-02-09T00:00:00.000Z',
116
+ html_url: 'https://example.com/release',
117
+ body: 'notes',
118
+ prerelease: false,
119
+ draft: false,
120
+ };
121
+ const fetchMock = vi.fn().mockResolvedValue({
122
+ ok: true,
123
+ status: 200,
124
+ statusText: 'OK',
125
+ json: async () => release,
126
+ });
127
+ vi.stubGlobal('fetch', fetchMock);
128
+ await expect(fetchLatestRelease()).resolves.toEqual(release);
129
+ expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/releases/latest'), {
130
+ headers: {
131
+ 'Accept': 'application/vnd.github.v3+json',
132
+ 'User-Agent': 'oh-my-copilot-updater',
133
+ },
134
+ });
135
+ });
136
+ it('uses GITHUB_TOKEN for latest release requests when GH_TOKEN is absent', async () => {
137
+ process.env.GITHUB_TOKEN = 'github-token-value';
138
+ const fetchMock = vi.fn().mockResolvedValue({
139
+ ok: true,
140
+ status: 200,
141
+ statusText: 'OK',
142
+ json: async () => ({
143
+ tag_name: 'v4.1.5',
144
+ name: '4.1.5',
145
+ published_at: '2026-02-09T00:00:00.000Z',
146
+ html_url: 'https://example.com/release',
147
+ body: 'notes',
148
+ prerelease: false,
149
+ draft: false,
150
+ }),
151
+ });
152
+ vi.stubGlobal('fetch', fetchMock);
153
+ await fetchLatestRelease();
154
+ expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/releases/latest'), expect.objectContaining({
155
+ headers: expect.objectContaining({
156
+ Authorization: 'Bearer github-token-value',
157
+ }),
158
+ }));
159
+ });
160
+ it('prefers GH_TOKEN over GITHUB_TOKEN for latest release requests', async () => {
161
+ process.env.GH_TOKEN = 'gh-token-value';
162
+ process.env.GITHUB_TOKEN = 'github-token-value';
163
+ const fetchMock = vi.fn().mockResolvedValue({
164
+ ok: true,
165
+ status: 200,
166
+ statusText: 'OK',
167
+ json: async () => ({
168
+ tag_name: 'v4.1.5',
169
+ name: '4.1.5',
170
+ published_at: '2026-02-09T00:00:00.000Z',
171
+ html_url: 'https://example.com/release',
172
+ body: 'notes',
173
+ prerelease: false,
174
+ draft: false,
175
+ }),
176
+ });
177
+ vi.stubGlobal('fetch', fetchMock);
178
+ await fetchLatestRelease();
179
+ expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/releases/latest'), expect.objectContaining({
180
+ headers: expect.objectContaining({
181
+ Authorization: 'Bearer gh-token-value',
182
+ }),
183
+ }));
184
+ });
185
+ it('adds a helpful rate-limit hint for unauthenticated 403 release responses', async () => {
186
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
187
+ ok: false,
188
+ status: 403,
189
+ statusText: 'Forbidden',
190
+ headers: new Headers({
191
+ 'x-ratelimit-remaining': '0',
192
+ 'x-ratelimit-reset': '1893456000',
193
+ }),
194
+ text: async () => JSON.stringify({ message: 'API rate limit exceeded' }),
195
+ }));
196
+ await expect(fetchLatestRelease()).rejects.toThrow(/GitHub API rate limit exceeded.*Set GH_TOKEN or GITHUB_TOKEN.*2030-01-01T00:00:00.000Z/);
197
+ });
198
+ it('does not leak a configured token in token-authenticated 403 errors', async () => {
199
+ process.env.GH_TOKEN = 'super-secret-token';
200
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
201
+ ok: false,
202
+ status: 403,
203
+ statusText: 'Forbidden',
204
+ headers: new Headers({
205
+ 'x-ratelimit-remaining': '0',
206
+ }),
207
+ text: async () => JSON.stringify({ message: 'API rate limit exceeded' }),
208
+ }));
209
+ await expect(fetchLatestRelease()).rejects.toThrow(/configured GitHub token appears to be rate limited/);
210
+ await expect(fetchLatestRelease()).rejects.not.toThrow(/super-secret-token/);
81
211
  });
82
212
  it('reconciles runtime state without re-injecting settings hooks', () => {
83
213
  mockedExistsSync.mockReturnValue(false);