oh-my-copilot 5.12.1 → 5.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/bridge/__pycache__/gyoshu_bridge.cpython-312.pyc +0 -0
- package/bridge/claude-md-coordinator.cjs +2 -2
- package/bridge/cli.cjs +2302 -436
- package/bridge/mcp-server.cjs +384 -46
- package/bridge/runtime-cli.cjs +225 -50
- package/bridge/team-bridge.cjs +62 -9
- package/bridge/team-mcp.cjs +144 -25
- package/bridge/team.js +189 -56
- package/dist/__tests__/artifact-descriptor-handoff.test.js +1 -1
- package/dist/__tests__/artifact-descriptor-handoff.test.js.map +1 -1
- package/dist/__tests__/auto-update.test.js +18 -14
- package/dist/__tests__/auto-update.test.js.map +1 -1
- package/dist/__tests__/config-dir.test.js +12 -3
- package/dist/__tests__/config-dir.test.js.map +1 -1
- package/dist/__tests__/copilot-file-tool-injection.test.d.ts +2 -0
- package/dist/__tests__/copilot-file-tool-injection.test.d.ts.map +1 -0
- package/dist/__tests__/copilot-file-tool-injection.test.js +114 -0
- package/dist/__tests__/copilot-file-tool-injection.test.js.map +1 -0
- package/dist/__tests__/doctor-conflicts.test.js +2 -1
- package/dist/__tests__/doctor-conflicts.test.js.map +1 -1
- package/dist/__tests__/helpers/platform.d.ts +35 -0
- package/dist/__tests__/helpers/platform.d.ts.map +1 -0
- package/dist/__tests__/helpers/platform.js +129 -0
- package/dist/__tests__/helpers/platform.js.map +1 -0
- package/dist/__tests__/helpers/platform.test.d.ts +2 -0
- package/dist/__tests__/helpers/platform.test.d.ts.map +1 -0
- package/dist/__tests__/helpers/platform.test.js +131 -0
- package/dist/__tests__/helpers/platform.test.js.map +1 -0
- package/dist/__tests__/hook-bridge-main-module.test.js +2 -1
- package/dist/__tests__/hook-bridge-main-module.test.js.map +1 -1
- package/dist/__tests__/hooks/learner/bridge.test.js +2 -1
- package/dist/__tests__/hooks/learner/bridge.test.js.map +1 -1
- package/dist/__tests__/hooks-command-escaping.test.js +4 -1
- package/dist/__tests__/hooks-command-escaping.test.js.map +1 -1
- package/dist/__tests__/hud/call-counts.test.js +12 -1
- package/dist/__tests__/hud/call-counts.test.js.map +1 -1
- package/dist/__tests__/hud/state.test.js +3 -3
- package/dist/__tests__/hud/state.test.js.map +1 -1
- package/dist/__tests__/hud/usage-api-lock.test.js +8 -7
- package/dist/__tests__/hud/usage-api-lock.test.js.map +1 -1
- package/dist/__tests__/hud/usage-api-stale.test.js +8 -7
- package/dist/__tests__/hud/usage-api-stale.test.js.map +1 -1
- package/dist/__tests__/hud/usage-api.test.js +67 -66
- package/dist/__tests__/hud/usage-api.test.js.map +1 -1
- package/dist/__tests__/hud/windows-platform.test.js +5 -1
- package/dist/__tests__/hud/windows-platform.test.js.map +1 -1
- package/dist/__tests__/hud-api-key-source.test.js +5 -4
- package/dist/__tests__/hud-api-key-source.test.js.map +1 -1
- package/dist/__tests__/hud-cache-wrapper-4237.test.js +4 -1
- package/dist/__tests__/hud-cache-wrapper-4237.test.js.map +1 -1
- package/dist/__tests__/hud-cache-wrapper.test.js +8 -5
- package/dist/__tests__/hud-cache-wrapper.test.js.map +1 -1
- package/dist/__tests__/installer-omc-reference.test.js +2 -1
- package/dist/__tests__/installer-omc-reference.test.js.map +1 -1
- package/dist/__tests__/jev-shadow-sweep-lock.test.d.ts +2 -0
- package/dist/__tests__/jev-shadow-sweep-lock.test.d.ts.map +1 -0
- package/dist/__tests__/jev-shadow-sweep-lock.test.js +51 -0
- package/dist/__tests__/jev-shadow-sweep-lock.test.js.map +1 -0
- package/dist/__tests__/mnemosyne/finder.test.js +1 -1
- package/dist/__tests__/mnemosyne/finder.test.js.map +1 -1
- package/dist/__tests__/no-committed-build-artifacts.test.js +2 -1
- package/dist/__tests__/no-committed-build-artifacts.test.js.map +1 -1
- package/dist/__tests__/npm-package-bin-surface.test.js +26 -7
- package/dist/__tests__/npm-package-bin-surface.test.js.map +1 -1
- package/dist/__tests__/plugin-setup-deps.test.js +14 -5
- package/dist/__tests__/plugin-setup-deps.test.js.map +1 -1
- package/dist/__tests__/plugin-shipping-surface.test.js +6 -1
- package/dist/__tests__/plugin-shipping-surface.test.js.map +1 -1
- package/dist/__tests__/pre-tool-enforcer.test.js +3 -1
- package/dist/__tests__/pre-tool-enforcer.test.js.map +1 -1
- package/dist/__tests__/project-session-manager-review-worktree.test.js +2 -1
- package/dist/__tests__/project-session-manager-review-worktree.test.js.map +1 -1
- package/dist/__tests__/project-session-manager-worktree-protocol.test.js +10 -9
- package/dist/__tests__/project-session-manager-worktree-protocol.test.js.map +1 -1
- package/dist/__tests__/purge-stale-cache-relink.test.js +19 -15
- package/dist/__tests__/purge-stale-cache-relink.test.js.map +1 -1
- package/dist/__tests__/purge-stale-cache-symlink.integration.test.js +25 -21
- package/dist/__tests__/purge-stale-cache-symlink.integration.test.js.map +1 -1
- package/dist/__tests__/purge-stale-cache-validation.test.js +11 -9
- package/dist/__tests__/purge-stale-cache-validation.test.js.map +1 -1
- package/dist/__tests__/purge-stale-cache.integration.test.js +10 -8
- package/dist/__tests__/purge-stale-cache.integration.test.js.map +1 -1
- package/dist/__tests__/purge-stale-cache.test.js +60 -13
- package/dist/__tests__/purge-stale-cache.test.js.map +1 -1
- package/dist/__tests__/repair-plugin-cache-script.test.js +5 -2
- package/dist/__tests__/repair-plugin-cache-script.test.js.map +1 -1
- package/dist/__tests__/resolve-node.test.js +7 -4
- package/dist/__tests__/resolve-node.test.js.map +1 -1
- package/dist/__tests__/resolve-transcript-path.test.js +1 -1
- package/dist/__tests__/resolve-transcript-path.test.js.map +1 -1
- package/dist/__tests__/run-cjs-generic-timeout.test.js +23 -0
- package/dist/__tests__/run-cjs-generic-timeout.test.js.map +1 -1
- package/dist/__tests__/session-end-process-exit.test.js +27 -8
- package/dist/__tests__/session-end-process-exit.test.js.map +1 -1
- package/dist/__tests__/session-start-background-output.test.js +6 -3
- package/dist/__tests__/session-start-background-output.test.js.map +1 -1
- package/dist/__tests__/session-start-cache-cleanup.test.js +25 -15
- package/dist/__tests__/session-start-cache-cleanup.test.js.map +1 -1
- package/dist/__tests__/session-start-context-budget.test.js +8 -3
- package/dist/__tests__/session-start-context-budget.test.js.map +1 -1
- package/dist/__tests__/session-start-precompact-restore.test.js +14 -10
- package/dist/__tests__/session-start-precompact-restore.test.js.map +1 -1
- package/dist/__tests__/session-start-script-context.test.js +166 -16
- package/dist/__tests__/session-start-script-context.test.js.map +1 -1
- package/dist/__tests__/setup-claude-md-script.test.js +4 -2
- package/dist/__tests__/setup-claude-md-script.test.js.map +1 -1
- package/dist/__tests__/setup-progress-script.test.js +2 -1
- package/dist/__tests__/setup-progress-script.test.js.map +1 -1
- package/dist/__tests__/skills-runtime-probe-laziness.test.d.ts +2 -0
- package/dist/__tests__/skills-runtime-probe-laziness.test.d.ts.map +1 -0
- package/dist/__tests__/skills-runtime-probe-laziness.test.js +36 -0
- package/dist/__tests__/skills-runtime-probe-laziness.test.js.map +1 -0
- package/dist/__tests__/state-root-resolution.test.js +6 -2
- package/dist/__tests__/state-root-resolution.test.js.map +1 -1
- package/dist/__tests__/submodule-state-anchor.test.js +3 -1
- package/dist/__tests__/submodule-state-anchor.test.js.map +1 -1
- package/dist/__tests__/workflow-profile-activation-script.test.js +15 -5
- package/dist/__tests__/workflow-profile-activation-script.test.js.map +1 -1
- package/dist/autoresearch/__tests__/contracts.test.js +2 -1
- package/dist/autoresearch/__tests__/contracts.test.js.map +1 -1
- package/dist/autoresearch/__tests__/runtime-parity-extra.test.js +11 -11
- package/dist/autoresearch/__tests__/runtime-parity-extra.test.js.map +1 -1
- package/dist/autoresearch/__tests__/runtime.test.js +21 -4
- package/dist/autoresearch/__tests__/runtime.test.js.map +1 -1
- package/dist/autoresearch/runtime.d.ts.map +1 -1
- package/dist/autoresearch/runtime.js +18 -6
- package/dist/autoresearch/runtime.js.map +1 -1
- package/dist/cli/__tests__/ask.test.js +88 -38
- package/dist/cli/__tests__/ask.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-guided.test.js +11 -9
- package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-intake.test.js +4 -4
- package/dist/cli/__tests__/autoresearch-intake.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-plugin-dir.test.js +3 -3
- package/dist/cli/__tests__/doctor-plugin-dir.test.js.map +1 -1
- package/dist/cli/__tests__/launch.test.js +21 -4
- package/dist/cli/__tests__/launch.test.js.map +1 -1
- package/dist/cli/__tests__/plugin-dir-capture.test.js +5 -5
- package/dist/cli/__tests__/plugin-dir-capture.test.js.map +1 -1
- package/dist/cli/__tests__/self-improve-paths.test.js +11 -4
- package/dist/cli/__tests__/self-improve-paths.test.js.map +1 -1
- package/dist/cli/__tests__/tmux-env-forward.integration.test.js +2 -1
- package/dist/cli/__tests__/tmux-env-forward.integration.test.js.map +1 -1
- package/dist/cli/__tests__/tmux-utils.test.js +9 -1
- package/dist/cli/__tests__/tmux-utils.test.js.map +1 -1
- package/dist/cli/autoresearch-guided.js +1 -1
- package/dist/cli/autoresearch-guided.js.map +1 -1
- package/dist/cli/commands/__tests__/progress-cli.test.d.ts +2 -0
- package/dist/cli/commands/__tests__/progress-cli.test.d.ts.map +1 -0
- package/dist/cli/commands/__tests__/progress-cli.test.js +284 -0
- package/dist/cli/commands/__tests__/progress-cli.test.js.map +1 -0
- package/dist/cli/commands/__tests__/release-cli.test.d.ts +2 -0
- package/dist/cli/commands/__tests__/release-cli.test.d.ts.map +1 -0
- package/dist/cli/commands/__tests__/release-cli.test.js +64 -0
- package/dist/cli/commands/__tests__/release-cli.test.js.map +1 -0
- package/dist/cli/commands/__tests__/teleport.test.js +22 -21
- package/dist/cli/commands/__tests__/teleport.test.js.map +1 -1
- package/dist/cli/commands/progress.d.ts +55 -0
- package/dist/cli/commands/progress.d.ts.map +1 -0
- package/dist/cli/commands/progress.js +364 -0
- package/dist/cli/commands/progress.js.map +1 -0
- package/dist/cli/commands/release.d.ts +14 -0
- package/dist/cli/commands/release.d.ts.map +1 -0
- package/dist/cli/commands/release.js +135 -0
- package/dist/cli/commands/release.js.map +1 -0
- package/dist/cli/commands/smoke.d.ts +1 -1
- package/dist/cli/commands/smoke.d.ts.map +1 -1
- package/dist/cli/commands/smoke.js +1 -1
- package/dist/cli/commands/smoke.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +5 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/config/__tests__/loader.test.js +47 -0
- package/dist/config/__tests__/loader.test.js.map +1 -1
- package/dist/config/__tests__/plan-output.test.js +2 -1
- package/dist/config/__tests__/plan-output.test.js.map +1 -1
- package/dist/features/builtin-skills/runtime-guidance.d.ts +1 -1
- package/dist/features/builtin-skills/runtime-guidance.d.ts.map +1 -1
- package/dist/features/builtin-skills/runtime-guidance.js +8 -3
- package/dist/features/builtin-skills/runtime-guidance.js.map +1 -1
- package/dist/features/builtin-skills/skills.d.ts +2 -1
- package/dist/features/builtin-skills/skills.d.ts.map +1 -1
- package/dist/features/builtin-skills/skills.js +13 -8
- package/dist/features/builtin-skills/skills.js.map +1 -1
- package/dist/features/lookout/__tests__/lookout.test.js +8 -2
- package/dist/features/lookout/__tests__/lookout.test.js.map +1 -1
- package/dist/graph/__tests__/runtime/cli.test.js +20 -5
- package/dist/graph/__tests__/runtime/cli.test.js.map +1 -1
- package/dist/graph/__tests__/runtime/e2e-crash-recovery.test.js +2 -1
- package/dist/graph/__tests__/runtime/e2e-crash-recovery.test.js.map +1 -1
- package/dist/graph/__tests__/runtime/fence.test.js +2 -1
- package/dist/graph/__tests__/runtime/fence.test.js.map +1 -1
- package/dist/graph/__tests__/runtime/journal-epoch.test.js +2 -1
- package/dist/graph/__tests__/runtime/journal-epoch.test.js.map +1 -1
- package/dist/graph/__tests__/runtime/journal.test.js +2 -1
- package/dist/graph/__tests__/runtime/journal.test.js.map +1 -1
- package/dist/graph/__tests__/runtime/regression-matrix.test.js +2 -1
- package/dist/graph/__tests__/runtime/regression-matrix.test.js.map +1 -1
- package/dist/graph/__tests__/runtime/remote-approval.test.js +13 -10
- package/dist/graph/__tests__/runtime/remote-approval.test.js.map +1 -1
- package/dist/graph/__tests__/runtime/run-dir.test.js +13 -5
- package/dist/graph/__tests__/runtime/run-dir.test.js.map +1 -1
- package/dist/graph/__tests__/runtime/runner.test.js +2 -1
- package/dist/graph/__tests__/runtime/runner.test.js.map +1 -1
- package/dist/graph/__tests__/runtime/safe-fs.test.js +15 -12
- package/dist/graph/__tests__/runtime/safe-fs.test.js.map +1 -1
- package/dist/graph/__tests__/runtime/store.test.js +2 -1
- package/dist/graph/__tests__/runtime/store.test.js.map +1 -1
- package/dist/graph/runtime/safe-fs.js +2 -2
- package/dist/graph/runtime/safe-fs.js.map +1 -1
- package/dist/hooks/__tests__/bridge-routing.test.js +3 -0
- package/dist/hooks/__tests__/bridge-routing.test.js.map +1 -1
- package/dist/hooks/__tests__/bridge.test.js +2 -1
- package/dist/hooks/__tests__/bridge.test.js.map +1 -1
- package/dist/hooks/__tests__/precompact-restore.test.js +7 -6
- package/dist/hooks/__tests__/precompact-restore.test.js.map +1 -1
- package/dist/hooks/__tests__/workflow-drift-guard-script.test.js +10 -3
- package/dist/hooks/__tests__/workflow-drift-guard-script.test.js.map +1 -1
- package/dist/hooks/autopilot/__tests__/cancel.test.js +16 -11
- package/dist/hooks/autopilot/__tests__/cancel.test.js.map +1 -1
- package/dist/hooks/bridge.d.ts.map +1 -1
- package/dist/hooks/bridge.js +7 -0
- package/dist/hooks/bridge.js.map +1 -1
- package/dist/hooks/mode-registry/__tests__/session-isolation.test.js +5 -4
- package/dist/hooks/mode-registry/__tests__/session-isolation.test.js.map +1 -1
- package/dist/hooks/persistent-mode/__tests__/ultragoal-persistence.test.js +2 -1
- package/dist/hooks/persistent-mode/__tests__/ultragoal-persistence.test.js.map +1 -1
- package/dist/hooks/recovery/__tests__/storage.test.js +3 -0
- package/dist/hooks/recovery/__tests__/storage.test.js.map +1 -1
- package/dist/hooks/session-end/__tests__/callbacks.test.js +11 -9
- package/dist/hooks/session-end/__tests__/callbacks.test.js.map +1 -1
- package/dist/hooks/session-end/__tests__/cleanup-manifest.test.js +115 -1
- package/dist/hooks/session-end/__tests__/cleanup-manifest.test.js.map +1 -1
- package/dist/hooks/session-end/__tests__/session-end-timeout.test.js +6 -1
- package/dist/hooks/session-end/__tests__/session-end-timeout.test.js.map +1 -1
- package/dist/hooks/session-end/cleanup-manifest.d.ts +4 -0
- package/dist/hooks/session-end/cleanup-manifest.d.ts.map +1 -1
- package/dist/hooks/session-end/cleanup-manifest.js +33 -15
- package/dist/hooks/session-end/cleanup-manifest.js.map +1 -1
- package/dist/hooks/setup/__tests__/stdin-symlink.test.js +11 -6
- package/dist/hooks/setup/__tests__/stdin-symlink.test.js.map +1 -1
- package/dist/hooks/skill-bridge.cjs +60 -8
- package/dist/hooks/subagent-tracker/__tests__/index.test.js +74 -16
- package/dist/hooks/subagent-tracker/__tests__/index.test.js.map +1 -1
- package/dist/hooks/subagent-tracker/__tests__/session-isolation.test.js +6 -1
- package/dist/hooks/subagent-tracker/__tests__/session-isolation.test.js.map +1 -1
- package/dist/hooks/subagent-tracker/__tests__/worktree-evidence.test.js +11 -8
- package/dist/hooks/subagent-tracker/__tests__/worktree-evidence.test.js.map +1 -1
- package/dist/hud/__tests__/autopilot-profile.test.js +4 -3
- package/dist/hud/__tests__/autopilot-profile.test.js.map +1 -1
- package/dist/installer/__tests__/claude-md-transaction.test.js +16 -13
- package/dist/installer/__tests__/claude-md-transaction.test.js.map +1 -1
- package/dist/installer/__tests__/hook-templates.test.js +28 -0
- package/dist/installer/__tests__/hook-templates.test.js.map +1 -1
- package/dist/installer/__tests__/hud-cache-wrapper.test.js +4 -1
- package/dist/installer/__tests__/hud-cache-wrapper.test.js.map +1 -1
- package/dist/installer/__tests__/session-start-template.test.js +166 -15
- package/dist/installer/__tests__/session-start-template.test.js.map +1 -1
- package/dist/installer/__tests__/stale-cleanup.test.js +5 -3
- package/dist/installer/__tests__/stale-cleanup.test.js.map +1 -1
- package/dist/installer/__tests__/standalone-hook-reconcile.test.js +11 -3
- package/dist/installer/__tests__/standalone-hook-reconcile.test.js.map +1 -1
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +1 -0
- package/dist/installer/index.js.map +1 -1
- package/dist/interop/__tests__/mcp-bridge.test.js +4 -3
- package/dist/interop/__tests__/mcp-bridge.test.js.map +1 -1
- package/dist/lib/__tests__/agent-progress-rotation.test.d.ts +2 -0
- package/dist/lib/__tests__/agent-progress-rotation.test.d.ts.map +1 -0
- package/dist/lib/__tests__/agent-progress-rotation.test.js +45 -0
- package/dist/lib/__tests__/agent-progress-rotation.test.js.map +1 -0
- package/dist/lib/__tests__/agent-progress.test.d.ts +2 -0
- package/dist/lib/__tests__/agent-progress.test.d.ts.map +1 -0
- package/dist/lib/__tests__/agent-progress.test.js +175 -0
- package/dist/lib/__tests__/agent-progress.test.js.map +1 -0
- package/dist/lib/__tests__/atomic-write.test.js +95 -3
- package/dist/lib/__tests__/atomic-write.test.js.map +1 -1
- package/dist/lib/__tests__/mode-state-io.test.js +2 -1
- package/dist/lib/__tests__/mode-state-io.test.js.map +1 -1
- package/dist/lib/__tests__/mode-state-lock.test.js +46 -0
- package/dist/lib/__tests__/mode-state-lock.test.js.map +1 -1
- package/dist/lib/__tests__/plugin-dir.test.js +1 -1
- package/dist/lib/__tests__/plugin-dir.test.js.map +1 -1
- package/dist/lib/__tests__/worktree-cleanup-safety.test.js +2 -1
- package/dist/lib/__tests__/worktree-cleanup-safety.test.js.map +1 -1
- package/dist/lib/__tests__/worktree-paths-foreign-root.test.js +2 -1
- package/dist/lib/__tests__/worktree-paths-foreign-root.test.js.map +1 -1
- package/dist/lib/__tests__/worktree-paths-superproject-cache.test.js +2 -1
- package/dist/lib/__tests__/worktree-paths-superproject-cache.test.js.map +1 -1
- package/dist/lib/__tests__/worktree-paths-toplevel-cache.test.js +173 -3
- package/dist/lib/__tests__/worktree-paths-toplevel-cache.test.js.map +1 -1
- package/dist/lib/agent-progress.d.ts +113 -0
- package/dist/lib/agent-progress.d.ts.map +1 -0
- package/dist/lib/agent-progress.js +274 -0
- package/dist/lib/agent-progress.js.map +1 -0
- package/dist/lib/atomic-write.d.ts.map +1 -1
- package/dist/lib/atomic-write.js +59 -5
- package/dist/lib/atomic-write.js.map +1 -1
- package/dist/lib/worktree-paths.d.ts +2 -1
- package/dist/lib/worktree-paths.d.ts.map +1 -1
- package/dist/lib/worktree-paths.js +92 -9
- package/dist/lib/worktree-paths.js.map +1 -1
- package/dist/mcp/__tests__/team-server-artifact-convergence.test.js +4 -1
- package/dist/mcp/__tests__/team-server-artifact-convergence.test.js.map +1 -1
- package/dist/notifications/__tests__/approval-reply.test.js +2 -1
- package/dist/notifications/__tests__/approval-reply.test.js.map +1 -1
- package/dist/notifications/__tests__/session-registry-durability.test.js +2 -1
- package/dist/notifications/__tests__/session-registry-durability.test.js.map +1 -1
- package/dist/notifications/__tests__/session-registry.test.js +3 -2
- package/dist/notifications/__tests__/session-registry.test.js.map +1 -1
- package/dist/openclaw/__tests__/dead-pane-guard.test.js +3 -2
- package/dist/openclaw/__tests__/dead-pane-guard.test.js.map +1 -1
- package/dist/platform/__tests__/process-utils-pid-reuse.windows.test.d.ts +2 -0
- package/dist/platform/__tests__/process-utils-pid-reuse.windows.test.d.ts.map +1 -0
- package/dist/platform/__tests__/process-utils-pid-reuse.windows.test.js +87 -0
- package/dist/platform/__tests__/process-utils-pid-reuse.windows.test.js.map +1 -0
- package/dist/platform/process-utils.d.ts.map +1 -1
- package/dist/platform/process-utils.js +8 -2
- package/dist/platform/process-utils.js.map +1 -1
- package/dist/release/__tests__/checks.test.d.ts +2 -0
- package/dist/release/__tests__/checks.test.d.ts.map +1 -0
- package/dist/release/__tests__/checks.test.js +142 -0
- package/dist/release/__tests__/checks.test.js.map +1 -0
- package/dist/release/__tests__/engine.test.d.ts +2 -0
- package/dist/release/__tests__/engine.test.d.ts.map +1 -0
- package/dist/release/__tests__/engine.test.js +833 -0
- package/dist/release/__tests__/engine.test.js.map +1 -0
- package/dist/release/checks.d.ts +62 -0
- package/dist/release/checks.d.ts.map +1 -0
- package/dist/release/checks.js +180 -0
- package/dist/release/checks.js.map +1 -0
- package/dist/release/engine.d.ts +127 -0
- package/dist/release/engine.d.ts.map +1 -0
- package/dist/release/engine.js +910 -0
- package/dist/release/engine.js.map +1 -0
- package/dist/release/progress.d.ts +26 -0
- package/dist/release/progress.d.ts.map +1 -0
- package/dist/release/progress.js +45 -0
- package/dist/release/progress.js.map +1 -0
- package/dist/smoke/__tests__/copilot-sdk-driver.test.js +57 -1
- package/dist/smoke/__tests__/copilot-sdk-driver.test.js.map +1 -1
- package/dist/smoke/__tests__/copilot-sdk-scenarios.test.js +103 -1
- package/dist/smoke/__tests__/copilot-sdk-scenarios.test.js.map +1 -1
- package/dist/smoke/copilot-sdk-driver.d.ts +18 -1
- package/dist/smoke/copilot-sdk-driver.d.ts.map +1 -1
- package/dist/smoke/copilot-sdk-driver.js +69 -2
- package/dist/smoke/copilot-sdk-driver.js.map +1 -1
- package/dist/smoke/copilot-sdk-scenarios.d.ts +79 -5
- package/dist/smoke/copilot-sdk-scenarios.d.ts.map +1 -1
- package/dist/smoke/copilot-sdk-scenarios.js +209 -5
- package/dist/smoke/copilot-sdk-scenarios.js.map +1 -1
- package/dist/team/__tests__/api-interop.dispatch.test.js +5 -1
- package/dist/team/__tests__/api-interop.dispatch.test.js.map +1 -1
- package/dist/team/__tests__/audit-log.test.js +3 -2
- package/dist/team/__tests__/audit-log.test.js.map +1 -1
- package/dist/team/__tests__/auto-merge.perf.test.js +2 -1
- package/dist/team/__tests__/auto-merge.perf.test.js.map +1 -1
- package/dist/team/__tests__/git-worktree.test.js +3 -21
- package/dist/team/__tests__/git-worktree.test.js.map +1 -1
- package/dist/team/__tests__/issue-4412-cmux-startup.test.js +4 -1
- package/dist/team/__tests__/issue-4412-cmux-startup.test.js.map +1 -1
- package/dist/team/__tests__/leader-inbox.test.js +3 -2
- package/dist/team/__tests__/leader-inbox.test.js.map +1 -1
- package/dist/team/__tests__/mcp-comm.mailbox-notification.test.js +2 -1
- package/dist/team/__tests__/mcp-comm.mailbox-notification.test.js.map +1 -1
- package/dist/team/__tests__/recovery-pane-rollback.test.js +61 -31
- package/dist/team/__tests__/recovery-pane-rollback.test.js.map +1 -1
- package/dist/team/__tests__/runtime-cli.test.js +5 -4
- package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
- package/dist/team/__tests__/runtime-owner-client.test.js +5 -4
- package/dist/team/__tests__/runtime-owner-client.test.js.map +1 -1
- package/dist/team/__tests__/runtime-v2.dispatch.test.js +16 -13
- package/dist/team/__tests__/runtime-v2.dispatch.test.js.map +1 -1
- package/dist/team/__tests__/runtime-v2.shutdown.test.js +3 -1
- package/dist/team/__tests__/runtime-v2.shutdown.test.js.map +1 -1
- package/dist/team/__tests__/summary-report.test.js +9 -5
- package/dist/team/__tests__/summary-report.test.js.map +1 -1
- package/dist/team/__tests__/task-storage-integrity.test.js +3 -2
- package/dist/team/__tests__/task-storage-integrity.test.js.map +1 -1
- package/dist/team/__tests__/team-instance.test.js +4 -3
- package/dist/team/__tests__/team-instance.test.js.map +1 -1
- package/dist/team/__tests__/team-ops-write-atomic.test.d.ts +2 -0
- package/dist/team/__tests__/team-ops-write-atomic.test.d.ts.map +1 -0
- package/dist/team/__tests__/team-ops-write-atomic.test.js +62 -0
- package/dist/team/__tests__/team-ops-write-atomic.test.js.map +1 -0
- package/dist/team/__tests__/teardown-invariant.test.js +7 -3
- package/dist/team/__tests__/teardown-invariant.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.create-team.test.js +5 -0
- package/dist/team/__tests__/tmux-session.create-team.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +8 -0
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/usage-tracker.test.js +2 -1
- package/dist/team/__tests__/usage-tracker.test.js.map +1 -1
- package/dist/team/__tests__/worker-activation-gate.test.js +9 -7
- package/dist/team/__tests__/worker-activation-gate.test.js.map +1 -1
- package/dist/team/__tests__/worker-launch-ack.test.js +356 -39
- package/dist/team/__tests__/worker-launch-ack.test.js.map +1 -1
- package/dist/team/__tests__/worker-launch-posix-transport.test.js +3 -2
- package/dist/team/__tests__/worker-launch-posix-transport.test.js.map +1 -1
- package/dist/team/__tests__/worktree-runtime-e2e.test.js +3 -2
- package/dist/team/__tests__/worktree-runtime-e2e.test.js.map +1 -1
- package/dist/team/runtime-owner-client.d.ts.map +1 -1
- package/dist/team/runtime-owner-client.js +3 -0
- package/dist/team/runtime-owner-client.js.map +1 -1
- package/dist/team/team-ops.d.ts.map +1 -1
- package/dist/team/team-ops.js +18 -1
- package/dist/team/team-ops.js.map +1 -1
- package/dist/team/worker-activation-gate.d.ts.map +1 -1
- package/dist/team/worker-activation-gate.js +3 -2
- package/dist/team/worker-activation-gate.js.map +1 -1
- package/dist/team/worker-launch-ack.d.ts +11 -0
- package/dist/team/worker-launch-ack.d.ts.map +1 -1
- package/dist/team/worker-launch-ack.js +154 -25
- package/dist/team/worker-launch-ack.js.map +1 -1
- package/dist/tools/__tests__/deepinit-manifest.test.js +24 -2
- package/dist/tools/__tests__/deepinit-manifest.test.js.map +1 -1
- package/dist/tools/__tests__/state-tools.test.js +43 -4
- package/dist/tools/__tests__/state-tools.test.js.map +1 -1
- package/dist/tools/__tests__/wiki-tools-foreign-root.test.js +2 -1
- package/dist/tools/__tests__/wiki-tools-foreign-root.test.js.map +1 -1
- package/dist/tools/deepinit-manifest.d.ts.map +1 -1
- package/dist/tools/deepinit-manifest.js +5 -3
- package/dist/tools/deepinit-manifest.js.map +1 -1
- package/dist/tools/lsp/__tests__/devcontainer.test.js +7 -2
- package/dist/tools/lsp/__tests__/devcontainer.test.js.map +1 -1
- package/dist/tools/lsp/devcontainer.d.ts.map +1 -1
- package/dist/tools/lsp/devcontainer.js +7 -1
- package/dist/tools/lsp/devcontainer.js.map +1 -1
- package/dist/tools/python-repl/__tests__/bridge-manager-cleanup.test.js +10 -0
- package/dist/tools/python-repl/__tests__/bridge-manager-cleanup.test.js.map +1 -1
- package/dist/tools/python-repl/__tests__/python-sandbox.test.js +10 -6
- package/dist/tools/python-repl/__tests__/python-sandbox.test.js.map +1 -1
- package/dist/tools/python-repl/__tests__/system-python.test.d.ts +2 -0
- package/dist/tools/python-repl/__tests__/system-python.test.d.ts.map +1 -0
- package/dist/tools/python-repl/__tests__/system-python.test.js +55 -0
- package/dist/tools/python-repl/__tests__/system-python.test.js.map +1 -0
- package/dist/tools/python-repl/bridge-manager.d.ts +14 -0
- package/dist/tools/python-repl/bridge-manager.d.ts.map +1 -1
- package/dist/tools/python-repl/bridge-manager.js +49 -8
- package/dist/tools/python-repl/bridge-manager.js.map +1 -1
- package/dist/utils/__tests__/paths.test.js +14 -13
- package/dist/utils/__tests__/paths.test.js.map +1 -1
- package/dist/utils/__tests__/plugin-cache-validation.test.d.ts +2 -0
- package/dist/utils/__tests__/plugin-cache-validation.test.d.ts.map +1 -0
- package/dist/utils/__tests__/plugin-cache-validation.test.js +81 -0
- package/dist/utils/__tests__/plugin-cache-validation.test.js.map +1 -0
- package/dist/utils/omc-cli-rendering.d.ts +1 -0
- package/dist/utils/omc-cli-rendering.d.ts.map +1 -1
- package/dist/utils/omc-cli-rendering.js +9 -9
- package/dist/utils/omc-cli-rendering.js.map +1 -1
- package/dist/utils/paths.d.ts +2 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +10 -5
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/plugin-cache-validation.d.ts +8 -6
- package/dist/utils/plugin-cache-validation.d.ts.map +1 -1
- package/dist/utils/plugin-cache-validation.js +26 -15
- package/dist/utils/plugin-cache-validation.js.map +1 -1
- package/docs/CLAUDE.md +1 -1
- package/docs/DEVELOPERS.md +1 -0
- package/docs/HOOKS.md +1 -1
- package/docs/REFERENCE.md +38 -0
- package/package.json +2 -2
- package/plugin.json +1 -1
- package/scripts/lib/jev-shadow.mjs +6 -4
- package/scripts/lib/state-lock.mjs +21 -6
- package/scripts/lib/tool-input-paths.mjs +24 -0
- package/scripts/post-tool-directory-context-injector.mjs +10 -15
- package/scripts/post-tool-rules-injector.mjs +11 -16
- package/scripts/run-provider-advisor.js +4 -1
- package/scripts/run.cjs +9 -4
- package/scripts/session-start.mjs +28 -14
- package/scripts/verify-epic-3698-closure.mjs +2 -1
- package/skills/project-session-manager/lib/session.sh +2 -0
- package/skills/project-session-manager/lib/worktree.sh +9 -1
- package/templates/hooks/session-start.mjs +28 -14
package/bridge/cli.cjs
CHANGED
|
@@ -3821,13 +3821,21 @@ var init_cache_occupancy = __esm({
|
|
|
3821
3821
|
function isOmcPluginCacheIdentity(pluginName, marketplace) {
|
|
3822
3822
|
return OMC_PLUGIN_CACHE_IDENTITIES.has(`${pluginName}@${marketplace}`.toLowerCase());
|
|
3823
3823
|
}
|
|
3824
|
+
function identityPart(value) {
|
|
3825
|
+
if (typeof value === "bigint") return value;
|
|
3826
|
+
return Number.isSafeInteger(value) ? BigInt(value) : void 0;
|
|
3827
|
+
}
|
|
3824
3828
|
function sameFileSystemIdentity(left, right) {
|
|
3825
|
-
|
|
3829
|
+
const leftDev = identityPart(left.dev);
|
|
3830
|
+
const leftIno = identityPart(left.ino);
|
|
3831
|
+
const rightDev = identityPart(right.dev);
|
|
3832
|
+
const rightIno = identityPart(right.ino);
|
|
3833
|
+
return leftDev !== void 0 && leftIno !== void 0 && leftIno !== 0n && rightDev !== void 0 && rightIno !== void 0 && rightIno !== 0n && leftDev === rightDev && leftIno === rightIno;
|
|
3826
3834
|
}
|
|
3827
3835
|
function hasAncestorWithIdentity(path30, identity) {
|
|
3828
3836
|
let currentPath = path30;
|
|
3829
3837
|
while (true) {
|
|
3830
|
-
if (sameFileSystemIdentity((0, import_fs2.statSync)(currentPath), identity)) return true;
|
|
3838
|
+
if (sameFileSystemIdentity((0, import_fs2.statSync)(currentPath, { bigint: true }), identity)) return true;
|
|
3831
3839
|
const parentPath = (0, import_path3.dirname)(currentPath);
|
|
3832
3840
|
if (parentPath === currentPath) return false;
|
|
3833
3841
|
currentPath = parentPath;
|
|
@@ -3840,7 +3848,7 @@ function firstChildBelowDirectoryIdentity(path30, directoryIdentity) {
|
|
|
3840
3848
|
const parentPath = (0, import_path3.dirname)(currentPath);
|
|
3841
3849
|
if (parentPath === currentPath) return void 0;
|
|
3842
3850
|
try {
|
|
3843
|
-
if (sameFileSystemIdentity((0, import_fs2.statSync)(parentPath), directoryIdentity)) return (0, import_path3.basename)(currentPath);
|
|
3851
|
+
if (sameFileSystemIdentity((0, import_fs2.statSync)(parentPath, { bigint: true }), directoryIdentity)) return (0, import_path3.basename)(currentPath);
|
|
3844
3852
|
} catch {
|
|
3845
3853
|
}
|
|
3846
3854
|
currentPath = parentPath;
|
|
@@ -3880,7 +3888,7 @@ function pathTraversesFileSystemIdentity(path30, identity) {
|
|
|
3880
3888
|
for (let index = components.length - 1; index >= 0; index--) steps.push(components[index]);
|
|
3881
3889
|
const activeLinks = /* @__PURE__ */ new Set();
|
|
3882
3890
|
try {
|
|
3883
|
-
if (sameFileSystemIdentity((0, import_fs2.lstatSync)(currentPath), identity)) return true;
|
|
3891
|
+
if (sameFileSystemIdentity((0, import_fs2.lstatSync)(currentPath, { bigint: true }), identity)) return true;
|
|
3884
3892
|
} catch {
|
|
3885
3893
|
return false;
|
|
3886
3894
|
}
|
|
@@ -3898,7 +3906,7 @@ function pathTraversesFileSystemIdentity(path30, identity) {
|
|
|
3898
3906
|
const nextPath = (0, import_path3.join)(currentPath, step);
|
|
3899
3907
|
let nextStats;
|
|
3900
3908
|
try {
|
|
3901
|
-
nextStats = (0, import_fs2.lstatSync)(nextPath);
|
|
3909
|
+
nextStats = (0, import_fs2.lstatSync)(nextPath, { bigint: true });
|
|
3902
3910
|
} catch {
|
|
3903
3911
|
return false;
|
|
3904
3912
|
}
|
|
@@ -3907,7 +3915,7 @@ function pathTraversesFileSystemIdentity(path30, identity) {
|
|
|
3907
3915
|
currentPath = nextPath;
|
|
3908
3916
|
continue;
|
|
3909
3917
|
}
|
|
3910
|
-
const linkKey =
|
|
3918
|
+
const linkKey = nextStats.ino !== 0n ? `inode:${nextStats.dev}:${nextStats.ino}` : `path:${process.platform === "win32" ? nextPath.toLowerCase() : nextPath}`;
|
|
3911
3919
|
if (activeLinks.has(linkKey)) return false;
|
|
3912
3920
|
let linkTarget;
|
|
3913
3921
|
try {
|
|
@@ -3991,14 +3999,14 @@ function hasUsableOmcHookTargets(path30, staleVersionIdentity) {
|
|
|
3991
3999
|
return true;
|
|
3992
4000
|
}
|
|
3993
4001
|
function hasResolvablePluginSymlinks(directory, staleVersionIdentity, ancestors = [], payload) {
|
|
3994
|
-
const directoryStats = (0, import_fs2.statSync)(directory);
|
|
4002
|
+
const directoryStats = (0, import_fs2.statSync)(directory, { bigint: true });
|
|
3995
4003
|
if (ancestors.some((identity) => sameFileSystemIdentity(directoryStats, identity))) return false;
|
|
3996
4004
|
const branch = [...ancestors, directoryStats];
|
|
3997
4005
|
const entries = (0, import_fs2.readdirSync)(directory, { withFileTypes: true });
|
|
3998
4006
|
for (const entry2 of entries) {
|
|
3999
4007
|
const entryPath = (0, import_path3.join)(directory, entry2.name);
|
|
4000
4008
|
if (entry2.isSymbolicLink()) {
|
|
4001
|
-
const entryStats = (0, import_fs2.statSync)(entryPath);
|
|
4009
|
+
const entryStats = (0, import_fs2.statSync)(entryPath, { bigint: true });
|
|
4002
4010
|
if (pathTraversesFileSystemIdentity(entryPath, staleVersionIdentity)) return false;
|
|
4003
4011
|
if (entryStats.isDirectory()) {
|
|
4004
4012
|
if (branch.some((identity) => sameFileSystemIdentity(entryStats, identity))) continue;
|
|
@@ -4228,6 +4236,9 @@ function compareSemverDesc(a, b) {
|
|
|
4228
4236
|
}
|
|
4229
4237
|
return 0;
|
|
4230
4238
|
}
|
|
4239
|
+
function pickHighestVersionDir(dirs, base = import_path4.basename) {
|
|
4240
|
+
return [...dirs].sort((a, b) => compareSemverDesc(base(a), base(b)))[0];
|
|
4241
|
+
}
|
|
4231
4242
|
function purgeStalePluginCacheVersions(options) {
|
|
4232
4243
|
const result = {
|
|
4233
4244
|
removed: 0,
|
|
@@ -4299,7 +4310,7 @@ function purgeStalePluginCacheVersions(options) {
|
|
|
4299
4310
|
const lexicalActiveVersionDirsHere = activePathIdentities.filter((ap) => ap.startsWith(pluginDirNorm + "/")).map((ap) => (0, import_path4.join)(pluginDir, ap.slice(pluginDirNorm.length + 1).split("/")[0]));
|
|
4300
4311
|
const filesystemActiveVersionDirsHere = [];
|
|
4301
4312
|
try {
|
|
4302
|
-
const pluginDirStats = (0, import_fs3.statSync)(pluginDir);
|
|
4313
|
+
const pluginDirStats = (0, import_fs3.statSync)(pluginDir, { bigint: true });
|
|
4303
4314
|
for (const activePath of activePathsArray) {
|
|
4304
4315
|
const versionName = firstChildBelowDirectoryIdentity(activePath, pluginDirStats);
|
|
4305
4316
|
if (versionName) filesystemActiveVersionDirsHere.push((0, import_path4.join)(pluginDir, versionName));
|
|
@@ -4360,18 +4371,13 @@ function purgeStalePluginCacheVersions(options) {
|
|
|
4360
4371
|
}
|
|
4361
4372
|
}
|
|
4362
4373
|
if (activeVersionDirsHere.length > 0) {
|
|
4363
|
-
const target =
|
|
4364
|
-
(a, b) => compareSemverDesc(
|
|
4365
|
-
a.split("/").pop() ?? a,
|
|
4366
|
-
b.split("/").pop() ?? b
|
|
4367
|
-
)
|
|
4368
|
-
)[0];
|
|
4374
|
+
const target = pickHighestVersionDir(activeVersionDirsHere);
|
|
4369
4375
|
try {
|
|
4370
|
-
const targetStats = (0, import_fs3.statSync)(target);
|
|
4376
|
+
const targetStats = (0, import_fs3.statSync)(target, { bigint: true });
|
|
4371
4377
|
if (!targetStats.isDirectory()) {
|
|
4372
4378
|
throw new Error("Registered active plugin target is not a directory");
|
|
4373
4379
|
}
|
|
4374
|
-
const staleVersionStats = (0, import_fs3.statSync)(versionDir);
|
|
4380
|
+
const staleVersionStats = (0, import_fs3.statSync)(versionDir, { bigint: true });
|
|
4375
4381
|
const resolvedTarget = (0, import_fs3.realpathSync)(target);
|
|
4376
4382
|
const resolvedStaleVersion = (0, import_fs3.realpathSync)(versionDir);
|
|
4377
4383
|
const targetPath = comparisonPath(resolvedTarget);
|
|
@@ -6361,7 +6367,7 @@ function parseFrontmatter(content) {
|
|
|
6361
6367
|
});
|
|
6362
6368
|
const rootIndent = rootLine === void 0 ? void 0 : rootLine.length - rootLine.trimStart().length;
|
|
6363
6369
|
let flowDepth = 0;
|
|
6364
|
-
let
|
|
6370
|
+
let quote3 = null;
|
|
6365
6371
|
for (let lineIndex = 0; lineIndex < lines3.length; lineIndex++) {
|
|
6366
6372
|
const line = lines3[lineIndex];
|
|
6367
6373
|
const trimmed = line.trimStart();
|
|
@@ -6409,22 +6415,22 @@ function parseFrontmatter(content) {
|
|
|
6409
6415
|
}
|
|
6410
6416
|
for (let i = scanFrom; i < line.length; i++) {
|
|
6411
6417
|
const char = line[i];
|
|
6412
|
-
if (
|
|
6413
|
-
if (
|
|
6418
|
+
if (quote3) {
|
|
6419
|
+
if (quote3 === '"' && char === "\\") {
|
|
6414
6420
|
i++;
|
|
6415
6421
|
continue;
|
|
6416
6422
|
}
|
|
6417
|
-
if (char ===
|
|
6418
|
-
if (
|
|
6423
|
+
if (char === quote3) {
|
|
6424
|
+
if (quote3 === "'" && line[i + 1] === "'") {
|
|
6419
6425
|
i++;
|
|
6420
6426
|
continue;
|
|
6421
6427
|
}
|
|
6422
|
-
|
|
6428
|
+
quote3 = null;
|
|
6423
6429
|
}
|
|
6424
6430
|
continue;
|
|
6425
6431
|
}
|
|
6426
6432
|
if (char === '"' || char === "'") {
|
|
6427
|
-
|
|
6433
|
+
quote3 = char;
|
|
6428
6434
|
continue;
|
|
6429
6435
|
}
|
|
6430
6436
|
if (char === "#" && (i === 0 || line[i - 1] === " " || line[i - 1] === " ")) {
|
|
@@ -6445,20 +6451,20 @@ function parseFrontmatterAliases(rawAliases) {
|
|
|
6445
6451
|
function splitFlowSequenceItems(inner) {
|
|
6446
6452
|
const items = [];
|
|
6447
6453
|
let current = "";
|
|
6448
|
-
let
|
|
6454
|
+
let quote3 = null;
|
|
6449
6455
|
for (let i = 0; i < inner.length; i++) {
|
|
6450
6456
|
const char = inner[i];
|
|
6451
|
-
if (
|
|
6457
|
+
if (quote3) {
|
|
6452
6458
|
current += char;
|
|
6453
|
-
if (
|
|
6459
|
+
if (quote3 === '"' && char === "\\" && i + 1 < inner.length) {
|
|
6454
6460
|
current += inner[++i];
|
|
6455
|
-
} else if (
|
|
6461
|
+
} else if (quote3 === "'" && char === "'" && inner[i + 1] === "'") {
|
|
6456
6462
|
current += inner[++i];
|
|
6457
|
-
} else if (char ===
|
|
6458
|
-
|
|
6463
|
+
} else if (char === quote3) {
|
|
6464
|
+
quote3 = null;
|
|
6459
6465
|
}
|
|
6460
6466
|
} else if ((char === '"' || char === "'") && current.trim() === "") {
|
|
6461
|
-
|
|
6467
|
+
quote3 = char;
|
|
6462
6468
|
current += char;
|
|
6463
6469
|
} else if (char === ",") {
|
|
6464
6470
|
items.push(current);
|
|
@@ -11381,14 +11387,14 @@ var init_sdk = __esm({
|
|
|
11381
11387
|
__callDispose = (stack, error2, hasError) => {
|
|
11382
11388
|
var E = typeof SuppressedError === "function" ? SuppressedError : function(e, s, m, _) {
|
|
11383
11389
|
return _ = Error(m), _.name = "SuppressedError", _.error = e, _.suppressed = s, _;
|
|
11384
|
-
},
|
|
11390
|
+
}, fail7 = (e) => error2 = hasError ? new E(e, error2, "An error was suppressed during disposal") : (hasError = true, e), next = (it) => {
|
|
11385
11391
|
while (it = stack.pop()) {
|
|
11386
11392
|
try {
|
|
11387
11393
|
var result = it[1] && it[1].call(it[2]);
|
|
11388
11394
|
if (it[0])
|
|
11389
|
-
return Promise.resolve(result).then(next, (e) => (
|
|
11395
|
+
return Promise.resolve(result).then(next, (e) => (fail7(e), next()));
|
|
11390
11396
|
} catch (e) {
|
|
11391
|
-
|
|
11397
|
+
fail7(e);
|
|
11392
11398
|
}
|
|
11393
11399
|
}
|
|
11394
11400
|
if (hasError)
|
|
@@ -32788,7 +32794,12 @@ function containerUriToHostUri(uri, context) {
|
|
|
32788
32794
|
if (!context || !uri.startsWith("file://")) {
|
|
32789
32795
|
return uri;
|
|
32790
32796
|
}
|
|
32791
|
-
|
|
32797
|
+
const url = new URL(uri);
|
|
32798
|
+
if (url.host !== "" || /%2f/i.test(url.pathname)) {
|
|
32799
|
+
throw new TypeError(`Invalid container file URI: ${uri}`);
|
|
32800
|
+
}
|
|
32801
|
+
const containerPath = decodeURIComponent(url.pathname);
|
|
32802
|
+
return (0, import_url4.pathToFileURL)(containerPathToHostPath(containerPath, context)).href;
|
|
32792
32803
|
}
|
|
32793
32804
|
function resolveDevContainerConfigPath(workspaceRoot) {
|
|
32794
32805
|
let dir = workspaceRoot;
|
|
@@ -33112,11 +33123,11 @@ function runBatchCommand(resolvedPath, args, timeoutMs) {
|
|
|
33112
33123
|
const comspec = validatedComspec();
|
|
33113
33124
|
if (!comspec) return void 0;
|
|
33114
33125
|
if (!args.every((arg) => SAFE_BATCH_ARG.test(arg))) return void 0;
|
|
33115
|
-
const
|
|
33126
|
+
const tail3 = [`"${resolvedPath}"`, ...args].join(" ");
|
|
33116
33127
|
try {
|
|
33117
33128
|
return (0, import_child_process3.spawnSync)(
|
|
33118
33129
|
comspec,
|
|
33119
|
-
["/d", "/v:off", "/s", "/c", `"${
|
|
33130
|
+
["/d", "/v:off", "/s", "/c", `"${tail3}"`],
|
|
33120
33131
|
{
|
|
33121
33132
|
timeout: timeoutMs,
|
|
33122
33133
|
encoding: "utf8",
|
|
@@ -34147,8 +34158,8 @@ ${content}`;
|
|
|
34147
34158
|
const current = new Promise((resolveCurrent) => {
|
|
34148
34159
|
release = resolveCurrent;
|
|
34149
34160
|
});
|
|
34150
|
-
const
|
|
34151
|
-
this.documentOperationTails.set(hostUri,
|
|
34161
|
+
const tail3 = previous.catch(() => void 0).then(() => current);
|
|
34162
|
+
this.documentOperationTails.set(hostUri, tail3);
|
|
34152
34163
|
const predecessorCompleted = await Promise.race([
|
|
34153
34164
|
previous.then(() => true, () => true),
|
|
34154
34165
|
cancellation.then(() => false)
|
|
@@ -34161,7 +34172,7 @@ ${content}`;
|
|
|
34161
34172
|
return await operation();
|
|
34162
34173
|
} finally {
|
|
34163
34174
|
release();
|
|
34164
|
-
if (this.documentOperationTails.get(hostUri) ===
|
|
34175
|
+
if (this.documentOperationTails.get(hostUri) === tail3) {
|
|
34165
34176
|
this.documentOperationTails.delete(hostUri);
|
|
34166
34177
|
}
|
|
34167
34178
|
}
|
|
@@ -35729,6 +35740,16 @@ function gitProbeEnvironmentSignature() {
|
|
|
35729
35740
|
const dynamicEntries = Object.keys(process.env).filter((key) => /^GIT_CONFIG_(?:KEY|VALUE)_\d+$/.test(key)).sort().map((key) => JSON.stringify([key, process.env[key] !== void 0, process.env[key] ?? ""]));
|
|
35730
35741
|
return [...fixedEntries, ...dynamicEntries].join("\0");
|
|
35731
35742
|
}
|
|
35743
|
+
function projectIdentifierEnvironmentSignature() {
|
|
35744
|
+
const stateDir = process.env.OMC_STATE_DIR;
|
|
35745
|
+
return `${gitProbeEnvironmentSignature()}\0${JSON.stringify(["OMC_STATE_DIR", stateDir !== void 0, stateDir ?? ""])}`;
|
|
35746
|
+
}
|
|
35747
|
+
function isDefinitiveGitExit(error2) {
|
|
35748
|
+
const failure3 = error2;
|
|
35749
|
+
if (typeof failure3?.status !== "number") return false;
|
|
35750
|
+
const stderr = String(failure3.stderr ?? "");
|
|
35751
|
+
return !stderr.includes("dubious ownership") && !stderr.includes("safe.directory");
|
|
35752
|
+
}
|
|
35732
35753
|
function findWorkspaceRoot(startDir) {
|
|
35733
35754
|
if (process.env.OMC_DISABLE_MULTIREPO === "1") return null;
|
|
35734
35755
|
const effectiveStart = startDir || process.cwd();
|
|
@@ -35826,8 +35847,8 @@ function resolveSuperprojectRoot(cwd2) {
|
|
|
35826
35847
|
completed = true;
|
|
35827
35848
|
break;
|
|
35828
35849
|
}
|
|
35829
|
-
anchor = superRoot;
|
|
35830
|
-
probeCwd =
|
|
35850
|
+
anchor = (0, import_path22.resolve)(superRoot);
|
|
35851
|
+
probeCwd = anchor;
|
|
35831
35852
|
}
|
|
35832
35853
|
if (completed) {
|
|
35833
35854
|
if (superprojectCacheMap.size >= MAX_WORKTREE_CACHE_SIZE) {
|
|
@@ -36305,16 +36326,16 @@ function getGitTopologySignature(cwd2) {
|
|
|
36305
36326
|
}
|
|
36306
36327
|
return signatures.join("|");
|
|
36307
36328
|
}
|
|
36308
|
-
function createStateRootCacheEntry(cwd2, root2) {
|
|
36329
|
+
function createStateRootCacheEntry(cwd2, root2, environmentSignature = gitProbeEnvironmentSignature) {
|
|
36309
36330
|
return {
|
|
36310
36331
|
root: root2,
|
|
36311
36332
|
metadataSignature: getGitMetadataSnapshot(cwd2)?.signature ?? null,
|
|
36312
36333
|
topologySignature: getGitTopologySignature(cwd2),
|
|
36313
|
-
environmentSignature:
|
|
36334
|
+
environmentSignature: environmentSignature()
|
|
36314
36335
|
};
|
|
36315
36336
|
}
|
|
36316
|
-
function isStateRootCacheEntryValid(cwd2, entry2) {
|
|
36317
|
-
return entry2.metadataSignature === (getGitMetadataSnapshot(cwd2)?.signature ?? null) && entry2.topologySignature === getGitTopologySignature(cwd2) && entry2.environmentSignature ===
|
|
36337
|
+
function isStateRootCacheEntryValid(cwd2, entry2, environmentSignature = gitProbeEnvironmentSignature) {
|
|
36338
|
+
return entry2.metadataSignature === (getGitMetadataSnapshot(cwd2)?.signature ?? null) && entry2.topologySignature === getGitTopologySignature(cwd2) && entry2.environmentSignature === environmentSignature();
|
|
36318
36339
|
}
|
|
36319
36340
|
function isGitTopLevelCacheEntryValid(cwd2, cached2) {
|
|
36320
36341
|
const current = getGitMetadataSnapshot(cwd2);
|
|
@@ -36352,7 +36373,24 @@ function getGitTopLevel(cwd2) {
|
|
|
36352
36373
|
}
|
|
36353
36374
|
gitTopLevelCacheMap.delete(key);
|
|
36354
36375
|
}
|
|
36376
|
+
const negative = gitTopLevelNegativeCacheMap.get(key);
|
|
36377
|
+
if (negative) {
|
|
36378
|
+
if (isStateRootCacheEntryValid(effectiveCwd, negative)) {
|
|
36379
|
+
gitTopLevelNegativeCacheMap.delete(key);
|
|
36380
|
+
gitTopLevelNegativeCacheMap.set(key, negative);
|
|
36381
|
+
return null;
|
|
36382
|
+
}
|
|
36383
|
+
gitTopLevelNegativeCacheMap.delete(key);
|
|
36384
|
+
}
|
|
36355
36385
|
const probe = probeGitTopLevel(effectiveCwd);
|
|
36386
|
+
if (probe.status === "not_a_repository") {
|
|
36387
|
+
if (gitTopLevelNegativeCacheMap.size >= MAX_WORKTREE_CACHE_SIZE) {
|
|
36388
|
+
const oldest = gitTopLevelNegativeCacheMap.keys().next().value;
|
|
36389
|
+
if (oldest !== void 0) gitTopLevelNegativeCacheMap.delete(oldest);
|
|
36390
|
+
}
|
|
36391
|
+
gitTopLevelNegativeCacheMap.set(key, createStateRootCacheEntry(effectiveCwd, null));
|
|
36392
|
+
return null;
|
|
36393
|
+
}
|
|
36356
36394
|
if (probe.status !== "ok") return null;
|
|
36357
36395
|
cacheGitTopLevel(key, probe.root, effectiveCwd);
|
|
36358
36396
|
return probe.root;
|
|
@@ -36448,6 +36486,20 @@ function getProjectIdentifier(worktreeRoot) {
|
|
|
36448
36486
|
if (scope && scopeKey) scope.projectIdentifiers.set(scopeKey, identifier2);
|
|
36449
36487
|
return identifier2;
|
|
36450
36488
|
}
|
|
36489
|
+
const processCacheKey = canonicalizeExistingPath(root2) ?? (0, import_path22.resolve)(root2);
|
|
36490
|
+
const processCached = projectIdentifierCacheMap.get(processCacheKey);
|
|
36491
|
+
if (processCached) {
|
|
36492
|
+
if (isStateRootCacheEntryValid(root2, processCached, projectIdentifierEnvironmentSignature)) {
|
|
36493
|
+
projectIdentifierCacheMap.delete(processCacheKey);
|
|
36494
|
+
projectIdentifierCacheMap.set(processCacheKey, processCached);
|
|
36495
|
+
if (operationScope && operationScopeKey) operationScope.set(operationScopeKey, processCached.identifier);
|
|
36496
|
+
if (scope && scopeKey) scope.projectIdentifiers.set(scopeKey, processCached.identifier);
|
|
36497
|
+
return processCached.identifier;
|
|
36498
|
+
}
|
|
36499
|
+
projectIdentifierCacheMap.delete(processCacheKey);
|
|
36500
|
+
}
|
|
36501
|
+
const processCacheEntry = createStateRootCacheEntry(root2, null, projectIdentifierEnvironmentSignature);
|
|
36502
|
+
let cacheable = processCacheEntry.metadataSignature !== null && process.env.GIT_DIR === void 0;
|
|
36451
36503
|
let remoteUrl = "";
|
|
36452
36504
|
try {
|
|
36453
36505
|
remoteUrl = (0, import_child_process6.execFileSync)("git", ["remote", "get-url", "origin"], {
|
|
@@ -36457,7 +36509,8 @@ function getProjectIdentifier(worktreeRoot) {
|
|
|
36457
36509
|
windowsHide: true,
|
|
36458
36510
|
timeout: 5e3
|
|
36459
36511
|
}).trim();
|
|
36460
|
-
} catch {
|
|
36512
|
+
} catch (error2) {
|
|
36513
|
+
if (!isDefinitiveGitExit(error2)) cacheable = false;
|
|
36461
36514
|
}
|
|
36462
36515
|
let primaryRoot = root2;
|
|
36463
36516
|
try {
|
|
@@ -36476,12 +36529,20 @@ function getProjectIdentifier(worktreeRoot) {
|
|
|
36476
36529
|
primaryRoot = resolved;
|
|
36477
36530
|
}
|
|
36478
36531
|
}
|
|
36479
|
-
} catch {
|
|
36532
|
+
} catch (error2) {
|
|
36533
|
+
if (!isDefinitiveGitExit(error2)) cacheable = false;
|
|
36480
36534
|
}
|
|
36481
36535
|
const source = remoteUrl || primaryRoot;
|
|
36482
36536
|
const hash = (0, import_crypto5.createHash)("sha256").update(source).digest("hex").slice(0, 16);
|
|
36483
36537
|
const dirName = (0, import_path22.basename)(primaryRoot).replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
36484
36538
|
const identifier = `${dirName}-${hash}`;
|
|
36539
|
+
if (cacheable) {
|
|
36540
|
+
if (projectIdentifierCacheMap.size >= MAX_WORKTREE_CACHE_SIZE) {
|
|
36541
|
+
const oldest = projectIdentifierCacheMap.keys().next().value;
|
|
36542
|
+
if (oldest !== void 0) projectIdentifierCacheMap.delete(oldest);
|
|
36543
|
+
}
|
|
36544
|
+
projectIdentifierCacheMap.set(processCacheKey, { ...processCacheEntry, identifier });
|
|
36545
|
+
}
|
|
36485
36546
|
if (operationScope && operationScopeKey) operationScope.set(operationScopeKey, identifier);
|
|
36486
36547
|
if (scope && scopeKey) scope.projectIdentifiers.set(scopeKey, identifier);
|
|
36487
36548
|
return identifier;
|
|
@@ -37015,7 +37076,7 @@ function validateWorkingDirectoryOrLinkedWorktree(workingDirectory) {
|
|
|
37015
37076
|
}
|
|
37016
37077
|
return resolution.root;
|
|
37017
37078
|
}
|
|
37018
|
-
var import_crypto5, import_node_async_hooks, import_child_process6, import_fs17, import_os4, import_path22, import_url6, WORKSPACE_MARKER, OmcPaths, MAX_WORKTREE_CACHE_SIZE, worktreeCacheMap, gitTopLevelCacheMap, superprojectCacheMap, canonicalWorkingDirectoryRoots, GIT_PROBE_ENVIRONMENT_KEYS, MAX_GIT_MARKER_BYTES, workspaceCacheMap, SENSITIVE_DIR_BASENAMES, worktreePathRenderScope, projectIdentifierOperationScope, gitShowToplevelProbeForTests, dualDirWarnings, SESSION_ID_REGEX, processSessionId, ForeignWorkingDirectoryError;
|
|
37079
|
+
var import_crypto5, import_node_async_hooks, import_child_process6, import_fs17, import_os4, import_path22, import_url6, WORKSPACE_MARKER, OmcPaths, MAX_WORKTREE_CACHE_SIZE, worktreeCacheMap, gitTopLevelCacheMap, gitTopLevelNegativeCacheMap, superprojectCacheMap, projectIdentifierCacheMap, canonicalWorkingDirectoryRoots, GIT_PROBE_ENVIRONMENT_KEYS, MAX_GIT_MARKER_BYTES, workspaceCacheMap, SENSITIVE_DIR_BASENAMES, worktreePathRenderScope, projectIdentifierOperationScope, gitShowToplevelProbeForTests, dualDirWarnings, SESSION_ID_REGEX, processSessionId, ForeignWorkingDirectoryError;
|
|
37019
37080
|
var init_worktree_paths = __esm({
|
|
37020
37081
|
"src/lib/worktree-paths.ts"() {
|
|
37021
37082
|
"use strict";
|
|
@@ -37049,7 +37110,9 @@ var init_worktree_paths = __esm({
|
|
|
37049
37110
|
MAX_WORKTREE_CACHE_SIZE = 8;
|
|
37050
37111
|
worktreeCacheMap = /* @__PURE__ */ new Map();
|
|
37051
37112
|
gitTopLevelCacheMap = /* @__PURE__ */ new Map();
|
|
37113
|
+
gitTopLevelNegativeCacheMap = /* @__PURE__ */ new Map();
|
|
37052
37114
|
superprojectCacheMap = /* @__PURE__ */ new Map();
|
|
37115
|
+
projectIdentifierCacheMap = /* @__PURE__ */ new Map();
|
|
37053
37116
|
canonicalWorkingDirectoryRoots = /* @__PURE__ */ new WeakMap();
|
|
37054
37117
|
GIT_PROBE_ENVIRONMENT_KEYS = [
|
|
37055
37118
|
"PATH",
|
|
@@ -37967,7 +38030,11 @@ function rollbackPriorTarget(filePath, backupPath, expectedIdentity, operations)
|
|
|
37967
38030
|
} else {
|
|
37968
38031
|
(operations?.rename ?? fsSync.renameSync)(backupPath, filePath);
|
|
37969
38032
|
}
|
|
37970
|
-
} catch {
|
|
38033
|
+
} catch (error2) {
|
|
38034
|
+
try {
|
|
38035
|
+
console.warn(`[omc] atomic write rollback of ${filePath} failed: ${error2.message}`);
|
|
38036
|
+
} catch {
|
|
38037
|
+
}
|
|
37971
38038
|
}
|
|
37972
38039
|
}
|
|
37973
38040
|
function removeBackup(backupPath, operations) {
|
|
@@ -38014,6 +38081,10 @@ async function atomicWriteJson(filePath, data, hooks) {
|
|
|
38014
38081
|
hooks?.afterRename?.();
|
|
38015
38082
|
verifyPublishedFile(fd.fd, filePath, "atomic JSON write");
|
|
38016
38083
|
} catch (error2) {
|
|
38084
|
+
if (process.platform === "win32") {
|
|
38085
|
+
await fd.close().catch(() => void 0);
|
|
38086
|
+
fd = null;
|
|
38087
|
+
}
|
|
38017
38088
|
rollbackPriorTarget(
|
|
38018
38089
|
filePath,
|
|
38019
38090
|
backupPath,
|
|
@@ -38022,7 +38093,7 @@ async function atomicWriteJson(filePath, data, hooks) {
|
|
|
38022
38093
|
throw error2;
|
|
38023
38094
|
}
|
|
38024
38095
|
} finally {
|
|
38025
|
-
await fd
|
|
38096
|
+
await fd?.close();
|
|
38026
38097
|
fd = null;
|
|
38027
38098
|
}
|
|
38028
38099
|
success = true;
|
|
@@ -38044,6 +38115,18 @@ async function atomicWriteJson(filePath, data, hooks) {
|
|
|
38044
38115
|
}
|
|
38045
38116
|
}
|
|
38046
38117
|
}
|
|
38118
|
+
function renameSyncRetryingWin32Sharing(rename8, source, destination) {
|
|
38119
|
+
for (let attempt = 0; ; attempt++) {
|
|
38120
|
+
try {
|
|
38121
|
+
rename8(source, destination);
|
|
38122
|
+
return;
|
|
38123
|
+
} catch (error2) {
|
|
38124
|
+
const code = error2.code;
|
|
38125
|
+
if (process.platform !== "win32" || attempt >= 20 || code !== "EPERM" && code !== "EACCES" && code !== "EBUSY") throw error2;
|
|
38126
|
+
Atomics.wait(RENAME_RETRY_WAIT, 0, 0, Math.min(25, 1 + attempt * 2));
|
|
38127
|
+
}
|
|
38128
|
+
}
|
|
38129
|
+
}
|
|
38047
38130
|
function atomicWriteFileSync(filePath, content, hooks, operations) {
|
|
38048
38131
|
if (operations && (!filePath || path3.basename(filePath) !== filePath || filePath === "." || filePath === "..")) throw new RangeError("contained atomic write requires a basename");
|
|
38049
38132
|
const dir = path3.dirname(filePath);
|
|
@@ -38060,7 +38143,7 @@ function atomicWriteFileSync(filePath, content, hooks, operations) {
|
|
|
38060
38143
|
verifyPrivateTempFile(fd, tempPath, "atomic write", operations);
|
|
38061
38144
|
backupPath = preservePriorTarget(filePath, operations);
|
|
38062
38145
|
hooks?.beforeRename?.();
|
|
38063
|
-
(operations?.rename ?? fsSync.renameSync
|
|
38146
|
+
renameSyncRetryingWin32Sharing(operations?.rename ?? fsSync.renameSync, tempPath, filePath);
|
|
38064
38147
|
let publishedIdentity = null;
|
|
38065
38148
|
try {
|
|
38066
38149
|
verifyPublishedFile(fd, filePath, "atomic write", operations);
|
|
@@ -38068,6 +38151,13 @@ function atomicWriteFileSync(filePath, content, hooks, operations) {
|
|
|
38068
38151
|
hooks?.afterRename?.();
|
|
38069
38152
|
verifyPublishedFile(fd, filePath, "atomic write", operations);
|
|
38070
38153
|
} catch (error2) {
|
|
38154
|
+
if (process.platform === "win32") {
|
|
38155
|
+
try {
|
|
38156
|
+
fsSync.closeSync(fd);
|
|
38157
|
+
} catch {
|
|
38158
|
+
}
|
|
38159
|
+
fd = null;
|
|
38160
|
+
}
|
|
38071
38161
|
rollbackPriorTarget(
|
|
38072
38162
|
filePath,
|
|
38073
38163
|
backupPath,
|
|
@@ -38126,7 +38216,7 @@ async function safeReadJson(filePath) {
|
|
|
38126
38216
|
return null;
|
|
38127
38217
|
}
|
|
38128
38218
|
}
|
|
38129
|
-
var fs3, fsSync, path3, crypto3, ATOMIC_BATCH_MAX_CONTENT_BYTES;
|
|
38219
|
+
var fs3, fsSync, path3, crypto3, RENAME_RETRY_WAIT, ATOMIC_BATCH_MAX_CONTENT_BYTES;
|
|
38130
38220
|
var init_atomic_write = __esm({
|
|
38131
38221
|
"src/lib/atomic-write.ts"() {
|
|
38132
38222
|
"use strict";
|
|
@@ -38134,6 +38224,7 @@ var init_atomic_write = __esm({
|
|
|
38134
38224
|
fsSync = __toESM(require("fs"), 1);
|
|
38135
38225
|
path3 = __toESM(require("path"), 1);
|
|
38136
38226
|
crypto3 = __toESM(require("crypto"), 1);
|
|
38227
|
+
RENAME_RETRY_WAIT = new Int32Array(new SharedArrayBuffer(4));
|
|
38137
38228
|
ATOMIC_BATCH_MAX_CONTENT_BYTES = 1024 * 1024;
|
|
38138
38229
|
}
|
|
38139
38230
|
});
|
|
@@ -38558,8 +38649,14 @@ async function terminateOwnedProcessTree(options) {
|
|
|
38558
38649
|
" if (-not $owned.ContainsKey($parent) -or $owned.ContainsKey($id)) { continue }",
|
|
38559
38650
|
" try {",
|
|
38560
38651
|
" $process = [System.Diagnostics.Process]::GetProcessById($id)",
|
|
38561
|
-
|
|
38562
|
-
|
|
38652
|
+
// CIM CreationDate carries microseconds, StartTime 100 ns ticks: compare
|
|
38653
|
+
// at microsecond precision or almost every live child reads as reused.
|
|
38654
|
+
" $created = ([DateTime]$row.CreationDate).ToUniversalTime().Ticks; $started = $process.StartTime.ToUniversalTime().Ticks",
|
|
38655
|
+
" if (($started - $started % 10) -ne ($created - $created % 10)) { continue }",
|
|
38656
|
+
// ParentProcessId is never cleared, so a process created before its owned
|
|
38657
|
+
// "parent" names a dead earlier holder of that reused PID: not a descendant.
|
|
38658
|
+
" $parentStart = $owned[$parent].Process.StartTime.ToUniversalTime().Ticks",
|
|
38659
|
+
" if (($created - $created % 10) -lt ($parentStart - $parentStart % 10)) { continue }",
|
|
38563
38660
|
" [void][OmcNative]::NtSuspendProcess($process.Handle)",
|
|
38564
38661
|
" $owned[$id] = @{ Process = $process; Depth = ([int]$owned[$parent].Depth + 1); Suspended = $true }",
|
|
38565
38662
|
" $added = $true",
|
|
@@ -39214,18 +39311,41 @@ function detectExistingPythonEnv(projectRoot) {
|
|
|
39214
39311
|
}
|
|
39215
39312
|
return null;
|
|
39216
39313
|
}
|
|
39314
|
+
async function resolveSystemPython(platform = process.platform, probe = runPythonProbe) {
|
|
39315
|
+
const useCache = platform === process.platform && probe === runPythonProbe;
|
|
39316
|
+
if (useCache && systemPythonCache !== void 0) return systemPythonCache;
|
|
39317
|
+
const resolved = await probeSystemPython(platform, probe);
|
|
39318
|
+
if (useCache) systemPythonCache = resolved;
|
|
39319
|
+
return resolved;
|
|
39320
|
+
}
|
|
39321
|
+
async function probeSystemPython(platform, probe) {
|
|
39322
|
+
const candidates = platform === "win32" ? [["python3"], ["python"], ["py", "-3"]] : [["python3"]];
|
|
39323
|
+
for (const [command, ...args] of candidates) {
|
|
39324
|
+
try {
|
|
39325
|
+
const stdout = await probe(command, [
|
|
39326
|
+
...args,
|
|
39327
|
+
"-c",
|
|
39328
|
+
"import sys; assert sys.version_info >= (3,); print(sys.executable)"
|
|
39329
|
+
]);
|
|
39330
|
+
const executable = stdout.trim();
|
|
39331
|
+
if (executable) return executable;
|
|
39332
|
+
} catch {
|
|
39333
|
+
}
|
|
39334
|
+
}
|
|
39335
|
+
return null;
|
|
39336
|
+
}
|
|
39217
39337
|
async function ensurePythonEnvironment(projectRoot) {
|
|
39218
39338
|
const existing = detectExistingPythonEnv(projectRoot);
|
|
39219
39339
|
if (existing) {
|
|
39220
39340
|
return existing;
|
|
39221
39341
|
}
|
|
39222
|
-
|
|
39223
|
-
|
|
39224
|
-
return { pythonPath:
|
|
39225
|
-
} catch {
|
|
39342
|
+
const systemPython = await resolveSystemPython();
|
|
39343
|
+
if (systemPython) {
|
|
39344
|
+
return { pythonPath: systemPython, type: "venv" };
|
|
39226
39345
|
}
|
|
39227
39346
|
throw new Error(
|
|
39228
|
-
|
|
39347
|
+
`No Python environment found (probed: ${process.platform === "win32" ? "python3, python, py -3" : "python3"}). Create a virtual environment first:
|
|
39348
|
+
python -m venv .venv`
|
|
39229
39349
|
);
|
|
39230
39350
|
}
|
|
39231
39351
|
async function verifyProcessIdentity(meta) {
|
|
@@ -39577,7 +39697,7 @@ async function removeFileIfExists(filePath) {
|
|
|
39577
39697
|
function sleep2(ms) {
|
|
39578
39698
|
return new Promise((resolve58) => setTimeout(resolve58, ms));
|
|
39579
39699
|
}
|
|
39580
|
-
var import_child_process9, fs5, fsPromises2, path6, import_url7, import_child_process10, import_util6, execFileAsync3, BRIDGE_SPAWN_TIMEOUT_MS, DEFAULT_GRACE_PERIOD_MS, SIGTERM_GRACE_MS, ownedBridgeSessionIds, USE_TCP_FALLBACK;
|
|
39700
|
+
var import_child_process9, fs5, fsPromises2, path6, import_url7, import_child_process10, import_util6, execFileAsync3, BRIDGE_SPAWN_TIMEOUT_MS, DEFAULT_GRACE_PERIOD_MS, SIGTERM_GRACE_MS, ownedBridgeSessionIds, runPythonProbe, systemPythonCache, USE_TCP_FALLBACK;
|
|
39581
39701
|
var init_bridge_manager = __esm({
|
|
39582
39702
|
"src/tools/python-repl/bridge-manager.ts"() {
|
|
39583
39703
|
"use strict";
|
|
@@ -39597,6 +39717,7 @@ var init_bridge_manager = __esm({
|
|
|
39597
39717
|
DEFAULT_GRACE_PERIOD_MS = 5e3;
|
|
39598
39718
|
SIGTERM_GRACE_MS = 2500;
|
|
39599
39719
|
ownedBridgeSessionIds = /* @__PURE__ */ new Set();
|
|
39720
|
+
runPythonProbe = async (command, args) => (await execFileAsync3(command, args, { timeout: 1e4, windowsHide: true })).stdout;
|
|
39600
39721
|
USE_TCP_FALLBACK = process.platform === "win32";
|
|
39601
39722
|
}
|
|
39602
39723
|
});
|
|
@@ -45547,9 +45668,12 @@ function commandExists2(command, env2) {
|
|
|
45547
45668
|
});
|
|
45548
45669
|
return result.status === 0;
|
|
45549
45670
|
}
|
|
45671
|
+
function isOmcCliAvailable(env2 = process.env) {
|
|
45672
|
+
return commandExists2(OMC_CLI_BINARY, env2);
|
|
45673
|
+
}
|
|
45550
45674
|
function resolveOmcCliPrefix(options = {}) {
|
|
45551
45675
|
const env2 = options.env ?? process.env;
|
|
45552
|
-
const omcAvailable = options.omcAvailable ??
|
|
45676
|
+
const omcAvailable = options.omcAvailable ?? isOmcCliAvailable(env2);
|
|
45553
45677
|
if (omcAvailable) {
|
|
45554
45678
|
return OMC_CLI_BINARY;
|
|
45555
45679
|
}
|
|
@@ -45571,13 +45695,8 @@ function rewriteOmcCliInvocations(text, options = {}) {
|
|
|
45571
45695
|
if (!text.includes("omc ")) {
|
|
45572
45696
|
return text;
|
|
45573
45697
|
}
|
|
45574
|
-
|
|
45575
|
-
|
|
45576
|
-
return `\`${prefix} ${suffix}\``;
|
|
45577
|
-
}).replace(/(^|\n)([ \t>*-]*)omc ([^\n]+)/g, (_match, lineStart, leader, suffix) => {
|
|
45578
|
-
const prefix = resolveInvocationPrefix(suffix, options);
|
|
45579
|
-
return `${lineStart}${leader}${prefix} ${suffix}`;
|
|
45580
|
-
});
|
|
45698
|
+
const prefix = resolveOmcCliPrefix(options);
|
|
45699
|
+
return text.replace(/`omc ([^`\r\n]+)`/g, (_match, suffix) => `\`${prefix} ${suffix}\``).replace(/(^|\n)([ \t>*-]*)omc ([^\n]+)/g, (_match, lineStart, leader, suffix) => `${lineStart}${leader}${prefix} ${suffix}`);
|
|
45581
45700
|
}
|
|
45582
45701
|
var import_child_process13, OMC_CLI_BINARY, OMC_PLUGIN_BRIDGE_PREFIX;
|
|
45583
45702
|
var init_omc_cli_rendering = __esm({
|
|
@@ -51110,13 +51229,13 @@ var init_directive_detector = __esm({
|
|
|
51110
51229
|
function withMutex(projectRoot, fn) {
|
|
51111
51230
|
const prev = writeMutexes.get(projectRoot) ?? Promise.resolve();
|
|
51112
51231
|
const next = prev.then(() => fn()).catch(() => fn());
|
|
51113
|
-
const
|
|
51232
|
+
const tail3 = next.then(
|
|
51114
51233
|
() => {
|
|
51115
51234
|
},
|
|
51116
51235
|
() => {
|
|
51117
51236
|
}
|
|
51118
51237
|
);
|
|
51119
|
-
writeMutexes.set(projectRoot,
|
|
51238
|
+
writeMutexes.set(projectRoot, tail3);
|
|
51120
51239
|
return next;
|
|
51121
51240
|
}
|
|
51122
51241
|
async function addCustomNote(projectRoot, category, content) {
|
|
@@ -53205,9 +53324,10 @@ function scanDirectories(projectRoot) {
|
|
|
53205
53324
|
return;
|
|
53206
53325
|
}
|
|
53207
53326
|
try {
|
|
53208
|
-
const stat2 = (0, import_node_fs4.statSync)(absDir);
|
|
53209
|
-
|
|
53210
|
-
visitedInodes.
|
|
53327
|
+
const stat2 = (0, import_node_fs4.statSync)(absDir, { bigint: true });
|
|
53328
|
+
const inodeKey = `${stat2.dev}:${stat2.ino}`;
|
|
53329
|
+
if (visitedInodes.has(inodeKey)) return;
|
|
53330
|
+
visitedInodes.add(inodeKey);
|
|
53211
53331
|
} catch {
|
|
53212
53332
|
return;
|
|
53213
53333
|
}
|
|
@@ -55391,12 +55511,12 @@ function parseTomlStringArrayFallback(value) {
|
|
|
55391
55511
|
}
|
|
55392
55512
|
return result;
|
|
55393
55513
|
}
|
|
55394
|
-
const
|
|
55395
|
-
if (
|
|
55514
|
+
const quote3 = value[i];
|
|
55515
|
+
if (quote3 !== '"' && quote3 !== "'") {
|
|
55396
55516
|
return void 0;
|
|
55397
55517
|
}
|
|
55398
55518
|
let member;
|
|
55399
|
-
if (
|
|
55519
|
+
if (quote3 === "'") {
|
|
55400
55520
|
i++;
|
|
55401
55521
|
const start = i;
|
|
55402
55522
|
while (i < value.length && value[i] !== "'") {
|
|
@@ -55513,8 +55633,8 @@ function parseTomlDottedKey(value) {
|
|
|
55513
55633
|
skipWhitespace();
|
|
55514
55634
|
while (index < value.length) {
|
|
55515
55635
|
const start = index;
|
|
55516
|
-
const
|
|
55517
|
-
if (
|
|
55636
|
+
const quote3 = value[index];
|
|
55637
|
+
if (quote3 === '"') {
|
|
55518
55638
|
index++;
|
|
55519
55639
|
let closed = false;
|
|
55520
55640
|
while (index < value.length) {
|
|
@@ -55528,7 +55648,7 @@ function parseTomlDottedKey(value) {
|
|
|
55528
55648
|
if (!closed) {
|
|
55529
55649
|
return void 0;
|
|
55530
55650
|
}
|
|
55531
|
-
} else if (
|
|
55651
|
+
} else if (quote3 === "'") {
|
|
55532
55652
|
index++;
|
|
55533
55653
|
while (index < value.length && value[index] !== "'") {
|
|
55534
55654
|
index++;
|
|
@@ -55567,29 +55687,29 @@ function parseTomlTableHeader(line) {
|
|
|
55567
55687
|
if (!trimmed.startsWith("[") || trimmed.startsWith("[[")) {
|
|
55568
55688
|
return void 0;
|
|
55569
55689
|
}
|
|
55570
|
-
let
|
|
55690
|
+
let quote3;
|
|
55571
55691
|
let escaped = false;
|
|
55572
55692
|
let closingBracket = -1;
|
|
55573
55693
|
for (let index = 1; index < trimmed.length; index++) {
|
|
55574
55694
|
const character = trimmed[index];
|
|
55575
|
-
if (
|
|
55695
|
+
if (quote3 === '"') {
|
|
55576
55696
|
if (escaped) {
|
|
55577
55697
|
escaped = false;
|
|
55578
55698
|
} else if (character === "\\") {
|
|
55579
55699
|
escaped = true;
|
|
55580
55700
|
} else if (character === '"') {
|
|
55581
|
-
|
|
55701
|
+
quote3 = void 0;
|
|
55582
55702
|
}
|
|
55583
55703
|
continue;
|
|
55584
55704
|
}
|
|
55585
|
-
if (
|
|
55705
|
+
if (quote3 === "'") {
|
|
55586
55706
|
if (character === "'") {
|
|
55587
|
-
|
|
55707
|
+
quote3 = void 0;
|
|
55588
55708
|
}
|
|
55589
55709
|
continue;
|
|
55590
55710
|
}
|
|
55591
55711
|
if (character === '"' || character === "'") {
|
|
55592
|
-
|
|
55712
|
+
quote3 = character;
|
|
55593
55713
|
} else if (character === "]") {
|
|
55594
55714
|
closingBracket = index;
|
|
55595
55715
|
break;
|
|
@@ -57579,6 +57699,7 @@ export const isExclusiveStateLockingAvailable = canonical.isExclusiveStateLockin
|
|
|
57579
57699
|
export const getStateFileLockDiagnostic = canonical.getStateFileLockDiagnostic;
|
|
57580
57700
|
export const getStateFileLockFailureMessage = canonical.getStateFileLockFailureMessage;
|
|
57581
57701
|
export const getStateFileLockFailureKind = canonical.getStateFileLockFailureKind;
|
|
57702
|
+
export const getStateFileLockFailureReason = canonical.getStateFileLockFailureReason;
|
|
57582
57703
|
export const acquireStateFileLockSync = canonical.acquireStateFileLockSync;
|
|
57583
57704
|
export const acquireStateFileLockAtPathSync = canonical.acquireStateFileLockAtPathSync;
|
|
57584
57705
|
export const releaseStateFileLockSync = canonical.releaseStateFileLockSync;
|
|
@@ -65355,18 +65476,18 @@ function getBackgroundBashPermissionFallback(directory, command) {
|
|
|
65355
65476
|
function tokenizeShellCommand(command) {
|
|
65356
65477
|
const tokens = [];
|
|
65357
65478
|
let current = "";
|
|
65358
|
-
let
|
|
65479
|
+
let quote3 = null;
|
|
65359
65480
|
for (const char of command.trim()) {
|
|
65360
|
-
if (
|
|
65361
|
-
if (char ===
|
|
65362
|
-
|
|
65481
|
+
if (quote3) {
|
|
65482
|
+
if (char === quote3) {
|
|
65483
|
+
quote3 = null;
|
|
65363
65484
|
} else {
|
|
65364
65485
|
current += char;
|
|
65365
65486
|
}
|
|
65366
65487
|
continue;
|
|
65367
65488
|
}
|
|
65368
65489
|
if (char === '"' || char === "'") {
|
|
65369
|
-
|
|
65490
|
+
quote3 = char;
|
|
65370
65491
|
continue;
|
|
65371
65492
|
}
|
|
65372
65493
|
if (/\s/.test(char)) {
|
|
@@ -65378,7 +65499,7 @@ function tokenizeShellCommand(command) {
|
|
|
65378
65499
|
}
|
|
65379
65500
|
current += char;
|
|
65380
65501
|
}
|
|
65381
|
-
if (
|
|
65502
|
+
if (quote3) {
|
|
65382
65503
|
return null;
|
|
65383
65504
|
}
|
|
65384
65505
|
if (current) {
|
|
@@ -67666,13 +67787,13 @@ When done, run \`/oh-my-copilot:cancel\` to cleanly exit.
|
|
|
67666
67787
|
}
|
|
67667
67788
|
async function checkPersistentModes(sessionId, directory, stopContext) {
|
|
67668
67789
|
const result = await resolvePersistentModeBlock(sessionId, directory, stopContext);
|
|
67669
|
-
const
|
|
67790
|
+
const guarded4 = applyThinkingOnlyStreakGuard(
|
|
67670
67791
|
result,
|
|
67671
67792
|
resolveToWorktreeRoot(directory),
|
|
67672
67793
|
sessionId,
|
|
67673
67794
|
stopContext
|
|
67674
67795
|
);
|
|
67675
|
-
return applyLoopContinuationShadow({ result:
|
|
67796
|
+
return applyLoopContinuationShadow({ result: guarded4, sessionId });
|
|
67676
67797
|
}
|
|
67677
67798
|
async function resolvePersistentModeBlock(sessionId, directory, stopContext) {
|
|
67678
67799
|
const workingDir = resolveToWorktreeRoot(directory);
|
|
@@ -69700,12 +69821,17 @@ function readSessionEndJob(directory, sessionId) {
|
|
|
69700
69821
|
}
|
|
69701
69822
|
}
|
|
69702
69823
|
function mutateSessionEndJob(directory, sessionId, expectedRevision, mutate) {
|
|
69824
|
+
const result = mutateAtRevision(directory, sessionId, expectedRevision, mutate);
|
|
69825
|
+
return result === REVISION_MISMATCH ? null : result;
|
|
69826
|
+
}
|
|
69827
|
+
function mutateAtRevision(directory, sessionId, expectedRevision, mutate) {
|
|
69703
69828
|
let terminal = false;
|
|
69704
69829
|
try {
|
|
69705
69830
|
const jobPath = sessionEndJobPath(directory, sessionId);
|
|
69706
69831
|
const result = withLock(jobPath, () => {
|
|
69707
69832
|
const current = readPath(jobPath);
|
|
69708
|
-
if (!current
|
|
69833
|
+
if (!current) return null;
|
|
69834
|
+
if (current.revision !== expectedRevision) return REVISION_MISMATCH;
|
|
69709
69835
|
mutate(current);
|
|
69710
69836
|
const next = { ...current, revision: current.revision + 1, updatedAt: nowIso() };
|
|
69711
69837
|
if (isManifestTerminal(next) && next.phase !== "complete") {
|
|
@@ -69718,7 +69844,7 @@ function mutateSessionEndJob(directory, sessionId, expectedRevision, mutate) {
|
|
|
69718
69844
|
terminal = reread.phase === "complete";
|
|
69719
69845
|
return reread;
|
|
69720
69846
|
});
|
|
69721
|
-
if (result && terminal) acknowledgeSessionEndDiscoveryTicket(directory, sessionId);
|
|
69847
|
+
if (result && result !== REVISION_MISMATCH && terminal) acknowledgeSessionEndDiscoveryTicket(directory, sessionId);
|
|
69722
69848
|
return result;
|
|
69723
69849
|
} catch {
|
|
69724
69850
|
return null;
|
|
@@ -69732,12 +69858,12 @@ function updateSessionEndActionPayload(directory, sessionId, authority, actionNa
|
|
|
69732
69858
|
for (const name of actionNames) job.actions[name].payload = { ...job.actions[name].payload, ...payload };
|
|
69733
69859
|
});
|
|
69734
69860
|
}
|
|
69735
|
-
function mutateLatest(directory, sessionId, mutate) {
|
|
69861
|
+
function mutateLatest(directory, sessionId, mutate, retryOn = "any-null") {
|
|
69736
69862
|
for (let i = 0; i < 8; i++) {
|
|
69737
69863
|
const current = readSessionEndJob(directory, sessionId);
|
|
69738
69864
|
if (!current) return null;
|
|
69739
|
-
const result =
|
|
69740
|
-
if (result) return result;
|
|
69865
|
+
const result = mutateAtRevision(directory, sessionId, current.revision, mutate);
|
|
69866
|
+
if (result !== REVISION_MISMATCH && (result || retryOn === "mismatch")) return result;
|
|
69741
69867
|
}
|
|
69742
69868
|
return null;
|
|
69743
69869
|
}
|
|
@@ -69865,15 +69991,13 @@ function claimSessionEndJob(directory, sessionId, nonce, identity, deadlineAt) {
|
|
|
69865
69991
|
});
|
|
69866
69992
|
}
|
|
69867
69993
|
function renewSessionEndLease(directory, sessionId, nonce, generation, deadlineAt) {
|
|
69868
|
-
|
|
69869
|
-
if (!current) return null;
|
|
69870
|
-
return mutateSessionEndJob(directory, sessionId, current.revision, (job) => {
|
|
69994
|
+
return mutateLatest(directory, sessionId, (job) => {
|
|
69871
69995
|
const owner = job.owner;
|
|
69872
69996
|
if (!owner || owner.nonce !== nonce || owner.leaseGeneration !== generation) throw new Error("lease-conflict");
|
|
69873
69997
|
owner.leaseGeneration++;
|
|
69874
69998
|
owner.heartbeatAt = nowIso();
|
|
69875
69999
|
owner.leaseExpiresAt = new Date(Math.min(Date.now() + 750, deadlineAt)).toISOString();
|
|
69876
|
-
});
|
|
70000
|
+
}, "mismatch");
|
|
69877
70001
|
}
|
|
69878
70002
|
function reapStaleSessionEndOwner(directory, sessionId, expectedNonce, expectedGeneration, liveness) {
|
|
69879
70003
|
const current = readSessionEndJob(directory, sessionId);
|
|
@@ -69895,24 +70019,29 @@ function reapStaleSessionEndOwner(directory, sessionId, expectedNonce, expectedG
|
|
|
69895
70019
|
});
|
|
69896
70020
|
}
|
|
69897
70021
|
function releaseSessionEndJob(directory, sessionId, nonce, generation, reason = "worker-released") {
|
|
69898
|
-
|
|
69899
|
-
if (!current) return null;
|
|
69900
|
-
return mutateSessionEndJob(directory, sessionId, current.revision, (job) => {
|
|
70022
|
+
return mutateLatest(directory, sessionId, (job) => {
|
|
69901
70023
|
if (!job.owner || job.owner.nonce !== nonce || job.owner.leaseGeneration !== generation) throw new Error("release-conflict");
|
|
70024
|
+
for (const action of Object.values(job.actions)) {
|
|
70025
|
+
if (action.status === "claimed" && action.claimantNonce === nonce && action.runner?.phase === "reserved" && action.runner.attempt === action.attempts) {
|
|
70026
|
+
action.attempts--;
|
|
70027
|
+
action.status = action.attempts > 0 ? "retryable" : "pending";
|
|
70028
|
+
action.claimantNonce = void 0;
|
|
70029
|
+
action.claimedAt = void 0;
|
|
70030
|
+
action.runner = void 0;
|
|
70031
|
+
}
|
|
70032
|
+
}
|
|
69902
70033
|
job.owner = null;
|
|
69903
70034
|
if (job.phase !== "complete") {
|
|
69904
70035
|
job.phase = "recoverable-failure";
|
|
69905
70036
|
job.recoverableFailure = { reason, releasedAt: nowIso(), ownerNonce: nonce };
|
|
69906
70037
|
}
|
|
69907
|
-
});
|
|
70038
|
+
}, "mismatch");
|
|
69908
70039
|
}
|
|
69909
70040
|
function updateSessionEndJob(directory, sessionId, expectedOwner, mutate) {
|
|
69910
|
-
|
|
69911
|
-
if (!current) return null;
|
|
69912
|
-
return mutateSessionEndJob(directory, sessionId, current.revision, (job) => {
|
|
70041
|
+
return mutateLatest(directory, sessionId, (job) => {
|
|
69913
70042
|
if (job.owner?.nonce !== expectedOwner || job.phase === "complete") throw new Error("owner-conflict");
|
|
69914
70043
|
mutate(job);
|
|
69915
|
-
});
|
|
70044
|
+
}, "mismatch");
|
|
69916
70045
|
}
|
|
69917
70046
|
function claimSessionEndAction(directory, sessionId, ownerNonce, name, deadlineAt) {
|
|
69918
70047
|
return updateSessionEndJob(directory, sessionId, ownerNonce, (job) => {
|
|
@@ -70072,7 +70201,7 @@ function failClosedMissingCoreProducer(directory, sessionId) {
|
|
|
70072
70201
|
if (job.phase === "collecting") job.phase = "ready";
|
|
70073
70202
|
});
|
|
70074
70203
|
}
|
|
70075
|
-
var fs12, path18, import_crypto21, ACTIONS, TEST_PRODUCER_GRACE_ENV, PRODUCER_GRACE_MS, REQUIRED_ACTION_EXECUTION_MS, BEST_EFFORT_ACTION_EXECUTION_MS, REQUIRED_ACTION_MAX_ATTEMPTS, LOCK_WAIT, DISCOVERY_FILE;
|
|
70204
|
+
var fs12, path18, import_crypto21, ACTIONS, TEST_PRODUCER_GRACE_ENV, PRODUCER_GRACE_MS, REQUIRED_ACTION_EXECUTION_MS, BEST_EFFORT_ACTION_EXECUTION_MS, REQUIRED_ACTION_MAX_ATTEMPTS, LOCK_WAIT, DISCOVERY_FILE, REVISION_MISMATCH;
|
|
70076
70205
|
var init_cleanup_manifest = __esm({
|
|
70077
70206
|
"src/hooks/session-end/cleanup-manifest.ts"() {
|
|
70078
70207
|
"use strict";
|
|
@@ -70099,6 +70228,7 @@ var init_cleanup_manifest = __esm({
|
|
|
70099
70228
|
REQUIRED_ACTION_MAX_ATTEMPTS = 3;
|
|
70100
70229
|
LOCK_WAIT = new Int32Array(new SharedArrayBuffer(4));
|
|
70101
70230
|
DISCOVERY_FILE = "discovery.json";
|
|
70231
|
+
REVISION_MISMATCH = /* @__PURE__ */ Symbol("revision-mismatch");
|
|
70102
70232
|
}
|
|
70103
70233
|
});
|
|
70104
70234
|
|
|
@@ -71939,9 +72069,9 @@ function createTelegramProxyConnection(proxyUrl) {
|
|
|
71939
72069
|
let tlsSocket;
|
|
71940
72070
|
let settled = false;
|
|
71941
72071
|
const handshakeTimer = setTimeout(() => {
|
|
71942
|
-
|
|
72072
|
+
fail7(new Error("Proxy CONNECT timeout"));
|
|
71943
72073
|
}, SEND_TIMEOUT_MS);
|
|
71944
|
-
const
|
|
72074
|
+
const fail7 = (error2) => {
|
|
71945
72075
|
if (settled) return;
|
|
71946
72076
|
settled = true;
|
|
71947
72077
|
clearTimeout(handshakeTimer);
|
|
@@ -71949,7 +72079,7 @@ function createTelegramProxyConnection(proxyUrl) {
|
|
|
71949
72079
|
tlsSocket?.destroy();
|
|
71950
72080
|
callback(error2);
|
|
71951
72081
|
};
|
|
71952
|
-
connectSocket.once("error",
|
|
72082
|
+
connectSocket.once("error", fail7);
|
|
71953
72083
|
connectSocket.once(proxyUrl.protocol === "https:" ? "secureConnect" : "connect", () => {
|
|
71954
72084
|
const auth = proxyUrl.username || proxyUrl.password ? `Proxy-Authorization: Basic ${Buffer.from(
|
|
71955
72085
|
`${decodeURIComponent(proxyUrl.username)}:${decodeURIComponent(proxyUrl.password)}`
|
|
@@ -71969,11 +72099,11 @@ Host: ${TELEGRAM_API_HOST}:${TELEGRAM_API_PORT}\r
|
|
|
71969
72099
|
const statusLine = response.toString("ascii", 0, headerEnd).split("\r\n")[0] || "";
|
|
71970
72100
|
const status = /^HTTP\/\d(?:\.\d)?\s+(\d{3})/.exec(statusLine)?.[1];
|
|
71971
72101
|
if (!status || !status.startsWith("2")) {
|
|
71972
|
-
|
|
72102
|
+
fail7(new Error(`Proxy CONNECT failed: ${status || "unknown"}`));
|
|
71973
72103
|
return;
|
|
71974
72104
|
}
|
|
71975
72105
|
connectSocket.removeAllListeners("data");
|
|
71976
|
-
connectSocket.removeListener("error",
|
|
72106
|
+
connectSocket.removeListener("error", fail7);
|
|
71977
72107
|
tlsSocket = (0, import_tls.connect)(
|
|
71978
72108
|
{ socket: connectSocket, servername: TELEGRAM_API_HOST },
|
|
71979
72109
|
() => {
|
|
@@ -71983,7 +72113,7 @@ Host: ${TELEGRAM_API_HOST}:${TELEGRAM_API_PORT}\r
|
|
|
71983
72113
|
callback(null, tlsSocket);
|
|
71984
72114
|
}
|
|
71985
72115
|
);
|
|
71986
|
-
tlsSocket.once("error",
|
|
72116
|
+
tlsSocket.once("error", fail7);
|
|
71987
72117
|
});
|
|
71988
72118
|
return void 0;
|
|
71989
72119
|
});
|
|
@@ -72875,16 +73005,20 @@ function renderDeepInterviewRuntimeGuidance(availability) {
|
|
|
72875
73005
|
"If Codex becomes unavailable, briefly note that and fall back to the Claude-only recommendations already listed in Phase 5."
|
|
72876
73006
|
].join("\n");
|
|
72877
73007
|
}
|
|
73008
|
+
function resolveAvailability(availability) {
|
|
73009
|
+
if (typeof availability === "function") return availability();
|
|
73010
|
+
return availability ?? detectSkillRuntimeAvailability();
|
|
73011
|
+
}
|
|
72878
73012
|
function renderSkillRuntimeGuidance(skillName, availability) {
|
|
72879
73013
|
switch (normalizeSkillName(skillName)) {
|
|
72880
73014
|
case "deep-interview":
|
|
72881
|
-
return renderDeepInterviewRuntimeGuidance(availability
|
|
73015
|
+
return renderDeepInterviewRuntimeGuidance(resolveAvailability(availability));
|
|
72882
73016
|
case "ralplan":
|
|
72883
73017
|
case "omc-plan":
|
|
72884
73018
|
case "plan":
|
|
72885
|
-
return renderPlanRuntimeGuidance(availability
|
|
73019
|
+
return renderPlanRuntimeGuidance(resolveAvailability(availability));
|
|
72886
73020
|
case "ralph":
|
|
72887
|
-
return renderRalphRuntimeGuidance(availability
|
|
73021
|
+
return renderRalphRuntimeGuidance(resolveAvailability(availability));
|
|
72888
73022
|
default:
|
|
72889
73023
|
return "";
|
|
72890
73024
|
}
|
|
@@ -73011,12 +73145,12 @@ function applyDeepInterviewRuntimeSettings(template) {
|
|
|
73011
73145
|
function normalizeSkillNameForRuntimeRendering(skillName) {
|
|
73012
73146
|
return skillName.trim().toLowerCase().replace(/^oh-my-copilot:/, "").replace(/^omc:/, "");
|
|
73013
73147
|
}
|
|
73014
|
-
function renderBundledSkillBody(skillName, body) {
|
|
73148
|
+
function renderBundledSkillBody(skillName, body, cliOptions) {
|
|
73015
73149
|
const normalizedSkillName = normalizeSkillNameForRuntimeRendering(skillName);
|
|
73016
|
-
const rewrittenBody = rewriteOmcCliInvocations(body.trim());
|
|
73150
|
+
const rewrittenBody = rewriteOmcCliInvocations(body.trim(), cliOptions);
|
|
73017
73151
|
return normalizedSkillName === "deep-interview" || normalizedSkillName === "deep-dive" ? applyDeepInterviewRuntimeSettings(rewrittenBody) : rewrittenBody;
|
|
73018
73152
|
}
|
|
73019
|
-
function loadSkillFromFile(skillPath, skillName) {
|
|
73153
|
+
function loadSkillFromFile(skillPath, skillName, context) {
|
|
73020
73154
|
try {
|
|
73021
73155
|
const content = (0, import_fs72.readFileSync)(skillPath, "utf-8");
|
|
73022
73156
|
const { metadata, body } = parseFrontmatter(content);
|
|
@@ -73024,10 +73158,10 @@ function loadSkillFromFile(skillPath, skillName) {
|
|
|
73024
73158
|
const safePrimaryName = toSafeSkillName(resolvedName);
|
|
73025
73159
|
const pipeline = parseSkillPipelineMetadata(metadata);
|
|
73026
73160
|
const fullBody = readSkillBodyOverride(skillPath, metadata, body);
|
|
73027
|
-
const renderedBody = renderBundledSkillBody(safePrimaryName, fullBody);
|
|
73161
|
+
const renderedBody = renderBundledSkillBody(safePrimaryName, fullBody, context.cliOptions);
|
|
73028
73162
|
const template = [
|
|
73029
73163
|
renderedBody,
|
|
73030
|
-
renderSkillRuntimeGuidance(safePrimaryName),
|
|
73164
|
+
renderSkillRuntimeGuidance(safePrimaryName, context.runtimeAvailability),
|
|
73031
73165
|
renderSkillPipelineGuidance(safePrimaryName, pipeline),
|
|
73032
73166
|
renderSkillResourcesGuidance(skillPath)
|
|
73033
73167
|
].filter((section) => section.trim().length > 0).join("\n\n");
|
|
@@ -73069,6 +73203,11 @@ function loadSkillsFromDirectory() {
|
|
|
73069
73203
|
}
|
|
73070
73204
|
const skills = [];
|
|
73071
73205
|
const seenNames = /* @__PURE__ */ new Set();
|
|
73206
|
+
let availability;
|
|
73207
|
+
const context = {
|
|
73208
|
+
cliOptions: { omcAvailable: isOmcCliAvailable() },
|
|
73209
|
+
runtimeAvailability: () => availability ??= detectSkillRuntimeAvailability()
|
|
73210
|
+
};
|
|
73072
73211
|
try {
|
|
73073
73212
|
const entries = (0, import_fs72.readdirSync)(SKILLS_DIR2, { withFileTypes: true }).sort((a, b) => {
|
|
73074
73213
|
if (a.name === "skillify") return -1;
|
|
@@ -73082,7 +73221,7 @@ function loadSkillsFromDirectory() {
|
|
|
73082
73221
|
}
|
|
73083
73222
|
const skillPath = (0, import_path85.join)(SKILLS_DIR2, entry2.name, "SKILL.md");
|
|
73084
73223
|
if ((0, import_fs72.existsSync)(skillPath)) {
|
|
73085
|
-
const skillEntries = loadSkillFromFile(skillPath, entry2.name);
|
|
73224
|
+
const skillEntries = loadSkillFromFile(skillPath, entry2.name, context);
|
|
73086
73225
|
for (const skill of skillEntries) {
|
|
73087
73226
|
const key = skill.name.toLowerCase();
|
|
73088
73227
|
if (seenNames.has(key)) continue;
|
|
@@ -75285,7 +75424,7 @@ function analyzePaneContent(content) {
|
|
|
75285
75424
|
}
|
|
75286
75425
|
function scanForBlockedPanes(lines3 = 15, stateDir) {
|
|
75287
75426
|
const panes = listTmuxPanes();
|
|
75288
|
-
const
|
|
75427
|
+
const blocked2 = [];
|
|
75289
75428
|
for (const pane of panes) {
|
|
75290
75429
|
let content;
|
|
75291
75430
|
if (stateDir) {
|
|
@@ -75296,7 +75435,7 @@ function scanForBlockedPanes(lines3 = 15, stateDir) {
|
|
|
75296
75435
|
}
|
|
75297
75436
|
const analysis = analyzePaneContent(content);
|
|
75298
75437
|
if (analysis.isBlocked) {
|
|
75299
|
-
|
|
75438
|
+
blocked2.push({
|
|
75300
75439
|
...pane,
|
|
75301
75440
|
analysis,
|
|
75302
75441
|
firstDetectedAt: /* @__PURE__ */ new Date(),
|
|
@@ -75304,7 +75443,7 @@ function scanForBlockedPanes(lines3 = 15, stateDir) {
|
|
|
75304
75443
|
});
|
|
75305
75444
|
}
|
|
75306
75445
|
}
|
|
75307
|
-
return
|
|
75446
|
+
return blocked2;
|
|
75308
75447
|
}
|
|
75309
75448
|
function revalidateBlockedPanes(trackedPanes, lines3 = 15) {
|
|
75310
75449
|
if (trackedPanes.length === 0) return [];
|
|
@@ -80423,7 +80562,17 @@ async function writeAtomic3(path30, data) {
|
|
|
80423
80562
|
try {
|
|
80424
80563
|
await (0, import_promises14.writeFile)(tmp, data, "utf8");
|
|
80425
80564
|
const { rename: rename8 } = await import("node:fs/promises");
|
|
80426
|
-
|
|
80565
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
80566
|
+
try {
|
|
80567
|
+
await rename8(tmp, path30);
|
|
80568
|
+
break;
|
|
80569
|
+
} catch (error2) {
|
|
80570
|
+
const delay = WIN32_RENAME_RETRY_DELAYS_MS[attempt];
|
|
80571
|
+
const code = error2.code ?? "";
|
|
80572
|
+
if (process.platform !== "win32" || delay === void 0 || !WIN32_RENAME_RETRY_CODES.has(code)) throw error2;
|
|
80573
|
+
await new Promise((resolve58) => setTimeout(resolve58, delay));
|
|
80574
|
+
}
|
|
80575
|
+
}
|
|
80427
80576
|
} finally {
|
|
80428
80577
|
await (0, import_promises14.rm)(tmp, { force: true }).catch(() => void 0);
|
|
80429
80578
|
}
|
|
@@ -81260,7 +81409,7 @@ async function teamMarkTaskCompleted(teamName, taskId, cwd2) {
|
|
|
81260
81409
|
await writeAtomic3(p, JSON.stringify(next, null, 2));
|
|
81261
81410
|
}, 5e3);
|
|
81262
81411
|
}
|
|
81263
|
-
var import_node_crypto7, import_node_fs10, import_promises14, import_node_path15;
|
|
81412
|
+
var import_node_crypto7, import_node_fs10, import_promises14, import_node_path15, WIN32_RENAME_RETRY_CODES, WIN32_RENAME_RETRY_DELAYS_MS;
|
|
81264
81413
|
var init_team_ops = __esm({
|
|
81265
81414
|
"src/team/team-ops.ts"() {
|
|
81266
81415
|
"use strict";
|
|
@@ -81277,6 +81426,8 @@ var init_team_ops = __esm({
|
|
|
81277
81426
|
init_tasks();
|
|
81278
81427
|
init_task_recovery_checkpoint();
|
|
81279
81428
|
init_worker_canonicalization();
|
|
81429
|
+
WIN32_RENAME_RETRY_CODES = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY"]);
|
|
81430
|
+
WIN32_RENAME_RETRY_DELAYS_MS = [5, 10, 20, 40, 80, 160, 320];
|
|
81280
81431
|
}
|
|
81281
81432
|
});
|
|
81282
81433
|
|
|
@@ -81657,15 +81808,23 @@ function buildWindowsSupervisorSource() {
|
|
|
81657
81808
|
// interactive provider never reaches the pane. Stdin is read through a
|
|
81658
81809
|
// StreamReader because [Console]::In.ReadLineAsync() blocks on .NET
|
|
81659
81810
|
// Framework, which hid provider exit until the next control line.
|
|
81660
|
-
|
|
81811
|
+
// The start identity is read while the provider is still suspended: a
|
|
81812
|
+
// short-lived provider can exit before a slow host reaches the ready
|
|
81813
|
+
// frame, and Get-Process on an exited PID throws, killing the supervisor.
|
|
81814
|
+
`public static class O { [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] public struct STARTUPINFO { public int cb; public IntPtr lpReserved; public IntPtr lpDesktop; public IntPtr lpTitle; public int dwX; public int dwY; public int dwXSize; public int dwYSize; public int dwXCountChars; public int dwYCountChars; public int dwFillAttribute; public int dwFlags; public short wShowWindow; public short cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public uint dwProcessId; public uint dwThreadId; } [StructLayout(LayoutKind.Sequential)] public struct JOBOBJECT_BASIC_LIMIT_INFORMATION { public long PerProcessUserTimeLimit; public long PerJobUserTimeLimit; public uint LimitFlags; public UIntPtr MinimumWorkingSetSize; public UIntPtr MaximumWorkingSetSize; public uint ActiveProcessLimit; public UIntPtr Affinity; public uint PriorityClass; public uint SchedulingClass; } [StructLayout(LayoutKind.Sequential)] public struct IO_COUNTERS { public ulong ReadOperationCount; public ulong WriteOperationCount; public ulong OtherOperationCount; public ulong ReadTransferCount; public ulong WriteTransferCount; public ulong OtherTransferCount; } [StructLayout(LayoutKind.Sequential)] public struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION { public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; public IO_COUNTERS IoInfo; public UIntPtr ProcessMemoryLimit; public UIntPtr JobMemoryLimit; public UIntPtr PeakProcessMemoryUsed; public UIntPtr PeakJobMemoryUsed; } [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] public static extern bool CreateProcessW(string app, StringBuilder cmd, IntPtr pa, IntPtr ta, bool inherit, uint flags, IntPtr env, string dir, ref STARTUPINFO si, out PROCESS_INFORMATION pi); [DllImport("kernel32.dll", SetLastError=true)] public static extern IntPtr CreateJobObjectW(IntPtr a, string n); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool SetInformationJobObject(IntPtr j, int c, IntPtr i, uint l); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool AssignProcessToJobObject(IntPtr j, IntPtr p); [DllImport("kernel32.dll", SetLastError=true)] public static extern uint ResumeThread(IntPtr h); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool TerminateJobObject(IntPtr j, uint c); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool TerminateProcess(IntPtr p, uint c); [DllImport("kernel32.dll", SetLastError=true)] public static extern uint WaitForSingleObject(IntPtr h, uint ms); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool GetExitCodeProcess(IntPtr h, out uint code); [DllImport("kernel32.dll")] public static extern bool CloseHandle(IntPtr h); [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] public static extern IntPtr CreateFileW(string n, uint a, uint s, IntPtr sa, uint d, uint f, IntPtr t); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool SetHandleInformation(IntPtr h, uint m, uint f); public static string Quote(string value) { var b = new StringBuilder(); b.Append('"'); int slashes = 0; foreach (var c in value) { if (c == '\\\\') { slashes++; continue; } if (c == '"') { b.Append('\\\\', slashes * 2 + 1); b.Append('"'); slashes = 0; continue; } b.Append('\\\\', slashes); slashes = 0; b.Append(c); } b.Append('\\\\', slashes * 2); b.Append('"'); return b.ToString(); } public static string BuildCommandLine(string[] argv) { var b = new StringBuilder(); for (var i = 0; i < argv.Length; i++) { if (i != 0) b.Append(' '); b.Append(Quote(argv[i])); } return b.ToString(); } public static string CmdQuote(string value) { var b = new StringBuilder(); b.Append('"'); int slashes = 0; foreach (var c in value) { if (c < ' ') throw new ArgumentException("worker_launch_provider_argv_invalid"); if (c == '\\\\') { slashes++; continue; } if (c == '"') { b.Append('\\\\', slashes * 2); b.Append('"'); b.Append('"'); slashes = 0; continue; } b.Append('\\\\', slashes); slashes = 0; b.Append(c); } b.Append('\\\\', slashes * 2); b.Append('"'); return b.ToString(); } public static string BuildCmdLine(string[] argv) { var b = new StringBuilder(); for (var i = 0; i < argv.Length; i++) { if (i != 0) b.Append(' '); b.Append(CmdQuote(argv[i])); } if (b.Length > ${WINDOWS_PROVIDER_LINE_MAX}) throw new ArgumentException("worker_launch_provider_argv_too_long"); return b.ToString(); } }`,
|
|
81661
81815
|
'"@',
|
|
81662
81816
|
"$pi = New-Object O+PROCESS_INFORMATION; $job = [IntPtr]::Zero; $envPtr = [IntPtr]::Zero; $cmd = $null; $conIn = [IntPtr]::Zero; $conOut = [IntPtr]::Zero",
|
|
81663
81817
|
"try {",
|
|
81664
|
-
|
|
81665
|
-
|
|
81666
|
-
|
|
81667
|
-
|
|
81668
|
-
|
|
81818
|
+
// A .cmd/.bat argv[0] is never handed to CreateProcessW, which would run
|
|
81819
|
+
// it through cmd.exe with the MSVC-quoted line (CVE-2024-27980). cmd.exe
|
|
81820
|
+
// itself is started instead and expands the cmd-quoted line once from
|
|
81821
|
+
// its environment block, clearing the variable before the provider runs.
|
|
81822
|
+
" $argv = [string[]]$payload.provider_argv; $app = [NullString]::Value; $providerLine = $null",
|
|
81823
|
+
` if ($argv[0] -match '\\.(cmd|bat)[. ]*$') { $providerLine = [O]::BuildCmdLine($argv); $app = Join-Path ([Environment]::SystemDirectory) 'cmd.exe'; $cmd = '"' + $app + '" /d /v:off /s /c "set "${PROVIDER_LINE_VAR}=" & %${PROVIDER_LINE_VAR}%"' } else { $cmd = [O]::BuildCommandLine($argv) }`,
|
|
81824
|
+
` $envPairs = @($payload.provider_env.psobject.Properties | Where-Object { $_.Name -ne '${PROVIDER_LINE_VAR}' } | ForEach-Object { [pscustomobject]@{ Name = $_.Name; Value = $_.Value } }); if ($null -ne $providerLine) { $envPairs += [pscustomobject]@{ Name = '${PROVIDER_LINE_VAR}'; Value = $providerLine } }; $envPairs = @($envPairs | Sort-Object Name | ForEach-Object { "$($_.Name)=$($_.Value)" }); $envText = (($envPairs -join [char]0) + [char]0 + [char]0); $envBytes = [Text.Encoding]::Unicode.GetBytes($envText); $envPtr = [Runtime.InteropServices.Marshal]::AllocHGlobal($envBytes.Length); [Runtime.InteropServices.Marshal]::Copy($envBytes, 0, $envPtr, $envBytes.Length)`,
|
|
81825
|
+
` $conIn = [O]::CreateFileW('CONIN$', [uint32]3221225472, 3, [IntPtr]::Zero, 3, 0, [IntPtr]::Zero); $conOut = [O]::CreateFileW('CONOUT$', [uint32]3221225472, 3, [IntPtr]::Zero, 3, 0, [IntPtr]::Zero); if ($conIn -eq [IntPtr]::Zero -or $conIn -eq [IntPtr]::new(-1) -or $conOut -eq [IntPtr]::Zero -or $conOut -eq [IntPtr]::new(-1)) { $conIn = [IntPtr]::Zero; $conOut = [IntPtr]::Zero; throw "worker_launch_console_unavailable" }; if (-not [O]::SetHandleInformation($conIn, 1, 1) -or -not [O]::SetHandleInformation($conOut, 1, 1)) { throw "worker_launch_console_unavailable" }; $si = New-Object O+STARTUPINFO; $si.cb = [Runtime.InteropServices.Marshal]::SizeOf($si); $si.dwFlags = 0x00000100; $si.hStdInput = $conIn; $si.hStdOutput = $conOut; $si.hStdError = $conOut; $flags = 0x00000004 -bor 0x00000400; if (-not [O]::CreateProcessW($app, $cmd, [IntPtr]::Zero, [IntPtr]::Zero, $true, $flags, $envPtr, $payload.cwd, [ref]$si, [ref]$pi)) { throw "worker_launch_create_process_failed" }`,
|
|
81826
|
+
' $job = [O]::CreateJobObjectW([IntPtr]::Zero, [NullString]::Value); if ($job -eq [IntPtr]::Zero) { throw "worker_launch_create_job_failed" }; $info = New-Object O+JOBOBJECT_EXTENDED_LIMIT_INFORMATION; $info.BasicLimitInformation.LimitFlags = 0x2000; $ptr = [Runtime.InteropServices.Marshal]::AllocHGlobal([Runtime.InteropServices.Marshal]::SizeOf($info)); try { [Runtime.InteropServices.Marshal]::StructureToPtr($info, $ptr, $false); if (-not [O]::SetInformationJobObject($job, 9, $ptr, [Runtime.InteropServices.Marshal]::SizeOf($info))) { throw "worker_launch_job_config_failed" } } finally { [Runtime.InteropServices.Marshal]::FreeHGlobal($ptr) }; if (-not [O]::AssignProcessToJobObject($job, $pi.hProcess)) { throw "worker_launch_assign_job_failed" }; $ticks = ([DateTime]((Get-Process -Id $pi.dwProcessId).StartTime)).ToUniversalTime().Ticks; if ([O]::ResumeThread($pi.hThread) -eq [uint32]::MaxValue) { throw "worker_launch_resume_failed" }',
|
|
81827
|
+
' $ready = @{ protocol="' + WINDOWS_SUPERVISOR_PROTOCOL + '"; kind="ready"; attempt_id=$payload.identity.attempt_id; instance_id=$payload.identity.instance_id; authority_digest=$payload.authority_digest; containment_nonce=$payload.containment_nonce; pid=$pi.dwProcessId; process_start_identity=("ticks:" + $ticks) } | ConvertTo-Json -Compress; [Console]::Out.WriteLine($ready); [Console]::Out.Flush()',
|
|
81669
81828
|
' $stdinReader = New-Object IO.StreamReader([Console]::OpenStandardInput()); $readTask = $stdinReader.ReadLineAsync(); while ($true) { if ([O]::WaitForSingleObject($pi.hProcess, 50) -eq 0) { $exitCode = [uint32]0; [O]::GetExitCodeProcess($pi.hProcess, [ref]$exitCode) | Out-Null; if (-not [O]::TerminateJobObject($job, $exitCode)) { throw "worker_launch_job_terminate_failed" }; if ([O]::WaitForSingleObject($job, 5000) -ne 0) { throw "worker_launch_job_cleanup_timeout" }; $terminal = @{ protocol="' + WINDOWS_SUPERVISOR_PROTOCOL + '"; kind="terminal"; attempt_id=$payload.identity.attempt_id; instance_id=$payload.identity.instance_id; authority_digest=$payload.authority_digest; containment_nonce=$payload.containment_nonce; pid=$pi.dwProcessId; outcome="exit"; cleanup_verified=$true; exit_code=$exitCode } | ConvertTo-Json -Compress; [Console]::Out.WriteLine($terminal); [Console]::Out.Flush(); break }; if (-not $readTask.IsCompleted) { continue }; $line = $readTask.Result; if ($null -eq $line) { throw "worker_launch_authority_lost" }; $readTask = $stdinReader.ReadLineAsync(); if ([string]::IsNullOrWhiteSpace($line) -or $line.Length -gt 4096) { continue }; try { $msg = $line | ConvertFrom-Json } catch { continue }; if ($msg.protocol -ne "' + WINDOWS_SUPERVISOR_PROTOCOL + '" -or $msg.attempt_id -ne $payload.identity.attempt_id -or $msg.instance_id -ne $payload.identity.instance_id -or $msg.authority_digest -ne $payload.authority_digest -or $msg.containment_nonce -ne $payload.containment_nonce -or $msg.kind -ne "terminate") { continue }; if (-not [O]::TerminateJobObject($job, 1)) { throw "worker_launch_job_terminate_failed" }; if ([O]::WaitForSingleObject($job, 5000) -ne 0) { throw "worker_launch_job_cleanup_timeout" }; $terminal = @{ protocol="' + WINDOWS_SUPERVISOR_PROTOCOL + '"; kind="terminal"; attempt_id=$payload.identity.attempt_id; instance_id=$payload.identity.instance_id; authority_digest=$payload.authority_digest; containment_nonce=$payload.containment_nonce; pid=$pi.dwProcessId; outcome="terminated"; cleanup_verified=$true } | ConvertTo-Json -Compress; [Console]::Out.WriteLine($terminal); [Console]::Out.Flush(); break }',
|
|
81670
81829
|
"} catch { if ($pi.hProcess -ne [IntPtr]::Zero) { if ($job -ne [IntPtr]::Zero) { [O]::TerminateJobObject($job, 1) | Out-Null } else { [O]::TerminateProcess($pi.hProcess, 1) | Out-Null }; [O]::WaitForSingleObject($pi.hProcess, 5000) | Out-Null }; throw } finally { if ($envPtr -ne [IntPtr]::Zero) { [Runtime.InteropServices.Marshal]::FreeHGlobal($envPtr) }; if ($conIn -ne [IntPtr]::Zero) { [O]::CloseHandle($conIn) | Out-Null }; if ($conOut -ne [IntPtr]::Zero) { [O]::CloseHandle($conOut) | Out-Null }; if ($pi.hThread -ne [IntPtr]::Zero) { [O]::CloseHandle($pi.hThread) | Out-Null }; if ($pi.hProcess -ne [IntPtr]::Zero) { [O]::CloseHandle($pi.hProcess) | Out-Null }; if ($job -ne [IntPtr]::Zero) { [O]::CloseHandle($job) | Out-Null } }"
|
|
81671
81830
|
// Fork fix: a real newline. "`n" is only an escape inside PowerShell strings;
|
|
@@ -81954,6 +82113,9 @@ async function loadCurrentWorkerLaunchAttempt(input) {
|
|
|
81954
82113
|
}
|
|
81955
82114
|
function buildWorkerLaunchBootstrapSpec(attempt, providerArgv, cwd2, options = {}) {
|
|
81956
82115
|
if (!isValidIdentity(attempt)) throw new Error("worker_launch_attempt_identity_invalid");
|
|
82116
|
+
if ((options.platform ?? process.platform) === "win32" && providerArgv[0] && isWindowsBatchProvider(providerArgv[0])) {
|
|
82117
|
+
buildWindowsBatchProviderLine(providerArgv);
|
|
82118
|
+
}
|
|
81957
82119
|
const providerEnv = normalizeProviderEnvironment(options.providerEnv, options.platform ?? process.platform);
|
|
81958
82120
|
const absoluteCwd = (0, import_node_path16.resolve)(cwd2);
|
|
81959
82121
|
const containmentNonce = (0, import_node_crypto8.randomUUID)();
|
|
@@ -82682,10 +82844,19 @@ function isDeterministicTransportPath(expectedPath, candidate, fileName) {
|
|
|
82682
82844
|
return isExactText(candidate) && (0, import_node_path16.resolve)(candidate) === (0, import_node_path16.resolve)((0, import_node_path16.join)((0, import_node_path16.dirname)(expectedPath), fileName));
|
|
82683
82845
|
}
|
|
82684
82846
|
function quoteWindowsCmdArgument(value) {
|
|
82685
|
-
if (/[\
|
|
82686
|
-
|
|
82847
|
+
if (/[\x00-\x1f]/.test(value)) throw new Error("worker_launch_provider_argv_invalid");
|
|
82848
|
+
const escaped = value.replace(/(\\*)"/g, '$1$1""').replace(/(\\+)$/, "$1$1");
|
|
82849
|
+
return `"${escaped}"`;
|
|
82850
|
+
}
|
|
82851
|
+
function isWindowsBatchProvider(command) {
|
|
82852
|
+
return /\.(cmd|bat)[. ]*$/i.test(command);
|
|
82853
|
+
}
|
|
82854
|
+
function buildWindowsBatchProviderLine(providerArgv) {
|
|
82855
|
+
const line = providerArgv.map(quoteWindowsCmdArgument).join(" ");
|
|
82856
|
+
if (line.length > WINDOWS_PROVIDER_LINE_MAX) throw new Error("worker_launch_provider_argv_too_long");
|
|
82857
|
+
return line;
|
|
82687
82858
|
}
|
|
82688
|
-
var import_node_crypto8, import_node_fs11, import_promises17, import_node_path16, import_node_os2, WORKER_LAUNCH_SCHEMA_VERSION, DEFAULT_ACK_TIMEOUT_MS, DEFAULT_POLL_INTERVAL_MS, DEFAULT_DECISION_TIMEOUT_MS, WORKER_LAUNCH_TRANSPORT_OWNER_KIND, WORKER_LAUNCH_TRANSPORT_CLEANUP_KIND, WORKER_LAUNCH_BOOTSTRAP_DESCRIPTOR_FILE, WORKER_LAUNCH_RECOVERY_GATE_CONTAINED_ENV, WORKER_LAUNCH_INTERNAL_ENV_KEYS, WORKER_LAUNCH_AUTHORITY_PROTOCOL, WINDOWS_SUPERVISOR_PROTOCOL, WINDOWS_RESERVED_ENV_KEYS, SAFE_BASELINE_ENV_KEYS, WINDOWS_BASELINE_ENV_KEYS;
|
|
82859
|
+
var import_node_crypto8, import_node_fs11, import_promises17, import_node_path16, import_node_os2, WORKER_LAUNCH_SCHEMA_VERSION, DEFAULT_ACK_TIMEOUT_MS, DEFAULT_POLL_INTERVAL_MS, DEFAULT_DECISION_TIMEOUT_MS, WORKER_LAUNCH_TRANSPORT_OWNER_KIND, WORKER_LAUNCH_TRANSPORT_CLEANUP_KIND, WORKER_LAUNCH_BOOTSTRAP_DESCRIPTOR_FILE, WORKER_LAUNCH_RECOVERY_GATE_CONTAINED_ENV, WORKER_LAUNCH_INTERNAL_ENV_KEYS, WORKER_LAUNCH_AUTHORITY_PROTOCOL, WINDOWS_SUPERVISOR_PROTOCOL, WINDOWS_RESERVED_ENV_KEYS, SAFE_BASELINE_ENV_KEYS, WINDOWS_BASELINE_ENV_KEYS, WINDOWS_PROVIDER_LINE_MAX, PROVIDER_LINE_VAR;
|
|
82689
82860
|
var init_worker_launch_ack = __esm({
|
|
82690
82861
|
"src/team/worker-launch-ack.ts"() {
|
|
82691
82862
|
"use strict";
|
|
@@ -82743,6 +82914,8 @@ var init_worker_launch_ack = __esm({
|
|
|
82743
82914
|
"PUBLIC",
|
|
82744
82915
|
"ALLUSERSPROFILE"
|
|
82745
82916
|
];
|
|
82917
|
+
WINDOWS_PROVIDER_LINE_MAX = 8e3;
|
|
82918
|
+
PROVIDER_LINE_VAR = "_OMC_PROVIDER_LINE";
|
|
82746
82919
|
}
|
|
82747
82920
|
});
|
|
82748
82921
|
|
|
@@ -83180,6 +83353,7 @@ function recoveryOwnerBootstrapCandidatePath(cwd2, teamName, expectedEpoch, nonc
|
|
|
83180
83353
|
return absPath(cwd2, TeamPaths.recoveryOwnerBootstrapCandidate(teamName, expectedEpoch, nonce));
|
|
83181
83354
|
}
|
|
83182
83355
|
async function syncParentDirectory(path30) {
|
|
83356
|
+
if (process.platform === "win32") return;
|
|
83183
83357
|
const directory = await (0, import_promises18.open)((0, import_node_path17.dirname)(path30), "r");
|
|
83184
83358
|
try {
|
|
83185
83359
|
await directory.sync();
|
|
@@ -84120,24 +84294,24 @@ async function runGuardedNativeTmuxCommand(identity, nativeCommand) {
|
|
|
84120
84294
|
exec: tmuxCmdAsync
|
|
84121
84295
|
});
|
|
84122
84296
|
}
|
|
84123
|
-
const
|
|
84297
|
+
const guarded4 = tmuxGuardedNativeCommand(identity, nativeCommand);
|
|
84124
84298
|
try {
|
|
84125
84299
|
const result = await tmuxCmdAsync(
|
|
84126
84300
|
tmuxArgsForIdentity(identity, [
|
|
84127
84301
|
"if-shell",
|
|
84128
|
-
|
|
84129
|
-
|
|
84130
|
-
|
|
84302
|
+
guarded4.condition,
|
|
84303
|
+
guarded4.success,
|
|
84304
|
+
guarded4.failure
|
|
84131
84305
|
]),
|
|
84132
84306
|
{ timeout: 5e3, stripTmux: true }
|
|
84133
84307
|
);
|
|
84134
84308
|
if (result.stderr.trim()) return { outcome: "unknown", stdout: result.stdout, stderr: result.stderr };
|
|
84135
84309
|
const outputLines = result.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
84136
|
-
const failureMarker = `OMC_TMUX_GUARD_FAIL_${
|
|
84310
|
+
const failureMarker = `OMC_TMUX_GUARD_FAIL_${guarded4.marker}`;
|
|
84137
84311
|
if (outputLines.includes(failureMarker)) {
|
|
84138
84312
|
return { outcome: "not_executed", stdout: result.stdout, stderr: result.stderr };
|
|
84139
84313
|
}
|
|
84140
|
-
if (outputLines.includes(
|
|
84314
|
+
if (outputLines.includes(guarded4.marker)) {
|
|
84141
84315
|
return { outcome: "executed", stdout: result.stdout, stderr: result.stderr };
|
|
84142
84316
|
}
|
|
84143
84317
|
return { outcome: "unknown", stdout: result.stdout, stderr: result.stderr };
|
|
@@ -86173,31 +86347,31 @@ async function killOwnedWorkerPane(ownership) {
|
|
|
86173
86347
|
}
|
|
86174
86348
|
function detectPaneTrustPromptKind(captured, provider) {
|
|
86175
86349
|
const lines3 = captured.split("\n").map((l) => l.replace(/\r/g, "").trim()).filter((l) => l.length > 0);
|
|
86176
|
-
const
|
|
86177
|
-
const hasCursorTrustBanner =
|
|
86178
|
-
const hasCursorTrustHint =
|
|
86179
|
-
if ((provider === void 0 || provider === "cursor") && hasCursorTrustBanner && (hasCursorTrustHint ||
|
|
86350
|
+
const tail3 = lines3.slice(-12);
|
|
86351
|
+
const hasCursorTrustBanner = tail3.some((l) => /Workspace Trust Required/i.test(l));
|
|
86352
|
+
const hasCursorTrustHint = tail3.some((l) => /Pass\s+--trust,\s*--yolo,\s*or\s+-f/i.test(l));
|
|
86353
|
+
if ((provider === void 0 || provider === "cursor") && hasCursorTrustBanner && (hasCursorTrustHint || tail3.some((l) => /Do you trust the contents of this directory\?/i.test(l)))) {
|
|
86180
86354
|
return "cursor_workspace_trust";
|
|
86181
86355
|
}
|
|
86182
|
-
const hasClaudeDirectoryQuestion =
|
|
86356
|
+
const hasClaudeDirectoryQuestion = tail3.some(
|
|
86183
86357
|
(l) => /(?:Do you trust the files in this folder|Quick safety check:\s*Is this a project you created or one you trust)\?/i.test(l)
|
|
86184
86358
|
);
|
|
86185
|
-
const hasClaudeDirectoryNoChoice =
|
|
86186
|
-
const hasClaudeDirectoryYesChoice =
|
|
86359
|
+
const hasClaudeDirectoryNoChoice = tail3.some((l) => /\bNo,\s*exit\b/i.test(l));
|
|
86360
|
+
const hasClaudeDirectoryYesChoice = tail3.some((l) => /\bYes,\s*(?:proceed|I trust this folder)\b/i.test(l));
|
|
86187
86361
|
if (provider === "claude" && hasClaudeDirectoryQuestion && hasClaudeDirectoryNoChoice && hasClaudeDirectoryYesChoice) {
|
|
86188
86362
|
return "claude_directory";
|
|
86189
86363
|
}
|
|
86190
|
-
const hasCopilotYesChoice =
|
|
86191
|
-
const hasCopilotNoChoice =
|
|
86364
|
+
const hasCopilotYesChoice = tail3.some((l) => /\b1\.\s*Yes\s*(?:│|$)/.test(l));
|
|
86365
|
+
const hasCopilotNoChoice = tail3.some((l) => /\b3\.\s*No\s*\(Esc\)/i.test(l));
|
|
86192
86366
|
if (provider === "copilot" && hasClaudeDirectoryQuestion && hasCopilotYesChoice && hasCopilotNoChoice) {
|
|
86193
86367
|
return "copilot_folder";
|
|
86194
86368
|
}
|
|
86195
|
-
const hasDirectoryQuestion =
|
|
86196
|
-
const hasDirectoryChoices =
|
|
86369
|
+
const hasDirectoryQuestion = tail3.some((l) => /Do you trust the contents of this directory\?/i.test(l));
|
|
86370
|
+
const hasDirectoryChoices = tail3.some((l) => /Yes,\s*continue|No,\s*quit|Press enter to continue/i.test(l));
|
|
86197
86371
|
if (hasDirectoryQuestion && hasDirectoryChoices) return "directory";
|
|
86198
|
-
const hasHookReview =
|
|
86199
|
-
const hasHookTrustChoice =
|
|
86200
|
-
const hasHookConfirm =
|
|
86372
|
+
const hasHookReview = tail3.some((l) => /Hooks need review/i.test(l));
|
|
86373
|
+
const hasHookTrustChoice = tail3.some((l) => /Continue without trusting/i.test(l));
|
|
86374
|
+
const hasHookConfirm = tail3.some((l) => /Press enter to confirm or esc to go back/i.test(l));
|
|
86201
86375
|
if (hasHookReview && hasHookTrustChoice && hasHookConfirm) return "codex_hooks";
|
|
86202
86376
|
return null;
|
|
86203
86377
|
}
|
|
@@ -86225,13 +86399,13 @@ function paneIsBootstrapping(captured, provider) {
|
|
|
86225
86399
|
}
|
|
86226
86400
|
function paneHasActiveTask(captured, provider) {
|
|
86227
86401
|
const lines3 = captured.split("\n").map((l) => l.replace(/\r/g, "").trim()).filter((l) => l.length > 0);
|
|
86228
|
-
const
|
|
86229
|
-
if (provider === "cursor" &&
|
|
86230
|
-
if (provider === "copilot" &&
|
|
86231
|
-
if (
|
|
86232
|
-
if (
|
|
86233
|
-
if (
|
|
86234
|
-
if (
|
|
86402
|
+
const tail3 = lines3.slice(-40);
|
|
86403
|
+
if (provider === "cursor" && tail3.some((l) => /ctrl\+c\s+to\s+stop/i.test(l))) return true;
|
|
86404
|
+
if (provider === "copilot" && tail3.some((l) => /^\S?\s*Working\b.*\besc\b/u.test(l))) return true;
|
|
86405
|
+
if (tail3.some((l) => /\b\d+\s+background terminal running\b/i.test(l))) return true;
|
|
86406
|
+
if (tail3.some((l) => /esc to interrupt/i.test(l))) return true;
|
|
86407
|
+
if (tail3.some((l) => /\bbackground terminal running\b/i.test(l))) return true;
|
|
86408
|
+
if (tail3.some((l) => /^[·✻✢✳✶✽✺✹✸✷*]\s+[A-Za-z][A-Za-z0-9''-]*(?:\s+[A-Za-z][A-Za-z0-9''-]*){0,3}(?:…|\.{3})(?:\s*\(.*\))?$/u.test(l))) return true;
|
|
86235
86409
|
return false;
|
|
86236
86410
|
}
|
|
86237
86411
|
function paneLooksReady(captured, provider) {
|
|
@@ -90479,8 +90653,8 @@ async function startMergeOrchestrator(config2) {
|
|
|
90479
90653
|
let persisted = { lastShas: {} };
|
|
90480
90654
|
if ((0, import_node_fs17.existsSync)(persistedPath)) {
|
|
90481
90655
|
try {
|
|
90482
|
-
const { readFileSync:
|
|
90483
|
-
persisted = JSON.parse(
|
|
90656
|
+
const { readFileSync: readFileSync143 } = await import("node:fs");
|
|
90657
|
+
persisted = JSON.parse(readFileSync143(persistedPath, "utf-8"));
|
|
90484
90658
|
} catch {
|
|
90485
90659
|
persisted = { lastShas: {} };
|
|
90486
90660
|
}
|
|
@@ -90925,8 +91099,8 @@ async function recoverFromRestart(config2) {
|
|
|
90925
91099
|
let persistedShasLoaded = 0;
|
|
90926
91100
|
if ((0, import_node_fs17.existsSync)(persistedPath)) {
|
|
90927
91101
|
try {
|
|
90928
|
-
const { readFileSync:
|
|
90929
|
-
const persisted = JSON.parse(
|
|
91102
|
+
const { readFileSync: readFileSync143 } = await import("node:fs");
|
|
91103
|
+
const persisted = JSON.parse(readFileSync143(persistedPath, "utf-8"));
|
|
90930
91104
|
persistedShasLoaded = Object.keys(persisted.lastShas ?? {}).length;
|
|
90931
91105
|
} catch {
|
|
90932
91106
|
persistedShasLoaded = 0;
|
|
@@ -91674,6 +91848,11 @@ function permitScopedRead(req, ctx) {
|
|
|
91674
91848
|
const platform = ctx.platform ?? process.platform;
|
|
91675
91849
|
return isUnder(req.path, ctx.pluginRoot, platform) || isUnder(req.path, ctx.projectDir, platform);
|
|
91676
91850
|
}
|
|
91851
|
+
function permitProjectFiles(req, ctx) {
|
|
91852
|
+
const platform = ctx.platform ?? process.platform;
|
|
91853
|
+
const target = req.kind === "read" ? req.path : req.kind === "write" ? req.resolvedPath ?? req.fileName : void 0;
|
|
91854
|
+
return typeof target === "string" && !!target && isUnder((0, import_path115.resolve)(ctx.projectDir, target), ctx.projectDir, platform);
|
|
91855
|
+
}
|
|
91677
91856
|
function evaluateTeam(run) {
|
|
91678
91857
|
const team = run.team;
|
|
91679
91858
|
if (!team) return scenarioCheckIds("team").slice(0, 8).map((id) => ({ id, ok: false, detail: run.error ? `no team evidence: ${excerpt(run.error, 200)}` : "no team evidence collected" }));
|
|
@@ -91806,6 +91985,121 @@ function evaluateChain(run) {
|
|
|
91806
91985
|
}
|
|
91807
91986
|
];
|
|
91808
91987
|
}
|
|
91988
|
+
function probeHooksJson(node, script, log3) {
|
|
91989
|
+
const hooks = {};
|
|
91990
|
+
for (const e of PROBE_ENTRIES) {
|
|
91991
|
+
(hooks[e.event] ??= []).push({
|
|
91992
|
+
type: "command",
|
|
91993
|
+
..."matcher" in e ? { matcher: e.matcher } : {},
|
|
91994
|
+
exec: node,
|
|
91995
|
+
args: [script, e.label, log3],
|
|
91996
|
+
timeoutSec: 10
|
|
91997
|
+
});
|
|
91998
|
+
}
|
|
91999
|
+
return { version: 1, hooks };
|
|
92000
|
+
}
|
|
92001
|
+
function fileToolCalls(events) {
|
|
92002
|
+
const done = new Map(events.filter((e) => e.type === "tool.execution_complete").map((e) => [str2(e.data?.toolCallId), e.data?.success === true]));
|
|
92003
|
+
return events.filter((e) => e.type === "tool.execution_start" && [...FILE_READ_TOOLS, ...FILE_WRITE_TOOLS].includes(str2(e.data?.toolName))).map((e) => ({ id: str2(e.data?.toolCallId), name: str2(e.data?.toolName), args: e.data?.arguments, ok: done.get(str2(e.data?.toolCallId)) === true }));
|
|
92004
|
+
}
|
|
92005
|
+
function asObject(value) {
|
|
92006
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
92007
|
+
}
|
|
92008
|
+
function inputPaths(input) {
|
|
92009
|
+
if (typeof input === "string") return [...input.matchAll(PATCH_FILE_LINE)].map((m) => m[1]);
|
|
92010
|
+
const o = asObject(input);
|
|
92011
|
+
const p = o ? str2(o.file_path) || str2(o.path) : "";
|
|
92012
|
+
return p ? [p] : [];
|
|
92013
|
+
}
|
|
92014
|
+
function probeTool(r) {
|
|
92015
|
+
const p = r.payload ?? {};
|
|
92016
|
+
return { name: str2(p.tool_name) || str2(p.toolName), input: p.tool_input ?? p.toolArgs };
|
|
92017
|
+
}
|
|
92018
|
+
function inputKey(input) {
|
|
92019
|
+
if (typeof input === "string") return `text:${input}`;
|
|
92020
|
+
const o = asObject(input);
|
|
92021
|
+
return o ? JSON.stringify(o, Object.keys(o).sort()) : "";
|
|
92022
|
+
}
|
|
92023
|
+
function recordsFor(call, records2, label) {
|
|
92024
|
+
const want = inputKey(call.args);
|
|
92025
|
+
return want ? records2.filter((r) => r.label === label && inputKey(probeTool(r).input) === want) : [];
|
|
92026
|
+
}
|
|
92027
|
+
function toolResultTexts(events, callId) {
|
|
92028
|
+
const out = [];
|
|
92029
|
+
for (const e of events) {
|
|
92030
|
+
if (str2(e.data?.toolCallId) !== callId) continue;
|
|
92031
|
+
if (e.type === "tool.execution_complete") out.push(str2(asObject(e.data?.result)?.content));
|
|
92032
|
+
if (e.type === "model.tool_execution") out.push(str2(asObject(e.data?.toolResult)?.textResultForLlm));
|
|
92033
|
+
}
|
|
92034
|
+
return out.filter(Boolean);
|
|
92035
|
+
}
|
|
92036
|
+
function evaluateFiletools(run) {
|
|
92037
|
+
const ft = run.filetools;
|
|
92038
|
+
const ids = scenarioCheckIds("filetools");
|
|
92039
|
+
if (!ft) return ids.slice(0, 8).map((id) => ({ id, ok: false, detail: run.error ? `no filetools evidence: ${excerpt(run.error, 200)}` : "no filetools evidence collected" }));
|
|
92040
|
+
const calls = fileToolCalls(run.events).filter((c) => c.ok);
|
|
92041
|
+
const reads = calls.filter((c) => FILE_READ_TOOLS.includes(c.name));
|
|
92042
|
+
const writes = calls.filter((c) => FILE_WRITE_TOOLS.includes(c.name));
|
|
92043
|
+
const toolsOk = reads.length > 0 && writes.length > 0 && ft.edited && ft.created;
|
|
92044
|
+
const seen = (claudeLabel, nativeLabel) => {
|
|
92045
|
+
const rows = calls.map((c) => ({ c, claude: recordsFor(c, ft.probe, claudeLabel), native: nativeLabel ? recordsFor(c, ft.probe, nativeLabel) : [] }));
|
|
92046
|
+
const ok = calls.length > 0 && rows.every((r) => r.claude.length > 0 && (!nativeLabel || r.native.length > 0));
|
|
92047
|
+
const names = (recs) => [...new Set(recs.map((x) => probeTool(x).name || "?"))].join("/") || "none";
|
|
92048
|
+
const detail = rows.map((r) => `${r.c.name}\u2192${names(r.claude)}${nativeLabel ? ` (native ${names(r.native)})` : ""}`).join(", ") || "no file tool calls";
|
|
92049
|
+
return { ok, detail, rows };
|
|
92050
|
+
};
|
|
92051
|
+
const pre = seen("PreToolUse", "preToolUse");
|
|
92052
|
+
const post = seen("PostToolUse", "postToolUse");
|
|
92053
|
+
const matcher = seen("PostToolUse:matcher");
|
|
92054
|
+
const claudeNames = new Set(FILE_TOOL_MATCHER.split("|"));
|
|
92055
|
+
const payloadRows = [...pre.rows, ...post.rows];
|
|
92056
|
+
const payloadOk = calls.length > 0 && payloadRows.every((r) => r.claude.every((x) => claudeNames.has(probeTool(x).name) && inputPaths(probeTool(x).input).length > 0) && r.native.every((x) => probeTool(x).name === r.c.name));
|
|
92057
|
+
const shape = (recs) => {
|
|
92058
|
+
if (!recs[0]) return "none";
|
|
92059
|
+
const { name, input } = probeTool(recs[0]);
|
|
92060
|
+
return typeof input === "string" ? `${name} "<patch: ${inputPaths(input).map((p) => p.split(/[\\/]/).slice(-2).join("/")).join(", ")}>"` : `${name} {${Object.keys(asObject(input) ?? {}).join(",")}}`;
|
|
92061
|
+
};
|
|
92062
|
+
const contextCall = (c) => inputPaths(c.args).some((p) => /readme\.md$/i.test(p));
|
|
92063
|
+
const injection = (nonce, from) => {
|
|
92064
|
+
const hookOut = run.events.some((e) => e.type === "hook.end" && e.data?.hookType === "postToolUse" && JSON.stringify(e.data?.output ?? "").includes(nonce));
|
|
92065
|
+
const carrier = from.find((c) => !contextCall(c) && toolResultTexts(run.events, c.id).some((t) => t.includes(nonce)));
|
|
92066
|
+
return {
|
|
92067
|
+
ok: hookOut && !!carrier,
|
|
92068
|
+
detail: `nonce ${hookOut ? "in" : "missing from"} a postToolUse hook.end output; ${carrier ? `in the ${carrier.name} tool result sent to the model` : "in no model-facing tool result"}`
|
|
92069
|
+
};
|
|
92070
|
+
};
|
|
92071
|
+
const read = injection(ft.nonce, reads);
|
|
92072
|
+
const write = injection(ft.writeNonce, writes);
|
|
92073
|
+
const echoed = assistantText2(run.events).includes(ft.nonce);
|
|
92074
|
+
return [
|
|
92075
|
+
{
|
|
92076
|
+
id: "scn.filetools.tools",
|
|
92077
|
+
ok: toolsOk,
|
|
92078
|
+
detail: `${calls.map((c) => c.name).join(", ") || "no file tool calls"} completed; notes.txt ${ft.edited ? "edited" : "unchanged"}, created.txt ${ft.created ? "created" : "missing"}`
|
|
92079
|
+
},
|
|
92080
|
+
hookCheck("scn.filetools.hooks", run.events, ["preToolUse", "postToolUse"]),
|
|
92081
|
+
{ id: "scn.filetools.pre", ok: pre.ok, detail: `PreToolUse probe: ${pre.detail}` },
|
|
92082
|
+
{ id: "scn.filetools.post", ok: post.ok, detail: `PostToolUse probe: ${post.detail}` },
|
|
92083
|
+
{ id: "scn.filetools.matcher", ok: matcher.ok, detail: `PostToolUse matcher ${FILE_TOOL_MATCHER}: ${matcher.detail}` },
|
|
92084
|
+
{
|
|
92085
|
+
id: "scn.filetools.payload",
|
|
92086
|
+
ok: payloadOk,
|
|
92087
|
+
detail: post.rows.map((r) => `${r.c.name}: tool_name ${shape(r.claude)}`).join("; ") || "no file tool calls",
|
|
92088
|
+
...payloadOk ? {} : { evidence: excerpt(JSON.stringify(payloadRows.map((r) => ({ call: r.c.name, claude: r.claude.map(probeTool), native: r.native.map(probeTool) })))) }
|
|
92089
|
+
},
|
|
92090
|
+
{
|
|
92091
|
+
id: "scn.filetools.injected",
|
|
92092
|
+
ok: read.ok,
|
|
92093
|
+
detail: `${FILETOOLS_FILES.context} ${read.detail}; model ${echoed ? "echoed it" : "did not echo it"}`,
|
|
92094
|
+
...read.ok ? {} : { evidence: excerpt(assistantText2(run.events)) }
|
|
92095
|
+
},
|
|
92096
|
+
{
|
|
92097
|
+
id: "scn.filetools.injected_write",
|
|
92098
|
+
ok: write.ok,
|
|
92099
|
+
detail: `${FILETOOLS_FILES.writeContext} ${write.detail}`
|
|
92100
|
+
}
|
|
92101
|
+
];
|
|
92102
|
+
}
|
|
91809
92103
|
function scenarioExcludedTools(name, mcpServer) {
|
|
91810
92104
|
return [hostSmokeToolName(mcpServer), ...SCENARIOS[name].excludedTools];
|
|
91811
92105
|
}
|
|
@@ -91815,6 +92109,7 @@ function scenarioCheckIds(name) {
|
|
|
91815
92109
|
guardrail: ["denied", "no_push", "hooks"],
|
|
91816
92110
|
skill: ["invoked"],
|
|
91817
92111
|
delegate: ["selected", "hooks", "completed"],
|
|
92112
|
+
filetools: ["tools", "hooks", "pre", "post", "matcher", "payload", "injected", "injected_write"],
|
|
91818
92113
|
chain: ["link1", "spawned", "inherited", "closed", "premium"],
|
|
91819
92114
|
team: ["started", "completed", "committed", "status", "shutdown", "retained", "duration", "premium"]
|
|
91820
92115
|
};
|
|
@@ -92111,6 +92406,7 @@ function evaluateScenario(run) {
|
|
|
92111
92406
|
guardrail: evaluateGuardrail,
|
|
92112
92407
|
skill: evaluateSkill,
|
|
92113
92408
|
delegate: evaluateDelegate,
|
|
92409
|
+
filetools: evaluateFiletools,
|
|
92114
92410
|
chain: evaluateChain,
|
|
92115
92411
|
team: evaluateTeam
|
|
92116
92412
|
}[run.name](run);
|
|
@@ -92124,7 +92420,7 @@ function chooseModel(listed, requested) {
|
|
|
92124
92420
|
if (cheap) return { model: cheap, label: cheap, note: `cheapest-looking of ${ids.length} listed` };
|
|
92125
92421
|
return { label: "auto", note: `models.list offers ${ids.join(", ") || "nothing"}; no cheap explicit model, runtime auto-routes` };
|
|
92126
92422
|
}
|
|
92127
|
-
var import_fs92, import_path115, ALL_SCENARIOS, OPT_IN_SCENARIOS, KNOWN_SCENARIOS, DEFAULT_SCENARIOS, PLUGIN_NAME2, DELEGATE_AGENT, MIN_PROTOCOL_VERSION, SDK_PACKAGE, SDK_MISSING_DETAIL, NO_SHELL_OR_WRITE_TOOLS, NO_WRITE_TOOLS, denyAll, GUARDRAIL_COMMAND, SCENARIOS, TEAM_FILES, TEAM_WORKERS, TEAM_MAX_PREMIUM_REQUESTS, TEAM_BUDGET_MS, CHAIN_INTENT_ID, CHAIN_SKILL, CHAIN_LINK1_STAGE, CHAIN_LINK2_STAGE, CHAIN_MAX_PREMIUM_REQUESTS, ledgerStr, SDK_STATIC_IDS, RUNTIME_MIN_MAX_CREDITS, CREDIT_CAP_SKIP_DETAIL, NANO, GUARDRAIL_MARKER, CHEAP_MODEL;
|
|
92423
|
+
var import_fs92, import_path115, ALL_SCENARIOS, OPT_IN_SCENARIOS, KNOWN_SCENARIOS, DEFAULT_SCENARIOS, PLUGIN_NAME2, DELEGATE_AGENT, MIN_PROTOCOL_VERSION, SDK_PACKAGE, SDK_MISSING_DETAIL, NO_SHELL_OR_WRITE_TOOLS, NO_WRITE_TOOLS, denyAll, GUARDRAIL_COMMAND, FILETOOLS_DIR, FILETOOLS_FILES, FILETOOLS_MARKER, FILE_TOOL_MATCHER, SCENARIOS, TEAM_FILES, TEAM_WORKERS, TEAM_MAX_PREMIUM_REQUESTS, TEAM_BUDGET_MS, CHAIN_INTENT_ID, CHAIN_SKILL, CHAIN_LINK1_STAGE, CHAIN_LINK2_STAGE, CHAIN_MAX_PREMIUM_REQUESTS, ledgerStr, PROBE_ENTRIES, FILE_READ_TOOLS, FILE_WRITE_TOOLS, PATCH_FILE_LINE, SDK_STATIC_IDS, RUNTIME_MIN_MAX_CREDITS, CREDIT_CAP_SKIP_DETAIL, NANO, GUARDRAIL_MARKER, CHEAP_MODEL;
|
|
92128
92424
|
var init_copilot_sdk_scenarios = __esm({
|
|
92129
92425
|
"src/smoke/copilot-sdk-scenarios.ts"() {
|
|
92130
92426
|
"use strict";
|
|
@@ -92132,7 +92428,7 @@ var init_copilot_sdk_scenarios = __esm({
|
|
|
92132
92428
|
import_path115 = require("path");
|
|
92133
92429
|
init_copilot_session_eval();
|
|
92134
92430
|
ALL_SCENARIOS = ["smoke", "guardrail", "skill", "delegate"];
|
|
92135
|
-
OPT_IN_SCENARIOS = ["chain", "team"];
|
|
92431
|
+
OPT_IN_SCENARIOS = ["filetools", "chain", "team"];
|
|
92136
92432
|
KNOWN_SCENARIOS = [...ALL_SCENARIOS, ...OPT_IN_SCENARIOS];
|
|
92137
92433
|
DEFAULT_SCENARIOS = ["smoke", "guardrail"];
|
|
92138
92434
|
PLUGIN_NAME2 = "oh-my-copilot";
|
|
@@ -92144,6 +92440,21 @@ var init_copilot_sdk_scenarios = __esm({
|
|
|
92144
92440
|
NO_WRITE_TOOLS = ["create", "edit"];
|
|
92145
92441
|
denyAll = () => false;
|
|
92146
92442
|
GUARDRAIL_COMMAND = /^\s*git\s+push\s+(--force|-f)\s+origin\s+main\s*$/;
|
|
92443
|
+
FILETOOLS_DIR = "filetools";
|
|
92444
|
+
FILETOOLS_FILES = {
|
|
92445
|
+
notes: `${FILETOOLS_DIR}/notes.txt`,
|
|
92446
|
+
created: `${FILETOOLS_DIR}/new/created.txt`,
|
|
92447
|
+
/**
|
|
92448
|
+
* Picked up by post-tool-directory-context-injector.mjs (README.md, not
|
|
92449
|
+
* AGENTS.md: Copilot loads AGENTS.md itself). The injector sends each
|
|
92450
|
+
* README once per session, so the read (view of notes.txt) and the write
|
|
92451
|
+
* (creating created.txt) each get their own.
|
|
92452
|
+
*/
|
|
92453
|
+
context: `${FILETOOLS_DIR}/README.md`,
|
|
92454
|
+
writeContext: `${FILETOOLS_DIR}/new/README.md`
|
|
92455
|
+
};
|
|
92456
|
+
FILETOOLS_MARKER = "Context marker:";
|
|
92457
|
+
FILE_TOOL_MATCHER = "Read|Write|Edit|MultiEdit";
|
|
92147
92458
|
SCENARIOS = {
|
|
92148
92459
|
smoke: {
|
|
92149
92460
|
name: "smoke",
|
|
@@ -92173,6 +92484,19 @@ var init_copilot_sdk_scenarios = __esm({
|
|
|
92173
92484
|
excludedTools: [...NO_SHELL_OR_WRITE_TOOLS],
|
|
92174
92485
|
permit: permitScopedRead
|
|
92175
92486
|
},
|
|
92487
|
+
// The fixture (FILETOOLS_FILES) and the probe plugin are written by the driver.
|
|
92488
|
+
filetools: {
|
|
92489
|
+
name: "filetools",
|
|
92490
|
+
prompt: [
|
|
92491
|
+
`Use only your file tools, never a shell, and touch no file outside the ${FILETOOLS_DIR} directory.`,
|
|
92492
|
+
`1. View ${FILETOOLS_FILES.notes}.`,
|
|
92493
|
+
`2. Edit ${FILETOOLS_FILES.notes} so that the line "status: draft" reads "status: done".`,
|
|
92494
|
+
`3. Create ${FILETOOLS_FILES.created} containing exactly the line "created".`,
|
|
92495
|
+
`Do not open any other file. Then, if context added during these steps contained lines starting with "${FILETOOLS_MARKER}", repeat each of them verbatim; otherwise reply NO MARKER.`
|
|
92496
|
+
].join("\n"),
|
|
92497
|
+
excludedTools: ["powershell", "shell"],
|
|
92498
|
+
permit: permitProjectFiles
|
|
92499
|
+
},
|
|
92176
92500
|
// Not an SDK session: the prompt is link 1's, spawned as a real `copilot -p`
|
|
92177
92501
|
// factory link (copilot-chain-scenario.ts) under the AFK profile.
|
|
92178
92502
|
chain: {
|
|
@@ -92204,6 +92528,16 @@ var init_copilot_sdk_scenarios = __esm({
|
|
|
92204
92528
|
CHAIN_LINK2_STAGE = "link-2";
|
|
92205
92529
|
CHAIN_MAX_PREMIUM_REQUESTS = 2;
|
|
92206
92530
|
ledgerStr = (ledger, key) => str2(ledger?.[key]);
|
|
92531
|
+
PROBE_ENTRIES = [
|
|
92532
|
+
{ event: "PreToolUse", label: "PreToolUse" },
|
|
92533
|
+
{ event: "PostToolUse", label: "PostToolUse" },
|
|
92534
|
+
{ event: "PostToolUse", label: "PostToolUse:matcher", matcher: FILE_TOOL_MATCHER },
|
|
92535
|
+
{ event: "preToolUse", label: "preToolUse" },
|
|
92536
|
+
{ event: "postToolUse", label: "postToolUse" }
|
|
92537
|
+
];
|
|
92538
|
+
FILE_READ_TOOLS = ["view"];
|
|
92539
|
+
FILE_WRITE_TOOLS = ["create", "edit", "str_replace_editor", "apply_patch"];
|
|
92540
|
+
PATCH_FILE_LINE = /^\*\*\* (?:(?:Add|Update|Delete) File|Move to): (.+?)\s*$/gm;
|
|
92207
92541
|
SDK_STATIC_IDS = ["sdk.available", "sdk.runtime", "sdk.plugins", "sdk.skills", "sdk.agents", "sdk.mcp", "sdk.tools_excluded"];
|
|
92208
92542
|
RUNTIME_MIN_MAX_CREDITS = 30;
|
|
92209
92543
|
CREDIT_CAP_SKIP_DETAIL = "skipped: credit cap reached";
|
|
@@ -92311,9 +92645,11 @@ __export(copilot_sdk_driver_exports, {
|
|
|
92311
92645
|
DEFAULT_SCENARIO_TIMEOUT_MS: () => DEFAULT_SCENARIO_TIMEOUT_MS,
|
|
92312
92646
|
RUNTIME_WEDGED_DETAIL: () => RUNTIME_WEDGED_DETAIL,
|
|
92313
92647
|
SDK_MIN_VERSION: () => SDK_MIN_VERSION,
|
|
92648
|
+
collectFiletools: () => collectFiletools,
|
|
92314
92649
|
globalModuleRoots: () => globalModuleRoots,
|
|
92315
92650
|
importFromDir: () => importFromDir,
|
|
92316
92651
|
loadCopilotSdk: () => loadCopilotSdk,
|
|
92652
|
+
prepareFiletools: () => prepareFiletools,
|
|
92317
92653
|
prepareSdkProject: () => prepareSdkProject,
|
|
92318
92654
|
resolveShimTarget: () => resolveShimTarget,
|
|
92319
92655
|
runSdkTier: () => runSdkTier,
|
|
@@ -92386,8 +92722,8 @@ function exportPath(target, condition) {
|
|
|
92386
92722
|
if (typeof cond === "string") return cond;
|
|
92387
92723
|
return typeof cond?.default === "string" ? cond.default : void 0;
|
|
92388
92724
|
}
|
|
92389
|
-
function npmRootG(env2,
|
|
92390
|
-
const res = process.platform === "win32" ?
|
|
92725
|
+
function npmRootG(env2, spawnSync18) {
|
|
92726
|
+
const res = process.platform === "win32" ? spawnSync18("npm root -g", { env: env2, encoding: "utf8", timeout: 15e3, windowsHide: true, shell: true }) : spawnSync18("npm", ["root", "-g"], { env: env2, encoding: "utf8", timeout: 15e3 });
|
|
92391
92727
|
const out = String(res.stdout ?? "").trim();
|
|
92392
92728
|
return res.status === 0 && out ? out : null;
|
|
92393
92729
|
}
|
|
@@ -92427,7 +92763,7 @@ function resolveShimTarget(shim, read = (p) => (0, import_fs93.readFileSync)(p,
|
|
|
92427
92763
|
}
|
|
92428
92764
|
return null;
|
|
92429
92765
|
}
|
|
92430
|
-
async function loadCopilotSdk(env2 = process.env,
|
|
92766
|
+
async function loadCopilotSdk(env2 = process.env, spawnSync18 = import_child_process28.spawnSync) {
|
|
92431
92767
|
const spec = SDK_PACKAGE;
|
|
92432
92768
|
try {
|
|
92433
92769
|
const mod = await import(spec);
|
|
@@ -92450,7 +92786,7 @@ async function loadCopilotSdk(env2 = process.env, spawnSync17 = import_child_pro
|
|
|
92450
92786
|
const hit = await tryRoot(root2);
|
|
92451
92787
|
if (hit) return hit;
|
|
92452
92788
|
}
|
|
92453
|
-
return tryRoot(npmRootG(env2,
|
|
92789
|
+
return tryRoot(npmRootG(env2, spawnSync18));
|
|
92454
92790
|
}
|
|
92455
92791
|
function withTimeout(promise, ms, label) {
|
|
92456
92792
|
let timer;
|
|
@@ -92499,8 +92835,8 @@ function pidAlive(pid) {
|
|
|
92499
92835
|
return err.code === "EPERM";
|
|
92500
92836
|
}
|
|
92501
92837
|
}
|
|
92502
|
-
function prepareSdkProject(
|
|
92503
|
-
const git5 = (args, cwd2) =>
|
|
92838
|
+
function prepareSdkProject(spawnSync18, projectDir, remoteDir, env2) {
|
|
92839
|
+
const git5 = (args, cwd2) => spawnSync18("git", args, { cwd: cwd2, env: env2, encoding: "utf8", timeout: 3e4, windowsHide: true });
|
|
92504
92840
|
(0, import_fs93.mkdirSync)(projectDir, { recursive: true });
|
|
92505
92841
|
(0, import_fs93.writeFileSync)((0, import_path116.join)(projectDir, "hello.txt"), "omg smoke fixture\n");
|
|
92506
92842
|
const steps = [
|
|
@@ -92517,8 +92853,72 @@ function prepareSdkProject(spawnSync17, projectDir, remoteDir, env2) {
|
|
|
92517
92853
|
}
|
|
92518
92854
|
return null;
|
|
92519
92855
|
}
|
|
92520
|
-
function
|
|
92521
|
-
const
|
|
92856
|
+
function prepareFiletools(projectDir, home, node = process.execPath) {
|
|
92857
|
+
const nonce = `omg-dirctx-${(0, import_crypto33.randomBytes)(6).toString("hex")}`;
|
|
92858
|
+
const writeNonce = `omg-dirctx-${(0, import_crypto33.randomBytes)(6).toString("hex")}`;
|
|
92859
|
+
(0, import_fs93.mkdirSync)((0, import_path116.join)(projectDir, (0, import_path116.dirname)(FILETOOLS_FILES.writeContext)), { recursive: true });
|
|
92860
|
+
(0, import_fs93.writeFileSync)((0, import_path116.join)(projectDir, FILETOOLS_FILES.notes), "status: draft\n");
|
|
92861
|
+
(0, import_fs93.writeFileSync)((0, import_path116.join)(projectDir, FILETOOLS_FILES.context), `# Filetools fixture
|
|
92862
|
+
|
|
92863
|
+
${FILETOOLS_MARKER} ${nonce}
|
|
92864
|
+
`);
|
|
92865
|
+
(0, import_fs93.writeFileSync)((0, import_path116.join)(projectDir, FILETOOLS_FILES.writeContext), `# Filetools new files
|
|
92866
|
+
|
|
92867
|
+
${FILETOOLS_MARKER} ${writeNonce}
|
|
92868
|
+
`);
|
|
92869
|
+
const probeDir = (0, import_path116.join)(home, "filetools-probe");
|
|
92870
|
+
const probeLog = (0, import_path116.join)(home, "filetools-probe.jsonl");
|
|
92871
|
+
const script = (0, import_path116.join)(probeDir, "probe.cjs");
|
|
92872
|
+
(0, import_fs93.mkdirSync)(probeDir, { recursive: true });
|
|
92873
|
+
(0, import_fs93.writeFileSync)((0, import_path116.join)(probeDir, "plugin.json"), `${JSON.stringify({ name: "omg-smoke-probe", version: "0.0.0", description: "omg smoke filetools hook probe", hooks: "./hooks.json" }, null, 2)}
|
|
92874
|
+
`);
|
|
92875
|
+
(0, import_fs93.writeFileSync)((0, import_path116.join)(probeDir, "hooks.json"), `${JSON.stringify(probeHooksJson(node, script, probeLog), null, 2)}
|
|
92876
|
+
`);
|
|
92877
|
+
(0, import_fs93.writeFileSync)(script, [
|
|
92878
|
+
"'use strict';",
|
|
92879
|
+
"const fs = require('fs');",
|
|
92880
|
+
"const [label, log] = process.argv.slice(2);",
|
|
92881
|
+
"const chunks = [];",
|
|
92882
|
+
"process.stdin.on('data', (c) => chunks.push(c));",
|
|
92883
|
+
"process.stdin.on('end', () => {",
|
|
92884
|
+
" const raw = Buffer.concat(chunks).toString('utf8');",
|
|
92885
|
+
" let payload = null;",
|
|
92886
|
+
" try { payload = JSON.parse(raw); } catch { /* recorded as null */ }",
|
|
92887
|
+
" fs.appendFileSync(log, JSON.stringify({ label, payload }) + '\\n');",
|
|
92888
|
+
"});",
|
|
92889
|
+
""
|
|
92890
|
+
].join("\n"));
|
|
92891
|
+
return { nonce, writeNonce, probeDir, probeLog };
|
|
92892
|
+
}
|
|
92893
|
+
function collectFiletools(projectDir, probe) {
|
|
92894
|
+
let records2 = [];
|
|
92895
|
+
try {
|
|
92896
|
+
records2 = (0, import_fs93.readFileSync)(probe.probeLog, "utf-8").split(/\r?\n/).filter(Boolean).flatMap((line) => {
|
|
92897
|
+
try {
|
|
92898
|
+
return [JSON.parse(line)];
|
|
92899
|
+
} catch {
|
|
92900
|
+
return [];
|
|
92901
|
+
}
|
|
92902
|
+
});
|
|
92903
|
+
} catch {
|
|
92904
|
+
}
|
|
92905
|
+
const read = (rel) => {
|
|
92906
|
+
try {
|
|
92907
|
+
return (0, import_fs93.readFileSync)((0, import_path116.join)(projectDir, rel), "utf-8");
|
|
92908
|
+
} catch {
|
|
92909
|
+
return null;
|
|
92910
|
+
}
|
|
92911
|
+
};
|
|
92912
|
+
return {
|
|
92913
|
+
nonce: probe.nonce,
|
|
92914
|
+
writeNonce: probe.writeNonce,
|
|
92915
|
+
probe: records2,
|
|
92916
|
+
edited: /^status: done\s*$/m.test(read(FILETOOLS_FILES.notes) ?? ""),
|
|
92917
|
+
created: read(FILETOOLS_FILES.created) !== null
|
|
92918
|
+
};
|
|
92919
|
+
}
|
|
92920
|
+
function remoteRefs(spawnSync18, remoteDir, env2) {
|
|
92921
|
+
const res = spawnSync18("git", ["--git-dir", remoteDir, "for-each-ref"], { env: env2, encoding: "utf8", timeout: 3e4, windowsHide: true });
|
|
92522
92922
|
return res.status === 0 ? String(res.stdout ?? "") : null;
|
|
92523
92923
|
}
|
|
92524
92924
|
function runtimeCreditCap(maxCredits) {
|
|
@@ -92765,7 +93165,9 @@ async function runScenario(client, input, name, model, modelLabel, eventsPath, b
|
|
|
92765
93165
|
let wedged = false;
|
|
92766
93166
|
let spent = 0;
|
|
92767
93167
|
let error2;
|
|
93168
|
+
let probe;
|
|
92768
93169
|
try {
|
|
93170
|
+
if (name === "filetools") probe = prepareFiletools(input.projectDir, input.home);
|
|
92769
93171
|
session = await withTimeout(client.createSession({
|
|
92770
93172
|
onPermissionRequest: (req) => spec.permit(req, permitCtx) ? { kind: "approve-once" } : reject(`omg smoke ${name}: ${req.kind ?? "request"} not permitted`),
|
|
92771
93173
|
onEvent: (event) => {
|
|
@@ -92778,7 +93180,7 @@ async function runScenario(client, input, name, model, modelLabel, eventsPath, b
|
|
|
92778
93180
|
onCap();
|
|
92779
93181
|
}
|
|
92780
93182
|
},
|
|
92781
|
-
pluginDirectories: [input.root],
|
|
93183
|
+
pluginDirectories: probe ? [input.root, probe.probeDir] : [input.root],
|
|
92782
93184
|
workingDirectory: input.projectDir,
|
|
92783
93185
|
disabledMcpServers: ["github-mcp-server"],
|
|
92784
93186
|
excludedTools: scenarioExcludedTools(name, input.mcpServer),
|
|
@@ -92832,6 +93234,7 @@ async function runScenario(client, input, name, model, modelLabel, eventsPath, b
|
|
|
92832
93234
|
timeoutMs: input.timeoutMs,
|
|
92833
93235
|
...error2 ? { error: error2 } : {},
|
|
92834
93236
|
...name === "guardrail" ? { remoteRefs: remoteRefs(input.spawnSync, input.remoteDir, input.env) } : {},
|
|
93237
|
+
...probe ? { filetools: collectFiletools(input.projectDir, probe) } : {},
|
|
92835
93238
|
model: modelLabel,
|
|
92836
93239
|
maxCredits: input.maxCredits,
|
|
92837
93240
|
budget,
|
|
@@ -92839,11 +93242,12 @@ async function runScenario(client, input, name, model, modelLabel, eventsPath, b
|
|
|
92839
93242
|
wedged
|
|
92840
93243
|
};
|
|
92841
93244
|
}
|
|
92842
|
-
var import_child_process28, import_fs93, import_module3, import_path116, import_url14, SDK_MIN_VERSION, DEFAULT_SCENARIO_TIMEOUT_MS, START_TIMEOUT_MS, RPC_TIMEOUT_MS, MCP_CONNECT_WAIT_MS, ABORT_GRACE_MS, SHUTDOWN_GRACE_MS, STOP_TIMEOUT_MS, TimeoutError, sleep6, reject, RUNTIME_WEDGED_DETAIL;
|
|
93245
|
+
var import_child_process28, import_crypto33, import_fs93, import_module3, import_path116, import_url14, SDK_MIN_VERSION, DEFAULT_SCENARIO_TIMEOUT_MS, START_TIMEOUT_MS, RPC_TIMEOUT_MS, MCP_CONNECT_WAIT_MS, ABORT_GRACE_MS, SHUTDOWN_GRACE_MS, STOP_TIMEOUT_MS, TimeoutError, sleep6, reject, RUNTIME_WEDGED_DETAIL;
|
|
92843
93246
|
var init_copilot_sdk_driver = __esm({
|
|
92844
93247
|
"src/smoke/copilot-sdk-driver.ts"() {
|
|
92845
93248
|
"use strict";
|
|
92846
93249
|
import_child_process28 = require("child_process");
|
|
93250
|
+
import_crypto33 = require("crypto");
|
|
92847
93251
|
import_fs93 = require("fs");
|
|
92848
93252
|
import_module3 = require("module");
|
|
92849
93253
|
import_path116 = require("path");
|
|
@@ -96808,7 +97212,7 @@ async function processCliWorkerVerdictsUnderLock(teamName, cwd2, expectedInstanc
|
|
|
96808
97212
|
).catch(logCursorTransitionMarkerFailure);
|
|
96809
97213
|
};
|
|
96810
97214
|
const { rename: rename8 } = await import("fs/promises");
|
|
96811
|
-
const { renameSync:
|
|
97215
|
+
const { renameSync: renameSync20, readFileSync: readFileSync143, existsSync: fsExistsSync } = await import("fs");
|
|
96812
97216
|
const { withFileLockSync: withFileLockSync2 } = await Promise.resolve().then(() => (init_file_lock(), file_lock_exports));
|
|
96813
97217
|
const quarantineNonCursorVerdict = async (outputFile, artifactFingerprint, workerName, taskId, taskVersion, reason) => {
|
|
96814
97218
|
const stalePath = nonCursorVerdictStalePath(outputFile, artifactFingerprint);
|
|
@@ -96881,7 +97285,7 @@ async function processCliWorkerVerdictsUnderLock(teamName, cwd2, expectedInstanc
|
|
|
96881
97285
|
if (fsExistsSync(outputFile)) {
|
|
96882
97286
|
const stalePath = `${processingOutputFile}.stale`;
|
|
96883
97287
|
try {
|
|
96884
|
-
|
|
97288
|
+
renameSync20(processingOutputFile, stalePath);
|
|
96885
97289
|
} catch {
|
|
96886
97290
|
}
|
|
96887
97291
|
} else {
|
|
@@ -96889,9 +97293,9 @@ async function processCliWorkerVerdictsUnderLock(teamName, cwd2, expectedInstanc
|
|
|
96889
97293
|
return;
|
|
96890
97294
|
}
|
|
96891
97295
|
}
|
|
96892
|
-
const raw =
|
|
97296
|
+
const raw = readFileSync143(outputFile, "utf-8");
|
|
96893
97297
|
parseCliWorkerVerdict(raw);
|
|
96894
|
-
|
|
97298
|
+
renameSync20(outputFile, processingOutputFile);
|
|
96895
97299
|
verdictFile = processingOutputFile;
|
|
96896
97300
|
});
|
|
96897
97301
|
}
|
|
@@ -98763,7 +99167,7 @@ function readOperationFileNoFollow(operations, name) {
|
|
|
98763
99167
|
}
|
|
98764
99168
|
function writeOperationFileAtomically(operations, name, contents) {
|
|
98765
99169
|
assertSafeContainedFileName(name);
|
|
98766
|
-
const temporary = `${name}.tmp.${(0,
|
|
99170
|
+
const temporary = `${name}.tmp.${(0, import_crypto34.randomBytes)(6).toString("hex")}`;
|
|
98767
99171
|
const fd = operations.open(
|
|
98768
99172
|
temporary,
|
|
98769
99173
|
import_fs97.constants.O_WRONLY | import_fs97.constants.O_CREAT | import_fs97.constants.O_EXCL | (import_fs97.constants.O_NONBLOCK ?? 0),
|
|
@@ -98863,11 +99267,11 @@ function guardedOperations(fd, checkActive) {
|
|
|
98863
99267
|
}
|
|
98864
99268
|
};
|
|
98865
99269
|
}
|
|
98866
|
-
var
|
|
99270
|
+
var import_crypto34, import_fs97, import_path121, NO_FOLLOW, UNSAFE_CONTROL, WINDOWS_DEVICE_NAME;
|
|
98867
99271
|
var init_safe_fs = __esm({
|
|
98868
99272
|
"src/graph/runtime/safe-fs.ts"() {
|
|
98869
99273
|
"use strict";
|
|
98870
|
-
|
|
99274
|
+
import_crypto34 = require("crypto");
|
|
98871
99275
|
import_fs97 = require("fs");
|
|
98872
99276
|
import_path121 = require("path");
|
|
98873
99277
|
init_contained_fd();
|
|
@@ -99759,7 +100163,7 @@ function startReplyListener(_config) {
|
|
|
99759
100163
|
child.unref();
|
|
99760
100164
|
const pid = child.pid;
|
|
99761
100165
|
if (pid) {
|
|
99762
|
-
const generation = (0,
|
|
100166
|
+
const generation = (0, import_crypto35.randomUUID)();
|
|
99763
100167
|
writePidFile({ pid, generation });
|
|
99764
100168
|
const state = {
|
|
99765
100169
|
isRunning: true,
|
|
@@ -99932,7 +100336,7 @@ function processSlackSocketMessage(rawMessage, connectionState, paneId, config2,
|
|
|
99932
100336
|
}
|
|
99933
100337
|
return { injected: success, validation };
|
|
99934
100338
|
}
|
|
99935
|
-
var import_fs99, import_path123, import_url16, import_child_process29,
|
|
100339
|
+
var import_fs99, import_path123, import_url16, import_child_process29, import_crypto35, import_https2, __filename2, SECURE_FILE_MODE2, MAX_LOG_SIZE_BYTES, DAEMON_ENV_ALLOWLIST, DEFAULT_STATE_DIR, PID_FILE_PATH, STATE_FILE_PATH, LOG_FILE_PATH, APPROVAL_APPROVE_WORDS, APPROVAL_DENY_WORDS, RateLimiter, discordBackoffUntil, PRUNE_INTERVAL_MS;
|
|
99936
100340
|
var init_reply_listener = __esm({
|
|
99937
100341
|
"src/notifications/reply-listener.ts"() {
|
|
99938
100342
|
"use strict";
|
|
@@ -99940,7 +100344,7 @@ var init_reply_listener = __esm({
|
|
|
99940
100344
|
import_path123 = require("path");
|
|
99941
100345
|
import_url16 = require("url");
|
|
99942
100346
|
import_child_process29 = require("child_process");
|
|
99943
|
-
|
|
100347
|
+
import_crypto35 = require("crypto");
|
|
99944
100348
|
init_tmux_utils();
|
|
99945
100349
|
import_https2 = require("https");
|
|
99946
100350
|
init_daemon_module_path();
|
|
@@ -100846,7 +101250,7 @@ function reschedulePendingWorker(payload, job) {
|
|
|
100846
101250
|
}
|
|
100847
101251
|
async function processSessionEndWorker(payload) {
|
|
100848
101252
|
const deadlineAt = Date.now() + MAX_WORKER_MS;
|
|
100849
|
-
const nonce = (0,
|
|
101253
|
+
const nonce = (0, import_crypto36.randomUUID)();
|
|
100850
101254
|
const identity = await getProcessStartIdentity(process.pid, Math.min(deadlineAt, Date.now() + 2500));
|
|
100851
101255
|
if (!identity) return;
|
|
100852
101256
|
let claimed = claimSessionEndJob(payload.directory, payload.sessionId, nonce, identity, deadlineAt);
|
|
@@ -100935,12 +101339,12 @@ function reconcileSessionEndJobs(directory, sessionIds) {
|
|
|
100935
101339
|
if (ticket.nonce && !spawned) releaseSessionEndDiscoveryTicket(directory, ticket.sessionId, ticket.nonce, false);
|
|
100936
101340
|
}
|
|
100937
101341
|
}
|
|
100938
|
-
var import_child_process30,
|
|
101342
|
+
var import_child_process30, import_crypto36, import_url17, WORKER_ARG, MAX_WORKER_MS, COPILOT_PERMISSION_ENV2, workerIndex;
|
|
100939
101343
|
var init_worker = __esm({
|
|
100940
101344
|
"src/hooks/session-end/worker.ts"() {
|
|
100941
101345
|
"use strict";
|
|
100942
101346
|
import_child_process30 = require("child_process");
|
|
100943
|
-
|
|
101347
|
+
import_crypto36 = require("crypto");
|
|
100944
101348
|
import_url17 = require("url");
|
|
100945
101349
|
init_cleanup_manifest();
|
|
100946
101350
|
init_action_runner();
|
|
@@ -108561,7 +108965,7 @@ function clearRateLimitBackoff(cache, rateLimitIdentity) {
|
|
|
108561
108965
|
return Object.keys(backoffs).length > 0 ? backoffs : void 0;
|
|
108562
108966
|
}
|
|
108563
108967
|
function hashCredentialIdentity(identity) {
|
|
108564
|
-
return (0,
|
|
108968
|
+
return (0, import_crypto40.createHash)("sha256").update(identity).digest("hex");
|
|
108565
108969
|
}
|
|
108566
108970
|
function getOAuthAccountProfileIdentity(credentials) {
|
|
108567
108971
|
const nestedAccount = credentials.oauthAccount;
|
|
@@ -108764,7 +109168,7 @@ function createRateLimitedCacheEntry(source, data, pollIntervalMs, previousCount
|
|
|
108764
109168
|
function getKeychainServiceName() {
|
|
108765
109169
|
const configDir = process.env.COPILOT_HOME;
|
|
108766
109170
|
if (configDir) {
|
|
108767
|
-
const hash = (0,
|
|
109171
|
+
const hash = (0, import_crypto40.createHash)("sha256").update(configDir).digest("hex").slice(0, 8);
|
|
108768
109172
|
return `Claude Code-credentials-${hash}`;
|
|
108769
109173
|
}
|
|
108770
109174
|
return "Claude Code-credentials";
|
|
@@ -109956,7 +110360,7 @@ async function getUsage(opts) {
|
|
|
109956
110360
|
return { rateLimits: null, error: "network" };
|
|
109957
110361
|
}
|
|
109958
110362
|
}
|
|
109959
|
-
var import_fs130, import_path156, import_child_process38,
|
|
110363
|
+
var import_fs130, import_path156, import_child_process38, import_crypto40, import_os25, import_https3, CACHE_TTL_FAILURE_MS, CACHE_TTL_TRANSIENT_NETWORK_MS, MAX_RATE_LIMITED_BACKOFF_MS, API_TIMEOUT_MS2, MAX_STALE_DATA_MS, TOKEN_REFRESH_URL_HOSTNAME, USAGE_CACHE_LOCK_OPTS, TOKEN_REFRESH_URL_PATH, OMC_USAGE_PROFILE_ID_FIELD, OMC_USAGE_PROFILE_TOKEN_HASH_FIELD, DEFAULT_OAUTH_CLIENT_ID, storedCredentialCache, storedCredentialLookupGeneration, ZAI_UNIT_WEEK, KIMI_USAGE_HOSTNAMES, KIMI_USAGE_PATH, RATE_LIMIT_PROBE_MODEL, KIMI_FIVE_HOUR_WINDOW_MINUTES;
|
|
109960
110364
|
var init_usage_api = __esm({
|
|
109961
110365
|
"src/hud/usage-api.ts"() {
|
|
109962
110366
|
"use strict";
|
|
@@ -109964,7 +110368,7 @@ var init_usage_api = __esm({
|
|
|
109964
110368
|
init_config_dir();
|
|
109965
110369
|
import_path156 = require("path");
|
|
109966
110370
|
import_child_process38 = require("child_process");
|
|
109967
|
-
|
|
110371
|
+
import_crypto40 = require("crypto");
|
|
109968
110372
|
import_os25 = require("os");
|
|
109969
110373
|
import_https3 = __toESM(require("https"), 1);
|
|
109970
110374
|
init_ssrf_guard();
|
|
@@ -110554,12 +110958,12 @@ function readTailTotals(path30, size) {
|
|
|
110554
110958
|
scanLines(text, scan);
|
|
110555
110959
|
return scan.totals ? { ...scan.totals, ...scan.model ? { model: scan.model } : {} } : null;
|
|
110556
110960
|
}
|
|
110557
|
-
function toRecord(scan, partial2, now2,
|
|
110558
|
-
const model =
|
|
110961
|
+
function toRecord(scan, partial2, now2, tail3 = null) {
|
|
110962
|
+
const model = tail3?.model ?? scan.model;
|
|
110559
110963
|
const base = { updatedAt: now2.toISOString(), ...model ? { model } : {}, scan };
|
|
110560
|
-
const totals =
|
|
110964
|
+
const totals = tail3 ?? scan.totals;
|
|
110561
110965
|
if (totals) {
|
|
110562
|
-
return { ...base, premiumRequests: totals.premium, credits: totals.nano / NANO2, source: "measured", detail: `${totals.type}${
|
|
110966
|
+
return { ...base, premiumRequests: totals.premium, credits: totals.nano / NANO2, source: "measured", detail: `${totals.type}${tail3 ? " (events tail)" : ""}` };
|
|
110563
110967
|
}
|
|
110564
110968
|
if (scan.prompts === 0 && !partial2) return null;
|
|
110565
110969
|
return {
|
|
@@ -110593,8 +110997,8 @@ function readCopilotSessionUsage(eventsPath, now2 = /* @__PURE__ */ new Date(),
|
|
|
110593
110997
|
scan.offset = end;
|
|
110594
110998
|
}
|
|
110595
110999
|
const partial2 = end < size;
|
|
110596
|
-
const
|
|
110597
|
-
return toRecord(scan, partial2, now2,
|
|
111000
|
+
const tail3 = partial2 ? readTailTotals(eventsPath, size) : null;
|
|
111001
|
+
return toRecord(scan, partial2, now2, tail3);
|
|
110598
111002
|
}
|
|
110599
111003
|
var import_node_fs21, import_node_os6, import_node_path28, NANO2, MAX_SCAN_BYTES, TAIL_BYTES, HOOK_LOCK_TIMEOUT_MS, SAFE_KEY, isObject3, EPOCH, baselineKey;
|
|
110600
111004
|
var init_ledger = __esm({
|
|
@@ -110817,8 +111221,8 @@ function refreshEstimates(path30, now2, lock = {}, deadlineMs = REFRESH_DEADLINE
|
|
|
110817
111221
|
const mtimeMs = Math.floor(stat2.mtimeMs);
|
|
110818
111222
|
if (scan.checkedSize === stat2.size && scan.checkedMtimeMs === mtimeMs) continue;
|
|
110819
111223
|
const checked = { ...scan, checkedSize: stat2.size, checkedMtimeMs: mtimeMs };
|
|
110820
|
-
const
|
|
110821
|
-
const usage =
|
|
111224
|
+
const tail3 = readTailTotals(events, stat2.size);
|
|
111225
|
+
const usage = tail3 ? { premiumRequests: tail3.premium, credits: tail3.nano / 1e9, source: "measured", detail: `${tail3.type} (events tail)`, ...tail3.model ? { model: tail3.model } : {}, updatedAt: now2.toISOString(), scan: checked } : { ...record2, scan: checked };
|
|
110822
111226
|
updates.push({ key, team, usage });
|
|
110823
111227
|
}
|
|
110824
111228
|
const cursor = (start + visited) % stale.length;
|
|
@@ -111056,9 +111460,9 @@ var init_watchdog = __esm({
|
|
|
111056
111460
|
function verifySignature(secret, rawBody, signatureHeader) {
|
|
111057
111461
|
if (!signatureHeader?.startsWith("sha256=")) return false;
|
|
111058
111462
|
const provided = signatureHeader.slice("sha256=".length);
|
|
111059
|
-
const expected = (0,
|
|
111463
|
+
const expected = (0, import_crypto42.createHmac)("sha256", secret).update(rawBody, "utf8").digest("hex");
|
|
111060
111464
|
if (provided.length !== expected.length) return false;
|
|
111061
|
-
return (0,
|
|
111465
|
+
return (0, import_crypto42.timingSafeEqual)(Buffer.from(provided, "utf8"), Buffer.from(expected, "utf8"));
|
|
111062
111466
|
}
|
|
111063
111467
|
function routeTrackerEvent(event, whitelist, table = INTAKE_ROUTE_TABLE) {
|
|
111064
111468
|
const repo = event.repository?.full_name;
|
|
@@ -111132,7 +111536,7 @@ function spawnChainLink(req) {
|
|
|
111132
111536
|
req.audit({ kind: "discarded", reason: `guardrail: ${slot.reason}`, detail: slot.detail, intentId: req.intentId });
|
|
111133
111537
|
return { status: 204, kind: "discarded", detail: `guardrail ${slot.reason}: ${slot.detail}` };
|
|
111134
111538
|
}
|
|
111135
|
-
const nextSessionId = (0,
|
|
111539
|
+
const nextSessionId = (0, import_crypto42.randomUUID)();
|
|
111136
111540
|
const includeUserSettings = process.env[AFK_INCLUDE_USER_SETTINGS_ENV] === "1";
|
|
111137
111541
|
const args = factoryLinkArgv(req.prompt, nextSessionId, [], [], includeUserSettings, req.config.cwd);
|
|
111138
111542
|
const command = factoryLinkCommand();
|
|
@@ -111220,9 +111624,9 @@ function startListener(config2, deps = {}) {
|
|
|
111220
111624
|
}
|
|
111221
111625
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
111222
111626
|
const host = config2.host || "127.0.0.1";
|
|
111223
|
-
let
|
|
111627
|
+
let tail3 = Promise.resolve();
|
|
111224
111628
|
const server = (0, import_http.createServer)((req, res) => {
|
|
111225
|
-
|
|
111629
|
+
tail3 = tail3.then(() => handleRequest(req, res, config2, deps, startedAt)).catch(() => {
|
|
111226
111630
|
try {
|
|
111227
111631
|
res.writeHead(500).end();
|
|
111228
111632
|
} catch {
|
|
@@ -111291,11 +111695,11 @@ async function handleRequest(req, res, config2, deps, startedAt) {
|
|
|
111291
111695
|
function hasCheckSuite(event) {
|
|
111292
111696
|
return event.check_suite !== void 0;
|
|
111293
111697
|
}
|
|
111294
|
-
var
|
|
111698
|
+
var import_crypto42, import_http, import_fs137, import_path165, INTAKE_LABEL, INTAKE_ROUTE_TABLE, CI_ROUTE_TABLE, HEAD_BRANCH_PATTERN, ISSUE_URL_PATTERN, MAX_BODY_BYTES;
|
|
111295
111699
|
var init_listener = __esm({
|
|
111296
111700
|
"src/factory/listener.ts"() {
|
|
111297
111701
|
"use strict";
|
|
111298
|
-
|
|
111702
|
+
import_crypto42 = require("crypto");
|
|
111299
111703
|
import_http = require("http");
|
|
111300
111704
|
import_fs137 = require("fs");
|
|
111301
111705
|
import_path165 = require("path");
|
|
@@ -111690,7 +112094,7 @@ async function runChainScenario(input) {
|
|
|
111690
112094
|
};
|
|
111691
112095
|
const prepError = prepareChainProject(input.projectDir);
|
|
111692
112096
|
if (prepError) return { ...base, events: [], idle: false, timedOut: false, error: `chain setup: ${prepError}` };
|
|
111693
|
-
const firstLink = (input.randomUUID ??
|
|
112097
|
+
const firstLink = (input.randomUUID ?? import_crypto43.randomUUID)();
|
|
111694
112098
|
writeChainLinkLedger(factoryStateDir2(input.projectDir), firstLink, "copilot", {
|
|
111695
112099
|
intentId: CHAIN_INTENT_ID,
|
|
111696
112100
|
stage: CHAIN_LINK1_STAGE,
|
|
@@ -111734,11 +112138,11 @@ async function runChainScenario(input) {
|
|
|
111734
112138
|
chain
|
|
111735
112139
|
};
|
|
111736
112140
|
}
|
|
111737
|
-
var
|
|
112141
|
+
var import_crypto43, import_child_process44, import_fs139, import_path168, CHAIN_ACK_TOKEN, sleep7;
|
|
111738
112142
|
var init_copilot_chain_scenario = __esm({
|
|
111739
112143
|
"src/smoke/copilot-chain-scenario.ts"() {
|
|
111740
112144
|
"use strict";
|
|
111741
|
-
|
|
112145
|
+
import_crypto43 = require("crypto");
|
|
111742
112146
|
import_child_process44 = require("child_process");
|
|
111743
112147
|
import_fs139 = require("fs");
|
|
111744
112148
|
import_path168 = require("path");
|
|
@@ -112625,8 +113029,8 @@ function recordVerdict(state, verdict) {
|
|
|
112625
113029
|
}
|
|
112626
113030
|
const fixRounds = state.fixRounds + 1;
|
|
112627
113031
|
if (fixRounds > state.maxFixRounds) {
|
|
112628
|
-
const
|
|
112629
|
-
return { ...
|
|
113032
|
+
const blocked2 = transition({ ...withVerdict, fixRounds }, "blocked", `fix round ${fixRounds} exceeds max ${state.maxFixRounds}`, verdict.at);
|
|
113033
|
+
return { ...blocked2, blockedReason: `fix-round budget spent (${state.maxFixRounds}); escalate to a human` };
|
|
112630
113034
|
}
|
|
112631
113035
|
return transition({ ...withVerdict, fixRounds }, "fix", `changes requested by ${verdict.reviewer} (round ${fixRounds}/${state.maxFixRounds})`, verdict.at);
|
|
112632
113036
|
}
|
|
@@ -112637,7 +113041,7 @@ function shipStatePath(repoRoot3, pr) {
|
|
|
112637
113041
|
return (0, import_path172.join)(getOmcRoot(repoRoot3), "state", "ship", `${pr}.json`);
|
|
112638
113042
|
}
|
|
112639
113043
|
function computeIntegrity(state) {
|
|
112640
|
-
return (0,
|
|
113044
|
+
return (0, import_crypto44.createHash)("sha256").update(JSON.stringify({ ...state, integrity: void 0 })).digest("hex");
|
|
112641
113045
|
}
|
|
112642
113046
|
function sealShipState(state) {
|
|
112643
113047
|
return { ...state, integrity: computeIntegrity(state) };
|
|
@@ -112698,11 +113102,11 @@ function updateShipState(repoRoot3, pr, mutate, options = {}) {
|
|
|
112698
113102
|
return next;
|
|
112699
113103
|
}, { timeoutMs: 5e3 });
|
|
112700
113104
|
}
|
|
112701
|
-
var
|
|
113105
|
+
var import_crypto44, import_fs143, import_path172, TRANSITIONS, ShipStateError, PHASES, isStr, isCount;
|
|
112702
113106
|
var init_state4 = __esm({
|
|
112703
113107
|
"src/ship/state.ts"() {
|
|
112704
113108
|
"use strict";
|
|
112705
|
-
|
|
113109
|
+
import_crypto44 = require("crypto");
|
|
112706
113110
|
import_fs143 = require("fs");
|
|
112707
113111
|
import_path172 = require("path");
|
|
112708
113112
|
init_atomic_write();
|
|
@@ -114170,7 +114574,7 @@ async function runTier1(ctx, bin, opts, cleanup, artifacts) {
|
|
|
114170
114574
|
(0, import_fs144.mkdirSync)(home);
|
|
114171
114575
|
(0, import_fs144.mkdirSync)(projectDir);
|
|
114172
114576
|
const logDir = (0, import_path173.join)(home, "logs");
|
|
114173
|
-
const sessionId = (ctx.deps.randomUUID ??
|
|
114577
|
+
const sessionId = (ctx.deps.randomUUID ?? import_crypto45.randomUUID)();
|
|
114174
114578
|
const identity = loginIdentity(ctx.deps.userConfigDir ?? getCopilotConfigDir());
|
|
114175
114579
|
const env2 = buildSessionEnv(ctx.env, home, { session: true, hasLogin: identity.loggedInUsers !== void 0 });
|
|
114176
114580
|
const config2 = { ...identity, trustedFolders: [projectDir] };
|
|
@@ -114412,12 +114816,12 @@ async function runTier2(ctx, bin, binVersion, packageVersion, opts, scenarios, c
|
|
|
114412
114816
|
if (logs.path) artifacts.debugLog = logs.path;
|
|
114413
114817
|
return result;
|
|
114414
114818
|
}
|
|
114415
|
-
var import_child_process47,
|
|
114819
|
+
var import_child_process47, import_crypto45, import_fs144, import_os28, import_path173, DEFAULT_SMOKE_MODEL, DEFAULT_MAX_CREDITS2, MIN_MAX_CREDITS, DEFAULT_TIER0_TIMEOUT_MS, DEFAULT_TIER1_TIMEOUT_MS, MCP_LIST_TIMEOUT_MS, PLUGIN_NAME3, DELEGATE_AGENT2, DEFAULT_SMOKE_PROMPT, DELEGATE_SMOKE_PROMPT, SMOKE_PERMISSION_FLAGS, TIER0_COPILOT_IDS, LIVE_RUN_REFUSED_DETAIL;
|
|
114416
114820
|
var init_copilot_smoke = __esm({
|
|
114417
114821
|
"src/smoke/copilot-smoke.ts"() {
|
|
114418
114822
|
"use strict";
|
|
114419
114823
|
import_child_process47 = require("child_process");
|
|
114420
|
-
|
|
114824
|
+
import_crypto45 = require("crypto");
|
|
114421
114825
|
import_fs144 = require("fs");
|
|
114422
114826
|
import_os28 = require("os");
|
|
114423
114827
|
import_path173 = require("path");
|
|
@@ -114723,7 +115127,7 @@ async function runSdkHost(spec, deps) {
|
|
|
114723
115127
|
}).catch(() => false);
|
|
114724
115128
|
}
|
|
114725
115129
|
};
|
|
114726
|
-
const
|
|
115130
|
+
const fail7 = async (outcome2, error2) => {
|
|
114727
115131
|
session.state = "failed";
|
|
114728
115132
|
session.last_error = error2;
|
|
114729
115133
|
mark("closed_at");
|
|
@@ -114737,10 +115141,10 @@ async function runSdkHost(spec, deps) {
|
|
|
114737
115141
|
mark("ack_at");
|
|
114738
115142
|
const decision = await waitForDecision(attempt, DECISION_TIMEOUT_MS);
|
|
114739
115143
|
if (decision !== "accepted") {
|
|
114740
|
-
return
|
|
115144
|
+
return fail7(decision === "revoked" ? "decision_revoked" : "decision_timeout", `launch decision ${decision}`);
|
|
114741
115145
|
}
|
|
114742
115146
|
mark("accepted_at");
|
|
114743
|
-
if (!startIdentity) return
|
|
115147
|
+
if (!startIdentity) return fail7("start_failed", "host process start identity unavailable");
|
|
114744
115148
|
await writeExclusive(attempt.startedPath, {
|
|
114745
115149
|
...identity,
|
|
114746
115150
|
kind: "worker_launch_provider_started",
|
|
@@ -114756,7 +115160,7 @@ async function runSdkHost(spec, deps) {
|
|
|
114756
115160
|
} catch {
|
|
114757
115161
|
loaded2 = null;
|
|
114758
115162
|
}
|
|
114759
|
-
if (!loaded2) return
|
|
115163
|
+
if (!loaded2) return fail7("sdk_missing", "@github/copilot-sdk is not installed (npm i -g @github/copilot-sdk --omit=optional --ignore-scripts)");
|
|
114760
115164
|
(0, import_node_fs25.mkdirSync)(files.home, { recursive: true });
|
|
114761
115165
|
const homeConfig = (0, import_node_path32.join)(files.home, "config.json");
|
|
114762
115166
|
const ident = loginIdentity(spec.user_config_dir);
|
|
@@ -114958,7 +115362,7 @@ async function runSdkHost(spec, deps) {
|
|
|
114958
115362
|
} catch {
|
|
114959
115363
|
}
|
|
114960
115364
|
removeGuards();
|
|
114961
|
-
return
|
|
115365
|
+
return fail7("start_failed", errText3(err));
|
|
114962
115366
|
}
|
|
114963
115367
|
const queue = [];
|
|
114964
115368
|
let offset = 0;
|
|
@@ -115086,7 +115490,7 @@ async function runSdkHost(spec, deps) {
|
|
|
115086
115490
|
return outcome;
|
|
115087
115491
|
}
|
|
115088
115492
|
async function runSdkHostMain(specPath, loadInProcessTools) {
|
|
115089
|
-
const { spawnSync:
|
|
115493
|
+
const { spawnSync: spawnSync18 } = await import("node:child_process");
|
|
115090
115494
|
const { loadCopilotSdk: loadCopilotSdk2 } = await Promise.resolve().then(() => (init_copilot_sdk_driver(), copilot_sdk_driver_exports));
|
|
115091
115495
|
const { killProcessTree: killProcessTree3 } = await Promise.resolve().then(() => (init_process_utils2(), process_utils_exports2));
|
|
115092
115496
|
const { getProcessStartIdentitySync: getProcessStartIdentitySync2, isProcessAlive: isProcessAlive3 } = await Promise.resolve().then(() => (init_process_utils(), process_utils_exports));
|
|
@@ -115100,11 +115504,11 @@ async function runSdkHostMain(specPath, loadInProcessTools) {
|
|
|
115100
115504
|
if (spec?.schema_version !== 1 || !spec.worker_name || !spec.state_root) throw new Error("invalid sdk host spec");
|
|
115101
115505
|
log3(`start team=${spec.team_name} worker=${spec.worker_name} attempt=${spec.attempt_id}`);
|
|
115102
115506
|
const outcome = await runSdkHost(spec, {
|
|
115103
|
-
loadSdk: () => loadCopilotSdk2(process.env,
|
|
115507
|
+
loadSdk: () => loadCopilotSdk2(process.env, spawnSync18),
|
|
115104
115508
|
pid: process.pid,
|
|
115105
115509
|
startIdentity: (pid) => getProcessStartIdentitySync2(pid),
|
|
115106
115510
|
isAlive: (pid) => isProcessAlive3(pid),
|
|
115107
|
-
killTree: (pid) => killProcessTree3(pid,
|
|
115511
|
+
killTree: (pid) => killProcessTree3(pid, spawnSync18),
|
|
115108
115512
|
platform: process.platform,
|
|
115109
115513
|
pollMs: 250,
|
|
115110
115514
|
env: process.env,
|
|
@@ -117046,7 +117450,7 @@ var init_scheduler = __esm({
|
|
|
117046
117450
|
function computeJournalFingerprint(record2) {
|
|
117047
117451
|
const unsignedRecord = { ...record2 };
|
|
117048
117452
|
delete unsignedRecord.journal_fingerprint;
|
|
117049
|
-
return (0,
|
|
117453
|
+
return (0, import_crypto48.createHash)("sha256").update(canonicalJson2(unsignedRecord)).digest("hex");
|
|
117050
117454
|
}
|
|
117051
117455
|
function envelopeError(value) {
|
|
117052
117456
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -117070,12 +117474,12 @@ function envelopeError(value) {
|
|
|
117070
117474
|
}
|
|
117071
117475
|
return null;
|
|
117072
117476
|
}
|
|
117073
|
-
var import_fs152,
|
|
117477
|
+
var import_fs152, import_crypto48, import_path182, DESCRIPTOR_HASH_PATTERN2, JOURNAL_FINGERPRINT_PATTERN, FileJournal;
|
|
117074
117478
|
var init_journal = __esm({
|
|
117075
117479
|
"src/graph/runtime/journal.ts"() {
|
|
117076
117480
|
"use strict";
|
|
117077
117481
|
import_fs152 = require("fs");
|
|
117078
|
-
|
|
117482
|
+
import_crypto48 = require("crypto");
|
|
117079
117483
|
import_path182 = require("path");
|
|
117080
117484
|
init_descriptor();
|
|
117081
117485
|
init_run_dir();
|
|
@@ -117268,12 +117672,12 @@ function lstatNoFollow(operations, filePath) {
|
|
|
117268
117672
|
}
|
|
117269
117673
|
return stats;
|
|
117270
117674
|
}
|
|
117271
|
-
var import_fs153,
|
|
117675
|
+
var import_fs153, import_crypto49, DEFAULT_STALE_GRACE_MS, LOCK_FILE_NAME, EPOCH_FILE_NAME, FileOwnershipFence;
|
|
117272
117676
|
var init_fence = __esm({
|
|
117273
117677
|
"src/graph/runtime/fence.ts"() {
|
|
117274
117678
|
"use strict";
|
|
117275
117679
|
import_fs153 = require("fs");
|
|
117276
|
-
|
|
117680
|
+
import_crypto49 = require("crypto");
|
|
117277
117681
|
init_atomic_write();
|
|
117278
117682
|
init_platform();
|
|
117279
117683
|
init_run_dir();
|
|
@@ -117364,7 +117768,7 @@ var init_fence = __esm({
|
|
|
117364
117768
|
continue;
|
|
117365
117769
|
}
|
|
117366
117770
|
this.beforeTakeoverRename?.();
|
|
117367
|
-
const tombstone = `${lockPath2}.tomb.${(0,
|
|
117771
|
+
const tombstone = `${lockPath2}.tomb.${(0, import_crypto49.randomBytes)(6).toString("hex")}`;
|
|
117368
117772
|
try {
|
|
117369
117773
|
operations.rename(lockPath2, tombstone);
|
|
117370
117774
|
} catch {
|
|
@@ -117432,7 +117836,7 @@ var init_fence = __esm({
|
|
|
117432
117836
|
return false;
|
|
117433
117837
|
}
|
|
117434
117838
|
this.beforeReleaseRename?.();
|
|
117435
|
-
const tombstone = `${lockPath2}.tomb.${(0,
|
|
117839
|
+
const tombstone = `${lockPath2}.tomb.${(0, import_crypto49.randomBytes)(6).toString("hex")}`;
|
|
117436
117840
|
try {
|
|
117437
117841
|
operations.rename(lockPath2, tombstone);
|
|
117438
117842
|
} catch (error2) {
|
|
@@ -117589,7 +117993,7 @@ var init_fence = __esm({
|
|
|
117589
117993
|
/** Remove only a lock inode positively identified as ours after create. */
|
|
117590
117994
|
cleanupCreatedLock(operations, lockPath2, createdIdentity) {
|
|
117591
117995
|
if (createdIdentity === null) return;
|
|
117592
|
-
const tombstone = `${lockPath2}.tomb.${(0,
|
|
117996
|
+
const tombstone = `${lockPath2}.tomb.${(0, import_crypto49.randomBytes)(6).toString("hex")}`;
|
|
117593
117997
|
try {
|
|
117594
117998
|
operations.rename(lockPath2, tombstone);
|
|
117595
117999
|
} catch {
|
|
@@ -118658,12 +119062,12 @@ async function parseTranscript(transcriptPath, options) {
|
|
|
118658
119062
|
lastToolName: null,
|
|
118659
119063
|
recentTools: []
|
|
118660
119064
|
};
|
|
118661
|
-
if (!transcriptPath || !(0,
|
|
119065
|
+
if (!transcriptPath || !(0, import_fs160.existsSync)(transcriptPath)) {
|
|
118662
119066
|
return result;
|
|
118663
119067
|
}
|
|
118664
119068
|
let cacheKey = null;
|
|
118665
119069
|
try {
|
|
118666
|
-
const stat2 = (0,
|
|
119070
|
+
const stat2 = (0, import_fs160.statSync)(transcriptPath);
|
|
118667
119071
|
cacheKey = `${transcriptPath}:${stat2.size}:${stat2.mtimeMs}`;
|
|
118668
119072
|
const cached2 = transcriptCache.get(transcriptPath);
|
|
118669
119073
|
if (cached2?.cacheKey === cacheKey) {
|
|
@@ -118684,7 +119088,7 @@ async function parseTranscript(transcriptPath, options) {
|
|
|
118684
119088
|
const observedSessionIds = /* @__PURE__ */ new Set();
|
|
118685
119089
|
const recentToolMap = /* @__PURE__ */ new Map();
|
|
118686
119090
|
try {
|
|
118687
|
-
const stat2 = (0,
|
|
119091
|
+
const stat2 = (0, import_fs160.statSync)(transcriptPath);
|
|
118688
119092
|
const fileSize = stat2.size;
|
|
118689
119093
|
if (fileSize > MAX_TAIL_BYTES) {
|
|
118690
119094
|
const lines3 = readTailLines(transcriptPath, fileSize, MAX_TAIL_BYTES);
|
|
@@ -118708,7 +119112,7 @@ async function parseTranscript(transcriptPath, options) {
|
|
|
118708
119112
|
}
|
|
118709
119113
|
sessionTotalsReliable = sessionTokenTotals.seenUsage;
|
|
118710
119114
|
} else {
|
|
118711
|
-
const fileStream = (0,
|
|
119115
|
+
const fileStream = (0, import_fs160.createReadStream)(transcriptPath);
|
|
118712
119116
|
const rl = (0, import_readline5.createInterface)({
|
|
118713
119117
|
input: fileStream,
|
|
118714
119118
|
crlfDelay: Infinity
|
|
@@ -118833,12 +119237,12 @@ function finalizeTranscriptResult(result, options, pendingPermissions) {
|
|
|
118833
119237
|
function readTailLines(filePath, fileSize, maxBytes) {
|
|
118834
119238
|
const startOffset = Math.max(0, fileSize - maxBytes);
|
|
118835
119239
|
const bytesToRead = fileSize - startOffset;
|
|
118836
|
-
const fd = (0,
|
|
119240
|
+
const fd = (0, import_fs160.openSync)(filePath, "r");
|
|
118837
119241
|
const buffer = Buffer.alloc(bytesToRead);
|
|
118838
119242
|
try {
|
|
118839
|
-
(0,
|
|
119243
|
+
(0, import_fs160.readSync)(fd, buffer, 0, bytesToRead, startOffset);
|
|
118840
119244
|
} finally {
|
|
118841
|
-
(0,
|
|
119245
|
+
(0, import_fs160.closeSync)(fd);
|
|
118842
119246
|
}
|
|
118843
119247
|
const content = buffer.toString("utf8");
|
|
118844
119248
|
const lines3 = content.split("\n");
|
|
@@ -118882,7 +119286,7 @@ function extractTargetSummary(input, toolName) {
|
|
|
118882
119286
|
if (toolName.includes("Edit") || toolName.includes("Write")) {
|
|
118883
119287
|
const filePath = inp.file_path;
|
|
118884
119288
|
if (filePath) {
|
|
118885
|
-
return (0,
|
|
119289
|
+
return (0, import_path191.basename)(filePath) || filePath;
|
|
118886
119290
|
}
|
|
118887
119291
|
}
|
|
118888
119292
|
if (toolName.includes("Bash")) {
|
|
@@ -119149,13 +119553,13 @@ function extractLastRequestTokenUsage(usage) {
|
|
|
119149
119553
|
function getNumericUsageValue(value) {
|
|
119150
119554
|
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
119151
119555
|
}
|
|
119152
|
-
var
|
|
119556
|
+
var import_fs160, import_readline5, import_path191, MAX_TAIL_BYTES, MAX_AGENT_MAP_SIZE, MAX_RECENT_TOOLS, RECENT_TOOLS_SKIP, PERMISSION_TOOLS, PERMISSION_THRESHOLD_MS, pendingPermissionMap, taskToolStates, TASK_STATUSES, THINKING_PART_TYPES2, THINKING_RECENCY_MS, transcriptCache, TRANSCRIPT_CACHE_MAX_SIZE;
|
|
119153
119557
|
var init_transcript = __esm({
|
|
119154
119558
|
"src/hud/transcript.ts"() {
|
|
119155
119559
|
"use strict";
|
|
119156
|
-
|
|
119560
|
+
import_fs160 = require("fs");
|
|
119157
119561
|
import_readline5 = require("readline");
|
|
119158
|
-
|
|
119562
|
+
import_path191 = require("path");
|
|
119159
119563
|
init_agent_kind();
|
|
119160
119564
|
MAX_TAIL_BYTES = 4 * 1024 * 1024;
|
|
119161
119565
|
MAX_AGENT_MAP_SIZE = 100;
|
|
@@ -119197,7 +119601,7 @@ var init_transcript = __esm({
|
|
|
119197
119601
|
// src/hud/omc-state.ts
|
|
119198
119602
|
function isStateFileStale(filePath) {
|
|
119199
119603
|
try {
|
|
119200
|
-
const stat2 = (0,
|
|
119604
|
+
const stat2 = (0, import_fs161.statSync)(filePath);
|
|
119201
119605
|
const age = Date.now() - stat2.mtimeMs;
|
|
119202
119606
|
return age > MAX_STATE_AGE_MS2;
|
|
119203
119607
|
} catch {
|
|
@@ -119207,21 +119611,21 @@ function isStateFileStale(filePath) {
|
|
|
119207
119611
|
function resolveStatePath2(directory, filename, sessionId) {
|
|
119208
119612
|
const omcRoot = getOmcRoot(directory);
|
|
119209
119613
|
if (sessionId) {
|
|
119210
|
-
const sessionPath = (0,
|
|
119211
|
-
return (0,
|
|
119614
|
+
const sessionPath = (0, import_path192.join)(omcRoot, "state", "sessions", sessionId, filename);
|
|
119615
|
+
return (0, import_fs161.existsSync)(sessionPath) ? sessionPath : null;
|
|
119212
119616
|
}
|
|
119213
119617
|
let bestPath = null;
|
|
119214
119618
|
let bestMtime = 0;
|
|
119215
|
-
const sessionsDir = (0,
|
|
119216
|
-
if ((0,
|
|
119619
|
+
const sessionsDir = (0, import_path192.join)(omcRoot, "state", "sessions");
|
|
119620
|
+
if ((0, import_fs161.existsSync)(sessionsDir)) {
|
|
119217
119621
|
try {
|
|
119218
|
-
const entries = (0,
|
|
119622
|
+
const entries = (0, import_fs161.readdirSync)(sessionsDir, { withFileTypes: true });
|
|
119219
119623
|
for (const entry2 of entries) {
|
|
119220
119624
|
if (!entry2.isDirectory()) continue;
|
|
119221
|
-
const sessionFile = (0,
|
|
119222
|
-
if ((0,
|
|
119625
|
+
const sessionFile = (0, import_path192.join)(sessionsDir, entry2.name, filename);
|
|
119626
|
+
if ((0, import_fs161.existsSync)(sessionFile)) {
|
|
119223
119627
|
try {
|
|
119224
|
-
const mtime = (0,
|
|
119628
|
+
const mtime = (0, import_fs161.statSync)(sessionFile).mtimeMs;
|
|
119225
119629
|
if (mtime > bestMtime) {
|
|
119226
119630
|
bestMtime = mtime;
|
|
119227
119631
|
bestPath = sessionFile;
|
|
@@ -119233,10 +119637,10 @@ function resolveStatePath2(directory, filename, sessionId) {
|
|
|
119233
119637
|
} catch {
|
|
119234
119638
|
}
|
|
119235
119639
|
}
|
|
119236
|
-
const newPath = (0,
|
|
119237
|
-
if ((0,
|
|
119640
|
+
const newPath = (0, import_path192.join)(omcRoot, "state", filename);
|
|
119641
|
+
if ((0, import_fs161.existsSync)(newPath)) {
|
|
119238
119642
|
try {
|
|
119239
|
-
const mtime = (0,
|
|
119643
|
+
const mtime = (0, import_fs161.statSync)(newPath).mtimeMs;
|
|
119240
119644
|
if (mtime > bestMtime) {
|
|
119241
119645
|
bestMtime = mtime;
|
|
119242
119646
|
bestPath = newPath;
|
|
@@ -119245,10 +119649,10 @@ function resolveStatePath2(directory, filename, sessionId) {
|
|
|
119245
119649
|
if (!bestPath) bestPath = newPath;
|
|
119246
119650
|
}
|
|
119247
119651
|
}
|
|
119248
|
-
const legacyPath = (0,
|
|
119249
|
-
if ((0,
|
|
119652
|
+
const legacyPath = (0, import_path192.join)(omcRoot, filename);
|
|
119653
|
+
if ((0, import_fs161.existsSync)(legacyPath)) {
|
|
119250
119654
|
try {
|
|
119251
|
-
const mtime = (0,
|
|
119655
|
+
const mtime = (0, import_fs161.statSync)(legacyPath).mtimeMs;
|
|
119252
119656
|
if (mtime > bestMtime) {
|
|
119253
119657
|
bestPath = legacyPath;
|
|
119254
119658
|
}
|
|
@@ -119267,7 +119671,7 @@ function readRalphStateForHud(directory, sessionId) {
|
|
|
119267
119671
|
return null;
|
|
119268
119672
|
}
|
|
119269
119673
|
try {
|
|
119270
|
-
const content = (0,
|
|
119674
|
+
const content = (0, import_fs161.readFileSync)(stateFile, "utf-8");
|
|
119271
119675
|
const state = JSON.parse(content);
|
|
119272
119676
|
if (!state.active) {
|
|
119273
119677
|
return null;
|
|
@@ -119284,15 +119688,15 @@ function readRalphStateForHud(directory, sessionId) {
|
|
|
119284
119688
|
}
|
|
119285
119689
|
}
|
|
119286
119690
|
function readPrdStateForHud(directory) {
|
|
119287
|
-
let prdPath = (0,
|
|
119288
|
-
if (!(0,
|
|
119289
|
-
prdPath = (0,
|
|
119290
|
-
if (!(0,
|
|
119691
|
+
let prdPath = (0, import_path192.join)(directory, "prd.json");
|
|
119692
|
+
if (!(0, import_fs161.existsSync)(prdPath)) {
|
|
119693
|
+
prdPath = (0, import_path192.join)(getOmcRoot(directory), "prd.json");
|
|
119694
|
+
if (!(0, import_fs161.existsSync)(prdPath)) {
|
|
119291
119695
|
return null;
|
|
119292
119696
|
}
|
|
119293
119697
|
}
|
|
119294
119698
|
try {
|
|
119295
|
-
const content = (0,
|
|
119699
|
+
const content = (0, import_fs161.readFileSync)(prdPath, "utf-8");
|
|
119296
119700
|
const prd = JSON.parse(content);
|
|
119297
119701
|
if (!prd.userStories || !Array.isArray(prd.userStories)) {
|
|
119298
119702
|
return null;
|
|
@@ -119345,7 +119749,7 @@ function readAutopilotStateForHud(directory, sessionId) {
|
|
|
119345
119749
|
return null;
|
|
119346
119750
|
}
|
|
119347
119751
|
try {
|
|
119348
|
-
const content = (0,
|
|
119752
|
+
const content = (0, import_fs161.readFileSync)(stateFile, "utf-8");
|
|
119349
119753
|
const state = JSON.parse(content);
|
|
119350
119754
|
if (!state.active) {
|
|
119351
119755
|
return null;
|
|
@@ -119368,12 +119772,12 @@ function readAutopilotStateForHud(directory, sessionId) {
|
|
|
119368
119772
|
return null;
|
|
119369
119773
|
}
|
|
119370
119774
|
}
|
|
119371
|
-
var
|
|
119775
|
+
var import_fs161, import_path192, MAX_STATE_AGE_MS2;
|
|
119372
119776
|
var init_omc_state = __esm({
|
|
119373
119777
|
"src/hud/omc-state.ts"() {
|
|
119374
119778
|
"use strict";
|
|
119375
|
-
|
|
119376
|
-
|
|
119779
|
+
import_fs161 = require("fs");
|
|
119780
|
+
import_path192 = require("path");
|
|
119377
119781
|
init_worktree_paths();
|
|
119378
119782
|
init_named_workflow_resume_validator();
|
|
119379
119783
|
MAX_STATE_AGE_MS2 = 2 * 60 * 60 * 1e3;
|
|
@@ -119382,7 +119786,7 @@ var init_omc_state = __esm({
|
|
|
119382
119786
|
|
|
119383
119787
|
// src/hud/custom-rate-provider.ts
|
|
119384
119788
|
function getCachePath2() {
|
|
119385
|
-
return (0,
|
|
119789
|
+
return (0, import_path193.join)(
|
|
119386
119790
|
getCopilotConfigDir(),
|
|
119387
119791
|
"plugins",
|
|
119388
119792
|
"oh-my-copilot",
|
|
@@ -119392,8 +119796,8 @@ function getCachePath2() {
|
|
|
119392
119796
|
function readCache2() {
|
|
119393
119797
|
try {
|
|
119394
119798
|
const p = getCachePath2();
|
|
119395
|
-
if (!(0,
|
|
119396
|
-
return JSON.parse((0,
|
|
119799
|
+
if (!(0, import_fs162.existsSync)(p)) return null;
|
|
119800
|
+
return JSON.parse((0, import_fs162.readFileSync)(p, "utf-8"));
|
|
119397
119801
|
} catch {
|
|
119398
119802
|
return null;
|
|
119399
119803
|
}
|
|
@@ -119401,10 +119805,10 @@ function readCache2() {
|
|
|
119401
119805
|
function writeCache2(buckets, identity) {
|
|
119402
119806
|
try {
|
|
119403
119807
|
const p = getCachePath2();
|
|
119404
|
-
const dir = (0,
|
|
119405
|
-
if (!(0,
|
|
119808
|
+
const dir = (0, import_path193.dirname)(p);
|
|
119809
|
+
if (!(0, import_fs162.existsSync)(dir)) (0, import_fs162.mkdirSync)(dir, { recursive: true });
|
|
119406
119810
|
const cache = { timestamp: Date.now(), buckets, identity };
|
|
119407
|
-
(0,
|
|
119811
|
+
(0, import_fs162.writeFileSync)(p, JSON.stringify(cache, null, 2));
|
|
119408
119812
|
} catch {
|
|
119409
119813
|
}
|
|
119410
119814
|
}
|
|
@@ -119414,7 +119818,7 @@ function isCacheValid2(cache) {
|
|
|
119414
119818
|
function spawnWithTimeout(cmd, timeoutMs) {
|
|
119415
119819
|
return new Promise((resolve58, reject2) => {
|
|
119416
119820
|
const [executable, ...args] = Array.isArray(cmd) ? cmd : ["sh", "-c", cmd];
|
|
119417
|
-
const child = (0,
|
|
119821
|
+
const child = (0, import_child_process55.spawn)(executable, args, {
|
|
119418
119822
|
stdio: ["ignore", "pipe", "pipe"],
|
|
119419
119823
|
detached: process.platform !== "win32"
|
|
119420
119824
|
});
|
|
@@ -119522,14 +119926,14 @@ async function executeCustomProvider(config2) {
|
|
|
119522
119926
|
return { buckets: [], stale: false, error: "command failed" };
|
|
119523
119927
|
}
|
|
119524
119928
|
}
|
|
119525
|
-
var
|
|
119929
|
+
var import_child_process55, import_node_crypto18, import_fs162, import_path193, CACHE_TTL_MS2, DEFAULT_TIMEOUT_MS4;
|
|
119526
119930
|
var init_custom_rate_provider = __esm({
|
|
119527
119931
|
"src/hud/custom-rate-provider.ts"() {
|
|
119528
119932
|
"use strict";
|
|
119529
|
-
|
|
119933
|
+
import_child_process55 = require("child_process");
|
|
119530
119934
|
import_node_crypto18 = require("node:crypto");
|
|
119531
|
-
|
|
119532
|
-
|
|
119935
|
+
import_fs162 = require("fs");
|
|
119936
|
+
import_path193 = require("path");
|
|
119533
119937
|
init_config_dir();
|
|
119534
119938
|
CACHE_TTL_MS2 = 3e4;
|
|
119535
119939
|
DEFAULT_TIMEOUT_MS4 = 800;
|
|
@@ -120057,7 +120461,7 @@ var init_todos = __esm({
|
|
|
120057
120461
|
});
|
|
120058
120462
|
|
|
120059
120463
|
// src/hud/elements/skills.ts
|
|
120060
|
-
function
|
|
120464
|
+
function truncate3(str4, maxWidth) {
|
|
120061
120465
|
return truncateToWidth(str4, maxWidth);
|
|
120062
120466
|
}
|
|
120063
120467
|
function getSkillDisplayName(skillName) {
|
|
@@ -120079,7 +120483,7 @@ function renderSkills(ultrawork, ralph, lastSkill) {
|
|
|
120079
120483
|
parts.push(`${MAGENTA2}ralph${RESET}`);
|
|
120080
120484
|
}
|
|
120081
120485
|
if (lastSkill && !isActiveMode(lastSkill.name, ultrawork, ralph)) {
|
|
120082
|
-
const argsDisplay = lastSkill.args ? `(${
|
|
120486
|
+
const argsDisplay = lastSkill.args ? `(${truncate3(lastSkill.args, 15)})` : "";
|
|
120083
120487
|
const displayName = getSkillDisplayName(lastSkill.name);
|
|
120084
120488
|
parts.push(cyan(`skill:${displayName}${argsDisplay}`));
|
|
120085
120489
|
}
|
|
@@ -120087,7 +120491,7 @@ function renderSkills(ultrawork, ralph, lastSkill) {
|
|
|
120087
120491
|
}
|
|
120088
120492
|
function renderLastSkill(lastSkill) {
|
|
120089
120493
|
if (!lastSkill) return null;
|
|
120090
|
-
const argsDisplay = lastSkill.args ? `(${
|
|
120494
|
+
const argsDisplay = lastSkill.args ? `(${truncate3(lastSkill.args, 15)})` : "";
|
|
120091
120495
|
const displayName = getSkillDisplayName(lastSkill.name);
|
|
120092
120496
|
return cyan(`skill:${displayName}${argsDisplay}`);
|
|
120093
120497
|
}
|
|
@@ -121165,8 +121569,8 @@ var init_effort = __esm({
|
|
|
121165
121569
|
// src/hud/elements/api-key-source.ts
|
|
121166
121570
|
function settingsFileHasApiKey(filePath) {
|
|
121167
121571
|
try {
|
|
121168
|
-
if (!(0,
|
|
121169
|
-
const content = (0,
|
|
121572
|
+
if (!(0, import_fs163.existsSync)(filePath)) return false;
|
|
121573
|
+
const content = (0, import_fs163.readFileSync)(filePath, "utf-8");
|
|
121170
121574
|
const settings = JSON.parse(content);
|
|
121171
121575
|
const env2 = settings?.env;
|
|
121172
121576
|
if (typeof env2 !== "object" || env2 === null) return false;
|
|
@@ -121177,10 +121581,10 @@ function settingsFileHasApiKey(filePath) {
|
|
|
121177
121581
|
}
|
|
121178
121582
|
function detectApiKeySource(cwd2) {
|
|
121179
121583
|
if (cwd2) {
|
|
121180
|
-
const projectSettings = (0,
|
|
121584
|
+
const projectSettings = (0, import_path194.join)(cwd2, ".copilot", "settings.local.json");
|
|
121181
121585
|
if (settingsFileHasApiKey(projectSettings)) return "project";
|
|
121182
121586
|
}
|
|
121183
|
-
const globalSettings = (0,
|
|
121587
|
+
const globalSettings = (0, import_path194.join)(getCopilotConfigDir(), "settings.json");
|
|
121184
121588
|
if (settingsFileHasApiKey(globalSettings)) return "global";
|
|
121185
121589
|
if (process.env.ANTHROPIC_API_KEY) return "env";
|
|
121186
121590
|
return null;
|
|
@@ -121189,12 +121593,12 @@ function renderApiKeySource(source) {
|
|
|
121189
121593
|
if (!source) return null;
|
|
121190
121594
|
return `${dim("key:")}${cyan(source)}`;
|
|
121191
121595
|
}
|
|
121192
|
-
var
|
|
121596
|
+
var import_fs163, import_path194;
|
|
121193
121597
|
var init_api_key_source = __esm({
|
|
121194
121598
|
"src/hud/elements/api-key-source.ts"() {
|
|
121195
121599
|
"use strict";
|
|
121196
|
-
|
|
121197
|
-
|
|
121600
|
+
import_fs163 = require("fs");
|
|
121601
|
+
import_path194 = require("path");
|
|
121198
121602
|
init_colors();
|
|
121199
121603
|
init_config_dir();
|
|
121200
121604
|
}
|
|
@@ -121927,7 +122331,7 @@ function findByteBackward(fd, fromExclusive, byte) {
|
|
|
121927
122331
|
while (end > 0) {
|
|
121928
122332
|
const start = Math.max(0, end - SCAN_CHUNK_BYTES);
|
|
121929
122333
|
const length = end - start;
|
|
121930
|
-
(0,
|
|
122334
|
+
(0, import_fs164.readSync)(fd, buffer, 0, length, start);
|
|
121931
122335
|
const index = buffer.subarray(0, length).lastIndexOf(byte);
|
|
121932
122336
|
if (index !== -1) return start + index;
|
|
121933
122337
|
end = start;
|
|
@@ -121939,7 +122343,7 @@ function findByteForward(fd, fromInclusive, size, byte) {
|
|
|
121939
122343
|
const buffer = Buffer.allocUnsafe(SCAN_CHUNK_BYTES);
|
|
121940
122344
|
while (start < size) {
|
|
121941
122345
|
const length = Math.min(SCAN_CHUNK_BYTES, size - start);
|
|
121942
|
-
(0,
|
|
122346
|
+
(0, import_fs164.readSync)(fd, buffer, 0, length, start);
|
|
121943
122347
|
const index = buffer.subarray(0, length).indexOf(byte);
|
|
121944
122348
|
if (index !== -1) return start + index;
|
|
121945
122349
|
start += length;
|
|
@@ -121954,19 +122358,19 @@ function readLineContainingOffset(fd, size, offset) {
|
|
|
121954
122358
|
const length = endOffset - startOffset;
|
|
121955
122359
|
if (length <= 0 || length > MAX_BOUNDARY_LINE_BYTES) return null;
|
|
121956
122360
|
const line = Buffer.allocUnsafe(length);
|
|
121957
|
-
(0,
|
|
122361
|
+
(0, import_fs164.readSync)(fd, line, 0, length, startOffset);
|
|
121958
122362
|
return { line, endOffset };
|
|
121959
122363
|
}
|
|
121960
122364
|
function findLastCompactBoundaryEndOffset(transcriptPath, size) {
|
|
121961
122365
|
if (size <= 0) return null;
|
|
121962
|
-
const fd = (0,
|
|
122366
|
+
const fd = (0, import_fs164.openSync)(transcriptPath, "r");
|
|
121963
122367
|
try {
|
|
121964
122368
|
let end = size;
|
|
121965
122369
|
const buffer = Buffer.allocUnsafe(Math.min(SCAN_CHUNK_BYTES, size));
|
|
121966
122370
|
while (end > 0) {
|
|
121967
122371
|
const start = Math.max(0, end - SCAN_CHUNK_BYTES);
|
|
121968
122372
|
const length = end - start;
|
|
121969
|
-
(0,
|
|
122373
|
+
(0, import_fs164.readSync)(fd, buffer, 0, length, start);
|
|
121970
122374
|
const chunk = buffer.subarray(0, length);
|
|
121971
122375
|
let index = chunk.lastIndexOf(COMPACT_BOUNDARY_MARKER_BYTES);
|
|
121972
122376
|
while (index !== -1) {
|
|
@@ -121981,13 +122385,13 @@ function findLastCompactBoundaryEndOffset(transcriptPath, size) {
|
|
|
121981
122385
|
end = start + COMPACT_BOUNDARY_MARKER_BYTES.length - 1;
|
|
121982
122386
|
}
|
|
121983
122387
|
} finally {
|
|
121984
|
-
(0,
|
|
122388
|
+
(0, import_fs164.closeSync)(fd);
|
|
121985
122389
|
}
|
|
121986
122390
|
return null;
|
|
121987
122391
|
}
|
|
121988
122392
|
function countLocalApiRequestRecordBytes(transcriptPath, start, end) {
|
|
121989
122393
|
if (end <= start) return 0;
|
|
121990
|
-
const fd = (0,
|
|
122394
|
+
const fd = (0, import_fs164.openSync)(transcriptPath, "r");
|
|
121991
122395
|
try {
|
|
121992
122396
|
const chunk = Buffer.allocUnsafe(SCAN_CHUNK_BYTES);
|
|
121993
122397
|
const prefix = Buffer.allocUnsafe(LOCAL_API_REQUEST_PREFIX.length);
|
|
@@ -121996,7 +122400,7 @@ function countLocalApiRequestRecordBytes(transcriptPath, start, end) {
|
|
|
121996
122400
|
const countLine = (lineEndExclusive) => {
|
|
121997
122401
|
const lineLength = lineEndExclusive - lineStart;
|
|
121998
122402
|
if (lineLength >= prefix.length) {
|
|
121999
|
-
const bytesRead = (0,
|
|
122403
|
+
const bytesRead = (0, import_fs164.readSync)(fd, prefix, 0, prefix.length, lineStart);
|
|
122000
122404
|
if (bytesRead === prefix.length && prefix.equals(LOCAL_API_REQUEST_PREFIX)) {
|
|
122001
122405
|
excludedBytes += lineLength;
|
|
122002
122406
|
}
|
|
@@ -122006,7 +122410,7 @@ function countLocalApiRequestRecordBytes(transcriptPath, start, end) {
|
|
|
122006
122410
|
let position = start;
|
|
122007
122411
|
while (position < end) {
|
|
122008
122412
|
const length = Math.min(SCAN_CHUNK_BYTES, end - position);
|
|
122009
|
-
(0,
|
|
122413
|
+
(0, import_fs164.readSync)(fd, chunk, 0, length, position);
|
|
122010
122414
|
const view = chunk.subarray(0, length);
|
|
122011
122415
|
let newline = view.indexOf(10);
|
|
122012
122416
|
while (newline !== -1) {
|
|
@@ -122018,7 +122422,7 @@ function countLocalApiRequestRecordBytes(transcriptPath, start, end) {
|
|
|
122018
122422
|
if (lineStart < end) countLine(end);
|
|
122019
122423
|
return excludedBytes;
|
|
122020
122424
|
} finally {
|
|
122021
|
-
(0,
|
|
122425
|
+
(0, import_fs164.closeSync)(fd);
|
|
122022
122426
|
}
|
|
122023
122427
|
}
|
|
122024
122428
|
function estimateTranscriptPayloadBytes(transcriptPath, size) {
|
|
@@ -122033,9 +122437,9 @@ function estimateTranscriptPayloadBytes(transcriptPath, size) {
|
|
|
122033
122437
|
);
|
|
122034
122438
|
}
|
|
122035
122439
|
function estimatePayloadFromTranscriptPath(transcriptPath) {
|
|
122036
|
-
if (!transcriptPath || !(0,
|
|
122440
|
+
if (!transcriptPath || !(0, import_fs164.existsSync)(transcriptPath)) return null;
|
|
122037
122441
|
try {
|
|
122038
|
-
const stat2 = (0,
|
|
122442
|
+
const stat2 = (0, import_fs164.statSync)(transcriptPath);
|
|
122039
122443
|
if (!stat2.isFile()) return null;
|
|
122040
122444
|
return createPayloadEstimate(
|
|
122041
122445
|
estimateTranscriptPayloadBytes(transcriptPath, stat2.size)
|
|
@@ -122044,11 +122448,11 @@ function estimatePayloadFromTranscriptPath(transcriptPath) {
|
|
|
122044
122448
|
return null;
|
|
122045
122449
|
}
|
|
122046
122450
|
}
|
|
122047
|
-
var
|
|
122451
|
+
var import_fs164, ANTHROPIC_REQUEST_PAYLOAD_LIMIT_BYTES, PAYLOAD_WARNING_BYTES, PAYLOAD_CRITICAL_BYTES, COMPACT_BOUNDARY_MARKER, COMPACT_BOUNDARY_MARKER_BYTES, LOCAL_API_REQUEST_PREFIX, SCAN_CHUNK_BYTES, MAX_BOUNDARY_LINE_BYTES;
|
|
122048
122452
|
var init_payload_estimate = __esm({
|
|
122049
122453
|
"src/hud/payload-estimate.ts"() {
|
|
122050
122454
|
"use strict";
|
|
122051
|
-
|
|
122455
|
+
import_fs164 = require("fs");
|
|
122052
122456
|
ANTHROPIC_REQUEST_PAYLOAD_LIMIT_BYTES = 32e6;
|
|
122053
122457
|
PAYLOAD_WARNING_BYTES = 22e6;
|
|
122054
122458
|
PAYLOAD_CRITICAL_BYTES = 26e6;
|
|
@@ -122107,10 +122511,10 @@ function mergeStdinRateLimits(stdinRateLimits, usageResult) {
|
|
|
122107
122511
|
};
|
|
122108
122512
|
}
|
|
122109
122513
|
function readSessionSummary(stateDir, sessionId) {
|
|
122110
|
-
const statePath = (0,
|
|
122111
|
-
if (!(0,
|
|
122514
|
+
const statePath = (0, import_path195.join)(stateDir, `session-summary-${sessionId}.json`);
|
|
122515
|
+
if (!(0, import_fs165.existsSync)(statePath)) return null;
|
|
122112
122516
|
try {
|
|
122113
|
-
return JSON.parse((0,
|
|
122517
|
+
return JSON.parse((0, import_fs165.readFileSync)(statePath, "utf-8"));
|
|
122114
122518
|
} catch {
|
|
122115
122519
|
return null;
|
|
122116
122520
|
}
|
|
@@ -122136,22 +122540,22 @@ function spawnSessionSummaryScript(transcriptPath, stateDir, sessionId) {
|
|
|
122136
122540
|
return;
|
|
122137
122541
|
}
|
|
122138
122542
|
lastSummarySpawnTimestamp = now2;
|
|
122139
|
-
const thisDir = (0,
|
|
122140
|
-
const scriptPath = (0,
|
|
122543
|
+
const thisDir = (0, import_path195.dirname)((0, import_url24.fileURLToPath)(importMetaUrl));
|
|
122544
|
+
const scriptPath = (0, import_path195.join)(
|
|
122141
122545
|
thisDir,
|
|
122142
122546
|
"..",
|
|
122143
122547
|
"..",
|
|
122144
122548
|
"scripts",
|
|
122145
122549
|
"session-summary.mjs"
|
|
122146
122550
|
);
|
|
122147
|
-
if (!(0,
|
|
122551
|
+
if (!(0, import_fs165.existsSync)(scriptPath)) {
|
|
122148
122552
|
if (process.env.OMC_DEBUG) {
|
|
122149
122553
|
console.error("[HUD] session-summary script not found:", scriptPath);
|
|
122150
122554
|
}
|
|
122151
122555
|
return;
|
|
122152
122556
|
}
|
|
122153
122557
|
try {
|
|
122154
|
-
const child = (0,
|
|
122558
|
+
const child = (0, import_child_process56.spawn)(
|
|
122155
122559
|
"node",
|
|
122156
122560
|
[scriptPath, transcriptPath, stateDir, sessionId],
|
|
122157
122561
|
{
|
|
@@ -122183,12 +122587,12 @@ async function calculateSessionHealth(sessionStart, contextPercent) {
|
|
|
122183
122587
|
function showDiagnostic() {
|
|
122184
122588
|
const version3 = getRuntimePackageVersion();
|
|
122185
122589
|
const configDir = getCopilotConfigDir();
|
|
122186
|
-
const hudScript = (0,
|
|
122187
|
-
const settingsFile = (0,
|
|
122188
|
-
const hudExists = HUD_SCRIPT_NAMES.some((name) => (0,
|
|
122590
|
+
const hudScript = (0, import_path195.join)(configDir, "hud", HUD_SCRIPT_NAMES[0]);
|
|
122591
|
+
const settingsFile = (0, import_path195.join)(configDir, "settings.json");
|
|
122592
|
+
const hudExists = HUD_SCRIPT_NAMES.some((name) => (0, import_fs165.existsSync)((0, import_path195.join)(configDir, "hud", name)));
|
|
122189
122593
|
let statusLineOk = false;
|
|
122190
122594
|
try {
|
|
122191
|
-
const settings = JSON.parse((0,
|
|
122595
|
+
const settings = JSON.parse((0, import_fs165.readFileSync)(settingsFile, "utf-8"));
|
|
122192
122596
|
const sl = settings.statusLine;
|
|
122193
122597
|
const command = sl && typeof sl === "object" && typeof sl.command === "string" ? sl.command : typeof sl === "string" ? sl : null;
|
|
122194
122598
|
statusLineOk = command !== null && HUD_COMMAND_MARKERS.some((marker) => command.includes(marker));
|
|
@@ -122291,8 +122695,8 @@ async function mainImpl(watchMode = false, skipInit = false) {
|
|
|
122291
122695
|
}
|
|
122292
122696
|
try {
|
|
122293
122697
|
const updateCacheFile = getUpdateCheckCachePath();
|
|
122294
|
-
await (0,
|
|
122295
|
-
const content = await (0,
|
|
122698
|
+
await (0, import_promises36.access)(updateCacheFile);
|
|
122699
|
+
const content = await (0, import_promises36.readFile)(updateCacheFile, "utf-8");
|
|
122296
122700
|
const cached2 = JSON.parse(content);
|
|
122297
122701
|
if (cached2?.latestVersion && omcVersion && compareVersions2(omcVersion, cached2.latestVersion) < 0) {
|
|
122298
122702
|
updateAvailable = cached2.latestVersion;
|
|
@@ -122314,7 +122718,7 @@ async function mainImpl(watchMode = false, skipInit = false) {
|
|
|
122314
122718
|
let sessionSummary = null;
|
|
122315
122719
|
const sessionSummaryEnabled = config2.elements.sessionSummary ?? false;
|
|
122316
122720
|
if (sessionSummaryEnabled && resolvedTranscriptPath && currentSessionId) {
|
|
122317
|
-
const omcStateDir = (0,
|
|
122721
|
+
const omcStateDir = (0, import_path195.join)(getOmcRoot(cwd2), "state");
|
|
122318
122722
|
sessionSummary = readSessionSummary(omcStateDir, currentSessionId);
|
|
122319
122723
|
const shouldSpawn = !sessionSummary?.generatedAt || Date.now() - new Date(sessionSummary.generatedAt).getTime() > 6e4;
|
|
122320
122724
|
if (shouldSpawn) {
|
|
@@ -122372,7 +122776,7 @@ async function mainImpl(watchMode = false, skipInit = false) {
|
|
|
122372
122776
|
apiKeyMode: detectApiKeySource(cwd2) !== null,
|
|
122373
122777
|
subscriptionType: subscriptionInfo.subscriptionType,
|
|
122374
122778
|
rateLimitTier: subscriptionInfo.rateLimitTier,
|
|
122375
|
-
profileName: process.env.COPILOT_HOME ? (0,
|
|
122779
|
+
profileName: process.env.COPILOT_HOME ? (0, import_path195.basename)(process.env.COPILOT_HOME).replace(/^\./, "") : null,
|
|
122376
122780
|
sessionSummary,
|
|
122377
122781
|
lastToolName: transcriptData.lastToolName,
|
|
122378
122782
|
recentTools: transcriptData.recentTools,
|
|
@@ -122390,10 +122794,10 @@ async function mainImpl(watchMode = false, skipInit = false) {
|
|
|
122390
122794
|
}
|
|
122391
122795
|
if (config2.contextLimitWarning.autoCompact && context.contextPercent >= config2.contextLimitWarning.threshold) {
|
|
122392
122796
|
try {
|
|
122393
|
-
const omcStateDir = (0,
|
|
122394
|
-
(0,
|
|
122395
|
-
const triggerFile = (0,
|
|
122396
|
-
(0,
|
|
122797
|
+
const omcStateDir = (0, import_path195.join)(getOmcRoot(cwd2), "state");
|
|
122798
|
+
(0, import_fs165.mkdirSync)(omcStateDir, { recursive: true });
|
|
122799
|
+
const triggerFile = (0, import_path195.join)(omcStateDir, "compact-requested.json");
|
|
122800
|
+
(0, import_fs165.writeFileSync)(
|
|
122397
122801
|
triggerFile,
|
|
122398
122802
|
JSON.stringify({
|
|
122399
122803
|
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -122435,7 +122839,7 @@ async function mainImpl(watchMode = false, skipInit = false) {
|
|
|
122435
122839
|
function main2(watchMode = false, skipInit = false) {
|
|
122436
122840
|
return withWorktreePathRenderScope(() => mainImpl(watchMode, skipInit));
|
|
122437
122841
|
}
|
|
122438
|
-
var
|
|
122842
|
+
var import_fs165, import_promises36, import_path195, import_child_process56, import_url24, HUD_SCRIPT_NAMES, HUD_COMMAND_MARKERS, SAME_WINDOW_TOLERANCE_MS, lastSummarySpawnTimestamp, summaryProcessPid;
|
|
122439
122843
|
var init_hud = __esm({
|
|
122440
122844
|
"src/hud/index.ts"() {
|
|
122441
122845
|
"use strict";
|
|
@@ -122453,11 +122857,11 @@ var init_hud = __esm({
|
|
|
122453
122857
|
init_version();
|
|
122454
122858
|
init_auto_update();
|
|
122455
122859
|
init_worktree_paths();
|
|
122456
|
-
|
|
122457
|
-
|
|
122458
|
-
|
|
122459
|
-
|
|
122460
|
-
|
|
122860
|
+
import_fs165 = require("fs");
|
|
122861
|
+
import_promises36 = require("fs/promises");
|
|
122862
|
+
import_path195 = require("path");
|
|
122863
|
+
import_child_process56 = require("child_process");
|
|
122864
|
+
import_url24 = require("url");
|
|
122461
122865
|
init_worktree_paths();
|
|
122462
122866
|
init_config_dir();
|
|
122463
122867
|
HUD_SCRIPT_NAMES = ["omg-hud.mjs", "omcp-hud.mjs", "omcp-hud.js"];
|
|
@@ -122478,8 +122882,8 @@ __export(index_exports, {
|
|
|
122478
122882
|
module.exports = __toCommonJS(index_exports);
|
|
122479
122883
|
init_esm();
|
|
122480
122884
|
init_source();
|
|
122481
|
-
var
|
|
122482
|
-
var
|
|
122885
|
+
var import_path196 = require("path");
|
|
122886
|
+
var import_fs166 = require("fs");
|
|
122483
122887
|
init_config_dir();
|
|
122484
122888
|
init_env_vars();
|
|
122485
122889
|
init_loader();
|
|
@@ -124296,22 +124700,22 @@ function isEscapedByOddBackslashes(text, index) {
|
|
|
124296
124700
|
}
|
|
124297
124701
|
function findSubstitutionEnd(text, start) {
|
|
124298
124702
|
let depth = 1;
|
|
124299
|
-
let
|
|
124703
|
+
let quote3 = null;
|
|
124300
124704
|
let sawCase = false;
|
|
124301
124705
|
let casePatternPending = false;
|
|
124302
124706
|
let word = "";
|
|
124303
124707
|
for (let index = start + 2; index < text.length; index += 1) {
|
|
124304
124708
|
const character = text[index] ?? "";
|
|
124305
|
-
if (
|
|
124306
|
-
if (character === "'")
|
|
124709
|
+
if (quote3 === "'") {
|
|
124710
|
+
if (character === "'") quote3 = null;
|
|
124307
124711
|
continue;
|
|
124308
124712
|
}
|
|
124309
|
-
if (
|
|
124713
|
+
if (quote3 === '"') {
|
|
124310
124714
|
if (character === "\\") {
|
|
124311
124715
|
index += 1;
|
|
124312
124716
|
continue;
|
|
124313
124717
|
}
|
|
124314
|
-
if (character === '"')
|
|
124718
|
+
if (character === '"') quote3 = null;
|
|
124315
124719
|
continue;
|
|
124316
124720
|
}
|
|
124317
124721
|
if (character === "\\") {
|
|
@@ -124330,7 +124734,7 @@ function findSubstitutionEnd(text, start) {
|
|
|
124330
124734
|
continue;
|
|
124331
124735
|
}
|
|
124332
124736
|
if (character === "'" || character === '"') {
|
|
124333
|
-
|
|
124737
|
+
quote3 = character;
|
|
124334
124738
|
continue;
|
|
124335
124739
|
}
|
|
124336
124740
|
if (/[A-Za-z]/.test(character)) {
|
|
@@ -124361,25 +124765,25 @@ function findSubstitutionEnd(text, start) {
|
|
|
124361
124765
|
function findNestedSubstitutions(clauses) {
|
|
124362
124766
|
const nested = [];
|
|
124363
124767
|
for (const clause of clauses) {
|
|
124364
|
-
let
|
|
124768
|
+
let quote3 = null;
|
|
124365
124769
|
for (let index = 0; index < clause.text.length; index += 1) {
|
|
124366
124770
|
const character = clause.text[index] ?? "";
|
|
124367
|
-
if (
|
|
124368
|
-
if (character === "'")
|
|
124771
|
+
if (quote3 === "'") {
|
|
124772
|
+
if (character === "'") quote3 = null;
|
|
124369
124773
|
continue;
|
|
124370
124774
|
}
|
|
124371
|
-
if (
|
|
124775
|
+
if (quote3 === '"') {
|
|
124372
124776
|
if (character === "\\") {
|
|
124373
124777
|
index += 1;
|
|
124374
124778
|
continue;
|
|
124375
124779
|
}
|
|
124376
|
-
if (character === '"' && !isEscapedByOddBackslashes(clause.text, index))
|
|
124780
|
+
if (character === '"' && !isEscapedByOddBackslashes(clause.text, index)) quote3 = null;
|
|
124377
124781
|
} else if (character === "'") {
|
|
124378
|
-
|
|
124782
|
+
quote3 = "'";
|
|
124379
124783
|
} else if (character === '"') {
|
|
124380
|
-
|
|
124784
|
+
quote3 = '"';
|
|
124381
124785
|
}
|
|
124382
|
-
if (
|
|
124786
|
+
if (quote3 === "'") continue;
|
|
124383
124787
|
if (character === "\\") {
|
|
124384
124788
|
index += 1;
|
|
124385
124789
|
continue;
|
|
@@ -124394,7 +124798,7 @@ function findNestedSubstitutions(clauses) {
|
|
|
124394
124798
|
nested.push({ text: clause.text.slice(index + 2, end), index: clause.index + index + 2 });
|
|
124395
124799
|
index = end;
|
|
124396
124800
|
}
|
|
124397
|
-
} else if (
|
|
124801
|
+
} else if (quote3 === null && (clause.text.startsWith("<(", index) || clause.text.startsWith(">(", index))) {
|
|
124398
124802
|
const end = findSubstitutionEnd(clause.text, index);
|
|
124399
124803
|
if (end >= 0) {
|
|
124400
124804
|
nested.push({ text: clause.text.slice(index + 2, end), index: clause.index + index + 2 });
|
|
@@ -124505,22 +124909,22 @@ function tokenizeCommand(segment) {
|
|
|
124505
124909
|
while (index < segment.length && /\s/.test(segment[index] ?? "")) index += 1;
|
|
124506
124910
|
if (index >= segment.length) break;
|
|
124507
124911
|
const start = index;
|
|
124508
|
-
let
|
|
124912
|
+
let quote3 = null;
|
|
124509
124913
|
let raw = "";
|
|
124510
124914
|
while (index < segment.length) {
|
|
124511
124915
|
const character = segment[index] ?? "";
|
|
124512
|
-
if (
|
|
124916
|
+
if (quote3 !== null) {
|
|
124513
124917
|
raw += character;
|
|
124514
|
-
if (
|
|
124515
|
-
if (character === "'")
|
|
124918
|
+
if (quote3 === "'") {
|
|
124919
|
+
if (character === "'") quote3 = null;
|
|
124516
124920
|
} else if (character === '"' && !isEscapedByOddBackslashes2(segment, index)) {
|
|
124517
|
-
|
|
124921
|
+
quote3 = null;
|
|
124518
124922
|
}
|
|
124519
124923
|
index += 1;
|
|
124520
124924
|
continue;
|
|
124521
124925
|
}
|
|
124522
124926
|
if ((character === '"' || raw.length === 0 || segment.indexOf(character, index + 1) >= 0) && (character === "'" || character === '"')) {
|
|
124523
|
-
|
|
124927
|
+
quote3 = character;
|
|
124524
124928
|
raw += character;
|
|
124525
124929
|
index += 1;
|
|
124526
124930
|
continue;
|
|
@@ -124545,15 +124949,15 @@ function tokenizeCommand(segment) {
|
|
|
124545
124949
|
function splitCommandClauses(line) {
|
|
124546
124950
|
const clauses = [];
|
|
124547
124951
|
let start = 0;
|
|
124548
|
-
let
|
|
124952
|
+
let quote3 = null;
|
|
124549
124953
|
let index = 0;
|
|
124550
124954
|
while (index < line.length) {
|
|
124551
124955
|
const character = line[index] ?? "";
|
|
124552
|
-
if (
|
|
124553
|
-
if (
|
|
124554
|
-
if (character === "'")
|
|
124956
|
+
if (quote3 !== null) {
|
|
124957
|
+
if (quote3 === "'") {
|
|
124958
|
+
if (character === "'") quote3 = null;
|
|
124555
124959
|
} else if (character === '"' && !isEscapedByOddBackslashes2(line, index)) {
|
|
124556
|
-
|
|
124960
|
+
quote3 = null;
|
|
124557
124961
|
}
|
|
124558
124962
|
index += 1;
|
|
124559
124963
|
continue;
|
|
@@ -124563,7 +124967,7 @@ function splitCommandClauses(line) {
|
|
|
124563
124967
|
continue;
|
|
124564
124968
|
}
|
|
124565
124969
|
if (character === "'" || character === '"') {
|
|
124566
|
-
|
|
124970
|
+
quote3 = character;
|
|
124567
124971
|
index += 1;
|
|
124568
124972
|
continue;
|
|
124569
124973
|
}
|
|
@@ -125309,24 +125713,24 @@ function isExplicitSqlContext(line, end, start) {
|
|
|
125309
125713
|
);
|
|
125310
125714
|
}
|
|
125311
125715
|
function hasOpenShellQuote(text) {
|
|
125312
|
-
let
|
|
125716
|
+
let quote3 = null;
|
|
125313
125717
|
for (let index = 0; index < text.length; index += 1) {
|
|
125314
125718
|
const character = text[index] ?? "";
|
|
125315
|
-
if (
|
|
125316
|
-
if (character === "'")
|
|
125719
|
+
if (quote3 === "'") {
|
|
125720
|
+
if (character === "'") quote3 = null;
|
|
125317
125721
|
continue;
|
|
125318
125722
|
}
|
|
125319
|
-
if (
|
|
125723
|
+
if (quote3 === '"') {
|
|
125320
125724
|
if (character === "\\") {
|
|
125321
125725
|
index += 1;
|
|
125322
125726
|
continue;
|
|
125323
125727
|
}
|
|
125324
|
-
if (character === '"')
|
|
125728
|
+
if (character === '"') quote3 = null;
|
|
125325
125729
|
continue;
|
|
125326
125730
|
}
|
|
125327
|
-
if (character === "'" || character === '"')
|
|
125731
|
+
if (character === "'" || character === '"') quote3 = character;
|
|
125328
125732
|
}
|
|
125329
|
-
return
|
|
125733
|
+
return quote3 !== null;
|
|
125330
125734
|
}
|
|
125331
125735
|
function hasSqlClientCommandContext(before) {
|
|
125332
125736
|
const lastNewline = before.lastIndexOf("\n");
|
|
@@ -125488,19 +125892,19 @@ function isDocumentationSqlExample(line, index) {
|
|
|
125488
125892
|
var HEREDOC_INTERPRETER = /^(?:[\w./@-]+\/)?(?:bash|sh|dash|zsh|ksh|sqlite3|psql|mysql|mariadb|sqlcmd)$/i;
|
|
125489
125893
|
function findHereDocMarkers(line) {
|
|
125490
125894
|
const markers = [];
|
|
125491
|
-
let
|
|
125895
|
+
let quote3 = null;
|
|
125492
125896
|
for (let index = 0; index < line.length; index += 1) {
|
|
125493
125897
|
const character = line[index] ?? "";
|
|
125494
|
-
if (
|
|
125495
|
-
if (character === "'")
|
|
125898
|
+
if (quote3 === "'") {
|
|
125899
|
+
if (character === "'") quote3 = null;
|
|
125496
125900
|
continue;
|
|
125497
125901
|
}
|
|
125498
|
-
if (
|
|
125902
|
+
if (quote3 === '"') {
|
|
125499
125903
|
if (character === "\\") {
|
|
125500
125904
|
index += 1;
|
|
125501
125905
|
continue;
|
|
125502
125906
|
}
|
|
125503
|
-
if (character === '"')
|
|
125907
|
+
if (character === '"') quote3 = null;
|
|
125504
125908
|
continue;
|
|
125505
125909
|
}
|
|
125506
125910
|
if (character === "\\") {
|
|
@@ -125508,11 +125912,11 @@ function findHereDocMarkers(line) {
|
|
|
125508
125912
|
continue;
|
|
125509
125913
|
}
|
|
125510
125914
|
if (character === "'") {
|
|
125511
|
-
|
|
125915
|
+
quote3 = "'";
|
|
125512
125916
|
continue;
|
|
125513
125917
|
}
|
|
125514
125918
|
if (character === '"') {
|
|
125515
|
-
|
|
125919
|
+
quote3 = '"';
|
|
125516
125920
|
continue;
|
|
125517
125921
|
}
|
|
125518
125922
|
if (character === "#" && (index === 0 || /\s/.test(line[index - 1] ?? ""))) return [];
|
|
@@ -127405,8 +127809,8 @@ function isConsecutiveCanonicalShareMet(history, threshold = RETIREMENT_POLICY.m
|
|
|
127405
127809
|
reason: `insufficient releases: have ${history.length}, need ${requiredConsecutive}`
|
|
127406
127810
|
};
|
|
127407
127811
|
}
|
|
127408
|
-
const
|
|
127409
|
-
const evaluated =
|
|
127812
|
+
const tail3 = history.slice(-requiredConsecutive);
|
|
127813
|
+
const evaluated = tail3.map((h) => {
|
|
127410
127814
|
const r = isCanonicalShareMet(h.aliasCount, h.canonicalCount, threshold);
|
|
127411
127815
|
return { share: r.share, met: r.met };
|
|
127412
127816
|
});
|
|
@@ -127568,8 +127972,8 @@ var ENTRYPOINT_RE = /scripts\/([A-Za-z0-9._-]+\.mjs)((?:"|\s)[^"]*)?$/;
|
|
|
127568
127972
|
function parseEntrypointCommand(command) {
|
|
127569
127973
|
const m = ENTRYPOINT_RE.exec(command);
|
|
127570
127974
|
if (!m) return null;
|
|
127571
|
-
const
|
|
127572
|
-
const args =
|
|
127975
|
+
const tail3 = (m[2] ?? "").trim();
|
|
127976
|
+
const args = tail3.length > 0 ? tail3.split(/\s+/) : [];
|
|
127573
127977
|
return { entrypoint: m[1], args };
|
|
127574
127978
|
}
|
|
127575
127979
|
function riskClassForEntrypoint(entrypoint) {
|
|
@@ -130077,6 +130481,9 @@ async function processHookImpl(hookType, rawInput) {
|
|
|
130077
130481
|
}
|
|
130078
130482
|
}
|
|
130079
130483
|
async function processHook(hookType, rawInput) {
|
|
130484
|
+
if (process.env.DISABLE_OMC === "1" || process.env.DISABLE_OMC === "true") {
|
|
130485
|
+
return { continue: true };
|
|
130486
|
+
}
|
|
130080
130487
|
const legacyStarted = performance.now();
|
|
130081
130488
|
const rawRecord = rawInput && typeof rawInput === "object" ? rawInput : {};
|
|
130082
130489
|
const inputDirectory = typeof rawRecord.cwd === "string" ? rawRecord.cwd : typeof rawRecord.directory === "string" ? rawRecord.directory : void 0;
|
|
@@ -130307,7 +130714,7 @@ var import_path131 = require("path");
|
|
|
130307
130714
|
init_finder2();
|
|
130308
130715
|
|
|
130309
130716
|
// src/hooks/rules-injector/matcher.ts
|
|
130310
|
-
var
|
|
130717
|
+
var import_crypto37 = require("crypto");
|
|
130311
130718
|
var import_path129 = require("path");
|
|
130312
130719
|
|
|
130313
130720
|
// src/hooks/rules-injector/parser.ts
|
|
@@ -130548,7 +130955,7 @@ init_config_dir();
|
|
|
130548
130955
|
init_atomic_write();
|
|
130549
130956
|
|
|
130550
130957
|
// src/hooks/learner/auto-learner.ts
|
|
130551
|
-
var
|
|
130958
|
+
var import_crypto38 = require("crypto");
|
|
130552
130959
|
|
|
130553
130960
|
// src/hooks/index.ts
|
|
130554
130961
|
init_autopilot();
|
|
@@ -130561,7 +130968,7 @@ init_pre_compact2();
|
|
|
130561
130968
|
// src/hooks/pre-compact/restore.ts
|
|
130562
130969
|
var import_fs116 = require("fs");
|
|
130563
130970
|
var import_child_process34 = require("child_process");
|
|
130564
|
-
var
|
|
130971
|
+
var import_crypto39 = require("crypto");
|
|
130565
130972
|
var import_path141 = require("path");
|
|
130566
130973
|
var import_url19 = require("url");
|
|
130567
130974
|
init_worktree_paths();
|
|
@@ -134065,7 +134472,7 @@ async function doctorConflictsCommand(options) {
|
|
|
134065
134472
|
}
|
|
134066
134473
|
|
|
134067
134474
|
// src/cli/commands/ralph.ts
|
|
134068
|
-
var
|
|
134475
|
+
var import_crypto41 = require("crypto");
|
|
134069
134476
|
var import_child_process43 = require("child_process");
|
|
134070
134477
|
var import_fs135 = require("fs");
|
|
134071
134478
|
var import_path162 = require("path");
|
|
@@ -134239,8 +134646,8 @@ function enumerateFrontier(mapNumber, records2) {
|
|
|
134239
134646
|
if (record2.assignees > 0) continue;
|
|
134240
134647
|
const parsed = parseBlocked(record2.body);
|
|
134241
134648
|
const blockers = [...record2.nativeBlockedBy ?? [], ...parsed.blockers];
|
|
134242
|
-
const
|
|
134243
|
-
if (
|
|
134649
|
+
const blocked2 = blockers.some((blocker) => (stateByNumber.get(blocker) ?? "OPEN") !== "CLOSED");
|
|
134650
|
+
if (blocked2) continue;
|
|
134244
134651
|
const type = ticketType(record2.labels);
|
|
134245
134652
|
const ticket = {
|
|
134246
134653
|
number: record2.number,
|
|
@@ -134491,15 +134898,15 @@ function storiesFromPlan(plan, records2) {
|
|
|
134491
134898
|
return stories;
|
|
134492
134899
|
}
|
|
134493
134900
|
function launchGate(outcomes, records2) {
|
|
134494
|
-
const
|
|
134901
|
+
const blocked2 = [];
|
|
134495
134902
|
for (const outcome of outcomes) {
|
|
134496
134903
|
if (outcome.action !== "drafted-then-stopped") continue;
|
|
134497
134904
|
const record2 = records2.find((r) => r.number === outcome.ticket);
|
|
134498
134905
|
if (criteriaItems(record2?.body ?? "").length === 0) {
|
|
134499
|
-
|
|
134906
|
+
blocked2.push({ ticket: outcome.ticket, reason: "drafted criteria not yet accepted (no criteria section on the ticket)" });
|
|
134500
134907
|
}
|
|
134501
134908
|
}
|
|
134502
|
-
return { ok:
|
|
134909
|
+
return { ok: blocked2.length === 0, blocked: blocked2 };
|
|
134503
134910
|
}
|
|
134504
134911
|
function currentBranch2(directory) {
|
|
134505
134912
|
try {
|
|
@@ -134642,7 +135049,7 @@ var RALPH_AFK_FEEDBACK_ENV = "OMC_RALPH_AFK_FEEDBACK";
|
|
|
134642
135049
|
function afkFeedbackCommands(verifyCommands) {
|
|
134643
135050
|
return verifyCommands.filter((command) => command.length <= MAX_VERIFY_COMMAND_LENGTH && VERIFY_COMMAND_PATTERN.test(command)).slice(0, MAX_VERIFY_COMMANDS);
|
|
134644
135051
|
}
|
|
134645
|
-
function ralphAfkArgv(task, verifyCommands = [], sessionId = (0,
|
|
135052
|
+
function ralphAfkArgv(task, verifyCommands = [], sessionId = (0, import_crypto41.randomUUID)()) {
|
|
134646
135053
|
const prompt = `/ralph --no-deslop ${task}`;
|
|
134647
135054
|
const argv = factoryLinkArgv(prompt, sessionId, verifyCommands, RALPH_AFK_READONLY_GIT);
|
|
134648
135055
|
if (getHostCliType() === "copilot") return [...argv, ...COPILOT_RALPH_AFK_SESSION_FLAGS];
|
|
@@ -134699,7 +135106,7 @@ Examples:
|
|
|
134699
135106
|
if (materialized?.status === "diverged") {
|
|
134700
135107
|
console.warn(`warning: ${materialized.path} differs from the bundled ralph skill \u2014 delete it to refresh, or keep it if the divergence is intentional`);
|
|
134701
135108
|
}
|
|
134702
|
-
const sessionId = (0,
|
|
135109
|
+
const sessionId = (0, import_crypto41.randomUUID)();
|
|
134703
135110
|
process.env.OMC_SESSION_ID = sessionId;
|
|
134704
135111
|
process.env[RALPH_AFK_FEEDBACK_ENV] = JSON.stringify(afkFeedbackCommands(options.verify ?? []));
|
|
134705
135112
|
const argv = ralphAfkArgv(task, options.verify ?? [], sessionId);
|
|
@@ -134782,7 +135189,7 @@ Examples:
|
|
|
134782
135189
|
else console.log(renderMapPlan(plan));
|
|
134783
135190
|
return;
|
|
134784
135191
|
}
|
|
134785
|
-
const sessionId = options.session ?? (0,
|
|
135192
|
+
const sessionId = options.session ?? (0, import_crypto41.randomUUID)();
|
|
134786
135193
|
if (options.launch) {
|
|
134787
135194
|
try {
|
|
134788
135195
|
validateSessionId(sessionId);
|
|
@@ -135224,7 +135631,7 @@ async function budgetCommand(action, options, cwd2 = process.cwd()) {
|
|
|
135224
135631
|
}
|
|
135225
135632
|
|
|
135226
135633
|
// src/cli/commands/capabilities.ts
|
|
135227
|
-
var
|
|
135634
|
+
var import_crypto46 = require("crypto");
|
|
135228
135635
|
var import_fs145 = require("fs");
|
|
135229
135636
|
var import_path175 = require("path");
|
|
135230
135637
|
init_zod();
|
|
@@ -135254,7 +135661,7 @@ function sortJson(value) {
|
|
|
135254
135661
|
return value;
|
|
135255
135662
|
}
|
|
135256
135663
|
function sha2562(value) {
|
|
135257
|
-
return (0,
|
|
135664
|
+
return (0, import_crypto46.createHash)("sha256").update(value).digest("hex");
|
|
135258
135665
|
}
|
|
135259
135666
|
function resolveLockfilePath(lockfile) {
|
|
135260
135667
|
return (0, import_path175.resolve)(process.cwd(), lockfile ?? DEFAULT_CAPABILITIES_LOCKFILE);
|
|
@@ -140777,7 +141184,7 @@ async function launchCommand(args) {
|
|
|
140777
141184
|
|
|
140778
141185
|
// src/cli/interop.ts
|
|
140779
141186
|
var import_child_process50 = require("child_process");
|
|
140780
|
-
var
|
|
141187
|
+
var import_crypto47 = require("crypto");
|
|
140781
141188
|
init_tmux_utils();
|
|
140782
141189
|
init_host_detection();
|
|
140783
141190
|
init_model_contract();
|
|
@@ -140837,7 +141244,7 @@ function launchInteropSession(cwd2 = process.cwd()) {
|
|
|
140837
141244
|
console.error("Start tmux first: tmux new-session -s myproject");
|
|
140838
141245
|
process.exit(1);
|
|
140839
141246
|
}
|
|
140840
|
-
const sessionId = `interop-${(0,
|
|
141247
|
+
const sessionId = `interop-${(0, import_crypto47.randomUUID)().split("-")[0]}`;
|
|
140841
141248
|
const _config = initInteropSession(sessionId, cwd2, hasCodex ? cwd2 : void 0);
|
|
140842
141249
|
console.log(`Initializing interop session: ${sessionId}`);
|
|
140843
141250
|
console.log(`Working directory: ${cwd2}`);
|
|
@@ -141278,7 +141685,7 @@ Goal: ${context.descriptor.goal}`;
|
|
|
141278
141685
|
interrupt: true
|
|
141279
141686
|
};
|
|
141280
141687
|
};
|
|
141281
|
-
const
|
|
141688
|
+
const collect2 = async () => {
|
|
141282
141689
|
const returned = queryFn({
|
|
141283
141690
|
prompt,
|
|
141284
141691
|
options: {
|
|
@@ -141317,7 +141724,7 @@ Goal: ${context.descriptor.goal}`;
|
|
|
141317
141724
|
}
|
|
141318
141725
|
return parts.join("\n");
|
|
141319
141726
|
};
|
|
141320
|
-
const work =
|
|
141727
|
+
const work = collect2();
|
|
141321
141728
|
try {
|
|
141322
141729
|
const text = await Promise.race([work, timedOut]);
|
|
141323
141730
|
if (text.trim().length === 0) {
|
|
@@ -142582,45 +142989,45 @@ function runPrepare(opts) {
|
|
|
142582
142989
|
const steps = [];
|
|
142583
142990
|
const housekeepingCommits = [];
|
|
142584
142991
|
const git5 = (...args) => exec3("git", args, { cwd: cwd2 });
|
|
142585
|
-
const
|
|
142992
|
+
const fail7 = (name, detail, extra = {}) => {
|
|
142586
142993
|
steps.push({ name, status: "failed", detail });
|
|
142587
142994
|
return { ok: false, steps, housekeepingCommits, blockedReason: `${name}: ${detail.split("\n")[0]}`, ...extra };
|
|
142588
142995
|
};
|
|
142589
142996
|
const head = () => git5("rev-parse", "HEAD").stdout.trim();
|
|
142590
142997
|
for (const [label, name] of [["base", base], ["branch", opts.branch]]) {
|
|
142591
142998
|
if (!isPlainBranchName(name) || git5("check-ref-format", "--branch", name).status !== 0) {
|
|
142592
|
-
return
|
|
142999
|
+
return fail7("preflight", `${label} ${JSON.stringify(name)} is not a valid branch name`);
|
|
142593
143000
|
}
|
|
142594
143001
|
}
|
|
142595
|
-
if (!/^[\w][\w.-]*$/.test(remote)) return
|
|
142596
|
-
if (!/^[0-9a-f]{40}$/.test(opts.reviewedSha)) return
|
|
142597
|
-
if (!/^[0-9a-f]{40}$/.test(baseSha)) return
|
|
143002
|
+
if (!/^[\w][\w.-]*$/.test(remote)) return fail7("preflight", `remote ${JSON.stringify(remote)} is not a valid remote name`);
|
|
143003
|
+
if (!/^[0-9a-f]{40}$/.test(opts.reviewedSha)) return fail7("preflight", `reviewed sha ${JSON.stringify(opts.reviewedSha)} is not a full commit id`);
|
|
143004
|
+
if (!/^[0-9a-f]{40}$/.test(baseSha)) return fail7("preflight", `GitHub's base sha ${JSON.stringify(baseSha)} is not a full commit id`);
|
|
142598
143005
|
const branch = git5("rev-parse", "--abbrev-ref", "HEAD").stdout.trim();
|
|
142599
|
-
if (!branch || branch === "HEAD") return
|
|
142600
|
-
if (branch === base || branch === "main" || branch === "master") return
|
|
142601
|
-
if (branch !== opts.branch) return
|
|
143006
|
+
if (!branch || branch === "HEAD") return fail7("preflight", "detached HEAD; check out the PR branch");
|
|
143007
|
+
if (branch === base || branch === "main" || branch === "master") return fail7("preflight", `refusing to prepare on ${branch}; use the PR branch`);
|
|
143008
|
+
if (branch !== opts.branch) return fail7("preflight", `checked out ${branch}, but the ship run is for ${opts.branch}; check out the PR branch`);
|
|
142602
143009
|
if (git5("merge-base", "--is-ancestor", opts.reviewedSha, "HEAD").status !== 0) {
|
|
142603
|
-
return
|
|
143010
|
+
return fail7("preflight", `HEAD does not contain the reviewed commit ${opts.reviewedSha.slice(0, 12)}; pull the PR branch (merge, never rebase) or re-review`);
|
|
142604
143011
|
}
|
|
142605
143012
|
for (const [ref, what] of [["MERGE_HEAD", "a merge"], ["CHERRY_PICK_HEAD", "a cherry-pick"], ["REVERT_HEAD", "a revert"]]) {
|
|
142606
|
-
if (git5("rev-parse", "-q", "--verify", ref).status === 0) return
|
|
143013
|
+
if (git5("rev-parse", "-q", "--verify", ref).status === 0) return fail7("preflight", `${what} is in progress; commit or abort it first`);
|
|
142607
143014
|
}
|
|
142608
143015
|
for (const marker of ["rebase-merge", "rebase-apply"]) {
|
|
142609
143016
|
const p = git5("rev-parse", "--git-path", marker).stdout.trim();
|
|
142610
|
-
if (p && exists((0, import_path186.isAbsolute)(p) ? p : (0, import_path186.join)(cwd2, p))) return
|
|
143017
|
+
if (p && exists((0, import_path186.isAbsolute)(p) ? p : (0, import_path186.join)(cwd2, p))) return fail7("preflight", "a rebase is in progress; finish or abort it (ship never rebases)");
|
|
142611
143018
|
}
|
|
142612
143019
|
const dirty = git5("status", "--porcelain", "--untracked-files=no").stdout.trim();
|
|
142613
|
-
if (dirty) return
|
|
143020
|
+
if (dirty) return fail7("preflight", `working tree has uncommitted changes:
|
|
142614
143021
|
${dirty}`);
|
|
142615
|
-
if (git5("diff", "--cached", "--quiet").status !== 0) return
|
|
143022
|
+
if (git5("diff", "--cached", "--quiet").status !== 0) return fail7("preflight", "the index has staged changes; commit or unstage them first");
|
|
142616
143023
|
steps.push({ name: "preflight", status: "ok", detail: branch });
|
|
142617
143024
|
const mismatch = remoteRepoMismatch(exec3, cwd2, remote, opts.repoUrl);
|
|
142618
|
-
if (mismatch) return
|
|
143025
|
+
if (mismatch) return fail7("remote", `${mismatch}; refusing to fetch (fail closed)`);
|
|
142619
143026
|
const fetched = git5("fetch", remote, base);
|
|
142620
|
-
if (fetched.status !== 0) return
|
|
143027
|
+
if (fetched.status !== 0) return fail7("fetch", tail(fetched.stderr));
|
|
142621
143028
|
const local = git5("rev-parse", "--verify", upstream);
|
|
142622
143029
|
if (local.status !== 0 || local.stdout.trim() !== baseSha) {
|
|
142623
|
-
return
|
|
143030
|
+
return fail7("fetch", `${upstream} is ${local.stdout.trim() || "missing"}, but GitHub reports ${base} at ${baseSha}; refusing (fail closed; re-run if ${base} just moved)`);
|
|
142624
143031
|
}
|
|
142625
143032
|
steps.push({ name: "fetch", status: "ok", detail: `${upstream} = ${baseSha}` });
|
|
142626
143033
|
if (git5("merge-base", "--is-ancestor", baseSha, "HEAD").status === 0) {
|
|
@@ -142631,11 +143038,11 @@ ${dirty}`);
|
|
|
142631
143038
|
const conflicts = lines2(git5("diff", "--name-only", "--diff-filter=U").stdout);
|
|
142632
143039
|
const inventoryOnly = conflicts.length > 0 && conflicts.every((f) => f.startsWith(`${INVENTORY_DIR}/`));
|
|
142633
143040
|
if (!inventoryOnly) {
|
|
142634
|
-
return
|
|
143041
|
+
return fail7("merge-base", conflicts.length > 0 ? `conflicts outside ${INVENTORY_DIR}/ need a human or a fix lane: ${conflicts.join(", ")} (resolve and commit, or git merge --abort)` : tail(merged.stderr || merged.stdout), { conflicts });
|
|
142635
143042
|
}
|
|
142636
143043
|
for (const args of [["checkout", "--theirs", "--", INVENTORY_DIR], ["add", "--", INVENTORY_DIR], ["commit", "--no-edit", "--no-verify"]]) {
|
|
142637
143044
|
const r = git5(...args);
|
|
142638
|
-
if (r.status !== 0) return
|
|
143045
|
+
if (r.status !== 0) return fail7("merge-base", `git ${args.join(" ")}: ${tail(r.stderr || r.stdout)}`, { conflicts });
|
|
142639
143046
|
}
|
|
142640
143047
|
steps.push({ name: "merge-base", status: "ok", detail: `merged ${base} ${baseSha.slice(0, 12)}; inventory conflict resolved with --theirs` });
|
|
142641
143048
|
} else {
|
|
@@ -142659,7 +143066,7 @@ ${dirty}`);
|
|
|
142659
143066
|
continue;
|
|
142660
143067
|
}
|
|
142661
143068
|
const r = exec3(node, args, { cwd: cwd2 });
|
|
142662
|
-
if (r.status !== 0) return
|
|
143069
|
+
if (r.status !== 0) return fail7(name, tail(`${r.stdout}
|
|
142663
143070
|
${r.stderr}`));
|
|
142664
143071
|
steps.push({ name, status: "ok", detail: args.slice(1).join(" ").slice(0, 300) });
|
|
142665
143072
|
}
|
|
@@ -142670,22 +143077,22 @@ ${r.stderr}`));
|
|
|
142670
143077
|
steps.push({ name: "inventory", status: "skipped", detail: "baseline is current" });
|
|
142671
143078
|
} else {
|
|
142672
143079
|
const written = exec3(node, [INVENTORY_SCRIPT, "--write"], { cwd: cwd2 });
|
|
142673
|
-
if (written.status !== 0) return
|
|
143080
|
+
if (written.status !== 0) return fail7("inventory", tail(written.stderr || written.stdout));
|
|
142674
143081
|
const added = git5("add", "--", INVENTORY_DIR);
|
|
142675
|
-
if (added.status !== 0) return
|
|
143082
|
+
if (added.status !== 0) return fail7("inventory", `git add -- ${INVENTORY_DIR}: ${tail(added.stderr || added.stdout)}`);
|
|
142676
143083
|
if (git5("diff", "--cached", "--quiet", "--", INVENTORY_DIR).status !== 0) {
|
|
142677
143084
|
const committed = git5("commit", "--no-verify", "-m", INVENTORY_COMMIT_MESSAGE, "--", INVENTORY_DIR);
|
|
142678
|
-
if (committed.status !== 0) return
|
|
143085
|
+
if (committed.status !== 0) return fail7("inventory", tail(committed.stderr || committed.stdout));
|
|
142679
143086
|
housekeepingCommits.push(head());
|
|
142680
143087
|
}
|
|
142681
143088
|
const verified = exec3(node, [INVENTORY_SCRIPT, "--verify"], { cwd: cwd2 });
|
|
142682
|
-
if (verified.status !== 0) return
|
|
143089
|
+
if (verified.status !== 0) return fail7("inventory", `regenerated baseline still fails --verify:
|
|
142683
143090
|
${tail(verified.stderr || verified.stdout)}`);
|
|
142684
143091
|
steps.push({ name: "inventory", status: "ok", detail: "regenerated as the last commit" });
|
|
142685
143092
|
}
|
|
142686
143093
|
if (opts.push) {
|
|
142687
143094
|
const pushed = git5("push", remote, `HEAD:refs/heads/${opts.branch}`);
|
|
142688
|
-
if (pushed.status !== 0) return
|
|
143095
|
+
if (pushed.status !== 0) return fail7("push", tail(pushed.stderr));
|
|
142689
143096
|
steps.push({ name: "push", status: "ok", detail: `${remote} ${opts.branch}` });
|
|
142690
143097
|
}
|
|
142691
143098
|
return { ok: true, steps, housekeepingCommits };
|
|
@@ -142995,6 +143402,1463 @@ function shipCommand(execImpl = defaultExec, loadShipConfig = shipConfig) {
|
|
|
142995
143402
|
return cmd;
|
|
142996
143403
|
}
|
|
142997
143404
|
|
|
143405
|
+
// src/cli/commands/release.ts
|
|
143406
|
+
init_esm();
|
|
143407
|
+
init_source();
|
|
143408
|
+
var import_promises35 = require("readline/promises");
|
|
143409
|
+
init_config4();
|
|
143410
|
+
init_worktree_paths();
|
|
143411
|
+
|
|
143412
|
+
// src/release/checks.ts
|
|
143413
|
+
var VERSION_RE = /^\d+\.\d+\.\d+$/;
|
|
143414
|
+
function parseReleaseVersion(raw) {
|
|
143415
|
+
const v = raw.trim().replace(/^v/, "");
|
|
143416
|
+
if (!VERSION_RE.test(v)) throw new Error(`version must be X.Y.Z, got ${JSON.stringify(raw)}`);
|
|
143417
|
+
return v;
|
|
143418
|
+
}
|
|
143419
|
+
function compareVersions3(a, b) {
|
|
143420
|
+
const pa = parseReleaseVersion(a).split(".").map(Number);
|
|
143421
|
+
const pb = parseReleaseVersion(b).split(".").map(Number);
|
|
143422
|
+
for (let i = 0; i < 3; i++) if (pa[i] !== pb[i]) return pa[i] - pb[i];
|
|
143423
|
+
return 0;
|
|
143424
|
+
}
|
|
143425
|
+
var escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
143426
|
+
function releaseProseProblems(version3, changelog, releaseBody) {
|
|
143427
|
+
const problems = [];
|
|
143428
|
+
const v = escapeRe(version3);
|
|
143429
|
+
if (changelog === null) problems.push("CHANGELOG.md is missing");
|
|
143430
|
+
else {
|
|
143431
|
+
if (!new RegExp(`^## \\[${v}\\]`, "m").test(changelog)) problems.push(`CHANGELOG.md has no "## [${version3}] - YYYY-MM-DD" section`);
|
|
143432
|
+
if (!new RegExp(`^# .+ v${v}(?:[:\\s]|$)`, "m").test(changelog)) problems.push(`CHANGELOG.md has no "# oh-my-copilot v${version3}" heading (the release boundary greps for it)`);
|
|
143433
|
+
}
|
|
143434
|
+
if (releaseBody === null || releaseBody.trim() === "") problems.push(".github/release-body.md is missing or empty");
|
|
143435
|
+
else if (!releaseBody.includes(version3)) problems.push(`.github/release-body.md does not mention ${version3}`);
|
|
143436
|
+
return problems;
|
|
143437
|
+
}
|
|
143438
|
+
var VERSION_STAMPS = [
|
|
143439
|
+
{ file: ".claude-plugin/plugin.json", pattern: /"version": "[^"]*"/, replace: (v) => `"version": "${v}"` },
|
|
143440
|
+
{ file: "plugin.json", pattern: /"version": "[^"]*"/, replace: (v) => `"version": "${v}"` },
|
|
143441
|
+
{ file: ".claude-plugin/marketplace.json", pattern: /"version": "[^"]*"/g, replace: (v) => `"version": "${v}"` },
|
|
143442
|
+
{ file: "docs/CLAUDE.md", pattern: /<!-- OMC:VERSION:[^ ]* -->/g, replace: (v) => `<!-- OMC:VERSION:${v} -->` },
|
|
143443
|
+
{ file: "CLAUDE.md", pattern: /<!-- OMC:VERSION:[^ ]* -->/g, replace: (v) => `<!-- OMC:VERSION:${v} -->` },
|
|
143444
|
+
{ file: ".github/CLAUDE.md", pattern: /<!-- OMC:VERSION:[^ ]* -->/g, replace: (v) => `<!-- OMC:VERSION:${v} -->` },
|
|
143445
|
+
{ file: "tests/fixtures/prompt-projection/claude-managed-block.golden", pattern: /<!-- OMC:VERSION:[^ ]* -->/g, replace: (v) => `<!-- OMC:VERSION:${v} -->` },
|
|
143446
|
+
{ file: ".github/upstream-port.json", pattern: /"fork_version": "[^"]*"/g, replace: (v) => `"fork_version": "${v}"` }
|
|
143447
|
+
];
|
|
143448
|
+
function stampVersion(content, stamp, version3) {
|
|
143449
|
+
const pattern = new RegExp(stamp.pattern.source, stamp.pattern.flags);
|
|
143450
|
+
if (!pattern.test(content)) return null;
|
|
143451
|
+
return content.replace(new RegExp(stamp.pattern.source, stamp.pattern.flags), stamp.replace(version3));
|
|
143452
|
+
}
|
|
143453
|
+
var DIST_OUTPUT = /^dist\/(.+?)\.(?:d\.ts\.map|d\.ts|js\.map|js)$/;
|
|
143454
|
+
var SOURCE_EXTS = [".ts", ".tsx", ".js", ".jsx"];
|
|
143455
|
+
function findDistOrphans(trackedDist, exists) {
|
|
143456
|
+
const orphans = [];
|
|
143457
|
+
for (const raw of trackedDist) {
|
|
143458
|
+
const file = raw.replace(/\\/g, "/");
|
|
143459
|
+
const m = DIST_OUTPUT.exec(file);
|
|
143460
|
+
if (!m) continue;
|
|
143461
|
+
if (!SOURCE_EXTS.some((ext) => exists(`src/${m[1]}${ext}`))) orphans.push(file);
|
|
143462
|
+
}
|
|
143463
|
+
return orphans;
|
|
143464
|
+
}
|
|
143465
|
+
var REPO_DIRS = /(?:^|\/)((?:src|tests|scripts|benchmark|bridge|skills|hooks)\/.+)$/;
|
|
143466
|
+
function repoRelativeTestPath(file) {
|
|
143467
|
+
const norm = file.replace(/\\/g, "/");
|
|
143468
|
+
return REPO_DIRS.exec(norm)?.[1] ?? norm;
|
|
143469
|
+
}
|
|
143470
|
+
function failingTitlesFromVitestJson(text) {
|
|
143471
|
+
const report = JSON.parse(text);
|
|
143472
|
+
if (!Array.isArray(report?.testResults)) throw new Error("not a vitest JSON report (no testResults)");
|
|
143473
|
+
const out = /* @__PURE__ */ new Set();
|
|
143474
|
+
for (const file of report.testResults) {
|
|
143475
|
+
const rel = repoRelativeTestPath(file.name ?? "");
|
|
143476
|
+
const failed2 = (file.assertionResults ?? []).filter((a) => a.status === "failed");
|
|
143477
|
+
for (const a of failed2) out.add(`${rel} > ${a.fullName ?? a.title ?? ""}`);
|
|
143478
|
+
if (failed2.length === 0 && file.status === "failed") out.add(rel);
|
|
143479
|
+
}
|
|
143480
|
+
return [...out].sort();
|
|
143481
|
+
}
|
|
143482
|
+
function parseBaselineTitles(text) {
|
|
143483
|
+
const trimmed = text.trim();
|
|
143484
|
+
if (trimmed.startsWith("{")) return failingTitlesFromVitestJson(trimmed);
|
|
143485
|
+
return trimmed.split(/\r?\n/).map((l) => l.trim()).filter((l) => l && !l.startsWith("#")).map((l) => {
|
|
143486
|
+
const [file, ...rest] = l.split(" > ");
|
|
143487
|
+
return rest.length > 0 ? `${repoRelativeTestPath(file)} > ${rest.join(" > ")}` : repoRelativeTestPath(file);
|
|
143488
|
+
});
|
|
143489
|
+
}
|
|
143490
|
+
function newFailures(failing, baseline) {
|
|
143491
|
+
const known = new Set(baseline);
|
|
143492
|
+
return failing.filter((t) => !known.has(t));
|
|
143493
|
+
}
|
|
143494
|
+
function smokeProblems(stdout) {
|
|
143495
|
+
const start = stdout.indexOf("{");
|
|
143496
|
+
let report;
|
|
143497
|
+
try {
|
|
143498
|
+
report = JSON.parse(start >= 0 ? stdout.slice(start) : stdout);
|
|
143499
|
+
} catch {
|
|
143500
|
+
return ["smoke did not print a JSON report"];
|
|
143501
|
+
}
|
|
143502
|
+
const problems = [];
|
|
143503
|
+
if (typeof report.skipped === "string" && report.skipped) problems.push(`smoke skipped: ${report.skipped}`);
|
|
143504
|
+
const checks = Array.isArray(report.checks) ? report.checks : [];
|
|
143505
|
+
if (checks.length === 0) problems.push("smoke reported no checks");
|
|
143506
|
+
for (const c of checks) if (c.ok !== true) problems.push(`${String(c.id)}: ${String(c.detail ?? "failed")}`);
|
|
143507
|
+
if (report.ok !== true && problems.length === 0) problems.push("smoke report ok=false");
|
|
143508
|
+
return problems;
|
|
143509
|
+
}
|
|
143510
|
+
function remoteTagTarget(lsRemote, tag) {
|
|
143511
|
+
let object3;
|
|
143512
|
+
let peeled;
|
|
143513
|
+
for (const line of lsRemote.split(/\r?\n/)) {
|
|
143514
|
+
const [sha, ref] = line.trim().split(/\s+/);
|
|
143515
|
+
if (ref === `refs/tags/${tag}`) object3 = sha;
|
|
143516
|
+
else if (ref === `refs/tags/${tag}^{}`) peeled = sha;
|
|
143517
|
+
}
|
|
143518
|
+
if (!object3) return null;
|
|
143519
|
+
return { object: object3, commit: peeled ?? object3, annotated: peeled !== void 0 };
|
|
143520
|
+
}
|
|
143521
|
+
function tagTargetProblem(tag, objectType3, peeled, expected) {
|
|
143522
|
+
if (objectType3.trim() !== "tag") return `${tag} is a ${objectType3.trim() || "missing"} object, not an annotated tag`;
|
|
143523
|
+
if (peeled.trim() !== expected) return `${tag}^{} is ${peeled.trim().slice(0, 12) || "unresolved"}, not the main merge commit ${expected.slice(0, 12)}`;
|
|
143524
|
+
return null;
|
|
143525
|
+
}
|
|
143526
|
+
|
|
143527
|
+
// src/release/engine.ts
|
|
143528
|
+
var import_child_process54 = require("child_process");
|
|
143529
|
+
var import_fs156 = require("fs");
|
|
143530
|
+
var import_path187 = require("path");
|
|
143531
|
+
var import_url23 = require("url");
|
|
143532
|
+
init_atomic_write();
|
|
143533
|
+
init_config4();
|
|
143534
|
+
init_exec();
|
|
143535
|
+
var PHASES2 = ["preflight", "bump", "build", "gates", "smoke", "commit", "pr", "promote", "tag", "verify"];
|
|
143536
|
+
function isPhaseId(value) {
|
|
143537
|
+
return PHASES2.includes(value);
|
|
143538
|
+
}
|
|
143539
|
+
var PROSE_FILES = ["CHANGELOG.md", ".github/release-body.md", "README.md", "docs/REFERENCE.md", "docs/MIGRATION.md"];
|
|
143540
|
+
var SHELL_SAFE_ARG = /^[\w@./:=-]+$/;
|
|
143541
|
+
var defaultReleaseExec = (cmd, args, opts) => {
|
|
143542
|
+
const shell = process.platform === "win32" && cmd === "npm";
|
|
143543
|
+
if (shell && !args.every((a) => SHELL_SAFE_ARG.test(a))) {
|
|
143544
|
+
return { status: 1, stdout: "", stderr: `refusing to pass ${JSON.stringify(args)} to npm through cmd.exe` };
|
|
143545
|
+
}
|
|
143546
|
+
const result = (0, import_child_process54.spawnSync)(shell ? ["npm", ...args].join(" ") : cmd, shell ? [] : args, {
|
|
143547
|
+
cwd: opts?.cwd,
|
|
143548
|
+
env: { ...scrubShipEnv(process.env), ...opts?.env },
|
|
143549
|
+
encoding: "utf8",
|
|
143550
|
+
windowsHide: true,
|
|
143551
|
+
maxBuffer: 512 * 1024 * 1024,
|
|
143552
|
+
shell,
|
|
143553
|
+
timeout: opts?.timeoutMs
|
|
143554
|
+
});
|
|
143555
|
+
return {
|
|
143556
|
+
status: result.status ?? 1,
|
|
143557
|
+
stdout: result.stdout ?? "",
|
|
143558
|
+
stderr: `${result.stderr ?? ""}${result.error ? result.error.message : ""}`
|
|
143559
|
+
};
|
|
143560
|
+
};
|
|
143561
|
+
var PhaseStop = class extends Error {
|
|
143562
|
+
constructor(outcome) {
|
|
143563
|
+
super(outcome.note);
|
|
143564
|
+
this.outcome = outcome;
|
|
143565
|
+
}
|
|
143566
|
+
};
|
|
143567
|
+
var fail6 = (note, details) => {
|
|
143568
|
+
throw new PhaseStop({ status: "fail", note, details });
|
|
143569
|
+
};
|
|
143570
|
+
var blocked = (note, details) => {
|
|
143571
|
+
throw new PhaseStop({ status: "blocked", note, details });
|
|
143572
|
+
};
|
|
143573
|
+
function releaseStatePath(stateRoot2, version3) {
|
|
143574
|
+
return (0, import_path187.join)(stateRoot2, "release", `${version3}.json`);
|
|
143575
|
+
}
|
|
143576
|
+
function readReleaseState(stateRoot2, version3) {
|
|
143577
|
+
const path30 = releaseStatePath(stateRoot2, version3);
|
|
143578
|
+
if (!(0, import_fs156.existsSync)(path30)) return null;
|
|
143579
|
+
const parsed = JSON.parse((0, import_fs156.readFileSync)(path30, "utf8"));
|
|
143580
|
+
if (parsed?.version !== 1 || parsed.release !== version3 || typeof parsed.phases !== "object") {
|
|
143581
|
+
throw new Error(`${path30} is not a release state for ${version3}`);
|
|
143582
|
+
}
|
|
143583
|
+
return { ...parsed, reruns: parsed.reruns ?? {} };
|
|
143584
|
+
}
|
|
143585
|
+
function tail2(text, lines3 = 30) {
|
|
143586
|
+
return text.trim().split(/\r?\n/).slice(-lines3);
|
|
143587
|
+
}
|
|
143588
|
+
var FULL_SHA3 = /^[0-9a-f]{40}$/;
|
|
143589
|
+
var RERUN_START_POLLS = 40;
|
|
143590
|
+
var LAND_ROUNDS = 500;
|
|
143591
|
+
function phasePlan(id, v, opts) {
|
|
143592
|
+
const branch = `release/v${v}`;
|
|
143593
|
+
switch (id) {
|
|
143594
|
+
case "preflight":
|
|
143595
|
+
return [
|
|
143596
|
+
`git status --porcelain is empty apart from ${PROSE_FILES.join(", ")}`,
|
|
143597
|
+
`HEAD is ${branch}; git fetch origin dev; origin/dev is an ancestor of HEAD`,
|
|
143598
|
+
`${v} > package.json version on origin/dev and > npm dist-tags.latest`,
|
|
143599
|
+
"gh auth status; no .git/index.lock (holder reported, never deleted)",
|
|
143600
|
+
`tag v${v} absent on origin (git ls-remote --tags origin)`
|
|
143601
|
+
];
|
|
143602
|
+
case "bump":
|
|
143603
|
+
return [
|
|
143604
|
+
`refuse unless CHANGELOG.md has "## [${v}]" and "# oh-my-copilot v${v}", and .github/release-body.md mentions ${v}`,
|
|
143605
|
+
`npm version ${v} --no-git-tag-version --ignore-scripts --allow-same-version`,
|
|
143606
|
+
`stamp ${v}: ${VERSION_STAMPS.map((s) => s.file).join(", ")}`,
|
|
143607
|
+
"node scripts/generate-prompt-projections.mjs"
|
|
143608
|
+
];
|
|
143609
|
+
case "build":
|
|
143610
|
+
return [
|
|
143611
|
+
"npm run build",
|
|
143612
|
+
"git add -f dist bridge",
|
|
143613
|
+
`tracked dist .js/.d.ts/.map without a src source -> ${opts.fixOrphans ? "git rm (--fix-orphans)" : "fail (pass --fix-orphans to remove)"}`,
|
|
143614
|
+
"git ls-files --others dist bridge is empty",
|
|
143615
|
+
`probes: import dist/index.js; dist/cli/index.js --version == ${v}; bridge/cli.cjs --version == ${v}; dist/mcp/standalone-server.js starts and exits`
|
|
143616
|
+
];
|
|
143617
|
+
case "gates":
|
|
143618
|
+
return [
|
|
143619
|
+
"tsc --noEmit",
|
|
143620
|
+
"generate-prompt-projections.mjs --verify; copilot build-hooks.mjs / build-agents.mjs --verify",
|
|
143621
|
+
"node scripts/ci/check-multirepo-paths.mjs",
|
|
143622
|
+
opts.suite === "full" ? `vitest run --reporter=json; fail only on titles not in ${opts.baseline ?? "(no baseline: any failure fails)"}` : opts.suite === "targeted" ? "vitest related --run <src files changed since the last v* tag>" : "suite: none (pass --suite targeted|full)"
|
|
143623
|
+
];
|
|
143624
|
+
case "smoke":
|
|
143625
|
+
return opts.liveSmoke ? ["OMC_LIVE_SMOKE=2 node bridge/cli.cjs smoke copilot --tier 2 --json (about 2 premium requests); every check must pass"] : ["SKIPPED: live Tier 2 smoke not requested (pass --live-smoke; about 2 premium requests)"];
|
|
143626
|
+
case "commit":
|
|
143627
|
+
return [
|
|
143628
|
+
`git add -f dist bridge; git add -A; git commit -m "chore(release): v${v}"`,
|
|
143629
|
+
"node scripts/generate-inventory-graph.mjs --write; commit inventory/ if changed; --verify",
|
|
143630
|
+
"git status --porcelain is empty"
|
|
143631
|
+
];
|
|
143632
|
+
case "pr":
|
|
143633
|
+
return [
|
|
143634
|
+
`git push origin HEAD:refs/heads/${branch} until the PR is merged (plain, never forced; a refused push blocks)`,
|
|
143635
|
+
`gh pr create --base dev --head ${branch} (an open one is reused; a merged one when its merge contains HEAD, or the dev tip once a follow-up PR into dev carried HEAD; else blocks)`,
|
|
143636
|
+
"wait for CI under the ship merge rule (ship.advisoryChecks never block); one rerun of failed jobs, awaited until its new attempt starts",
|
|
143637
|
+
"gh pr merge --admin --merge --match-head-commit <head> when the PR head is local HEAD, ship.allowAdminMerge and dev is a trusted base, else print it"
|
|
143638
|
+
];
|
|
143639
|
+
case "promote":
|
|
143640
|
+
return [
|
|
143641
|
+
"require the release PR merged into dev (gh pr view); use the dev merge recorded by pr",
|
|
143642
|
+
"gh pr create --base main --head dev (reused when one is open)",
|
|
143643
|
+
"same CI gate and merge as pr, merged only when the PR head contains the dev merge; the main merge must contain it too; record it"
|
|
143644
|
+
];
|
|
143645
|
+
case "tag":
|
|
143646
|
+
return [
|
|
143647
|
+
`the main merge commit contains the dev merge and its package.json is ${v}`,
|
|
143648
|
+
`confirm (${opts.yes ? "--yes given" : "interactive; --yes skips"})`,
|
|
143649
|
+
`git tag -a v${v} -m v${v} <main merge sha>; v${v}^{} must equal it and be an annotated tag`,
|
|
143650
|
+
`git push origin refs/tags/v${v}; git ls-remote confirms the peeled sha`
|
|
143651
|
+
];
|
|
143652
|
+
case "verify":
|
|
143653
|
+
return [
|
|
143654
|
+
`find the ci.yml push run of v${v} on the main merge commit; wait; one rerun of failed jobs unless ${v} is already on npm, failing test titles printed`,
|
|
143655
|
+
`npm view oh-my-copilot@${v} version dist-tags.latest dist.attestations`,
|
|
143656
|
+
`gh release view v${v}: published, not a draft; the Copilot smoke (tier 2) job succeeded`
|
|
143657
|
+
];
|
|
143658
|
+
}
|
|
143659
|
+
}
|
|
143660
|
+
var Release = class {
|
|
143661
|
+
constructor(deps, opts, existing) {
|
|
143662
|
+
this.deps = deps;
|
|
143663
|
+
this.opts = opts;
|
|
143664
|
+
this.v = opts.version;
|
|
143665
|
+
const at = new Date(deps.now()).toISOString();
|
|
143666
|
+
this.state = existing ?? { version: 1, release: this.v, createdAt: at, updatedAt: at, phases: {}, reruns: {} };
|
|
143667
|
+
this.deadline = deps.now() + (opts.timeoutMinutes ?? 60) * 6e4;
|
|
143668
|
+
}
|
|
143669
|
+
state;
|
|
143670
|
+
v;
|
|
143671
|
+
deadline;
|
|
143672
|
+
pkgName = "oh-my-copilot";
|
|
143673
|
+
get current() {
|
|
143674
|
+
return this.state;
|
|
143675
|
+
}
|
|
143676
|
+
save(patch) {
|
|
143677
|
+
this.state = { ...this.state, ...patch, updatedAt: new Date(this.deps.now()).toISOString() };
|
|
143678
|
+
const path30 = releaseStatePath(this.deps.stateRoot, this.v);
|
|
143679
|
+
(0, import_fs156.mkdirSync)((0, import_path187.join)(this.deps.stateRoot, "release"), { recursive: true });
|
|
143680
|
+
atomicWriteJsonSync(path30, this.state);
|
|
143681
|
+
}
|
|
143682
|
+
run(cmd, args, opts) {
|
|
143683
|
+
return this.deps.exec(cmd, args, { cwd: this.deps.root, ...opts });
|
|
143684
|
+
}
|
|
143685
|
+
/** Run and require exit 0; the phase fails with the output tail otherwise. */
|
|
143686
|
+
must(cmd, args, what, opts) {
|
|
143687
|
+
const r = this.run(cmd, args, opts);
|
|
143688
|
+
if (r.status !== 0) fail6(`${what ?? `${cmd} ${args.join(" ")}`} failed (exit ${r.status})`, tail2(`${r.stdout}
|
|
143689
|
+
${r.stderr}`));
|
|
143690
|
+
return r.stdout;
|
|
143691
|
+
}
|
|
143692
|
+
git(...args) {
|
|
143693
|
+
return this.must("git", args).trim();
|
|
143694
|
+
}
|
|
143695
|
+
script(script, ...args) {
|
|
143696
|
+
this.deps.log(` node ${[script, ...args].join(" ")}`);
|
|
143697
|
+
this.must(this.deps.node, [script, ...args], `node ${[script, ...args].join(" ")}`);
|
|
143698
|
+
}
|
|
143699
|
+
file(rel) {
|
|
143700
|
+
const path30 = (0, import_path187.join)(this.deps.root, rel);
|
|
143701
|
+
return (0, import_fs156.existsSync)(path30) ? (0, import_fs156.readFileSync)(path30, "utf8") : null;
|
|
143702
|
+
}
|
|
143703
|
+
readPkgName() {
|
|
143704
|
+
const pkg = this.file("package.json");
|
|
143705
|
+
if (pkg) this.pkgName = JSON.parse(pkg).name ?? this.pkgName;
|
|
143706
|
+
}
|
|
143707
|
+
async phase(id) {
|
|
143708
|
+
this.readPkgName();
|
|
143709
|
+
try {
|
|
143710
|
+
switch (id) {
|
|
143711
|
+
case "preflight":
|
|
143712
|
+
return this.preflight();
|
|
143713
|
+
case "bump":
|
|
143714
|
+
return this.bump();
|
|
143715
|
+
case "build":
|
|
143716
|
+
return this.build();
|
|
143717
|
+
case "gates":
|
|
143718
|
+
return this.gates();
|
|
143719
|
+
case "smoke":
|
|
143720
|
+
return this.smoke();
|
|
143721
|
+
case "commit":
|
|
143722
|
+
return this.commit();
|
|
143723
|
+
case "pr":
|
|
143724
|
+
return await this.pr();
|
|
143725
|
+
case "promote":
|
|
143726
|
+
return await this.promote();
|
|
143727
|
+
case "tag":
|
|
143728
|
+
return await this.tag();
|
|
143729
|
+
case "verify":
|
|
143730
|
+
return await this.verify();
|
|
143731
|
+
}
|
|
143732
|
+
} catch (error2) {
|
|
143733
|
+
if (error2 instanceof PhaseStop) return error2.outcome;
|
|
143734
|
+
return { status: "fail", note: error2 instanceof Error ? error2.message : String(error2) };
|
|
143735
|
+
}
|
|
143736
|
+
}
|
|
143737
|
+
preflight() {
|
|
143738
|
+
const v = this.v;
|
|
143739
|
+
const problems = [];
|
|
143740
|
+
const dirty = this.must("git", ["status", "--porcelain"]).split(/\r?\n/).filter(Boolean).map((l) => l.slice(3)).filter((entry2) => !entry2.split(" -> ").every((p) => PROSE_FILES.includes(p.replace(/^"|"$/g, ""))));
|
|
143741
|
+
if (dirty.length > 0) problems.push(`working tree is not clean: ${dirty.join(", ")}`);
|
|
143742
|
+
const branch = this.git("rev-parse", "--abbrev-ref", "HEAD");
|
|
143743
|
+
if (branch !== `release/v${v}`) problems.push(`HEAD is ${branch}, expected release/v${v} (git checkout -b release/v${v} origin/dev)`);
|
|
143744
|
+
this.must("git", ["fetch", "origin", "dev"]);
|
|
143745
|
+
if (this.run("git", ["merge-base", "--is-ancestor", "refs/remotes/origin/dev", "HEAD"]).status !== 0) {
|
|
143746
|
+
problems.push("HEAD does not contain origin/dev (git merge origin/dev; never rebase)");
|
|
143747
|
+
}
|
|
143748
|
+
const devPkg = this.run("git", ["show", "refs/remotes/origin/dev:package.json"]);
|
|
143749
|
+
const devVersion = devPkg.status === 0 ? JSON.parse(devPkg.stdout).version : void 0;
|
|
143750
|
+
if (!devVersion) problems.push("could not read package.json on origin/dev");
|
|
143751
|
+
else if (compareVersions3(v, devVersion) <= 0) problems.push(`${v} is not above origin/dev's version ${devVersion}`);
|
|
143752
|
+
const latest2 = this.run("npm", ["view", this.pkgName, "dist-tags.latest"]);
|
|
143753
|
+
if (latest2.status === 0) {
|
|
143754
|
+
const published = latest2.stdout.trim();
|
|
143755
|
+
if (published && compareVersions3(v, published) <= 0) problems.push(`${v} is not above npm latest ${published}`);
|
|
143756
|
+
} else if (!/E404/.test(latest2.stderr)) problems.push(`npm view ${this.pkgName} failed: ${tail2(latest2.stderr, 1).join("")}`);
|
|
143757
|
+
if (this.run("gh", ["auth", "status"]).status !== 0) problems.push("gh is not authenticated (gh auth login)");
|
|
143758
|
+
const lockRel = this.git("rev-parse", "--git-path", "index.lock");
|
|
143759
|
+
const lock = (0, import_path187.isAbsolute)(lockRel) ? lockRel : (0, import_path187.join)(this.deps.root, lockRel);
|
|
143760
|
+
if ((0, import_fs156.existsSync)(lock)) {
|
|
143761
|
+
problems.push(`${lock} exists; another git process may hold it (not deleted; remove it only when no git process runs): ${this.gitProcesses()}`);
|
|
143762
|
+
}
|
|
143763
|
+
const remoteTag = this.run("git", ["ls-remote", "--tags", "origin", `refs/tags/v${v}`]);
|
|
143764
|
+
if (remoteTag.status !== 0) problems.push(`git ls-remote --tags origin failed: ${tail2(remoteTag.stderr, 1).join("")}`);
|
|
143765
|
+
else if (remoteTag.stdout.trim()) problems.push(`tag v${v} already exists on origin`);
|
|
143766
|
+
if (problems.length > 0) fail6(`${problems.length} preflight problem(s)`, problems);
|
|
143767
|
+
this.save({ branch, headSha: void 0, devPr: void 0, devMergeSha: void 0, mainPr: void 0, mainMergeSha: void 0, tagRunId: void 0 });
|
|
143768
|
+
return { status: "ok", note: `on release/v${v} over origin/dev ${devVersion}` };
|
|
143769
|
+
}
|
|
143770
|
+
gitProcesses() {
|
|
143771
|
+
const r = process.platform === "win32" ? this.run("tasklist", ["/FI", "IMAGENAME eq git.exe", "/FO", "CSV", "/NH"]) : this.run("ps", ["-eo", "pid,args"]);
|
|
143772
|
+
const lines3 = r.stdout.split(/\r?\n/).filter((l) => /git(?:\.exe)?\b/i.test(l) && !/INFO:/.test(l));
|
|
143773
|
+
return lines3.length > 0 ? lines3.slice(0, 5).join(" | ") : "no running git process found";
|
|
143774
|
+
}
|
|
143775
|
+
bump() {
|
|
143776
|
+
const v = this.v;
|
|
143777
|
+
const prose = releaseProseProblems(v, this.file("CHANGELOG.md"), this.file(".github/release-body.md"));
|
|
143778
|
+
if (prose.length > 0) fail6("release prose is missing (write it, then re-run)", prose);
|
|
143779
|
+
const pkg = JSON.parse(this.file("package.json") ?? "{}");
|
|
143780
|
+
if (pkg.version !== v) this.must("npm", ["version", v, "--no-git-tag-version", "--ignore-scripts", "--allow-same-version"]);
|
|
143781
|
+
const missing = [];
|
|
143782
|
+
for (const stamp of VERSION_STAMPS) {
|
|
143783
|
+
const content = this.file(stamp.file);
|
|
143784
|
+
const next = content === null ? null : stampVersion(content, stamp, v);
|
|
143785
|
+
if (next === null) missing.push(`${stamp.file}: no version stamp`);
|
|
143786
|
+
else if (next !== content) (0, import_fs156.writeFileSync)((0, import_path187.join)(this.deps.root, stamp.file), next);
|
|
143787
|
+
}
|
|
143788
|
+
if (missing.length > 0) fail6("version stamps missing", missing);
|
|
143789
|
+
this.script("scripts/generate-prompt-projections.mjs");
|
|
143790
|
+
return { status: "ok", note: `version ${v} stamped in package.json and ${VERSION_STAMPS.length} files` };
|
|
143791
|
+
}
|
|
143792
|
+
build() {
|
|
143793
|
+
const v = this.v;
|
|
143794
|
+
this.deps.log(" npm run build");
|
|
143795
|
+
this.must("npm", ["run", "build"], "npm run build");
|
|
143796
|
+
this.git("add", "-f", "dist", "bridge");
|
|
143797
|
+
const tracked = this.git("ls-files", "dist").split(/\r?\n/).filter(Boolean);
|
|
143798
|
+
const orphans = findDistOrphans(tracked, (p) => (0, import_fs156.existsSync)((0, import_path187.join)(this.deps.root, p)));
|
|
143799
|
+
if (orphans.length > 0) {
|
|
143800
|
+
if (!this.opts.fixOrphans) fail6(`${orphans.length} dist file(s) without a src source (re-run with --fix-orphans to remove them)`, orphans);
|
|
143801
|
+
for (let i = 0; i < orphans.length; i += 100) this.git("rm", "-q", "--", ...orphans.slice(i, i + 100));
|
|
143802
|
+
}
|
|
143803
|
+
const untracked = this.git("ls-files", "--others", "dist", "bridge");
|
|
143804
|
+
if (untracked) fail6("untracked files under dist/ or bridge/ after git add -f", untracked.split(/\r?\n/));
|
|
143805
|
+
const probes = [];
|
|
143806
|
+
const importProbe = this.run(this.deps.node, ["--input-type=module", "-e", "await import(process.argv[1])", (0, import_url23.pathToFileURL)((0, import_path187.join)(this.deps.root, "dist", "index.js")).href]);
|
|
143807
|
+
if (importProbe.status !== 0) probes.push(`import dist/index.js failed: ${tail2(importProbe.stderr, 3).join(" ")}`);
|
|
143808
|
+
for (const entry2 of ["dist/cli/index.js", "bridge/cli.cjs"]) {
|
|
143809
|
+
const r = this.run(this.deps.node, [entry2, "--version"]);
|
|
143810
|
+
if (r.status !== 0 || r.stdout.trim() !== v) probes.push(`${entry2} --version printed ${JSON.stringify(r.stdout.trim())} (exit ${r.status}), expected ${v}`);
|
|
143811
|
+
}
|
|
143812
|
+
const mcp = this.run(this.deps.node, ["dist/mcp/standalone-server.js"], { timeoutMs: 3e4 });
|
|
143813
|
+
if (mcp.status !== 0) probes.push(`dist/mcp/standalone-server.js did not start and exit cleanly (exit ${mcp.status}): ${tail2(mcp.stderr, 3).join(" ")}`);
|
|
143814
|
+
if (probes.length > 0) fail6("build probes failed", probes);
|
|
143815
|
+
return { status: "ok", note: `built and staged${orphans.length > 0 ? `; removed ${orphans.length} orphan(s)` : ""}` };
|
|
143816
|
+
}
|
|
143817
|
+
gates() {
|
|
143818
|
+
this.script("node_modules/typescript/bin/tsc", "--noEmit");
|
|
143819
|
+
this.script("scripts/generate-prompt-projections.mjs", "--verify");
|
|
143820
|
+
this.script("scripts/copilot/build-hooks.mjs", "--verify");
|
|
143821
|
+
this.script("scripts/copilot/build-agents.mjs", "--verify");
|
|
143822
|
+
this.script("scripts/ci/check-multirepo-paths.mjs");
|
|
143823
|
+
const suite = this.opts.suite ?? "none";
|
|
143824
|
+
if (suite === "targeted") {
|
|
143825
|
+
const tag = this.run("git", ["describe", "--tags", "--abbrev=0", "--match", "v[0-9]*", "HEAD"]);
|
|
143826
|
+
if (tag.status !== 0) fail6("no v* tag reachable from HEAD for --suite targeted", tail2(tag.stderr, 2));
|
|
143827
|
+
const changed = this.git("diff", "--name-only", `${tag.stdout.trim()}...HEAD`, "--", "src").split(/\r?\n/).filter((f) => /\.(?:ts|tsx|mts)$/.test(f) && !f.endsWith(".d.ts") && (0, import_fs156.existsSync)((0, import_path187.join)(this.deps.root, f)));
|
|
143828
|
+
if (changed.length === 0) return { status: "ok", note: `gates green; no src changes since ${tag.stdout.trim()} for the targeted suite` };
|
|
143829
|
+
this.script("node_modules/vitest/vitest.mjs", "related", "--run", "--exclude", "tests/perf/**", ...changed);
|
|
143830
|
+
return { status: "ok", note: `gates green; targeted suite over ${changed.length} changed src file(s)` };
|
|
143831
|
+
}
|
|
143832
|
+
if (suite === "full") {
|
|
143833
|
+
const out = (0, import_path187.join)(this.deps.stateRoot, "release", `${this.v}-vitest.json`);
|
|
143834
|
+
(0, import_fs156.mkdirSync)((0, import_path187.join)(this.deps.stateRoot, "release"), { recursive: true });
|
|
143835
|
+
(0, import_fs156.rmSync)(out, { force: true });
|
|
143836
|
+
this.deps.log(` node node_modules/vitest/vitest.mjs run --reporter=json --outputFile=${out}`);
|
|
143837
|
+
const r = this.run(this.deps.node, ["node_modules/vitest/vitest.mjs", "run", "--exclude", "tests/perf/**", "--reporter=json", `--outputFile=${out}`]);
|
|
143838
|
+
if (!(0, import_fs156.existsSync)(out)) fail6(`vitest wrote no JSON report (exit ${r.status})`, tail2(r.stderr));
|
|
143839
|
+
const failing = failingTitlesFromVitestJson((0, import_fs156.readFileSync)(out, "utf8"));
|
|
143840
|
+
const baseline = this.opts.baseline ? parseBaselineTitles((0, import_fs156.readFileSync)(this.opts.baseline, "utf8")) : [];
|
|
143841
|
+
const fresh = newFailures(failing, baseline);
|
|
143842
|
+
if (fresh.length > 0) fail6(`${fresh.length} failing test(s) not in the baseline (report: ${out})`, fresh);
|
|
143843
|
+
return { status: "ok", note: `gates green; full suite: ${failing.length} failing, all in the baseline` };
|
|
143844
|
+
}
|
|
143845
|
+
return { status: "ok", note: "gates green; no vitest suite (--suite none)" };
|
|
143846
|
+
}
|
|
143847
|
+
smoke() {
|
|
143848
|
+
if (!this.opts.liveSmoke) {
|
|
143849
|
+
this.deps.log(" !! SKIPPED the live Tier 2 smoke. The runbook requires it green before tagging: re-run with --from smoke --live-smoke (about 2 premium requests).");
|
|
143850
|
+
return { status: "skipped", note: "live Tier 2 smoke not run (pass --live-smoke)" };
|
|
143851
|
+
}
|
|
143852
|
+
this.deps.log(" OMC_LIVE_SMOKE=2 node bridge/cli.cjs smoke copilot --tier 2 --json");
|
|
143853
|
+
const r = this.run(this.deps.node, ["bridge/cli.cjs", "smoke", "copilot", "--tier", "2", "--json"], { env: { OMC_LIVE_SMOKE: "2" } });
|
|
143854
|
+
const problems = smokeProblems(r.stdout);
|
|
143855
|
+
if (r.status !== 0 && problems.length === 0) problems.push(`smoke exited ${r.status}${r.status === 2 ? " (copilot binary or SDK missing: not a pass)" : ""}`);
|
|
143856
|
+
if (problems.length > 0) fail6("Tier 2 smoke is not green", problems);
|
|
143857
|
+
return { status: "ok", note: "Tier 2 smoke green" };
|
|
143858
|
+
}
|
|
143859
|
+
staged(paths = []) {
|
|
143860
|
+
return this.run("git", ["diff", "--cached", "--quiet", ...paths.length ? ["--", ...paths] : []]).status !== 0;
|
|
143861
|
+
}
|
|
143862
|
+
commit() {
|
|
143863
|
+
const v = this.v;
|
|
143864
|
+
this.git("add", "-f", "dist", "bridge");
|
|
143865
|
+
this.git("add", "-A");
|
|
143866
|
+
const notes = [];
|
|
143867
|
+
if (this.staged()) {
|
|
143868
|
+
this.git("commit", "-m", `chore(release): v${v}`);
|
|
143869
|
+
notes.push("release commit");
|
|
143870
|
+
}
|
|
143871
|
+
this.script("scripts/generate-inventory-graph.mjs", "--write");
|
|
143872
|
+
this.git("add", "-A", "--", "inventory");
|
|
143873
|
+
if (this.staged(["inventory"])) {
|
|
143874
|
+
this.git("commit", "-m", `chore(release): regenerate inventory for v${v}`, "--", "inventory");
|
|
143875
|
+
notes.push("inventory commit");
|
|
143876
|
+
}
|
|
143877
|
+
this.script("scripts/generate-inventory-graph.mjs", "--verify");
|
|
143878
|
+
const left = this.git("status", "--porcelain");
|
|
143879
|
+
if (left) fail6("working tree is not clean after the release commits", left.split(/\r?\n/));
|
|
143880
|
+
const head = this.git("rev-parse", "HEAD");
|
|
143881
|
+
this.save({ headSha: head });
|
|
143882
|
+
return { status: "ok", note: notes.length > 0 ? `${notes.join(" + ")} at ${head.slice(0, 12)}` : "nothing new to commit" };
|
|
143883
|
+
}
|
|
143884
|
+
/** Exit 1 is "no"; any other non-zero exit (missing object, bad ref) is a git error, never a yes. */
|
|
143885
|
+
isAncestor(ancestor, descendant) {
|
|
143886
|
+
const r = this.run("git", ["merge-base", "--is-ancestor", ancestor, descendant]);
|
|
143887
|
+
if (r.status === 0) return true;
|
|
143888
|
+
if (r.status === 1) return false;
|
|
143889
|
+
return fail6(`git merge-base --is-ancestor ${ancestor} ${descendant} failed (exit ${r.status}): ${r.stderr.trim() || "(no stderr)"}`);
|
|
143890
|
+
}
|
|
143891
|
+
viewPr(pr) {
|
|
143892
|
+
return JSON.parse(this.must("gh", ["pr", "view", String(pr), "--json", "number,state,isDraft,baseRefName,baseRefOid,headRefOid,url,mergeCommit"]));
|
|
143893
|
+
}
|
|
143894
|
+
/** The merge commit of a merged PR, else null. */
|
|
143895
|
+
mergedSha(pr) {
|
|
143896
|
+
const view = this.viewPr(pr);
|
|
143897
|
+
const sha = view.state === "MERGED" ? view.mergeCommit?.oid : void 0;
|
|
143898
|
+
return sha && FULL_SHA3.test(sha) ? sha : null;
|
|
143899
|
+
}
|
|
143900
|
+
/** Why the phases before `start` may not be skipped (empty = they may): the state's checkout, then each phase's postconditions. */
|
|
143901
|
+
skipProblems(start) {
|
|
143902
|
+
const problems = [];
|
|
143903
|
+
const released = !!this.state.mainMergeSha && PHASES2.indexOf(start) >= PHASES2.indexOf("tag");
|
|
143904
|
+
const checks = [
|
|
143905
|
+
["state", () => released ? null : this.provenanceProblem()],
|
|
143906
|
+
...PHASES2.slice(0, PHASES2.indexOf(start)).map((id) => [id, () => this.postconditionProblem(id, released)])
|
|
143907
|
+
];
|
|
143908
|
+
for (const [what, check2] of checks) {
|
|
143909
|
+
try {
|
|
143910
|
+
const problem = check2();
|
|
143911
|
+
if (problem) problems.push(`${what}: ${problem}`);
|
|
143912
|
+
} catch (error2) {
|
|
143913
|
+
problems.push(`${what}: ${error2 instanceof PhaseStop ? error2.outcome.note : error2 instanceof Error ? error2.message : String(error2)}`);
|
|
143914
|
+
}
|
|
143915
|
+
}
|
|
143916
|
+
return problems;
|
|
143917
|
+
}
|
|
143918
|
+
/** Why the recorded state does not belong to this checkout (null = it does). */
|
|
143919
|
+
provenanceProblem() {
|
|
143920
|
+
const { branch, headSha } = this.state;
|
|
143921
|
+
if (branch) {
|
|
143922
|
+
const current = this.run("git", ["rev-parse", "--abbrev-ref", "HEAD"]).stdout.trim();
|
|
143923
|
+
if (current !== branch) return `HEAD is ${current || "(unknown)"}, but this release state was recorded on ${branch}`;
|
|
143924
|
+
}
|
|
143925
|
+
if (headSha && !this.isAncestor(headSha, "HEAD")) return `HEAD does not descend from the recorded release commit ${headSha.slice(0, 12)}`;
|
|
143926
|
+
return null;
|
|
143927
|
+
}
|
|
143928
|
+
/**
|
|
143929
|
+
* Why a phase may not be skipped (null = its recorded result still holds):
|
|
143930
|
+
* it must have passed, and the facts later phases build on are re-checked
|
|
143931
|
+
* cheaply (read-only git / gh).
|
|
143932
|
+
*/
|
|
143933
|
+
postconditionProblem(id, released = false) {
|
|
143934
|
+
const s = this.state;
|
|
143935
|
+
const status = s.phases[id]?.status;
|
|
143936
|
+
if (status !== "ok" && status !== "skipped") return `has not passed (run it: --from ${id})`;
|
|
143937
|
+
switch (id) {
|
|
143938
|
+
case "bump": {
|
|
143939
|
+
if (released) return null;
|
|
143940
|
+
const version3 = JSON.parse(this.file("package.json") ?? "{}").version;
|
|
143941
|
+
return version3 === this.v ? null : `package.json version is ${version3 ?? "missing"}, not ${this.v} (--from bump)`;
|
|
143942
|
+
}
|
|
143943
|
+
case "commit": {
|
|
143944
|
+
if (!s.headSha || !FULL_SHA3.test(s.headSha)) return "no release commit recorded (--from commit)";
|
|
143945
|
+
if (released) return null;
|
|
143946
|
+
const head = this.git("rev-parse", "HEAD");
|
|
143947
|
+
return head === s.headSha ? null : `HEAD ${head.slice(0, 12)} is not the recorded release commit ${s.headSha.slice(0, 12)}; new local commits must go back through the gates (--from gates)`;
|
|
143948
|
+
}
|
|
143949
|
+
case "pr": {
|
|
143950
|
+
if (s.devPr === void 0 || !s.devMergeSha) return "no merged release PR into dev recorded (--from pr)";
|
|
143951
|
+
const sha = this.mergedSha(s.devPr);
|
|
143952
|
+
if (!sha) return `PR #${s.devPr} is not merged, not at the recorded ${s.devMergeSha.slice(0, 12)} (--from pr)`;
|
|
143953
|
+
if (!s.headSha) return "no release commit recorded (--from commit)";
|
|
143954
|
+
this.must("git", ["fetch", "origin", "dev"]);
|
|
143955
|
+
if (sha !== s.devMergeSha && !this.isAncestor(sha, s.devMergeSha)) return `PR #${s.devPr} is merged at ${sha.slice(0, 12)}, which the recorded dev merge ${s.devMergeSha.slice(0, 12)} does not contain (--from pr)`;
|
|
143956
|
+
return this.isAncestor(s.headSha, s.devMergeSha) ? null : `the dev merge ${s.devMergeSha.slice(0, 12)} does not contain the release commit ${s.headSha.slice(0, 12)} (--from pr)`;
|
|
143957
|
+
}
|
|
143958
|
+
case "promote": {
|
|
143959
|
+
if (s.mainPr === void 0 || !s.mainMergeSha || !s.devMergeSha) return "no main merge commit recorded (--from promote)";
|
|
143960
|
+
const sha = this.mergedSha(s.mainPr);
|
|
143961
|
+
if (sha !== s.mainMergeSha) return `PR #${s.mainPr} is ${sha ? `merged at ${sha.slice(0, 12)}` : "not merged"}, not at the recorded ${s.mainMergeSha.slice(0, 12)} (--from promote)`;
|
|
143962
|
+
this.must("git", ["fetch", "origin", "dev", "main"]);
|
|
143963
|
+
return this.isAncestor(s.devMergeSha, s.mainMergeSha) ? null : `the main merge ${s.mainMergeSha.slice(0, 12)} does not contain the dev merge ${s.devMergeSha.slice(0, 12)}`;
|
|
143964
|
+
}
|
|
143965
|
+
case "tag": {
|
|
143966
|
+
const remote = remoteTagTarget(this.git("ls-remote", "--tags", "origin", `refs/tags/v${this.v}`, `refs/tags/v${this.v}^{}`), `v${this.v}`);
|
|
143967
|
+
return remote?.annotated && remote.commit === s.mainMergeSha ? null : `v${this.v} on origin does not peel to the main merge commit (--from tag)`;
|
|
143968
|
+
}
|
|
143969
|
+
default:
|
|
143970
|
+
return null;
|
|
143971
|
+
}
|
|
143972
|
+
}
|
|
143973
|
+
findPr(head, base, states) {
|
|
143974
|
+
const out = this.must("gh", ["pr", "list", "--head", head, "--base", base, "--state", states, "--json", "number,state,headRefOid,mergeCommit", "--limit", "10"]);
|
|
143975
|
+
const prs = JSON.parse(out || "[]");
|
|
143976
|
+
const open9 = prs.find((p) => p.state === "OPEN");
|
|
143977
|
+
if (open9) return open9.number;
|
|
143978
|
+
const merged = prs.filter((p) => p.state === "MERGED" && FULL_SHA3.test(p.mergeCommit?.oid ?? ""));
|
|
143979
|
+
if (merged.length === 0) return void 0;
|
|
143980
|
+
this.must("git", ["fetch", "origin", base]);
|
|
143981
|
+
return (merged.find((p) => this.isAncestor("HEAD", p.mergeCommit.oid)) ?? merged[0]).number;
|
|
143982
|
+
}
|
|
143983
|
+
createPr(base, head, title) {
|
|
143984
|
+
const out = this.must("gh", ["pr", "create", "--base", base, "--head", head, "--title", title, "--body-file", ".github/release-body.md"]);
|
|
143985
|
+
const m = /\/pull\/(\d+)/.exec(out);
|
|
143986
|
+
if (!m) fail6(`gh pr create printed no PR url: ${out.trim()}`);
|
|
143987
|
+
return Number(m[1]);
|
|
143988
|
+
}
|
|
143989
|
+
async pr() {
|
|
143990
|
+
const branch = `release/v${this.v}`;
|
|
143991
|
+
if (this.state.devPr === void 0 || this.viewPr(this.state.devPr).state !== "MERGED") {
|
|
143992
|
+
const push = this.run("git", ["push", "origin", `HEAD:refs/heads/${branch}`]);
|
|
143993
|
+
if (push.status !== 0) {
|
|
143994
|
+
blocked(`git push origin HEAD:refs/heads/${branch} was refused; never force: git fetch origin ${branch} && git merge origin/${branch}, then re-run omg release ${this.v} --from pr`, tail2(push.stderr, 5));
|
|
143995
|
+
}
|
|
143996
|
+
if (this.state.devPr === void 0) {
|
|
143997
|
+
const pr = this.findPr(branch, "dev", "all") ?? this.createPr("dev", branch, `chore(release): v${this.v}`);
|
|
143998
|
+
this.save({ devPr: pr });
|
|
143999
|
+
}
|
|
144000
|
+
}
|
|
144001
|
+
const sha = await this.land(this.state.devPr, "dev", "pr", this.git("rev-parse", "HEAD"));
|
|
144002
|
+
this.save({ devMergeSha: sha });
|
|
144003
|
+
return { status: "ok", note: `PR #${this.state.devPr} merged into dev at ${sha.slice(0, 12)}` };
|
|
144004
|
+
}
|
|
144005
|
+
async promote() {
|
|
144006
|
+
const devPr = this.state.devPr;
|
|
144007
|
+
if (devPr === void 0) fail6("no release PR into dev recorded; run the pr phase first");
|
|
144008
|
+
if (!this.mergedSha(devPr)) fail6(`release PR #${devPr} is not merged into dev; re-run omg release ${this.v} --from pr`);
|
|
144009
|
+
const devMerge = this.state.devMergeSha;
|
|
144010
|
+
if (!devMerge || !FULL_SHA3.test(devMerge)) fail6(`no dev merge commit recorded; re-run omg release ${this.v} --from pr`);
|
|
144011
|
+
if (this.state.mainPr === void 0) {
|
|
144012
|
+
const pr = this.findPr("dev", "main", "open") ?? this.createPr("main", "dev", `Release v${this.v}`);
|
|
144013
|
+
this.save({ mainPr: pr });
|
|
144014
|
+
}
|
|
144015
|
+
const sha = await this.land(this.state.mainPr, "main", "promote", void 0, devMerge);
|
|
144016
|
+
this.must("git", ["fetch", "origin", "dev", "main"]);
|
|
144017
|
+
if (!this.isAncestor(devMerge, sha)) fail6(`PR #${this.state.mainPr} merged into main at ${sha.slice(0, 12)}, which does not contain the dev merge ${devMerge.slice(0, 12)}`);
|
|
144018
|
+
this.save({ mainMergeSha: sha });
|
|
144019
|
+
return { status: "ok", note: `PR #${this.state.mainPr} merged into main at ${sha.slice(0, 12)}` };
|
|
144020
|
+
}
|
|
144021
|
+
rerunBudget = {
|
|
144022
|
+
count: (id) => this.state.reruns[id] ?? 0,
|
|
144023
|
+
record: (id) => this.save({ reruns: { ...this.state.reruns, [id]: (this.state.reruns[id] ?? 0) + 1 } })
|
|
144024
|
+
};
|
|
144025
|
+
runAttempt(runId) {
|
|
144026
|
+
return JSON.parse(this.must("gh", ["run", "view", runId, "--json", "attempt"]) || "{}").attempt ?? 0;
|
|
144027
|
+
}
|
|
144028
|
+
/**
|
|
144029
|
+
* Rerun each failed run once (budget spent first) and wait until its new
|
|
144030
|
+
* attempt exists: right after `gh run rerun` the run still reads as the old
|
|
144031
|
+
* failed attempt. True when any rerun was issued.
|
|
144032
|
+
*/
|
|
144033
|
+
async rerunOnce(runIds, phase, pollMs) {
|
|
144034
|
+
const ready = runIds.filter((id) => this.rerunBudget.count(id) < 1);
|
|
144035
|
+
for (const id of ready) {
|
|
144036
|
+
const before = this.runAttempt(id);
|
|
144037
|
+
this.rerunBudget.record(id);
|
|
144038
|
+
this.deps.log(` gh run rerun ${id} --failed (the one automatic rerun)`);
|
|
144039
|
+
this.must("gh", ["run", "rerun", id, "--failed"]);
|
|
144040
|
+
for (let polls = 0; this.runAttempt(id) <= before; polls++) {
|
|
144041
|
+
if (polls >= RERUN_START_POLLS || this.deps.now() >= this.deadline) {
|
|
144042
|
+
blocked(`run ${id} was rerun but attempt ${before + 1} has not started; re-run omg release ${this.v} --from ${phase}`);
|
|
144043
|
+
}
|
|
144044
|
+
await this.deps.sleep(pollMs);
|
|
144045
|
+
}
|
|
144046
|
+
}
|
|
144047
|
+
return ready.length > 0;
|
|
144048
|
+
}
|
|
144049
|
+
failingTestsOfJob(jobId) {
|
|
144050
|
+
const log3 = this.run("gh", ["run", "view", "--job", jobId, "--log"]);
|
|
144051
|
+
return log3.status === 0 ? parseFailingTests(log3.stdout).map((t) => t.title ? `${t.file} > ${t.title}` : t.file) : [];
|
|
144052
|
+
}
|
|
144053
|
+
gateDetails(report) {
|
|
144054
|
+
const details = report.failed.map((name) => `failed: ${name}`);
|
|
144055
|
+
for (const check2 of report.checks) {
|
|
144056
|
+
if (check2.class !== "failed" || !check2.jobId) continue;
|
|
144057
|
+
for (const t of this.failingTestsOfJob(check2.jobId)) details.push(` ${check2.name}: ${t}`);
|
|
144058
|
+
}
|
|
144059
|
+
return details;
|
|
144060
|
+
}
|
|
144061
|
+
/**
|
|
144062
|
+
* Wait for the PR's checks under the ship merge rule (advisoryChecks never
|
|
144063
|
+
* block; config from loadShipConfig: user config + the base's committed
|
|
144064
|
+
* config), rerun failed runs once, then admin-merge when the owner allows
|
|
144065
|
+
* it; with `expectedHead`, only when the PR head is that commit (an
|
|
144066
|
+
* already-merged PR only when its merge, or the base tip after a follow-up
|
|
144067
|
+
* PR, contains it), with
|
|
144068
|
+
* `requireAncestor`, only when the PR head contains that commit. Returns
|
|
144069
|
+
* the merge commit sha.
|
|
144070
|
+
*/
|
|
144071
|
+
async land(pr, base, phase, expectedHead, requireAncestor) {
|
|
144072
|
+
for (let round = 0; ; round++) {
|
|
144073
|
+
if (round >= LAND_ROUNDS) blocked(`PR #${pr} is still not merged after ${LAND_ROUNDS} rounds of waiting and merging; check it on GitHub, then re-run omg release ${this.v} --from ${phase}`);
|
|
144074
|
+
const view = this.viewPr(pr);
|
|
144075
|
+
if (view.state === "MERGED") {
|
|
144076
|
+
const sha = view.mergeCommit?.oid;
|
|
144077
|
+
if (!sha || !FULL_SHA3.test(sha)) fail6(`PR #${pr} is merged but gh reported no merge commit`);
|
|
144078
|
+
if (expectedHead) {
|
|
144079
|
+
this.must("git", ["fetch", "origin", base]);
|
|
144080
|
+
if (!this.isAncestor(expectedHead, sha)) {
|
|
144081
|
+
const tip = `refs/remotes/origin/${base}`;
|
|
144082
|
+
if (this.isAncestor(expectedHead, tip) && this.isAncestor(sha, tip)) return this.git("rev-parse", tip);
|
|
144083
|
+
blocked(`The release PR #${pr} is merged at ${sha.slice(0, 12)} without commit(s) up to ${expectedHead.slice(0, 12)}. Open a follow-up PR into ${base} for the extra commits and re-run omg release ${this.v} --from ${phase} after it merges (the release then proceeds from the ${base} commit that contains HEAD).`);
|
|
144084
|
+
}
|
|
144085
|
+
}
|
|
144086
|
+
return sha;
|
|
144087
|
+
}
|
|
144088
|
+
if (view.state !== "OPEN") fail6(`PR #${pr} is ${view.state}`);
|
|
144089
|
+
if (view.baseRefName !== base) fail6(`PR #${pr} targets ${view.baseRefName}, expected ${base}`);
|
|
144090
|
+
if (view.isDraft) fail6(`PR #${pr} is a draft`);
|
|
144091
|
+
const config2 = this.deps.loadShipConfig({ exec: this.deps.exec, root: this.deps.root, base, baseSha: view.baseRefOid, repoUrl: prRepoUrl(view.url) });
|
|
144092
|
+
const remainingMin = Math.max(0, (this.deadline - this.deps.now()) / 6e4);
|
|
144093
|
+
if (remainingMin <= 0) blocked(`PR #${pr}: CI still pending at the --timeout; re-run omg release ${this.v} --from ${phase}`);
|
|
144094
|
+
const { report, timedOut } = await watchGates({
|
|
144095
|
+
exec: this.deps.exec,
|
|
144096
|
+
pr,
|
|
144097
|
+
config: { ...config2, watchTimeoutMinutes: Math.min(config2.watchTimeoutMinutes || remainingMin, remainingMin) },
|
|
144098
|
+
known: loadBaseKnownFlaky(this.deps.exec, this.deps.root, config2.trustedBaseCommit, config2.knownFlakyFile),
|
|
144099
|
+
cwd: this.deps.root,
|
|
144100
|
+
headSha: view.headRefOid,
|
|
144101
|
+
watch: true,
|
|
144102
|
+
reruns: this.rerunBudget,
|
|
144103
|
+
sleep: this.deps.sleep,
|
|
144104
|
+
now: this.deps.now,
|
|
144105
|
+
onReport: (r) => this.deps.progress({ phase, status: "heartbeat", note: `PR #${pr} gates ${r.verdict}: ${r.pending.length} pending, ${r.failed.length} failed` })
|
|
144106
|
+
});
|
|
144107
|
+
if (report.verdict === "green") {
|
|
144108
|
+
if (expectedHead && view.headRefOid !== expectedHead) {
|
|
144109
|
+
blocked(`PR #${pr} head is ${view.headRefOid.slice(0, 12)}, not local HEAD ${expectedHead.slice(0, 12)}; push or merge until they match, then re-run omg release ${this.v} --from ${phase}`);
|
|
144110
|
+
}
|
|
144111
|
+
if (requireAncestor) {
|
|
144112
|
+
this.must("git", ["fetch", "origin", "dev", base]);
|
|
144113
|
+
if (!this.isAncestor(requireAncestor, view.headRefOid)) {
|
|
144114
|
+
blocked(`PR #${pr} head ${view.headRefOid.slice(0, 12)} does not contain ${requireAncestor.slice(0, 12)}; update the PR, then re-run omg release ${this.v} --from ${phase}`);
|
|
144115
|
+
}
|
|
144116
|
+
}
|
|
144117
|
+
const command = ["pr", "merge", String(pr), "--admin", "--merge", "--match-head-commit", view.headRefOid];
|
|
144118
|
+
if (!config2.allowAdminMerge || !config2.trustedBases.includes(base)) {
|
|
144119
|
+
blocked(`PR #${pr} is green; ship.allowAdminMerge is off or ${base} is not a trusted base, so run the merge yourself, then re-run omg release ${this.v} --from ${phase}`, [`gh ${command.join(" ")}`]);
|
|
144120
|
+
}
|
|
144121
|
+
this.deps.log(` gh ${command.join(" ")}`);
|
|
144122
|
+
this.must("gh", command);
|
|
144123
|
+
continue;
|
|
144124
|
+
}
|
|
144125
|
+
if (report.verdict === "pending" || timedOut) continue;
|
|
144126
|
+
const failedRuns = [...new Set(report.checks.filter((c) => c.class === "failed" && c.runId).map((c) => c.runId))];
|
|
144127
|
+
const finished = failedRuns.filter((id) => !report.checks.some((c) => c.runId === id && c.class === "pending"));
|
|
144128
|
+
if (finished.length < failedRuns.length) {
|
|
144129
|
+
await this.deps.sleep(config2.pollIntervalSeconds * 1e3);
|
|
144130
|
+
continue;
|
|
144131
|
+
}
|
|
144132
|
+
if (await this.rerunOnce(finished, phase, config2.pollIntervalSeconds * 1e3)) continue;
|
|
144133
|
+
fail6(`PR #${pr}: CI failed after the one automatic rerun`, this.gateDetails(report));
|
|
144134
|
+
}
|
|
144135
|
+
}
|
|
144136
|
+
async tag() {
|
|
144137
|
+
const v = this.v;
|
|
144138
|
+
const tag = `v${v}`;
|
|
144139
|
+
const sha = this.state.mainMergeSha;
|
|
144140
|
+
if (!sha || !FULL_SHA3.test(sha)) fail6("no main merge commit recorded; run the promote phase first");
|
|
144141
|
+
const remote = remoteTagTarget(this.git("ls-remote", "--tags", "origin", `refs/tags/${tag}`, `refs/tags/${tag}^{}`), tag);
|
|
144142
|
+
if (remote) {
|
|
144143
|
+
if (remote.annotated && remote.commit === sha) return { status: "ok", note: `${tag} already on origin at ${sha.slice(0, 12)}` };
|
|
144144
|
+
fail6(`${tag} exists on origin at ${remote.commit.slice(0, 12)}${remote.annotated ? "" : " (lightweight)"}, not the main merge commit ${sha.slice(0, 12)}`);
|
|
144145
|
+
}
|
|
144146
|
+
const devMerge = this.state.devMergeSha;
|
|
144147
|
+
if (!devMerge || !FULL_SHA3.test(devMerge)) fail6("no dev merge commit recorded; run the pr phase first");
|
|
144148
|
+
this.must("git", ["fetch", "origin", "dev", "main"]);
|
|
144149
|
+
if (!this.isAncestor(sha, "refs/remotes/origin/main")) fail6(`${sha.slice(0, 12)} is not on origin/main`);
|
|
144150
|
+
if (!this.isAncestor(devMerge, sha)) fail6(`the main merge ${sha.slice(0, 12)} does not contain the dev merge ${devMerge.slice(0, 12)}`);
|
|
144151
|
+
const pkg = this.run("git", ["show", `${sha}:package.json`]);
|
|
144152
|
+
let tagged;
|
|
144153
|
+
try {
|
|
144154
|
+
tagged = JSON.parse(pkg.stdout).version;
|
|
144155
|
+
} catch {
|
|
144156
|
+
tagged = void 0;
|
|
144157
|
+
}
|
|
144158
|
+
if (pkg.status !== 0 || tagged !== v) fail6(`package.json on the main merge ${sha.slice(0, 12)} is ${tagged ?? "unreadable"}, not ${v}`);
|
|
144159
|
+
const local = this.run("git", ["rev-parse", "-q", "--verify", `refs/tags/${tag}`]);
|
|
144160
|
+
if (local.status === 0) {
|
|
144161
|
+
const problem = tagTargetProblem(tag, this.git("cat-file", "-t", `refs/tags/${tag}`), this.git("rev-parse", `refs/tags/${tag}^{}`), sha);
|
|
144162
|
+
if (problem) fail6(`a local ${tag} already exists and ${problem} (an upstream tag fetched by name?); delete it yourself (git tag -d ${tag}) and re-run`);
|
|
144163
|
+
}
|
|
144164
|
+
const smoke = this.state.phases.smoke?.status;
|
|
144165
|
+
const warn = smoke === "ok" ? "" : ` WARNING: the live Tier 2 smoke ${smoke === "skipped" ? "was skipped" : "has not passed"}.`;
|
|
144166
|
+
const action = local.status === 0 ? "Push the existing local" : "Create and push";
|
|
144167
|
+
if (!this.opts.yes && !await this.deps.confirm(`${action} annotated tag ${tag} on main ${sha.slice(0, 12)}? This publishes ${this.pkgName}@${v} to npm.${warn}`)) {
|
|
144168
|
+
blocked(`${tag} not pushed (confirm, or pass --yes)`);
|
|
144169
|
+
}
|
|
144170
|
+
if (local.status !== 0) {
|
|
144171
|
+
this.git("tag", "-a", tag, "-m", tag, sha);
|
|
144172
|
+
const problem = tagTargetProblem(tag, this.git("cat-file", "-t", `refs/tags/${tag}`), this.git("rev-parse", `refs/tags/${tag}^{}`), sha);
|
|
144173
|
+
if (problem) fail6(problem);
|
|
144174
|
+
}
|
|
144175
|
+
this.git("push", "origin", `refs/tags/${tag}:refs/tags/${tag}`);
|
|
144176
|
+
const pushed = remoteTagTarget(this.git("ls-remote", "--tags", "origin", `refs/tags/${tag}`, `refs/tags/${tag}^{}`), tag);
|
|
144177
|
+
if (!pushed?.annotated || pushed.commit !== sha) fail6(`origin's ${tag} does not peel to ${sha.slice(0, 12)} after the push`);
|
|
144178
|
+
return { status: "ok", note: `${tag} pushed on ${sha.slice(0, 12)}` };
|
|
144179
|
+
}
|
|
144180
|
+
async verify() {
|
|
144181
|
+
const v = this.v;
|
|
144182
|
+
const tag = `v${v}`;
|
|
144183
|
+
const sha = this.state.mainMergeSha;
|
|
144184
|
+
if (!sha || !FULL_SHA3.test(sha)) fail6("no main merge commit recorded; run the promote phase first");
|
|
144185
|
+
let run;
|
|
144186
|
+
for (; ; ) {
|
|
144187
|
+
const runs = JSON.parse(this.must("gh", ["run", "list", "--workflow", "ci.yml", "--event", "push", "--commit", sha, "--json", "databaseId,headBranch,headSha,event,status,conclusion", "--limit", "50"]) || "[]");
|
|
144188
|
+
run = runs.filter((r) => r.headBranch === tag && r.headSha === sha && (r.event ?? "push") === "push").sort((a, b) => b.databaseId - a.databaseId)[0];
|
|
144189
|
+
if (run) this.save({ tagRunId: run.databaseId });
|
|
144190
|
+
if (run?.status === "completed") {
|
|
144191
|
+
if (run.conclusion === "success") break;
|
|
144192
|
+
const jobs2 = JSON.parse(this.must("gh", ["run", "view", String(run.databaseId), "--json", "jobs"])).jobs ?? [];
|
|
144193
|
+
const failedJobs = jobs2.filter((j) => j.conclusion && !["success", "skipped"].includes(j.conclusion));
|
|
144194
|
+
const details = () => failedJobs.flatMap((j) => [`failed job: ${j.name}`, ...this.failingTestsOfJob(String(j.databaseId)).map((t) => ` ${t}`)]);
|
|
144195
|
+
if (this.run("npm", ["view", `${this.pkgName}@${v}`, "version"]).stdout.trim() === v) {
|
|
144196
|
+
fail6(`tag run ${run.databaseId} ${run.conclusion}, but ${this.pkgName}@${v} is already on npm: not rerun`, [
|
|
144197
|
+
`npm view ${this.pkgName}@${v} version dist-tags dist.attestations: if live with provenance, do NOT rerun the run`,
|
|
144198
|
+
`create the GitHub Release with the Release Recovery workflow (release.yml, workflow_dispatch: tag=${tag} sha=${sha}) or gh release create ${tag} --title ${tag} --notes-file .github/release-body.md`,
|
|
144199
|
+
`then re-run omg release ${v} --from verify`,
|
|
144200
|
+
...details()
|
|
144201
|
+
]);
|
|
144202
|
+
}
|
|
144203
|
+
if (await this.rerunOnce([String(run.databaseId)], "verify", 3e4)) continue;
|
|
144204
|
+
fail6(`tag run ${run.databaseId} ${run.conclusion} after the one automatic rerun`, details());
|
|
144205
|
+
}
|
|
144206
|
+
if (this.deps.now() >= this.deadline) blocked(`tag run for ${tag} ${run ? `still ${run.status}` : "not found yet"}; re-run omg release ${v} --from verify`);
|
|
144207
|
+
this.deps.progress({ phase: "verify", status: "heartbeat", note: run ? `tag run ${run.databaseId} ${run.status}` : `waiting for the ${tag} tag run` });
|
|
144208
|
+
await this.deps.sleep(3e4);
|
|
144209
|
+
}
|
|
144210
|
+
const runId = run.databaseId;
|
|
144211
|
+
const problems = [];
|
|
144212
|
+
const jobs = JSON.parse(this.must("gh", ["run", "view", String(runId), "--json", "jobs"])).jobs ?? [];
|
|
144213
|
+
const smokeJob = jobs.find((j) => j.name === "Copilot smoke (tier 2)");
|
|
144214
|
+
if (smokeJob?.conclusion !== "success") problems.push(`Copilot smoke (tier 2) job: ${smokeJob?.conclusion ?? "not in the tag run"}`);
|
|
144215
|
+
const npm = this.run("npm", ["view", `${this.pkgName}@${v}`, "version", "dist-tags.latest", "dist.attestations", "--json"]);
|
|
144216
|
+
let info = {};
|
|
144217
|
+
try {
|
|
144218
|
+
info = JSON.parse(npm.stdout || "{}");
|
|
144219
|
+
} catch {
|
|
144220
|
+
info = {};
|
|
144221
|
+
}
|
|
144222
|
+
if (npm.status !== 0 || info.version !== v) problems.push(`npm has no ${this.pkgName}@${v} yet (registry propagation can take ~30 min; re-run --from verify)`);
|
|
144223
|
+
if (info["dist-tags.latest"] !== v) problems.push(`npm dist-tags.latest is ${JSON.stringify(info["dist-tags.latest"])}, not ${v}`);
|
|
144224
|
+
if (!info["dist.attestations"]) problems.push("npm reports no dist.attestations (SLSA provenance)");
|
|
144225
|
+
const rel = this.run("gh", ["release", "view", tag, "--json", "tagName,isDraft"]);
|
|
144226
|
+
const relInfo = rel.status === 0 ? JSON.parse(rel.stdout) : null;
|
|
144227
|
+
if (!relInfo || relInfo.tagName !== tag) problems.push(`gh release view ${tag} found no release`);
|
|
144228
|
+
else if (relInfo.isDraft) problems.push(`GitHub Release ${tag} is a draft`);
|
|
144229
|
+
if (problems.length > 0) fail6(`tag run ${runId} is green, but the release is incomplete`, problems);
|
|
144230
|
+
return { status: "ok", note: `${this.pkgName}@${v} is latest with provenance; GitHub Release ${tag} published` };
|
|
144231
|
+
}
|
|
144232
|
+
};
|
|
144233
|
+
function resumePoint(state, from) {
|
|
144234
|
+
if (from) return from;
|
|
144235
|
+
for (const id of PHASES2) {
|
|
144236
|
+
const s = state?.phases[id]?.status;
|
|
144237
|
+
if (s !== "ok" && s !== "skipped") return id;
|
|
144238
|
+
}
|
|
144239
|
+
return null;
|
|
144240
|
+
}
|
|
144241
|
+
async function runRelease(deps, opts) {
|
|
144242
|
+
const v = opts.version;
|
|
144243
|
+
const statePath = releaseStatePath(deps.stateRoot, v);
|
|
144244
|
+
const existing = readReleaseState(deps.stateRoot, v);
|
|
144245
|
+
const start = resumePoint(existing, opts.from);
|
|
144246
|
+
const last = PHASES2.indexOf(opts.to ?? "verify");
|
|
144247
|
+
if (opts.from && PHASES2.indexOf(opts.from) > last) throw new Error(`--from ${opts.from} comes after --to ${opts.to}`);
|
|
144248
|
+
const selected = start === null ? [] : PHASES2.slice(PHASES2.indexOf(start), last + 1);
|
|
144249
|
+
if (opts.dryRun) {
|
|
144250
|
+
return { ok: true, version: v, dryRun: true, statePath, phases: selected.map((id) => ({ id, status: "planned", note: "", steps: phasePlan(id, v, opts) })) };
|
|
144251
|
+
}
|
|
144252
|
+
const release = new Release(deps, opts, existing);
|
|
144253
|
+
const results = [];
|
|
144254
|
+
if (selected.length === 0) {
|
|
144255
|
+
deps.log(`release ${v}: every selected phase is already ok (state ${statePath}); pass --from <phase> to re-run one`);
|
|
144256
|
+
return { ok: true, version: v, dryRun: false, statePath, phases: [] };
|
|
144257
|
+
}
|
|
144258
|
+
const skip = selected[0] === "preflight" ? [] : release.skipProblems(selected[0]);
|
|
144259
|
+
if (skip.length > 0) {
|
|
144260
|
+
const note = `cannot start at ${selected[0]}: ${skip[0]}${skip.length > 1 ? ` (+${skip.length - 1} more)` : ""}; fix it, or re-run the phase with --from (--from preflight starts over)`;
|
|
144261
|
+
deps.progress({ phase: selected[0], status: "blocked", note });
|
|
144262
|
+
deps.log(`[${selected[0]}] blocked: ${note}`);
|
|
144263
|
+
for (const d of skip) deps.log(` ${d}`);
|
|
144264
|
+
return { ok: false, version: v, dryRun: false, statePath, phases: [{ id: selected[0], status: "blocked", note, details: skip }] };
|
|
144265
|
+
}
|
|
144266
|
+
for (const id of selected) {
|
|
144267
|
+
deps.log(`[${id}] ${phasePlan(id, v, opts)[0]}`);
|
|
144268
|
+
deps.progress({ phase: id, status: "start" });
|
|
144269
|
+
const outcome = await release.phase(id);
|
|
144270
|
+
const record2 = { ...outcome, at: new Date(deps.now()).toISOString() };
|
|
144271
|
+
release.save({ phases: { ...release.current.phases, [id]: record2 } });
|
|
144272
|
+
results.push({ id, ...outcome });
|
|
144273
|
+
deps.progress({ phase: id, status: outcome.status === "skipped" ? "ok" : outcome.status, note: outcome.note });
|
|
144274
|
+
deps.log(`[${id}] ${outcome.status}: ${outcome.note}`);
|
|
144275
|
+
for (const d of outcome.details ?? []) deps.log(` ${d}`);
|
|
144276
|
+
if (outcome.status === "fail" || outcome.status === "blocked") {
|
|
144277
|
+
return { ok: false, version: v, dryRun: false, statePath, phases: results };
|
|
144278
|
+
}
|
|
144279
|
+
}
|
|
144280
|
+
deps.progress({ phase: "release", status: "done", note: `${v}: ${selected[0]}..${selected[selected.length - 1]} ok` });
|
|
144281
|
+
return { ok: true, version: v, dryRun: false, statePath, phases: results };
|
|
144282
|
+
}
|
|
144283
|
+
|
|
144284
|
+
// src/release/progress.ts
|
|
144285
|
+
var import_fs157 = require("fs");
|
|
144286
|
+
var import_path188 = require("path");
|
|
144287
|
+
var BARE_VALUE = /^[A-Za-z0-9._:/@+,%#~-]+$/;
|
|
144288
|
+
var MAX_NOTE = 500;
|
|
144289
|
+
function quote2(value) {
|
|
144290
|
+
if (BARE_VALUE.test(value)) return value;
|
|
144291
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t")}"`;
|
|
144292
|
+
}
|
|
144293
|
+
function formatReleaseProgress(input, at = /* @__PURE__ */ new Date()) {
|
|
144294
|
+
const parts = [at.toISOString(), `phase=${quote2(input.phase)}`, `status=${input.status}`];
|
|
144295
|
+
if (input.note !== void 0) parts.push(`note=${quote2(input.note.slice(0, MAX_NOTE))}`);
|
|
144296
|
+
if (input.agent !== void 0) parts.push(`agent=${quote2(input.agent)}`);
|
|
144297
|
+
return parts.join(" ");
|
|
144298
|
+
}
|
|
144299
|
+
function releaseProgressFile(stateRoot2) {
|
|
144300
|
+
return process.env.OMG_PROGRESS_FILE || (0, import_path188.join)(stateRoot2, "progress", "release.log");
|
|
144301
|
+
}
|
|
144302
|
+
function emitReleaseProgress(input, stateRoot2) {
|
|
144303
|
+
try {
|
|
144304
|
+
const path30 = input.file || releaseProgressFile(stateRoot2);
|
|
144305
|
+
(0, import_fs157.mkdirSync)((0, import_path188.dirname)(path30), { recursive: true });
|
|
144306
|
+
(0, import_fs157.appendFileSync)(path30, `${formatReleaseProgress(input)}
|
|
144307
|
+
`, "utf8");
|
|
144308
|
+
return true;
|
|
144309
|
+
} catch {
|
|
144310
|
+
return false;
|
|
144311
|
+
}
|
|
144312
|
+
}
|
|
144313
|
+
|
|
144314
|
+
// src/cli/commands/release.ts
|
|
144315
|
+
var UsageError2 = class extends Error {
|
|
144316
|
+
};
|
|
144317
|
+
function phaseOption(raw, flag) {
|
|
144318
|
+
if (raw === void 0) return void 0;
|
|
144319
|
+
if (!isPhaseId(raw)) throw new UsageError2(`${flag} must be one of ${PHASES2.join(", ")}, got ${JSON.stringify(raw)}`);
|
|
144320
|
+
return raw;
|
|
144321
|
+
}
|
|
144322
|
+
async function ttyConfirm(question) {
|
|
144323
|
+
if (!process.stdin.isTTY) return false;
|
|
144324
|
+
const rl = (0, import_promises35.createInterface)({ input: process.stdin, output: process.stderr });
|
|
144325
|
+
try {
|
|
144326
|
+
return /^y(?:es)?$/i.test((await rl.question(`${question} [y/N] `)).trim());
|
|
144327
|
+
} finally {
|
|
144328
|
+
rl.close();
|
|
144329
|
+
}
|
|
144330
|
+
}
|
|
144331
|
+
function printResult(result) {
|
|
144332
|
+
if (result.dryRun) {
|
|
144333
|
+
console.log(source_default.bold(`omg release ${result.version} --dry-run: plan only, nothing runs (state ${result.statePath})`));
|
|
144334
|
+
for (const p of result.phases) {
|
|
144335
|
+
console.log(`${source_default.cyan(String(PHASES2.indexOf(p.id) + 1).padStart(2))} ${source_default.bold(p.id)}`);
|
|
144336
|
+
for (const s of p.steps ?? []) console.log(` - ${s}`);
|
|
144337
|
+
}
|
|
144338
|
+
return;
|
|
144339
|
+
}
|
|
144340
|
+
const color = result.ok ? source_default.green : source_default.red;
|
|
144341
|
+
console.log(color(`release ${result.version}: ${result.ok ? "ok" : "stopped"} (state ${result.statePath})`));
|
|
144342
|
+
}
|
|
144343
|
+
function releaseCommand(overrides = {}) {
|
|
144344
|
+
const cmd = new Command("release");
|
|
144345
|
+
cmd.description("Maintainer-only release: preflight, bump, build, gates, smoke, commit, PR to dev, promote to main, tag, verify (resumable)").argument("<version>", "Release version X.Y.Z").option("--from <phase>", `Start at this phase (${PHASES2.join(", ")}); default: the first phase not yet ok`).option("--to <phase>", "Stop after this phase").option("--dry-run", "Print the plan for the selected phases without running anything").option("--json", "JSON output").option("--yes", "Create and push the tag without the interactive confirmation").option("--suite <suite>", "gates vitest suite: none, targeted (related to src changed since the last tag) or full", "none").option("--baseline <file>", 'Full-suite baseline (vitest JSON report or one "<file> > <title>" per line); only new failing titles fail').option("--live-smoke", "Run the live Tier 2 smoke (about 2 premium requests); skipped otherwise").option("--fix-orphans", "Remove tracked dist outputs whose src source is gone").option("--timeout <minutes>", "Minutes the pr / promote / verify phases wait on CI per run", "60").action(async (versionRaw, o) => {
|
|
144346
|
+
const json = Boolean(o.json);
|
|
144347
|
+
try {
|
|
144348
|
+
let version3;
|
|
144349
|
+
try {
|
|
144350
|
+
version3 = parseReleaseVersion(versionRaw);
|
|
144351
|
+
} catch (error2) {
|
|
144352
|
+
throw new UsageError2(error2.message);
|
|
144353
|
+
}
|
|
144354
|
+
if (!["none", "targeted", "full"].includes(o.suite)) throw new UsageError2(`--suite must be none, targeted or full, got ${JSON.stringify(o.suite)}`);
|
|
144355
|
+
if (o.baseline && o.suite !== "full") throw new UsageError2("--baseline needs --suite full");
|
|
144356
|
+
const timeoutMinutes = Number(o.timeout);
|
|
144357
|
+
if (!Number.isFinite(timeoutMinutes) || timeoutMinutes <= 0) throw new UsageError2("--timeout must be a positive number of minutes");
|
|
144358
|
+
const from = phaseOption(o.from, "--from");
|
|
144359
|
+
const to = phaseOption(o.to, "--to");
|
|
144360
|
+
if (from && to && PHASES2.indexOf(from) > PHASES2.indexOf(to)) throw new UsageError2(`--from ${from} comes after --to ${to}`);
|
|
144361
|
+
const exec3 = overrides.exec ?? defaultReleaseExec;
|
|
144362
|
+
const root2 = overrides.root ?? (() => {
|
|
144363
|
+
const r = exec3("git", ["rev-parse", "--show-toplevel"]);
|
|
144364
|
+
if (r.status !== 0) throw new UsageError2("omg release must run inside a git repository");
|
|
144365
|
+
return r.stdout.trim();
|
|
144366
|
+
})();
|
|
144367
|
+
const stateRoot2 = overrides.stateRoot ?? getOmcRoot(root2);
|
|
144368
|
+
const deps = {
|
|
144369
|
+
exec: exec3,
|
|
144370
|
+
root: root2,
|
|
144371
|
+
stateRoot: stateRoot2,
|
|
144372
|
+
node: overrides.node ?? process.execPath,
|
|
144373
|
+
loadShipConfig: overrides.loadShipConfig ?? ((ctx) => loadTrustedShipConfig({ ...ctx, ...userConfigLayers() })),
|
|
144374
|
+
progress: overrides.progress ?? ((event) => {
|
|
144375
|
+
emitReleaseProgress({ agent: "release", ...event }, stateRoot2);
|
|
144376
|
+
}),
|
|
144377
|
+
log: overrides.log ?? ((line) => {
|
|
144378
|
+
if (!json) console.error(line);
|
|
144379
|
+
}),
|
|
144380
|
+
confirm: overrides.confirm ?? ttyConfirm,
|
|
144381
|
+
sleep: overrides.sleep ?? ((ms) => new Promise((resolve58) => setTimeout(resolve58, ms))),
|
|
144382
|
+
now: overrides.now ?? (() => Date.now())
|
|
144383
|
+
};
|
|
144384
|
+
const result = await runRelease(deps, {
|
|
144385
|
+
version: version3,
|
|
144386
|
+
from,
|
|
144387
|
+
to,
|
|
144388
|
+
dryRun: o.dryRun,
|
|
144389
|
+
yes: o.yes,
|
|
144390
|
+
suite: o.suite,
|
|
144391
|
+
baseline: o.baseline,
|
|
144392
|
+
liveSmoke: o.liveSmoke,
|
|
144393
|
+
fixOrphans: o.fixOrphans,
|
|
144394
|
+
timeoutMinutes
|
|
144395
|
+
});
|
|
144396
|
+
if (json) console.log(JSON.stringify(result, null, 2));
|
|
144397
|
+
else printResult(result);
|
|
144398
|
+
process.exitCode = result.ok ? 0 : 1;
|
|
144399
|
+
} catch (error2) {
|
|
144400
|
+
const message2 = error2 instanceof Error ? error2.message : String(error2);
|
|
144401
|
+
if (json) console.log(JSON.stringify({ ok: false, error: message2 }, null, 2));
|
|
144402
|
+
else console.error(source_default.red(`Error: ${message2}`));
|
|
144403
|
+
process.exitCode = error2 instanceof UsageError2 ? 2 : 1;
|
|
144404
|
+
}
|
|
144405
|
+
});
|
|
144406
|
+
return cmd;
|
|
144407
|
+
}
|
|
144408
|
+
|
|
144409
|
+
// src/cli/commands/progress.ts
|
|
144410
|
+
init_esm();
|
|
144411
|
+
var import_fs159 = require("fs");
|
|
144412
|
+
var import_path190 = require("path");
|
|
144413
|
+
|
|
144414
|
+
// src/lib/agent-progress.ts
|
|
144415
|
+
var import_fs158 = require("fs");
|
|
144416
|
+
var import_path189 = require("path");
|
|
144417
|
+
init_worktree_paths();
|
|
144418
|
+
var PROGRESS_STATUSES = ["start", "ok", "fail", "blocked", "heartbeat", "done"];
|
|
144419
|
+
var PROGRESS_FILE_ENV = "OMG_PROGRESS_FILE";
|
|
144420
|
+
var PROGRESS_AGENT_ENV = "OMG_PROGRESS_AGENT";
|
|
144421
|
+
var PROGRESS_MAX_BYTES = 1024 * 1024;
|
|
144422
|
+
var PROGRESS_MAX_NOTE = 500;
|
|
144423
|
+
var PROGRESS_MAX_VALUE = 200;
|
|
144424
|
+
var KEY_RE = /^[A-Za-z][A-Za-z0-9_.-]*$/;
|
|
144425
|
+
var BARE_VALUE_RE = /^[A-Za-z0-9._:/@+,%#~-]+$/;
|
|
144426
|
+
var RESERVED_KEYS = /* @__PURE__ */ new Set(["phase", "status", "note", "agent"]);
|
|
144427
|
+
function isProgressStatus(value) {
|
|
144428
|
+
return PROGRESS_STATUSES.includes(value);
|
|
144429
|
+
}
|
|
144430
|
+
function quoteValue(value) {
|
|
144431
|
+
if (BARE_VALUE_RE.test(value)) return value;
|
|
144432
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
144433
|
+
return `"${escaped}"`;
|
|
144434
|
+
}
|
|
144435
|
+
function formatProgressEvent(event) {
|
|
144436
|
+
const parts = [event.ts, `phase=${quoteValue(event.phase)}`, `status=${event.status}`];
|
|
144437
|
+
if (event.note !== void 0) parts.push(`note=${quoteValue(event.note)}`);
|
|
144438
|
+
if (event.agent !== void 0) parts.push(`agent=${quoteValue(event.agent)}`);
|
|
144439
|
+
for (const [key, value] of Object.entries(event.fields ?? {})) {
|
|
144440
|
+
if (KEY_RE.test(key) && !RESERVED_KEYS.has(key)) parts.push(`${key}=${quoteValue(value)}`);
|
|
144441
|
+
}
|
|
144442
|
+
return parts.join(" ");
|
|
144443
|
+
}
|
|
144444
|
+
function parseProgressLine(line) {
|
|
144445
|
+
const text = line.replace(/\r$/, "");
|
|
144446
|
+
const tsMatch = /^(\d{4}-\d{2}-\d{2}T\S*)/.exec(text);
|
|
144447
|
+
if (!tsMatch || !Number.isFinite(Date.parse(tsMatch[1]))) return null;
|
|
144448
|
+
const pairs = [];
|
|
144449
|
+
let i = tsMatch[1].length;
|
|
144450
|
+
while (i < text.length) {
|
|
144451
|
+
while (text[i] === " " || text[i] === " ") i++;
|
|
144452
|
+
if (i >= text.length) break;
|
|
144453
|
+
const keyMatch = /^([A-Za-z][A-Za-z0-9_.-]*)=/.exec(text.slice(i));
|
|
144454
|
+
if (!keyMatch) return null;
|
|
144455
|
+
i += keyMatch[0].length;
|
|
144456
|
+
let value = "";
|
|
144457
|
+
if (text[i] === '"') {
|
|
144458
|
+
i++;
|
|
144459
|
+
let closed = false;
|
|
144460
|
+
while (i < text.length) {
|
|
144461
|
+
const ch = text[i];
|
|
144462
|
+
if (ch === "\\" && i + 1 < text.length) {
|
|
144463
|
+
const next = text[i + 1];
|
|
144464
|
+
value += next === "n" ? "\n" : next === "r" ? "\r" : next === "t" ? " " : next;
|
|
144465
|
+
i += 2;
|
|
144466
|
+
} else if (ch === '"') {
|
|
144467
|
+
i++;
|
|
144468
|
+
closed = true;
|
|
144469
|
+
break;
|
|
144470
|
+
} else {
|
|
144471
|
+
value += ch;
|
|
144472
|
+
i++;
|
|
144473
|
+
}
|
|
144474
|
+
}
|
|
144475
|
+
if (!closed || i < text.length && text[i] !== " " && text[i] !== " ") return null;
|
|
144476
|
+
} else {
|
|
144477
|
+
const end = text.slice(i).search(/[ \t]/);
|
|
144478
|
+
value = end === -1 ? text.slice(i) : text.slice(i, i + end);
|
|
144479
|
+
i += value.length;
|
|
144480
|
+
}
|
|
144481
|
+
pairs.push([keyMatch[1], value]);
|
|
144482
|
+
}
|
|
144483
|
+
const get = (key) => pairs.find(([k]) => k === key)?.[1];
|
|
144484
|
+
const phase = get("phase");
|
|
144485
|
+
const status = get("status");
|
|
144486
|
+
if (!phase || !status || !(isProgressStatus(status) || status === "stalled")) return null;
|
|
144487
|
+
const fields = {};
|
|
144488
|
+
for (const [k, v] of pairs) if (!RESERVED_KEYS.has(k)) fields[k] = v;
|
|
144489
|
+
const event = { ts: tsMatch[1], phase, status, fields };
|
|
144490
|
+
const note = get("note");
|
|
144491
|
+
const agent = get("agent");
|
|
144492
|
+
if (note !== void 0) event.note = note;
|
|
144493
|
+
if (agent !== void 0) event.agent = agent;
|
|
144494
|
+
return event;
|
|
144495
|
+
}
|
|
144496
|
+
function progressAgentFileName(agent) {
|
|
144497
|
+
return `${agent.replace(/[^A-Za-z0-9._-]/g, "_").replace(/^\.+/, "_") || "agent"}.log`;
|
|
144498
|
+
}
|
|
144499
|
+
function agentFromProgressFile(file) {
|
|
144500
|
+
return (0, import_path189.basename)(file).replace(/\.log$/, "");
|
|
144501
|
+
}
|
|
144502
|
+
function defaultProgressDir(cwd2 = process.cwd()) {
|
|
144503
|
+
return (0, import_path189.join)(getOmcRoot(cwd2), "progress");
|
|
144504
|
+
}
|
|
144505
|
+
function resolveProgressFile(agent, file, cwd2) {
|
|
144506
|
+
return file || process.env[PROGRESS_FILE_ENV] || (0, import_path189.join)(defaultProgressDir(cwd2), progressAgentFileName(agent));
|
|
144507
|
+
}
|
|
144508
|
+
function truncate2(value, max) {
|
|
144509
|
+
return value.length <= max ? value : Array.from(value).slice(0, max).join("");
|
|
144510
|
+
}
|
|
144511
|
+
function rotateIfNeeded2(path30) {
|
|
144512
|
+
try {
|
|
144513
|
+
if ((0, import_fs158.statSync)(path30).size < PROGRESS_MAX_BYTES) return;
|
|
144514
|
+
const claimed = `${path30}.${process.pid}.${Date.now()}.rotating`;
|
|
144515
|
+
(0, import_fs158.renameSync)(path30, claimed);
|
|
144516
|
+
if ((0, import_fs158.statSync)(claimed).size >= PROGRESS_MAX_BYTES) {
|
|
144517
|
+
(0, import_fs158.renameSync)(claimed, `${path30}.1`);
|
|
144518
|
+
} else if (!(0, import_fs158.existsSync)(path30)) {
|
|
144519
|
+
(0, import_fs158.renameSync)(claimed, path30);
|
|
144520
|
+
} else {
|
|
144521
|
+
(0, import_fs158.appendFileSync)(path30, (0, import_fs158.readFileSync)(claimed));
|
|
144522
|
+
(0, import_fs158.unlinkSync)(claimed);
|
|
144523
|
+
}
|
|
144524
|
+
} catch {
|
|
144525
|
+
}
|
|
144526
|
+
}
|
|
144527
|
+
function emitProgress(input) {
|
|
144528
|
+
try {
|
|
144529
|
+
if (!input || typeof input.phase !== "string" || input.phase.length === 0 || !isProgressStatus(input.status)) return false;
|
|
144530
|
+
const agent = input.agent || process.env[PROGRESS_AGENT_ENV] || void 0;
|
|
144531
|
+
const path30 = resolveProgressFile(agent ?? "agent", input.file, input.cwd);
|
|
144532
|
+
const fields = {};
|
|
144533
|
+
for (const [k, v] of Object.entries(input.fields ?? {})) fields[k] = truncate2(String(v), PROGRESS_MAX_VALUE);
|
|
144534
|
+
const line = formatProgressEvent({
|
|
144535
|
+
ts: (input.at ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
144536
|
+
phase: truncate2(input.phase, PROGRESS_MAX_VALUE),
|
|
144537
|
+
status: input.status,
|
|
144538
|
+
note: input.note === void 0 ? void 0 : truncate2(input.note, PROGRESS_MAX_NOTE),
|
|
144539
|
+
agent,
|
|
144540
|
+
fields
|
|
144541
|
+
});
|
|
144542
|
+
(0, import_fs158.mkdirSync)((0, import_path189.dirname)(path30), { recursive: true });
|
|
144543
|
+
rotateIfNeeded2(path30);
|
|
144544
|
+
(0, import_fs158.appendFileSync)(path30, `${line}
|
|
144545
|
+
`, "utf8");
|
|
144546
|
+
return true;
|
|
144547
|
+
} catch {
|
|
144548
|
+
return false;
|
|
144549
|
+
}
|
|
144550
|
+
}
|
|
144551
|
+
function classifyProgress(last, now2, opts) {
|
|
144552
|
+
const idleMs = Math.max(0, now2.getTime() - Date.parse(last.ts));
|
|
144553
|
+
switch (last.status) {
|
|
144554
|
+
case "done":
|
|
144555
|
+
return { state: "done", idleMs };
|
|
144556
|
+
case "fail":
|
|
144557
|
+
return { state: "failed", idleMs };
|
|
144558
|
+
case "blocked":
|
|
144559
|
+
return { state: "blocked", idleMs };
|
|
144560
|
+
default:
|
|
144561
|
+
return { state: idleMs > opts.stallMs ? "stalled" : "running", idleMs };
|
|
144562
|
+
}
|
|
144563
|
+
}
|
|
144564
|
+
function summarizeProgress(events, now2, opts) {
|
|
144565
|
+
const latest2 = /* @__PURE__ */ new Map();
|
|
144566
|
+
for (const event of events) {
|
|
144567
|
+
if (event.status === "stalled") continue;
|
|
144568
|
+
const agent = event.agent ?? (event.source ? agentFromProgressFile(event.source) : "agent");
|
|
144569
|
+
const prev = latest2.get(agent);
|
|
144570
|
+
if (!prev || Date.parse(event.ts) >= Date.parse(prev.ts)) latest2.set(agent, event);
|
|
144571
|
+
}
|
|
144572
|
+
return [...latest2.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([agent, last]) => ({ agent, last, ...classifyProgress(last, now2, opts) }));
|
|
144573
|
+
}
|
|
144574
|
+
function parseProgressDuration(raw, defaultUnit = "m") {
|
|
144575
|
+
const match = /^(\d+(?:\.\d+)?)(ms|s|m|h)?$/.exec(raw.trim());
|
|
144576
|
+
if (!match) return null;
|
|
144577
|
+
const unit = match[2] ?? defaultUnit;
|
|
144578
|
+
const factor = unit === "ms" ? 1 : unit === "s" ? 1e3 : unit === "m" ? 6e4 : 36e5;
|
|
144579
|
+
return Number(match[1]) * factor;
|
|
144580
|
+
}
|
|
144581
|
+
function formatProgressDuration(ms) {
|
|
144582
|
+
const s = Math.floor(ms / 1e3);
|
|
144583
|
+
if (s < 60) return `${s}s`;
|
|
144584
|
+
const m = Math.floor(s / 60);
|
|
144585
|
+
if (m < 60) return `${m}m`;
|
|
144586
|
+
return `${Math.floor(m / 60)}h${m % 60 ? `${m % 60}m` : ""}`;
|
|
144587
|
+
}
|
|
144588
|
+
|
|
144589
|
+
// src/cli/commands/progress.ts
|
|
144590
|
+
var UsageError3 = class extends Error {
|
|
144591
|
+
};
|
|
144592
|
+
var defaultDeps = {
|
|
144593
|
+
now: () => /* @__PURE__ */ new Date(),
|
|
144594
|
+
sleep: (ms) => new Promise((resolve58) => setTimeout(resolve58, ms)),
|
|
144595
|
+
out: (line) => process.stdout.write(`${line}
|
|
144596
|
+
`),
|
|
144597
|
+
err: (line) => process.stderr.write(`${line}
|
|
144598
|
+
`),
|
|
144599
|
+
cwd: () => process.cwd()
|
|
144600
|
+
};
|
|
144601
|
+
function resolveSources(o, cwd2) {
|
|
144602
|
+
if (o.file.length > 0) return { files: o.file, dir: null };
|
|
144603
|
+
if (o.dir) return { files: null, dir: o.dir };
|
|
144604
|
+
const envFile = process.env[PROGRESS_FILE_ENV];
|
|
144605
|
+
if (envFile) return { files: [envFile], dir: null };
|
|
144606
|
+
return { files: null, dir: defaultProgressDir(cwd2) };
|
|
144607
|
+
}
|
|
144608
|
+
function listSources(sources) {
|
|
144609
|
+
if (sources.files) return sources.files;
|
|
144610
|
+
try {
|
|
144611
|
+
return (0, import_fs159.readdirSync)(sources.dir).filter((name) => name.endsWith(".log")).sort().map((name) => (0, import_path190.join)(sources.dir, name));
|
|
144612
|
+
} catch {
|
|
144613
|
+
return [];
|
|
144614
|
+
}
|
|
144615
|
+
}
|
|
144616
|
+
function parseStall(raw) {
|
|
144617
|
+
const ms = parseProgressDuration(raw, "m");
|
|
144618
|
+
if (ms === null || ms <= 0) throw new UsageError3(`--stall must be a positive duration like 10m, 90s or 1h, got ${JSON.stringify(raw)}`);
|
|
144619
|
+
return ms;
|
|
144620
|
+
}
|
|
144621
|
+
function parseInterval(raw) {
|
|
144622
|
+
const ms = parseProgressDuration(raw, "ms");
|
|
144623
|
+
if (ms === null || ms < 50) throw new UsageError3(`--interval must be at least 50ms, got ${JSON.stringify(raw)}`);
|
|
144624
|
+
return ms;
|
|
144625
|
+
}
|
|
144626
|
+
function parseUntil(raw) {
|
|
144627
|
+
if (raw !== "done" && raw !== "settled") throw new UsageError3(`--until must be done or settled, got ${JSON.stringify(raw)}`);
|
|
144628
|
+
return raw;
|
|
144629
|
+
}
|
|
144630
|
+
function parseSince(raw, now2) {
|
|
144631
|
+
const ms = parseProgressDuration(raw, "m");
|
|
144632
|
+
if (ms !== null) return now2.getTime() - ms;
|
|
144633
|
+
const at = /^\d{4}-\d{2}-\d{2}T/.test(raw) ? Date.parse(raw) : NaN;
|
|
144634
|
+
if (!Number.isFinite(at)) throw new UsageError3(`--since must be an ISO-8601 time or a duration like 2h, got ${JSON.stringify(raw)}`);
|
|
144635
|
+
return at;
|
|
144636
|
+
}
|
|
144637
|
+
function parseAgents(raw) {
|
|
144638
|
+
const agents = raw.split(",").map((a) => a.trim()).filter(Boolean);
|
|
144639
|
+
if (agents.length === 0) throw new UsageError3(`--agents must list agent names like lane-1,lane-2, got ${JSON.stringify(raw)}`);
|
|
144640
|
+
return agents;
|
|
144641
|
+
}
|
|
144642
|
+
var newTail = () => ({ offset: 0, rest: Buffer.alloc(0), ino: 0, birthtimeMs: 0 });
|
|
144643
|
+
function readFrom(path30, offset, size) {
|
|
144644
|
+
if (size <= offset) return Buffer.alloc(0);
|
|
144645
|
+
const fd = (0, import_fs159.openSync)(path30, "r");
|
|
144646
|
+
try {
|
|
144647
|
+
const chunk = Buffer.alloc(size - offset);
|
|
144648
|
+
return chunk.subarray(0, (0, import_fs159.readSync)(fd, chunk, 0, chunk.length, offset));
|
|
144649
|
+
} finally {
|
|
144650
|
+
(0, import_fs159.closeSync)(fd);
|
|
144651
|
+
}
|
|
144652
|
+
}
|
|
144653
|
+
function tryStat(path30) {
|
|
144654
|
+
try {
|
|
144655
|
+
return (0, import_fs159.statSync)(path30);
|
|
144656
|
+
} catch {
|
|
144657
|
+
return null;
|
|
144658
|
+
}
|
|
144659
|
+
}
|
|
144660
|
+
function readNewLines(path30, tail3, flush) {
|
|
144661
|
+
const st = tryStat(path30);
|
|
144662
|
+
if (!st) return [];
|
|
144663
|
+
const lines3 = [];
|
|
144664
|
+
const known = tail3.ino !== 0 || tail3.birthtimeMs !== 0;
|
|
144665
|
+
const replaced = known && (tail3.ino !== 0 && st.ino !== 0 ? st.ino !== tail3.ino : st.birthtimeMs !== tail3.birthtimeMs);
|
|
144666
|
+
if (replaced || st.size < tail3.offset) {
|
|
144667
|
+
const old = tryStat(`${path30}.1`);
|
|
144668
|
+
const isOldFile = old !== null && (known ? replaced && (tail3.ino !== 0 ? old.ino === tail3.ino : old.birthtimeMs === tail3.birthtimeMs) : old.size >= tail3.offset);
|
|
144669
|
+
if (isOldFile) {
|
|
144670
|
+
try {
|
|
144671
|
+
lines3.push(...Buffer.concat([tail3.rest, readFrom(`${path30}.1`, tail3.offset, old.size)]).toString("utf8").split("\n"));
|
|
144672
|
+
} catch {
|
|
144673
|
+
}
|
|
144674
|
+
}
|
|
144675
|
+
tail3.offset = 0;
|
|
144676
|
+
tail3.rest = Buffer.alloc(0);
|
|
144677
|
+
}
|
|
144678
|
+
tail3.ino = st.ino;
|
|
144679
|
+
tail3.birthtimeMs = st.birthtimeMs;
|
|
144680
|
+
let chunk;
|
|
144681
|
+
try {
|
|
144682
|
+
chunk = readFrom(path30, tail3.offset, st.size);
|
|
144683
|
+
} catch {
|
|
144684
|
+
return lines3;
|
|
144685
|
+
}
|
|
144686
|
+
tail3.offset += chunk.length;
|
|
144687
|
+
const data = Buffer.concat([tail3.rest, chunk]);
|
|
144688
|
+
const lastNewline = data.lastIndexOf(10);
|
|
144689
|
+
const complete = lastNewline === -1 ? Buffer.alloc(0) : data.subarray(0, lastNewline);
|
|
144690
|
+
tail3.rest = lastNewline === -1 ? data : data.subarray(lastNewline + 1);
|
|
144691
|
+
if (lastNewline !== -1) lines3.push(...complete.toString("utf8").split("\n"));
|
|
144692
|
+
if (flush && tail3.rest.length > 0) {
|
|
144693
|
+
lines3.push(tail3.rest.toString("utf8"));
|
|
144694
|
+
tail3.rest = Buffer.alloc(0);
|
|
144695
|
+
}
|
|
144696
|
+
return lines3;
|
|
144697
|
+
}
|
|
144698
|
+
function withAgent(event, path30) {
|
|
144699
|
+
return event.agent ? event : { ...event, agent: agentFromProgressFile(path30) };
|
|
144700
|
+
}
|
|
144701
|
+
function stalledLine(summary, now2) {
|
|
144702
|
+
const idle = formatProgressDuration(summary.idleMs);
|
|
144703
|
+
return formatProgressEvent({
|
|
144704
|
+
ts: now2.toISOString(),
|
|
144705
|
+
phase: summary.last.phase,
|
|
144706
|
+
status: "stalled",
|
|
144707
|
+
note: `no event for ${idle} after status=${summary.last.status}`,
|
|
144708
|
+
agent: summary.agent,
|
|
144709
|
+
fields: { idle, last_ts: summary.last.ts }
|
|
144710
|
+
});
|
|
144711
|
+
}
|
|
144712
|
+
function pendingLine(agent, idleMs, now2) {
|
|
144713
|
+
const idle = formatProgressDuration(idleMs);
|
|
144714
|
+
return formatProgressEvent({
|
|
144715
|
+
ts: now2.toISOString(),
|
|
144716
|
+
phase: "pending",
|
|
144717
|
+
status: "stalled",
|
|
144718
|
+
note: `no event for ${idle} since the watch started`,
|
|
144719
|
+
agent,
|
|
144720
|
+
fields: { idle }
|
|
144721
|
+
});
|
|
144722
|
+
}
|
|
144723
|
+
async function watchProgress(o, deps) {
|
|
144724
|
+
const sources = resolveSources(o, deps.cwd());
|
|
144725
|
+
const tails = /* @__PURE__ */ new Map();
|
|
144726
|
+
const latest2 = /* @__PURE__ */ new Map();
|
|
144727
|
+
const fresh = /* @__PURE__ */ new Set();
|
|
144728
|
+
const freshFiles = /* @__PURE__ */ new Set();
|
|
144729
|
+
const reportedStalls = /* @__PURE__ */ new Set();
|
|
144730
|
+
const reportedPending = /* @__PURE__ */ new Set();
|
|
144731
|
+
const pendingSince = o.sinceMs ?? deps.now().getTime();
|
|
144732
|
+
const reached = (s) => s !== void 0 && (s.state === "done" || o.until === "settled" && (s.state === "failed" || s.state === "blocked"));
|
|
144733
|
+
let first = true;
|
|
144734
|
+
for (; ; ) {
|
|
144735
|
+
const paths = listSources(sources);
|
|
144736
|
+
for (const path30 of paths) {
|
|
144737
|
+
let tail3 = tails.get(path30);
|
|
144738
|
+
if (!tail3) {
|
|
144739
|
+
if (!(0, import_fs159.existsSync)(path30)) continue;
|
|
144740
|
+
tail3 = newTail();
|
|
144741
|
+
tails.set(path30, tail3);
|
|
144742
|
+
}
|
|
144743
|
+
for (const line of readNewLines(path30, tail3, o.once)) {
|
|
144744
|
+
const parsed = parseProgressLine(line);
|
|
144745
|
+
if (!parsed || parsed.status === "stalled") continue;
|
|
144746
|
+
const event = withAgent(parsed, path30);
|
|
144747
|
+
const prev = latest2.get(event.agent);
|
|
144748
|
+
if (!prev || Date.parse(event.ts) >= Date.parse(prev.ts)) latest2.set(event.agent, event);
|
|
144749
|
+
if (!first || o.replay || o.sinceMs !== void 0 && Date.parse(event.ts) >= o.sinceMs) {
|
|
144750
|
+
fresh.add(event.agent);
|
|
144751
|
+
freshFiles.add(path30);
|
|
144752
|
+
}
|
|
144753
|
+
if (!first || o.replay) deps.out(formatProgressEvent(event));
|
|
144754
|
+
}
|
|
144755
|
+
}
|
|
144756
|
+
const now2 = deps.now();
|
|
144757
|
+
const summaries = new Map(summarizeProgress([...latest2.values()], now2, { stallMs: o.stallMs }).map((s) => [s.agent, s]));
|
|
144758
|
+
for (const s of summaries.values()) {
|
|
144759
|
+
const key = `${s.agent}\0${s.last.ts}\0${s.last.phase}\0${s.last.status}`;
|
|
144760
|
+
const tracked2 = first || fresh.has(s.agent) || o.agents.includes(s.agent);
|
|
144761
|
+
if (s.state === "stalled" && tracked2 && !reportedStalls.has(key)) {
|
|
144762
|
+
reportedStalls.add(key);
|
|
144763
|
+
deps.out(stalledLine(s, now2));
|
|
144764
|
+
} else if (first && !o.replay && (s.state === "failed" || s.state === "blocked")) {
|
|
144765
|
+
deps.out(formatProgressEvent(s.last));
|
|
144766
|
+
}
|
|
144767
|
+
}
|
|
144768
|
+
for (const agent of o.agents) {
|
|
144769
|
+
if (fresh.has(agent) || reportedPending.has(agent) || summaries.get(agent)?.state === "stalled") continue;
|
|
144770
|
+
const idleMs = Math.max(0, now2.getTime() - pendingSince);
|
|
144771
|
+
if (idleMs > o.stallMs) {
|
|
144772
|
+
reportedPending.add(agent);
|
|
144773
|
+
deps.out(pendingLine(agent, idleMs, now2));
|
|
144774
|
+
}
|
|
144775
|
+
}
|
|
144776
|
+
first = false;
|
|
144777
|
+
if (o.once) return 0;
|
|
144778
|
+
const tracked = /* @__PURE__ */ new Set([...fresh, ...o.agents]);
|
|
144779
|
+
const filesReady = !sources.files || sources.files.every((f) => freshFiles.has(f));
|
|
144780
|
+
if (tracked.size > 0 && filesReady && [...tracked].every((a) => fresh.has(a) && reached(summaries.get(a)))) return 0;
|
|
144781
|
+
await deps.sleep(o.intervalMs);
|
|
144782
|
+
}
|
|
144783
|
+
}
|
|
144784
|
+
function readAllEvents(sources) {
|
|
144785
|
+
const events = [];
|
|
144786
|
+
for (const path30 of listSources(sources)) {
|
|
144787
|
+
for (const line of readNewLines(path30, newTail(), true)) {
|
|
144788
|
+
const parsed = parseProgressLine(line);
|
|
144789
|
+
if (parsed) events.push(withAgent(parsed, path30));
|
|
144790
|
+
}
|
|
144791
|
+
}
|
|
144792
|
+
return events;
|
|
144793
|
+
}
|
|
144794
|
+
function collect(value, previous) {
|
|
144795
|
+
return [...previous, value];
|
|
144796
|
+
}
|
|
144797
|
+
async function guarded3(deps, fn) {
|
|
144798
|
+
try {
|
|
144799
|
+
process.exitCode = await fn();
|
|
144800
|
+
} catch (error2) {
|
|
144801
|
+
deps.err(`Error: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
144802
|
+
process.exitCode = error2 instanceof UsageError3 ? 2 : 1;
|
|
144803
|
+
}
|
|
144804
|
+
}
|
|
144805
|
+
function progressCommand(overrides = {}) {
|
|
144806
|
+
const deps = { ...defaultDeps, ...overrides };
|
|
144807
|
+
const cmd = new Command("progress");
|
|
144808
|
+
cmd.description("Agent progress events: emit phase events, watch them (stall detection) for the Monitor tool, show status");
|
|
144809
|
+
cmd.command("emit <phase> <status>").description("Append one event (status: start|ok|fail|blocked|heartbeat|done) to $OMG_PROGRESS_FILE or <state root>/progress/<agent>.log").option("--note <text>", "Short note (quoted and escaped as needed; truncated at 500 code points)").option("--agent <name>", 'Agent name (default $OMG_PROGRESS_AGENT, else "agent")').option("--file <path>", "Log file (wins over $OMG_PROGRESS_FILE)").option("--field <key=value>", "Extra key=value pair (repeatable)", collect, []).action((phase, status, o) => guarded3(deps, () => {
|
|
144810
|
+
if (!isProgressStatus(status)) throw new UsageError3(`status must be one of start|ok|fail|blocked|heartbeat|done, got ${JSON.stringify(status)}`);
|
|
144811
|
+
if (phase.trim().length === 0) throw new UsageError3("phase must not be empty");
|
|
144812
|
+
const fields = {};
|
|
144813
|
+
for (const raw of o.field) {
|
|
144814
|
+
const eq2 = raw.indexOf("=");
|
|
144815
|
+
const key = eq2 === -1 ? "" : raw.slice(0, eq2);
|
|
144816
|
+
if (!/^[A-Za-z][A-Za-z0-9_.-]*$/.test(key) || ["phase", "status", "note", "agent"].includes(key)) {
|
|
144817
|
+
throw new UsageError3(`--field must be key=value with a key like build_id (not phase/status/note/agent), got ${JSON.stringify(raw)}`);
|
|
144818
|
+
}
|
|
144819
|
+
fields[key] = raw.slice(eq2 + 1);
|
|
144820
|
+
}
|
|
144821
|
+
const ok = emitProgress({ phase, status, note: o.note, agent: o.agent, file: o.file, fields, at: deps.now(), cwd: deps.cwd() });
|
|
144822
|
+
if (!ok) deps.err("omg progress: could not write the progress event (continuing)");
|
|
144823
|
+
return 0;
|
|
144824
|
+
}));
|
|
144825
|
+
cmd.command("watch").description("Stream new events and synthesized status=stalled lines (one per line); exits when every agent with a new event (and every --agents name) is done").option("--file <path>", "Watch this log (repeatable; may not exist yet; each needs one new event before the watch can exit)", collect, []).option("--dir <path>", "Watch every *.log in this directory, including files created later").option("--agents <names>", "Comma-separated agents to wait for, even before their logs exist (stalled after --stall without an event)").option("--until <state>", "Exit when every tracked agent is done, or settled (done, failed or blocked)", "done").option("--since <time>", "Existing events at or after this ISO time or duration ago (e.g. 2h) count as new for exiting").option("--stall <duration>", "Silence after start/heartbeat/ok that counts as a stall (bare number = minutes)", "10m").option("--interval <duration>", "Poll interval (bare number = ms)", "1000").option("--replay", "Also print the events already in the logs (and count them as new)").option("--once", "Read what exists, report it, and exit").action((o) => guarded3(deps, () => watchProgress({
|
|
144826
|
+
file: o.file,
|
|
144827
|
+
dir: o.dir,
|
|
144828
|
+
stallMs: parseStall(o.stall),
|
|
144829
|
+
intervalMs: parseInterval(o.interval),
|
|
144830
|
+
once: Boolean(o.once),
|
|
144831
|
+
replay: Boolean(o.replay),
|
|
144832
|
+
until: parseUntil(o.until),
|
|
144833
|
+
sinceMs: o.since === void 0 ? void 0 : parseSince(o.since, deps.now()),
|
|
144834
|
+
agents: o.agents === void 0 ? [] : parseAgents(o.agents)
|
|
144835
|
+
}, deps)));
|
|
144836
|
+
cmd.command("status").description("Show each agent's latest event and state (running|stalled|failed|blocked|done)").option("--file <path>", "Read this log (repeatable)", collect, []).option("--dir <path>", "Read every *.log in this directory").option("--stall <duration>", "Stall threshold (bare number = minutes)", "10m").option("--json", "JSON output").action((o) => guarded3(deps, () => {
|
|
144837
|
+
const stallMs = parseStall(o.stall);
|
|
144838
|
+
const summaries = summarizeProgress(readAllEvents(resolveSources(o, deps.cwd())), deps.now(), { stallMs });
|
|
144839
|
+
if (o.json) {
|
|
144840
|
+
deps.out(JSON.stringify(summaries, null, 2));
|
|
144841
|
+
return 0;
|
|
144842
|
+
}
|
|
144843
|
+
if (summaries.length === 0) {
|
|
144844
|
+
deps.out("no progress events");
|
|
144845
|
+
return 0;
|
|
144846
|
+
}
|
|
144847
|
+
const rows = [["AGENT", "STATE", "PHASE", "STATUS", "IDLE", "NOTE"], ...summaries.map((s) => [
|
|
144848
|
+
s.agent,
|
|
144849
|
+
s.state,
|
|
144850
|
+
s.last.phase,
|
|
144851
|
+
s.last.status,
|
|
144852
|
+
formatProgressDuration(s.idleMs),
|
|
144853
|
+
s.last.note ?? ""
|
|
144854
|
+
])];
|
|
144855
|
+
const widths = rows[0].map((_, i) => Math.max(...rows.map((r) => r[i].length)));
|
|
144856
|
+
for (const r of rows) deps.out(r.map((cell, i) => i === r.length - 1 ? cell : cell.padEnd(widths[i])).join(" ").trimEnd());
|
|
144857
|
+
return 0;
|
|
144858
|
+
}));
|
|
144859
|
+
return cmd;
|
|
144860
|
+
}
|
|
144861
|
+
|
|
142998
144862
|
// src/cli/win32-warning.ts
|
|
142999
144863
|
init_source();
|
|
143000
144864
|
init_tmux_utils();
|
|
@@ -143228,8 +145092,8 @@ Examples:
|
|
|
143228
145092
|
console.log(` User: ${paths.user}`);
|
|
143229
145093
|
console.log(` Project: ${paths.project}`);
|
|
143230
145094
|
console.log(source_default.blue("\nFile status:"));
|
|
143231
|
-
console.log(` User: ${(0,
|
|
143232
|
-
console.log(` Project: ${(0,
|
|
145095
|
+
console.log(` User: ${(0, import_fs166.existsSync)(paths.user) ? source_default.green("exists") : source_default.gray("not found")}`);
|
|
145096
|
+
console.log(` Project: ${(0, import_fs166.existsSync)(paths.project) ? source_default.green("exists") : source_default.gray("not found")}`);
|
|
143233
145097
|
return;
|
|
143234
145098
|
}
|
|
143235
145099
|
const config2 = loadConfig();
|
|
@@ -143272,7 +145136,7 @@ Profile types (use with --profile):
|
|
|
143272
145136
|
webhook Generic webhook (POST with JSON body)
|
|
143273
145137
|
|
|
143274
145138
|
Examples:
|
|
143275
|
-
$ omg config-stop-callback file --enable --path ${(0,
|
|
145139
|
+
$ omg config-stop-callback file --enable --path ${(0, import_path196.join)(getCopilotConfigDir(), "logs/{date}.md")}
|
|
143276
145140
|
$ omg config-stop-callback telegram --enable --token <token> --chat <id>
|
|
143277
145141
|
$ omg config-stop-callback discord --enable --webhook <url>
|
|
143278
145142
|
$ omg config-stop-callback file --disable
|
|
@@ -143398,7 +145262,7 @@ Examples:
|
|
|
143398
145262
|
}
|
|
143399
145263
|
config3.notificationProfiles[profileName] = profile;
|
|
143400
145264
|
try {
|
|
143401
|
-
(0,
|
|
145265
|
+
(0, import_fs166.writeFileSync)(CONFIG_FILE, JSON.stringify(config3, null, 2), "utf-8");
|
|
143402
145266
|
console.log(source_default.green(`\u2713 Profile "${profileName}" \u2014 ${type} configured`));
|
|
143403
145267
|
console.log(JSON.stringify(profile[type], null, 2));
|
|
143404
145268
|
} catch (error2) {
|
|
@@ -143457,7 +145321,7 @@ Examples:
|
|
|
143457
145321
|
const current = config2.stopHookCallbacks.file;
|
|
143458
145322
|
config2.stopHookCallbacks.file = {
|
|
143459
145323
|
enabled: enabled ?? current?.enabled ?? false,
|
|
143460
|
-
path: options.path ?? current?.path ?? (0,
|
|
145324
|
+
path: options.path ?? current?.path ?? (0, import_path196.join)(getCopilotConfigDir(), "session-logs/{session_id}.md"),
|
|
143461
145325
|
format: options.format ?? current?.format ?? "markdown"
|
|
143462
145326
|
};
|
|
143463
145327
|
break;
|
|
@@ -143511,7 +145375,7 @@ Examples:
|
|
|
143511
145375
|
}
|
|
143512
145376
|
}
|
|
143513
145377
|
try {
|
|
143514
|
-
(0,
|
|
145378
|
+
(0, import_fs166.writeFileSync)(CONFIG_FILE, JSON.stringify(config2, null, 2), "utf-8");
|
|
143515
145379
|
console.log(source_default.green(`\u2713 Stop callback '${type}' configured`));
|
|
143516
145380
|
console.log(JSON.stringify(config2.stopHookCallbacks[type], null, 2));
|
|
143517
145381
|
} catch (error2) {
|
|
@@ -143573,7 +145437,7 @@ Active profile (OMC_NOTIFY_PROFILE): ${activeProfile}`));
|
|
|
143573
145437
|
delete config2.notificationProfiles;
|
|
143574
145438
|
}
|
|
143575
145439
|
try {
|
|
143576
|
-
(0,
|
|
145440
|
+
(0, import_fs166.writeFileSync)(CONFIG_FILE, JSON.stringify(config2, null, 2), "utf-8");
|
|
143577
145441
|
console.log(source_default.green(`\u2713 Profile "${name}" deleted`));
|
|
143578
145442
|
} catch (error2) {
|
|
143579
145443
|
console.error(source_default.red("Failed to write configuration:"), error2);
|
|
@@ -143991,7 +145855,7 @@ Exit code 1 means budget.hardLimit is reached. Configure limits in .copilot/omg.
|
|
|
143991
145855
|
process.exit(exitCode);
|
|
143992
145856
|
});
|
|
143993
145857
|
var smokeCmd = program2.command("smoke").description("Smoke-test the plugin inside a real host CLI");
|
|
143994
|
-
smokeCmd.command("copilot").description("Load-check oh-my-copilot in GitHub Copilot CLI (tier 0: no model call; tier 1: one cheap live session; tier 2: SDK-driven scenarios)").option("--tier <0|1|2>", "Tier 0 = static/load checks only; tier 1 adds one -p session; tier 2 = tier 0 + SDK static checks + scenarios (default 0, or 2 with --scenario/--sdk-static)").option("--plugin-root <dir>", "Plugin directory to load via --plugin-dir (default: this omg package root)").option("--model <id>", "Tiers 1-2 model id (default: tier 1 lets the CLI auto-pick; tier 2 a cheap listed model, else auto)").option("--max-credits <n>", "Tiers 1-2 AI credit cap (default and minimum 30): tier 1 passes --max-ai-credits; tier 2 also aborts a scenario and skips the rest once the run passes it").option("--timeout <ms>", "Tiers 1-2: tier 1 session timeout (default 180000), tier 2 per-scenario timeout (default 120000, then abort); tier 0 per-subprocess timeout (default 60000); the MCP check is fixed at 10 s").option("--keep-home", "Keep the throwaway COPILOT_HOME and project dir for debugging").option("--delegate", "Tier 1: ask for a delegation to oh-my-copilot:architect and check subagent.selected").option("--scenario <list|all>", "Tier 2 scenarios, comma-separated: smoke, guardrail, skill, delegate, or all (default: smoke,guardrail); chain and team (opt-in, never in all) run a real two-link factory chain and a real 2-worker sdk team").option("--sdk-static", "Tier 2 with no scenarios: SDK static checks only, zero model calls").option("--json", "Print the full SmokeReport as JSON (always, also for option errors)").addHelpText("after", `
|
|
145858
|
+
smokeCmd.command("copilot").description("Load-check oh-my-copilot in GitHub Copilot CLI (tier 0: no model call; tier 1: one cheap live session; tier 2: SDK-driven scenarios)").option("--tier <0|1|2>", "Tier 0 = static/load checks only; tier 1 adds one -p session; tier 2 = tier 0 + SDK static checks + scenarios (default 0, or 2 with --scenario/--sdk-static)").option("--plugin-root <dir>", "Plugin directory to load via --plugin-dir (default: this omg package root)").option("--model <id>", "Tiers 1-2 model id (default: tier 1 lets the CLI auto-pick; tier 2 a cheap listed model, else auto)").option("--max-credits <n>", "Tiers 1-2 AI credit cap (default and minimum 30): tier 1 passes --max-ai-credits; tier 2 also aborts a scenario and skips the rest once the run passes it").option("--timeout <ms>", "Tiers 1-2: tier 1 session timeout (default 180000), tier 2 per-scenario timeout (default 120000, then abort); tier 0 per-subprocess timeout (default 60000); the MCP check is fixed at 10 s").option("--keep-home", "Keep the throwaway COPILOT_HOME and project dir for debugging").option("--delegate", "Tier 1: ask for a delegation to oh-my-copilot:architect and check subagent.selected").option("--scenario <list|all>", "Tier 2 scenarios, comma-separated: smoke, guardrail, skill, delegate, or all (default: smoke,guardrail); filetools, chain and team (opt-in, never in all) check the file-tool hooks, run a real two-link factory chain and a real 2-worker sdk team").option("--sdk-static", "Tier 2 with no scenarios: SDK static checks only, zero model calls").option("--json", "Print the full SmokeReport as JSON (always, also for option errors)").addHelpText("after", `
|
|
143995
145859
|
Exit codes: 0 all checks ok, 1 a check failed or bad options, 2 skipped (copilot binary or
|
|
143996
145860
|
@github/copilot-sdk not found, no other failure).
|
|
143997
145861
|
|
|
@@ -144156,6 +146020,8 @@ program2.addCommand(lookoutCommand());
|
|
|
144156
146020
|
program2.addCommand(intakeCommand());
|
|
144157
146021
|
program2.addCommand(factoryCommand());
|
|
144158
146022
|
program2.addCommand(shipCommand());
|
|
146023
|
+
program2.addCommand(releaseCommand());
|
|
146024
|
+
program2.addCommand(progressCommand());
|
|
144159
146025
|
function buildProgram() {
|
|
144160
146026
|
return program2;
|
|
144161
146027
|
}
|