lazycodex-ai 5.1.61 → 5.1.63
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/dist/cli/index.js +1722 -281
- package/dist/cli/service-auth/closed-device-login.fixture.d.ts +1 -0
- package/dist/cli/service-auth/credential-lock.d.ts +8 -2
- package/dist/cli/service-auth/index.d.ts +2 -1
- package/dist/cli/service-auth/keychain-helper/access.d.ts +27 -0
- package/dist/cli/service-auth/keychain-helper/approval-cache.d.ts +51 -0
- package/dist/cli/service-auth/keychain-helper/client.d.ts +68 -0
- package/dist/cli/service-auth/keychain-helper/creator-handoff.d.ts +31 -0
- package/dist/cli/service-auth/keychain-helper/darwin-backend.d.ts +75 -0
- package/dist/cli/service-auth/keychain-helper/darwin-read.d.ts +46 -0
- package/dist/cli/service-auth/keychain-helper/darwin-store.d.ts +28 -0
- package/dist/cli/service-auth/keychain-helper/fake-keychain.test-support.d.ts +85 -0
- package/dist/cli/service-auth/keychain-helper/location.d.ts +28 -0
- package/dist/cli/service-auth/keychain-helper/migration.d.ts +20 -0
- package/dist/cli/service-auth/keychain-helper/owner-marker.d.ts +7 -0
- package/dist/cli/service-auth/keychain-helper/pin.d.ts +20 -0
- package/dist/cli/service-auth/keychain-helper/process-copy.test-support.d.ts +3 -0
- package/dist/cli/service-auth/keychain-helper/process-state.d.ts +19 -0
- package/dist/cli/service-auth/keychain-helper/prompt-lock.d.ts +14 -0
- package/dist/cli/service-auth/keychain-helper/recovery.d.ts +34 -0
- package/dist/cli/service-auth/keychain-helper/runtime-capabilities.d.ts +13 -0
- package/dist/cli/service-auth/keychain-helper/secrets-gate.d.ts +4 -0
- package/dist/cli/service-auth/keychain-helper/signature.d.ts +17 -0
- package/dist/cli/service-auth/keychain-helper/store-binding.d.ts +46 -0
- package/dist/cli/service-auth/keystore.d.ts +18 -3
- package/dist/cli/service-auth/session.d.ts +29 -2
- package/dist/cli/service-auth/sync-pin-retire.d.ts +7 -0
- package/dist/cli-node/index.js +1722 -281
- package/package.json +1 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-doctor/SKILL.md +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +2 -0
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-unclear.md +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/directive.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/define-goal.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +10 -10
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +12 -12
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +6 -3
- package/packages/omo-codex/plugin/skills/ast-grep/AGENTS.md +2 -2
- package/packages/omo-codex/plugin/skills/ast-grep/README.md +4 -4
- package/packages/omo-codex/plugin/skills/ast-grep/SKILL.md +10 -8
- package/packages/omo-codex/plugin/skills/ast-grep/references/cli.md +4 -3
- package/packages/omo-codex/plugin/skills/ast-grep/references/patterns.md +5 -5
- package/packages/omo-codex/plugin/skills/ast-grep/references/pitfalls.md +3 -3
- package/packages/omo-codex/plugin/skills/ast-grep/references/recipes.md +6 -4
- package/packages/omo-codex/plugin/skills/ast-grep/references/yaml-rules.md +3 -3
- package/packages/omo-codex/plugin/skills/ast-grep/scripts/ast_grep_helper.py +3 -3
- package/packages/omo-codex/plugin/skills/browser/SKILL.md +2 -3
- package/packages/omo-codex/plugin/skills/browser/references/owned-engine/README.md +1 -1
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/AGENTS.md +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +2 -1
- package/packages/omo-codex/plugin/skills/data-scientist/SKILL.md +8 -6
- package/packages/omo-codex/plugin/skills/data-scientist/references/placement.md +9 -5
- package/packages/omo-codex/plugin/skills/data-scientist/references/uv-setup.md +3 -3
- package/packages/omo-codex/plugin/skills/data-scientist/references/visualization.md +19 -4
- package/packages/omo-codex/plugin/skills/debugging/SKILL.md +5 -5
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/02-investigate.md +2 -2
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/06-fix.md +2 -0
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/09-cleanup.md +2 -2
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/partial-runtime-evidence.md +1 -1
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/bundled-js-binary.md +1 -1
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/native-binary.md +1 -1
- package/packages/omo-codex/plugin/skills/debugging/references/tools/browser-qa.md +1 -2
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +4 -4
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/references/design/component-catalogs.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/references/design/print-paged-media.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/react-dev-tooling-skill.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-a-direction.md +5 -5
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/routing.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/references/perfection/README.md +1 -2
- package/packages/omo-codex/plugin/skills/frontend/references/perfection/react-perf-tooling.md +27 -8
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/lighthouse-audit.py +0 -1
- package/packages/omo-codex/plugin/skills/git-master/SKILL.md +12 -2
- package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/lcx-doctor/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/lsp-setup/SKILL.md +24 -15
- package/packages/omo-codex/plugin/skills/lsp-setup/references/bash/README.md +3 -3
- package/packages/omo-codex/plugin/skills/lsp-setup/references/c-cpp/README.md +2 -2
- package/packages/omo-codex/plugin/skills/lsp-setup/references/csharp/README.md +2 -2
- package/packages/omo-codex/plugin/skills/lsp-setup/references/dart/README.md +2 -2
- package/packages/omo-codex/plugin/skills/lsp-setup/references/elixir/README.md +2 -2
- package/packages/omo-codex/plugin/skills/lsp-setup/references/go/README.md +2 -2
- package/packages/omo-codex/plugin/skills/lsp-setup/references/haskell/README.md +2 -2
- package/packages/omo-codex/plugin/skills/lsp-setup/references/java/README.md +3 -3
- package/packages/omo-codex/plugin/skills/lsp-setup/references/julia/README.md +3 -3
- package/packages/omo-codex/plugin/skills/lsp-setup/references/kotlin/README.md +4 -4
- package/packages/omo-codex/plugin/skills/lsp-setup/references/lua/README.md +2 -2
- package/packages/omo-codex/plugin/skills/lsp-setup/references/php/README.md +3 -3
- package/packages/omo-codex/plugin/skills/lsp-setup/references/python/README.md +13 -12
- package/packages/omo-codex/plugin/skills/lsp-setup/references/ruby/README.md +2 -2
- package/packages/omo-codex/plugin/skills/lsp-setup/references/rust/README.md +2 -2
- package/packages/omo-codex/plugin/skills/lsp-setup/references/swift/README.md +4 -4
- package/packages/omo-codex/plugin/skills/lsp-setup/references/terraform/README.md +2 -2
- package/packages/omo-codex/plugin/skills/lsp-setup/references/typescript/README.md +3 -3
- package/packages/omo-codex/plugin/skills/lsp-setup/references/yaml/README.md +2 -2
- package/packages/omo-codex/plugin/skills/lsp-setup/references/zig/README.md +2 -2
- package/packages/omo-codex/plugin/skills/lsp-setup/scripts/detect-lsp.ts +1 -1
- package/packages/omo-codex/plugin/skills/lsp-setup/scripts/lsp-server-table.ts +3 -2
- package/packages/omo-codex/plugin/skills/programming/SKILL.md +5 -5
- package/packages/omo-codex/plugin/skills/programming/references/code-smells.md +2 -2
- package/packages/omo-codex/plugin/skills/programming/references/go/README.md +3 -3
- package/packages/omo-codex/plugin/skills/programming/references/python/README.md +8 -8
- package/packages/omo-codex/plugin/skills/programming/references/python/data-processing.md +9 -9
- package/packages/omo-codex/plugin/skills/programming/references/python/libraries.md +3 -3
- package/packages/omo-codex/plugin/skills/programming/references/python/one-liners.md +1 -1
- package/packages/omo-codex/plugin/skills/programming/references/python/pyproject-strict.md +1 -1
- package/packages/omo-codex/plugin/skills/programming/references/rust/libraries.md +2 -2
- package/packages/omo-codex/plugin/skills/programming/references/rust-ub/README.md +3 -3
- package/packages/omo-codex/plugin/skills/programming/references/typescript/README.md +5 -5
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/new-project.ts +1 -1
- package/packages/omo-codex/plugin/skills/refactor/SKILL.md +36 -36
- package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +6 -6
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +11 -8
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +4 -4
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/agent-reach/README.md +2 -2
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/agent-reach/career.md +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/agent-reach/social.md +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/agent-reach/web.md +4 -4
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +2 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +17 -18
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/fallback.md +10 -6
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/jina.md +12 -12
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/naver.md +3 -3
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/playwright.md +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/rss.md +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/tls-impersonate.md +12 -7
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +2 -0
- package/packages/omo-codex/plugin/skills/ulw-execute/SKILL.md +9 -6
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-loop/references/define-goal.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +10 -10
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-unclear.md +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +4 -4
- package/packages/omo-codex/plugin/skills/ulw-research/references/deliverable-phase.md +5 -5
- package/packages/omo-codex/plugin/skills/ulw-research/references/report-visualization.md +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/references/research-collection.md +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/references/unit-rules.md +2 -2
- package/packages/omo-codex/plugin/skills/visual-qa/AGENTS.md +1 -1
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +5 -5
- package/packages/omo-codex/plugin/skills/visual-qa/references/browser-setup.md +4 -2
- package/packages/omo-codex/plugin/test/sync-skills-codex-compatibility.test.mjs +2 -0
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +7 -3
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +2 -2
- package/packages/prompts-core/prompts/ultrawork/codex.md +2 -0
- package/packages/shared-skills/skills/ast-grep/AGENTS.md +2 -2
- package/packages/shared-skills/skills/ast-grep/README.md +4 -4
- package/packages/shared-skills/skills/ast-grep/SKILL.md +10 -8
- package/packages/shared-skills/skills/ast-grep/references/cli.md +4 -3
- package/packages/shared-skills/skills/ast-grep/references/patterns.md +5 -5
- package/packages/shared-skills/skills/ast-grep/references/pitfalls.md +3 -3
- package/packages/shared-skills/skills/ast-grep/references/recipes.md +6 -4
- package/packages/shared-skills/skills/ast-grep/references/yaml-rules.md +3 -3
- package/packages/shared-skills/skills/ast-grep/scripts/ast_grep_helper.py +3 -3
- package/packages/shared-skills/skills/browser/SKILL.md +2 -3
- package/packages/shared-skills/skills/browser/references/owned-engine/README.md +1 -1
- package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +2 -1
- package/packages/shared-skills/skills/data-scientist/SKILL.md +8 -6
- package/packages/shared-skills/skills/data-scientist/references/placement.md +9 -5
- package/packages/shared-skills/skills/data-scientist/references/uv-setup.md +3 -3
- package/packages/shared-skills/skills/data-scientist/references/visualization.md +19 -4
- package/packages/shared-skills/skills/debugging/SKILL.md +5 -5
- package/packages/shared-skills/skills/debugging/references/methodology/02-investigate.md +2 -2
- package/packages/shared-skills/skills/debugging/references/methodology/06-fix.md +2 -0
- package/packages/shared-skills/skills/debugging/references/methodology/09-cleanup.md +2 -2
- package/packages/shared-skills/skills/debugging/references/methodology/partial-runtime-evidence.md +1 -1
- package/packages/shared-skills/skills/debugging/references/runtimes/bundled-js-binary.md +1 -1
- package/packages/shared-skills/skills/debugging/references/runtimes/native-binary.md +1 -1
- package/packages/shared-skills/skills/debugging/references/tools/browser-qa.md +1 -2
- package/packages/shared-skills/skills/frontend/SKILL.md +4 -4
- package/packages/shared-skills/skills/frontend/references/design/README.md +2 -2
- package/packages/shared-skills/skills/frontend/references/design/component-catalogs.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +2 -2
- package/packages/shared-skills/skills/frontend/references/design/print-paged-media.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/react-dev-tooling-skill.md +1 -1
- package/packages/shared-skills/skills/frontend/references/designpowers/lane-a-direction.md +5 -5
- package/packages/shared-skills/skills/frontend/references/designpowers/routing.md +2 -2
- package/packages/shared-skills/skills/frontend/references/perfection/README.md +1 -2
- package/packages/shared-skills/skills/frontend/references/perfection/react-perf-tooling.md +27 -8
- package/packages/shared-skills/skills/frontend/scripts/perfection/lighthouse-audit.py +0 -1
- package/packages/shared-skills/skills/git-master/SKILL.md +12 -2
- package/packages/shared-skills/skills/init-deep/SKILL.md +1 -1
- package/packages/shared-skills/skills/lsp-setup/SKILL.md +24 -15
- package/packages/shared-skills/skills/lsp-setup/references/bash/README.md +3 -3
- package/packages/shared-skills/skills/lsp-setup/references/c-cpp/README.md +2 -2
- package/packages/shared-skills/skills/lsp-setup/references/csharp/README.md +2 -2
- package/packages/shared-skills/skills/lsp-setup/references/dart/README.md +2 -2
- package/packages/shared-skills/skills/lsp-setup/references/elixir/README.md +2 -2
- package/packages/shared-skills/skills/lsp-setup/references/go/README.md +2 -2
- package/packages/shared-skills/skills/lsp-setup/references/haskell/README.md +2 -2
- package/packages/shared-skills/skills/lsp-setup/references/java/README.md +3 -3
- package/packages/shared-skills/skills/lsp-setup/references/julia/README.md +3 -3
- package/packages/shared-skills/skills/lsp-setup/references/kotlin/README.md +4 -4
- package/packages/shared-skills/skills/lsp-setup/references/lua/README.md +2 -2
- package/packages/shared-skills/skills/lsp-setup/references/php/README.md +3 -3
- package/packages/shared-skills/skills/lsp-setup/references/python/README.md +13 -12
- package/packages/shared-skills/skills/lsp-setup/references/ruby/README.md +2 -2
- package/packages/shared-skills/skills/lsp-setup/references/rust/README.md +2 -2
- package/packages/shared-skills/skills/lsp-setup/references/swift/README.md +4 -4
- package/packages/shared-skills/skills/lsp-setup/references/terraform/README.md +2 -2
- package/packages/shared-skills/skills/lsp-setup/references/typescript/README.md +3 -3
- package/packages/shared-skills/skills/lsp-setup/references/yaml/README.md +2 -2
- package/packages/shared-skills/skills/lsp-setup/references/zig/README.md +2 -2
- package/packages/shared-skills/skills/lsp-setup/scripts/detect-lsp.ts +1 -1
- package/packages/shared-skills/skills/lsp-setup/scripts/lsp-server-table.ts +3 -2
- package/packages/shared-skills/skills/programming/SKILL.md +5 -5
- package/packages/shared-skills/skills/programming/references/code-smells.md +2 -2
- package/packages/shared-skills/skills/programming/references/go/README.md +3 -3
- package/packages/shared-skills/skills/programming/references/python/README.md +8 -8
- package/packages/shared-skills/skills/programming/references/python/data-processing.md +9 -9
- package/packages/shared-skills/skills/programming/references/python/libraries.md +3 -3
- package/packages/shared-skills/skills/programming/references/python/one-liners.md +1 -1
- package/packages/shared-skills/skills/programming/references/python/pyproject-strict.md +1 -1
- package/packages/shared-skills/skills/programming/references/rust/libraries.md +2 -2
- package/packages/shared-skills/skills/programming/references/rust-ub/README.md +3 -3
- package/packages/shared-skills/skills/programming/references/typescript/README.md +5 -5
- package/packages/shared-skills/skills/programming/scripts/typescript/new-project.ts +1 -1
- package/packages/shared-skills/skills/refactor/SKILL.md +36 -36
- package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +6 -6
- package/packages/shared-skills/skills/review-work/SKILL.md +2 -2
- package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +11 -8
- package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +4 -4
- package/packages/shared-skills/skills/ultimate-browsing/references/agent-reach/README.md +2 -2
- package/packages/shared-skills/skills/ultimate-browsing/references/agent-reach/career.md +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/references/agent-reach/social.md +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/references/agent-reach/web.md +4 -4
- package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +2 -1
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +17 -18
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/fallback.md +10 -6
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/jina.md +12 -12
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/naver.md +3 -3
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/playwright.md +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/rss.md +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/tls-impersonate.md +12 -7
- package/packages/shared-skills/skills/ulw-execute/SKILL.md +9 -6
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +2 -2
- package/packages/shared-skills/skills/ulw-research/SKILL.md +5 -5
- package/packages/shared-skills/skills/ulw-research/references/deliverable-phase.md +5 -5
- package/packages/shared-skills/skills/ulw-research/references/report-visualization.md +2 -2
- package/packages/shared-skills/skills/ulw-research/references/research-collection.md +2 -2
- package/packages/shared-skills/skills/ulw-research/references/unit-rules.md +2 -2
- package/packages/shared-skills/skills/visual-qa/AGENTS.md +1 -1
- package/packages/shared-skills/skills/visual-qa/SKILL.md +5 -5
- package/packages/shared-skills/skills/visual-qa/references/browser-setup.md +4 -2
package/dist/cli-node/index.js
CHANGED
|
@@ -2133,7 +2133,7 @@ var package_default;
|
|
|
2133
2133
|
var init_package = __esm(() => {
|
|
2134
2134
|
package_default = {
|
|
2135
2135
|
name: "oh-my-opencode",
|
|
2136
|
-
version: "5.1.
|
|
2136
|
+
version: "5.1.63",
|
|
2137
2137
|
description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
|
|
2138
2138
|
main: "./dist/index.js",
|
|
2139
2139
|
types: "dist/index.d.ts",
|
|
@@ -2320,7 +2320,7 @@ var init_package = __esm(() => {
|
|
|
2320
2320
|
},
|
|
2321
2321
|
devDependencies: {
|
|
2322
2322
|
"@clack/prompts": "^1.8.1",
|
|
2323
|
-
"@code-yeongyu/senpi": "2026.11.
|
|
2323
|
+
"@code-yeongyu/senpi": "2026.11.5-1",
|
|
2324
2324
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
2325
2325
|
"@oh-my-opencode/agents-md-core": "workspace:*",
|
|
2326
2326
|
"@oh-my-opencode/ast-grep-mcp": "workspace:*",
|
|
@@ -2385,18 +2385,18 @@ var init_package = __esm(() => {
|
|
|
2385
2385
|
typescript: "^7.0.2"
|
|
2386
2386
|
},
|
|
2387
2387
|
optionalDependencies: {
|
|
2388
|
-
"oh-my-opencode-darwin-arm64": "5.1.
|
|
2389
|
-
"oh-my-opencode-darwin-x64": "5.1.
|
|
2390
|
-
"oh-my-opencode-darwin-x64-baseline": "5.1.
|
|
2391
|
-
"oh-my-opencode-linux-arm64": "5.1.
|
|
2392
|
-
"oh-my-opencode-linux-arm64-musl": "5.1.
|
|
2393
|
-
"oh-my-opencode-linux-x64": "5.1.
|
|
2394
|
-
"oh-my-opencode-linux-x64-baseline": "5.1.
|
|
2395
|
-
"oh-my-opencode-linux-x64-musl": "5.1.
|
|
2396
|
-
"oh-my-opencode-linux-x64-musl-baseline": "5.1.
|
|
2397
|
-
"oh-my-opencode-windows-arm64": "5.1.
|
|
2398
|
-
"oh-my-opencode-windows-x64": "5.1.
|
|
2399
|
-
"oh-my-opencode-windows-x64-baseline": "5.1.
|
|
2388
|
+
"oh-my-opencode-darwin-arm64": "5.1.63",
|
|
2389
|
+
"oh-my-opencode-darwin-x64": "5.1.63",
|
|
2390
|
+
"oh-my-opencode-darwin-x64-baseline": "5.1.63",
|
|
2391
|
+
"oh-my-opencode-linux-arm64": "5.1.63",
|
|
2392
|
+
"oh-my-opencode-linux-arm64-musl": "5.1.63",
|
|
2393
|
+
"oh-my-opencode-linux-x64": "5.1.63",
|
|
2394
|
+
"oh-my-opencode-linux-x64-baseline": "5.1.63",
|
|
2395
|
+
"oh-my-opencode-linux-x64-musl": "5.1.63",
|
|
2396
|
+
"oh-my-opencode-linux-x64-musl-baseline": "5.1.63",
|
|
2397
|
+
"oh-my-opencode-windows-arm64": "5.1.63",
|
|
2398
|
+
"oh-my-opencode-windows-x64": "5.1.63",
|
|
2399
|
+
"oh-my-opencode-windows-x64-baseline": "5.1.63"
|
|
2400
2400
|
},
|
|
2401
2401
|
overrides: {
|
|
2402
2402
|
hono: "^4.13.8",
|
|
@@ -7340,7 +7340,34 @@ var init_which = __esm(() => {
|
|
|
7340
7340
|
});
|
|
7341
7341
|
|
|
7342
7342
|
// packages/utils/src/runtime/file.ts
|
|
7343
|
-
|
|
7343
|
+
import { access, readFile, unlink, writeFile } from "node:fs/promises";
|
|
7344
|
+
function createNodeFile(path) {
|
|
7345
|
+
return {
|
|
7346
|
+
text() {
|
|
7347
|
+
return readFile(path, "utf8");
|
|
7348
|
+
},
|
|
7349
|
+
async arrayBuffer() {
|
|
7350
|
+
const buffer = await readFile(path);
|
|
7351
|
+
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
7352
|
+
},
|
|
7353
|
+
exists() {
|
|
7354
|
+
return access(path).then(() => true, () => false);
|
|
7355
|
+
},
|
|
7356
|
+
delete() {
|
|
7357
|
+
return unlink(path);
|
|
7358
|
+
}
|
|
7359
|
+
};
|
|
7360
|
+
}
|
|
7361
|
+
function bunFile(path) {
|
|
7362
|
+
const bun = runtime3.Bun;
|
|
7363
|
+
if (bun)
|
|
7364
|
+
return bun.file(path);
|
|
7365
|
+
return createNodeFile(path);
|
|
7366
|
+
}
|
|
7367
|
+
var runtime3;
|
|
7368
|
+
var init_file = __esm(() => {
|
|
7369
|
+
runtime3 = globalThis;
|
|
7370
|
+
});
|
|
7344
7371
|
|
|
7345
7372
|
// packages/utils/src/runtime/git-bash.ts
|
|
7346
7373
|
import { execFileSync } from "node:child_process";
|
|
@@ -12284,7 +12311,9 @@ var init_zip_extractor = __esm(() => {
|
|
|
12284
12311
|
});
|
|
12285
12312
|
|
|
12286
12313
|
// packages/omo-opencode/src/shared/bun-file-shim.ts
|
|
12287
|
-
var init_bun_file_shim = () => {
|
|
12314
|
+
var init_bun_file_shim = __esm(() => {
|
|
12315
|
+
init_runtime();
|
|
12316
|
+
});
|
|
12288
12317
|
|
|
12289
12318
|
// packages/omo-opencode/src/shared/binary-downloader.ts
|
|
12290
12319
|
import { chmodSync, existsSync as existsSync9, mkdirSync as mkdirSync4, unlinkSync as unlinkSync3 } from "node:fs";
|
|
@@ -92789,7 +92818,7 @@ var package_default2;
|
|
|
92789
92818
|
var init_package2 = __esm(() => {
|
|
92790
92819
|
package_default2 = {
|
|
92791
92820
|
name: "@oh-my-opencode/omo-codex",
|
|
92792
|
-
version: "5.1.
|
|
92821
|
+
version: "5.1.63",
|
|
92793
92822
|
type: "module",
|
|
92794
92823
|
private: true,
|
|
92795
92824
|
description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
|
|
@@ -93405,7 +93434,7 @@ var init_check_for_update = __esm(() => {
|
|
|
93405
93434
|
});
|
|
93406
93435
|
|
|
93407
93436
|
// packages/omo-opencode/src/hooks/auto-update-checker/checker/sync-package-json.ts
|
|
93408
|
-
import * as
|
|
93437
|
+
import * as crypto2 from "node:crypto";
|
|
93409
93438
|
import * as fs8 from "node:fs";
|
|
93410
93439
|
import * as path11 from "node:path";
|
|
93411
93440
|
function safeUnlink(filePath) {
|
|
@@ -93429,7 +93458,7 @@ function getPackageNameFromIntent(pluginInfo) {
|
|
|
93429
93458
|
return ACCEPTED_PACKAGE_NAMES2.find((packageName) => pluginInfo.entry === packageName || pluginInfo.entry.startsWith(`${packageName}@`)) ?? PACKAGE_NAME3;
|
|
93430
93459
|
}
|
|
93431
93460
|
function writeCachePackageJson(cachePackageJsonPath, pkgJson) {
|
|
93432
|
-
const tmpPath = `${cachePackageJsonPath}.${
|
|
93461
|
+
const tmpPath = `${cachePackageJsonPath}.${crypto2.randomUUID()}`;
|
|
93433
93462
|
try {
|
|
93434
93463
|
fs8.mkdirSync(path11.dirname(cachePackageJsonPath), { recursive: true });
|
|
93435
93464
|
fs8.writeFileSync(tmpPath, JSON.stringify(pkgJson, null, 2));
|
|
@@ -94350,7 +94379,7 @@ import { existsSync as existsSync27 } from "node:fs";
|
|
|
94350
94379
|
import { homedir as homedir7 } from "node:os";
|
|
94351
94380
|
|
|
94352
94381
|
// packages/omo-codex/src/install/codex-cache-bins.ts
|
|
94353
|
-
import { chmod, lstat as lstat4, mkdir, readFile as
|
|
94382
|
+
import { chmod, lstat as lstat4, mkdir, readFile as readFile4, readdir as readdir2, readlink as readlink3, rm as rm3, stat as stat2, symlink, writeFile as writeFile2 } from "node:fs/promises";
|
|
94354
94383
|
import { basename as basename4, isAbsolute as isAbsolute2, join as join26, relative, resolve as resolve6, sep } from "node:path";
|
|
94355
94384
|
|
|
94356
94385
|
// packages/omo-codex/src/install/codex-cache-command-shim.ts
|
|
@@ -94394,7 +94423,7 @@ function windowsCommandShim(targetPath) {
|
|
|
94394
94423
|
}
|
|
94395
94424
|
|
|
94396
94425
|
// packages/omo-codex/src/install/codex-cache-dangling-bins.ts
|
|
94397
|
-
import { lstat as lstat2, readFile, readdir, readlink, rm, stat } from "node:fs/promises";
|
|
94426
|
+
import { lstat as lstat2, readFile as readFile2, readdir, readlink, rm, stat } from "node:fs/promises";
|
|
94398
94427
|
import { dirname as dirname10, isAbsolute, join as join23, resolve as resolve5 } from "node:path";
|
|
94399
94428
|
|
|
94400
94429
|
// packages/omo-codex/src/install/codex-cache-fs.ts
|
|
@@ -94456,7 +94485,7 @@ async function removeDanglingGeneratedCommandShim(linkPath) {
|
|
|
94456
94485
|
const linkStat = await lstat2(linkPath);
|
|
94457
94486
|
if (!linkStat.isFile())
|
|
94458
94487
|
return;
|
|
94459
|
-
const content = await
|
|
94488
|
+
const content = await readFile2(linkPath, "utf8");
|
|
94460
94489
|
if (!content.includes(COMMAND_SHIM_MARKER))
|
|
94461
94490
|
return;
|
|
94462
94491
|
const target = extractCommandShimTarget(content);
|
|
@@ -94504,7 +94533,7 @@ function hasOmoCodexPluginPrefix(parts, endExclusive) {
|
|
|
94504
94533
|
}
|
|
94505
94534
|
|
|
94506
94535
|
// packages/omo-codex/src/install/codex-cache-legacy-bins.ts
|
|
94507
|
-
import { lstat as lstat3, readFile as
|
|
94536
|
+
import { lstat as lstat3, readFile as readFile3, readlink as readlink2, rm as rm2 } from "node:fs/promises";
|
|
94508
94537
|
import { join as join24 } from "node:path";
|
|
94509
94538
|
var LEGACY_CODEX_COMPONENT_BINS = [
|
|
94510
94539
|
{ name: "omo", component: "ulw-loop" },
|
|
@@ -94539,7 +94568,7 @@ async function removeLegacyCodexComponentBin(linkPath, component, platform) {
|
|
|
94539
94568
|
}
|
|
94540
94569
|
if (!stat.isFile())
|
|
94541
94570
|
return;
|
|
94542
|
-
const content = await
|
|
94571
|
+
const content = await readFile3(linkPath, "utf8");
|
|
94543
94572
|
if (content.includes(COMMAND_SHIM_MARKER))
|
|
94544
94573
|
await rm2(linkPath, { force: true });
|
|
94545
94574
|
} catch (error) {
|
|
@@ -94776,7 +94805,7 @@ async function collectPackageBins(directory, root, links) {
|
|
|
94776
94805
|
}
|
|
94777
94806
|
}
|
|
94778
94807
|
async function appendPackageBinLinks(packageJsonPath, packageRoot, root, links) {
|
|
94779
|
-
const packageJson = JSON.parse(await
|
|
94808
|
+
const packageJson = JSON.parse(await readFile4(packageJsonPath, "utf8"));
|
|
94780
94809
|
if (!isPlainRecord4(packageJson))
|
|
94781
94810
|
return;
|
|
94782
94811
|
const packageName = packageJson.name;
|
|
@@ -94828,13 +94857,13 @@ async function replaceSymlink(linkPath, targetPath) {
|
|
|
94828
94857
|
async function replaceCommandShim(linkPath, targetPath) {
|
|
94829
94858
|
if (await existingNonShim(linkPath))
|
|
94830
94859
|
throw new Error(`${linkPath} already exists and is not a command shim`);
|
|
94831
|
-
await
|
|
94860
|
+
await writeFile2(linkPath, windowsCommandShim(targetPath));
|
|
94832
94861
|
}
|
|
94833
94862
|
async function replaceRuntimeWrapper(linkPath, content) {
|
|
94834
94863
|
if (await existingNonRuntimeWrapper(linkPath))
|
|
94835
94864
|
throw new Error(`${linkPath} already exists and is not a generated OMO runtime wrapper`);
|
|
94836
94865
|
await rm3(linkPath, { force: true });
|
|
94837
|
-
await
|
|
94866
|
+
await writeFile2(linkPath, content);
|
|
94838
94867
|
}
|
|
94839
94868
|
async function removeGeneratedRuntimeWrapper(path) {
|
|
94840
94869
|
try {
|
|
@@ -94852,7 +94881,7 @@ async function removeGeneratedRuntimeWrapper(path) {
|
|
|
94852
94881
|
}
|
|
94853
94882
|
async function readGeneratedWrapperContent(path) {
|
|
94854
94883
|
try {
|
|
94855
|
-
return await
|
|
94884
|
+
return await readFile4(path, "utf8");
|
|
94856
94885
|
} catch (error) {
|
|
94857
94886
|
if (isNodeErrorWithCode(error) && (error.code === "ENOENT" || error.code === "EISDIR"))
|
|
94858
94887
|
return "";
|
|
@@ -94866,7 +94895,7 @@ async function existingNonRuntimeWrapper(path) {
|
|
|
94866
94895
|
return false;
|
|
94867
94896
|
if (!stat.isFile())
|
|
94868
94897
|
return true;
|
|
94869
|
-
const content = await
|
|
94898
|
+
const content = await readFile4(path, "utf8");
|
|
94870
94899
|
return !content.includes(RUNTIME_WRAPPER_MARKER);
|
|
94871
94900
|
} catch (error) {
|
|
94872
94901
|
if (isNodeErrorWithCode(error) && error.code === "ENOENT")
|
|
@@ -94879,7 +94908,7 @@ async function existingNonShim(path) {
|
|
|
94879
94908
|
const stat = await lstat4(path);
|
|
94880
94909
|
if (!stat.isFile())
|
|
94881
94910
|
return true;
|
|
94882
|
-
const content = await
|
|
94911
|
+
const content = await readFile4(path, "utf8");
|
|
94883
94912
|
if (content.includes(COMMAND_SHIM_MARKER))
|
|
94884
94913
|
return false;
|
|
94885
94914
|
throw new Error(`${path} already exists and is not a generated command shim`);
|
|
@@ -94903,11 +94932,11 @@ async function existingNonSymlink(path) {
|
|
|
94903
94932
|
}
|
|
94904
94933
|
}
|
|
94905
94934
|
// packages/omo-codex/src/install/codex-cache-install.ts
|
|
94906
|
-
import { cp as cp3, mkdir as mkdir3, readFile as
|
|
94935
|
+
import { cp as cp3, mkdir as mkdir3, readFile as readFile9, readdir as readdir5, rename as rename2, rm as rm5 } from "node:fs/promises";
|
|
94907
94936
|
import { basename as basename5, dirname as dirname13, join as join33, sep as sep6 } from "node:path";
|
|
94908
94937
|
|
|
94909
94938
|
// packages/omo-codex/src/install/codex-cache-bundled-mcps.ts
|
|
94910
|
-
import { cp, mkdir as mkdir2, readFile as
|
|
94939
|
+
import { cp, mkdir as mkdir2, readFile as readFile5, stat as stat3 } from "node:fs/promises";
|
|
94911
94940
|
import { dirname as dirname11, join as join27, resolve as resolve7 } from "node:path";
|
|
94912
94941
|
var BUNDLED_MCP_RUNTIMES = [
|
|
94913
94942
|
{
|
|
@@ -94949,7 +94978,7 @@ async function copyBundledMcpRuntimeDist(pluginRoot, sourceRoot, runtime) {
|
|
|
94949
94978
|
async function readSourceMcpArgs(path) {
|
|
94950
94979
|
let parsed;
|
|
94951
94980
|
try {
|
|
94952
|
-
parsed = JSON.parse(await
|
|
94981
|
+
parsed = JSON.parse(await readFile5(path, "utf8"));
|
|
94953
94982
|
} catch (error) {
|
|
94954
94983
|
if (error instanceof Error)
|
|
94955
94984
|
return new Set;
|
|
@@ -94980,7 +95009,7 @@ async function isDirectory(path) {
|
|
|
94980
95009
|
|
|
94981
95010
|
// packages/omo-codex/src/install/codex-cache-local-dependencies.ts
|
|
94982
95011
|
import { realpathSync as realpathSync7 } from "node:fs";
|
|
94983
|
-
import { readFile as
|
|
95012
|
+
import { readFile as readFile6, readdir as readdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
94984
95013
|
import { dirname as dirname12, isAbsolute as isAbsolute4, join as join29, relative as relative3, resolve as resolve9, sep as sep2 } from "node:path";
|
|
94985
95014
|
|
|
94986
95015
|
// packages/omo-codex/src/install/codex-cache-paths.ts
|
|
@@ -95046,7 +95075,7 @@ async function rewriteCachedPackageLocalFileDependencies(pluginRoot, sourceRoot)
|
|
|
95046
95075
|
const packageLock = await readPackageLock(pluginRoot);
|
|
95047
95076
|
let rewroteAnyPackageJson = false;
|
|
95048
95077
|
for (const packageJsonPath of packageJsonPaths) {
|
|
95049
|
-
const raw = await
|
|
95078
|
+
const raw = await readFile6(packageJsonPath, "utf8");
|
|
95050
95079
|
const parsed = JSON.parse(raw);
|
|
95051
95080
|
if (!isPlainRecord4(parsed))
|
|
95052
95081
|
continue;
|
|
@@ -95081,20 +95110,20 @@ async function rewriteCachedPackageLocalFileDependencies(pluginRoot, sourceRoot)
|
|
|
95081
95110
|
}
|
|
95082
95111
|
}
|
|
95083
95112
|
if (changed) {
|
|
95084
|
-
await
|
|
95113
|
+
await writeFile3(packageJsonPath, `${JSON.stringify(parsed, null, "\t")}
|
|
95085
95114
|
`);
|
|
95086
95115
|
rewroteAnyPackageJson = true;
|
|
95087
95116
|
}
|
|
95088
95117
|
}
|
|
95089
95118
|
if (packageLock.changed)
|
|
95090
|
-
await
|
|
95119
|
+
await writeFile3(packageLock.path, `${JSON.stringify(packageLock.value, null, "\t")}
|
|
95091
95120
|
`);
|
|
95092
95121
|
return rewroteAnyPackageJson;
|
|
95093
95122
|
}
|
|
95094
95123
|
async function readPackageLock(pluginRoot) {
|
|
95095
95124
|
const path = join29(pluginRoot, "package-lock.json");
|
|
95096
95125
|
try {
|
|
95097
|
-
const parsed = JSON.parse(await
|
|
95126
|
+
const parsed = JSON.parse(await readFile6(path, "utf8"));
|
|
95098
95127
|
return { path, value: isPlainRecord4(parsed) ? parsed : null, changed: false };
|
|
95099
95128
|
} catch (error) {
|
|
95100
95129
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
@@ -95168,14 +95197,14 @@ async function collectPackageJsonPaths(directory, root, paths) {
|
|
|
95168
95197
|
}
|
|
95169
95198
|
|
|
95170
95199
|
// packages/omo-codex/src/install/codex-cache-mcp-manifest.ts
|
|
95171
|
-
import { readFile as
|
|
95200
|
+
import { readFile as readFile7, writeFile as writeFile4 } from "node:fs/promises";
|
|
95172
95201
|
import { join as join30, sep as sep3 } from "node:path";
|
|
95173
95202
|
var CONTEXT7_API_KEY_ENV = "CONTEXT7_API_KEY";
|
|
95174
95203
|
async function rewriteCachedMcpManifest(pluginRoot, sourceRoot = pluginRoot) {
|
|
95175
95204
|
const manifestPath = join30(pluginRoot, ".mcp.json");
|
|
95176
95205
|
if (!await fileExistsStrict(manifestPath))
|
|
95177
95206
|
return;
|
|
95178
|
-
const raw = await
|
|
95207
|
+
const raw = await readFile7(manifestPath, "utf8");
|
|
95179
95208
|
const parsed = JSON.parse(raw);
|
|
95180
95209
|
if (!isPlainRecord4(parsed) || !isPlainRecord4(parsed.mcpServers))
|
|
95181
95210
|
return;
|
|
@@ -95209,7 +95238,7 @@ async function rewriteCachedMcpManifest(pluginRoot, sourceRoot = pluginRoot) {
|
|
|
95209
95238
|
}
|
|
95210
95239
|
}
|
|
95211
95240
|
if (changed)
|
|
95212
|
-
await
|
|
95241
|
+
await writeFile4(manifestPath, `${JSON.stringify(parsed, null, "\t")}
|
|
95213
95242
|
`);
|
|
95214
95243
|
}
|
|
95215
95244
|
function sanitizeContext7Auth(server) {
|
|
@@ -95268,7 +95297,7 @@ async function rewriteCachedManifestRoot(pluginRoot, fromRoot, toRoot) {
|
|
|
95268
95297
|
const manifestPath = join30(pluginRoot, ".mcp.json");
|
|
95269
95298
|
if (!await fileExistsStrict(manifestPath))
|
|
95270
95299
|
return;
|
|
95271
|
-
const raw = await
|
|
95300
|
+
const raw = await readFile7(manifestPath, "utf8");
|
|
95272
95301
|
const parsed = JSON.parse(raw);
|
|
95273
95302
|
if (!isPlainRecord4(parsed) || !isPlainRecord4(parsed.mcpServers))
|
|
95274
95303
|
return;
|
|
@@ -95295,7 +95324,7 @@ async function rewriteCachedManifestRoot(pluginRoot, fromRoot, toRoot) {
|
|
|
95295
95324
|
}
|
|
95296
95325
|
}
|
|
95297
95326
|
if (changed)
|
|
95298
|
-
await
|
|
95327
|
+
await writeFile4(manifestPath, `${JSON.stringify(parsed, null, "\t")}
|
|
95299
95328
|
`);
|
|
95300
95329
|
}
|
|
95301
95330
|
|
|
@@ -95357,7 +95386,7 @@ async function unsupportedEntries(root, directory) {
|
|
|
95357
95386
|
}
|
|
95358
95387
|
|
|
95359
95388
|
// packages/omo-codex/src/install/codex-hook-targets.ts
|
|
95360
|
-
import { readFile as
|
|
95389
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
95361
95390
|
import { join as join32, sep as sep5 } from "node:path";
|
|
95362
95391
|
var PLUGIN_ROOT_TARGET_PATTERN = /\$\{PLUGIN_ROOT\}[\\/]+([^"']+)/g;
|
|
95363
95392
|
async function findMissingHookCommandTargets(pluginRoot) {
|
|
@@ -95365,7 +95394,7 @@ async function findMissingHookCommandTargets(pluginRoot) {
|
|
|
95365
95394
|
for (const manifestPath of await hookManifestPaths(pluginRoot)) {
|
|
95366
95395
|
if (!await fileExistsStrict(manifestPath))
|
|
95367
95396
|
continue;
|
|
95368
|
-
const parsed = JSON.parse(await
|
|
95397
|
+
const parsed = JSON.parse(await readFile8(manifestPath, "utf8"));
|
|
95369
95398
|
collectCommands(parsed, commands);
|
|
95370
95399
|
}
|
|
95371
95400
|
const missing = [];
|
|
@@ -95389,7 +95418,7 @@ async function hookManifestPaths(pluginRoot) {
|
|
|
95389
95418
|
const pluginManifestPath = join32(pluginRoot, ".codex-plugin", "plugin.json");
|
|
95390
95419
|
if (!await fileExistsStrict(pluginManifestPath))
|
|
95391
95420
|
return [join32(pluginRoot, "hooks", "hooks.json")];
|
|
95392
|
-
const parsed = JSON.parse(await
|
|
95421
|
+
const parsed = JSON.parse(await readFile8(pluginManifestPath, "utf8"));
|
|
95393
95422
|
if (!isPlainRecord4(parsed))
|
|
95394
95423
|
return [];
|
|
95395
95424
|
if (typeof parsed.hooks === "string" && parsed.hooks.trim() !== "") {
|
|
@@ -95476,7 +95505,7 @@ async function maybeRunNpmInstall(cwd, runCommand, env, args = ["install"]) {
|
|
|
95476
95505
|
async function maybeRunNpmBuild(cwd, runCommand, env) {
|
|
95477
95506
|
if (!await fileExistsStrict(join33(cwd, "package.json")))
|
|
95478
95507
|
return;
|
|
95479
|
-
const packageJson = JSON.parse(await
|
|
95508
|
+
const packageJson = JSON.parse(await readFile9(join33(cwd, "package.json"), "utf8"));
|
|
95480
95509
|
if (!isPlainRecord4(packageJson))
|
|
95481
95510
|
return;
|
|
95482
95511
|
const scripts = packageJson.scripts;
|
|
@@ -95487,7 +95516,7 @@ async function maybeRunNpmBuild(cwd, runCommand, env) {
|
|
|
95487
95516
|
async function maybeRunNpmSyncSkills(cwd, runCommand, env) {
|
|
95488
95517
|
if (!await fileExistsStrict(join33(cwd, "package.json")))
|
|
95489
95518
|
return;
|
|
95490
|
-
const packageJson = JSON.parse(await
|
|
95519
|
+
const packageJson = JSON.parse(await readFile9(join33(cwd, "package.json"), "utf8"));
|
|
95491
95520
|
if (!isPlainRecord4(packageJson))
|
|
95492
95521
|
return;
|
|
95493
95522
|
const scripts = packageJson.scripts;
|
|
@@ -95550,7 +95579,7 @@ var removedSparkshellPromptSurfaceFiles = new Set(["directive.md", "plugin.json"
|
|
|
95550
95579
|
var removedSparkshellTextFilePattern = /\.(?:json|md|toml|ya?ml)$/i;
|
|
95551
95580
|
async function assertNoRemovedSparkshellPromptReferences(pluginRoot) {
|
|
95552
95581
|
for (const filePath of await listRemovedSparkshellPromptSurfaceFiles(pluginRoot, "")) {
|
|
95553
|
-
const content = await
|
|
95582
|
+
const content = await readFile9(join33(pluginRoot, filePath), "utf8");
|
|
95554
95583
|
if (!removedSparkshellReferencePattern.test(content))
|
|
95555
95584
|
continue;
|
|
95556
95585
|
throw new Error(`removed sparkshell reference found in Codex plugin prompt surface: ${filePath}`);
|
|
@@ -95699,7 +95728,7 @@ async function isBrokenCacheSymlink(path) {
|
|
|
95699
95728
|
}
|
|
95700
95729
|
}
|
|
95701
95730
|
// packages/omo-codex/src/install/codex-cached-marketplace-manifest.ts
|
|
95702
|
-
import { mkdir as mkdir4, rename as rename3, rm as rm7, stat as stat5, writeFile as
|
|
95731
|
+
import { mkdir as mkdir4, rename as rename3, rm as rm7, stat as stat5, writeFile as writeFile5 } from "node:fs/promises";
|
|
95703
95732
|
import { join as join35 } from "node:path";
|
|
95704
95733
|
async function writeCachedMarketplaceManifest(input) {
|
|
95705
95734
|
const marketplaceDir = join35(input.marketplaceRoot, ".agents", "plugins");
|
|
@@ -95712,7 +95741,7 @@ async function writeCachedMarketplaceManifest(input) {
|
|
|
95712
95741
|
const manifestPath = join35(marketplaceDir, "marketplace.json");
|
|
95713
95742
|
const tempPath = join35(marketplaceDir, `.marketplace.json.tmp-${process.pid}-${Date.now()}`);
|
|
95714
95743
|
try {
|
|
95715
|
-
await
|
|
95744
|
+
await writeFile5(tempPath, `${JSON.stringify({
|
|
95716
95745
|
name: input.marketplaceName,
|
|
95717
95746
|
plugins: input.plugins.map((plugin) => ({
|
|
95718
95747
|
name: plugin.name,
|
|
@@ -95738,7 +95767,7 @@ async function isDirectory2(path) {
|
|
|
95738
95767
|
|
|
95739
95768
|
// packages/omo-codex/src/install/codex-package-layout.ts
|
|
95740
95769
|
import { existsSync as existsSync24 } from "node:fs";
|
|
95741
|
-
import { readFile as
|
|
95770
|
+
import { readFile as readFile10 } from "node:fs/promises";
|
|
95742
95771
|
import { join as join36 } from "node:path";
|
|
95743
95772
|
var PACKAGED_CODEX_INSTALLER_NAMES = new Set([
|
|
95744
95773
|
"@code-yeongyu/lazycodex",
|
|
@@ -95754,14 +95783,14 @@ async function shouldBuildSourcePackages(repoRoot) {
|
|
|
95754
95783
|
const packageJsonPath = join36(repoRoot, "package.json");
|
|
95755
95784
|
if (!existsSync24(packageJsonPath))
|
|
95756
95785
|
return true;
|
|
95757
|
-
const packageJson = JSON.parse(await
|
|
95786
|
+
const packageJson = JSON.parse(await readFile10(packageJsonPath, "utf8"));
|
|
95758
95787
|
if (!isPlainRecord4(packageJson) || typeof packageJson.name !== "string")
|
|
95759
95788
|
return true;
|
|
95760
95789
|
return !PACKAGED_CODEX_INSTALLER_NAMES.has(packageJson.name);
|
|
95761
95790
|
}
|
|
95762
95791
|
|
|
95763
95792
|
// packages/omo-codex/src/install/codex-config-toml.ts
|
|
95764
|
-
import { mkdir as mkdir5, readFile as
|
|
95793
|
+
import { mkdir as mkdir5, readFile as readFile12 } from "node:fs/promises";
|
|
95765
95794
|
import { dirname as dirname16 } from "node:path";
|
|
95766
95795
|
|
|
95767
95796
|
// packages/omo-codex/src/install/toml-section-editor.ts
|
|
@@ -96358,18 +96387,18 @@ function tomlKeySegment(value) {
|
|
|
96358
96387
|
}
|
|
96359
96388
|
|
|
96360
96389
|
// packages/omo-codex/src/install/codex-config-atomic-write.ts
|
|
96361
|
-
import { lstat as lstat7, readlink as readlink4, realpath, rename as rename4, unlink, writeFile as
|
|
96390
|
+
import { lstat as lstat7, readlink as readlink4, realpath, rename as rename4, unlink as unlink2, writeFile as writeFile6 } from "node:fs/promises";
|
|
96362
96391
|
import { basename as basename6, dirname as dirname14, isAbsolute as isAbsolute5, join as join37, resolve as resolve10 } from "node:path";
|
|
96363
96392
|
var RENAME_RETRY_DELAYS_MS = [10, 25, 50];
|
|
96364
96393
|
var RETRIABLE_RENAME_CODES = new Set(["EPERM", "EBUSY"]);
|
|
96365
96394
|
async function writeFileAtomic(targetPath, data) {
|
|
96366
96395
|
const writeTarget = await resolveSymlinkTarget(targetPath);
|
|
96367
96396
|
const temporaryPath = join37(dirname14(writeTarget), `.tmp-${basename6(writeTarget)}-${process.pid}-${Date.now()}`);
|
|
96368
|
-
await
|
|
96397
|
+
await writeFile6(temporaryPath, data);
|
|
96369
96398
|
try {
|
|
96370
96399
|
await renameWithRetry(temporaryPath, writeTarget);
|
|
96371
96400
|
} catch (error) {
|
|
96372
|
-
await
|
|
96401
|
+
await unlink2(temporaryPath).catch((unlinkError) => {
|
|
96373
96402
|
if (unlinkError instanceof Error)
|
|
96374
96403
|
return;
|
|
96375
96404
|
return;
|
|
@@ -96864,7 +96893,7 @@ function isRootSetting(line, key) {
|
|
|
96864
96893
|
|
|
96865
96894
|
// packages/omo-codex/src/install/codex-model-catalog.ts
|
|
96866
96895
|
init_latest_models();
|
|
96867
|
-
import { readFile as
|
|
96896
|
+
import { readFile as readFile11 } from "node:fs/promises";
|
|
96868
96897
|
import { join as join38 } from "node:path";
|
|
96869
96898
|
var FALLBACK_CODEX_MODEL_CATALOG = {
|
|
96870
96899
|
current: {
|
|
@@ -96898,7 +96927,7 @@ var FALLBACK_CODEX_MODEL_CATALOG = {
|
|
|
96898
96927
|
async function readCodexModelCatalog(codexPackageRoot) {
|
|
96899
96928
|
const catalogPath = join38(codexPackageRoot, "plugin", "model-catalog.json");
|
|
96900
96929
|
try {
|
|
96901
|
-
const parsed = JSON.parse(await
|
|
96930
|
+
const parsed = JSON.parse(await readFile11(catalogPath, "utf8"));
|
|
96902
96931
|
return parseCodexModelCatalog(parsed) ?? FALLBACK_CODEX_MODEL_CATALOG;
|
|
96903
96932
|
} catch (error) {
|
|
96904
96933
|
if (error instanceof Error)
|
|
@@ -97123,7 +97152,7 @@ async function updateCodexConfig(input) {
|
|
|
97123
97152
|
await mkdir5(dirname16(input.configPath), { recursive: true });
|
|
97124
97153
|
let config;
|
|
97125
97154
|
try {
|
|
97126
|
-
config = await
|
|
97155
|
+
config = await readFile12(input.configPath, "utf8");
|
|
97127
97156
|
} catch (error) {
|
|
97128
97157
|
if (!isMissingFileError(error))
|
|
97129
97158
|
throw error;
|
|
@@ -97171,7 +97200,7 @@ function isMissingFileError(error) {
|
|
|
97171
97200
|
|
|
97172
97201
|
// packages/omo-codex/src/install/codex-hook-trust.ts
|
|
97173
97202
|
import { createHash as createHash3 } from "node:crypto";
|
|
97174
|
-
import { readFile as
|
|
97203
|
+
import { readFile as readFile13 } from "node:fs/promises";
|
|
97175
97204
|
import { join as join40 } from "node:path";
|
|
97176
97205
|
var EVENT_LABELS = new Map([
|
|
97177
97206
|
["PreToolUse", "pre_tool_use"],
|
|
@@ -97189,7 +97218,7 @@ async function trustedHookStatesForPlugin(input) {
|
|
|
97189
97218
|
const manifestPath = join40(input.pluginRoot, ".codex-plugin", "plugin.json");
|
|
97190
97219
|
if (!await exists(manifestPath))
|
|
97191
97220
|
return [];
|
|
97192
|
-
const manifest = JSON.parse(await
|
|
97221
|
+
const manifest = JSON.parse(await readFile13(manifestPath, "utf8"));
|
|
97193
97222
|
if (!isPlainRecord4(manifest))
|
|
97194
97223
|
return [];
|
|
97195
97224
|
const states = [];
|
|
@@ -97197,7 +97226,7 @@ async function trustedHookStatesForPlugin(input) {
|
|
|
97197
97226
|
const hooksPath = join40(input.pluginRoot, hookPath);
|
|
97198
97227
|
if (!await exists(hooksPath))
|
|
97199
97228
|
continue;
|
|
97200
|
-
const parsed = JSON.parse(await
|
|
97229
|
+
const parsed = JSON.parse(await readFile13(hooksPath, "utf8"));
|
|
97201
97230
|
if (!isPlainRecord4(parsed) || !isPlainRecord4(parsed.hooks))
|
|
97202
97231
|
continue;
|
|
97203
97232
|
states.push(...trustedHookStatesForHooksFile({
|
|
@@ -97280,7 +97309,7 @@ function stripDotSlash2(value) {
|
|
|
97280
97309
|
}
|
|
97281
97310
|
async function exists(path) {
|
|
97282
97311
|
try {
|
|
97283
|
-
await
|
|
97312
|
+
await readFile13(path, "utf8");
|
|
97284
97313
|
return true;
|
|
97285
97314
|
} catch (error) {
|
|
97286
97315
|
if (error instanceof Error)
|
|
@@ -97380,7 +97409,7 @@ function recordAt2(value, key) {
|
|
|
97380
97409
|
}
|
|
97381
97410
|
|
|
97382
97411
|
// packages/omo-codex/src/install/codex-marketplace-snapshot.ts
|
|
97383
|
-
import { cp as cp4, mkdir as mkdir6, rename as rename5, rm as rm8, writeFile as
|
|
97412
|
+
import { cp as cp4, mkdir as mkdir6, rename as rename5, rm as rm8, writeFile as writeFile7 } from "node:fs/promises";
|
|
97384
97413
|
import { join as join41, sep as sep7 } from "node:path";
|
|
97385
97414
|
var INSTALLED_MARKETPLACES_DIR = ".tmp/marketplaces";
|
|
97386
97415
|
async function writeInstalledMarketplaceSnapshot(input) {
|
|
@@ -97400,7 +97429,7 @@ async function writeMarketplaceManifest(marketplaceRoot, marketplace) {
|
|
|
97400
97429
|
const manifestDir = join41(marketplaceRoot, ".agents", "plugins");
|
|
97401
97430
|
await mkdir6(manifestDir, { recursive: true });
|
|
97402
97431
|
const tempPath = join41(manifestDir, `.marketplace-${process.pid}-${Date.now()}.json.tmp`);
|
|
97403
|
-
await
|
|
97432
|
+
await writeFile7(tempPath, `${JSON.stringify(marketplace, null, "\t")}
|
|
97404
97433
|
`);
|
|
97405
97434
|
await rename5(tempPath, join41(manifestDir, "marketplace.json"));
|
|
97406
97435
|
}
|
|
@@ -97429,15 +97458,15 @@ function shouldCopyMarketplaceSourcePath(path, root) {
|
|
|
97429
97458
|
}
|
|
97430
97459
|
|
|
97431
97460
|
// packages/omo-codex/src/install/link-cached-plugin-agents.ts
|
|
97432
|
-
import { copyFile, lstat as lstat11, mkdir as mkdir7, readdir as readdir8, readFile as
|
|
97461
|
+
import { copyFile, lstat as lstat11, mkdir as mkdir7, readdir as readdir8, readFile as readFile18, rm as rm12, writeFile as writeFile10 } from "node:fs/promises";
|
|
97433
97462
|
import { basename as basename7, join as join46 } from "node:path";
|
|
97434
97463
|
|
|
97435
97464
|
// packages/omo-codex/src/install/agent-model-overrides.ts
|
|
97436
|
-
import { readFile as
|
|
97465
|
+
import { readFile as readFile15, rm as rm9, writeFile as writeFile9 } from "node:fs/promises";
|
|
97437
97466
|
import { join as join43 } from "node:path";
|
|
97438
97467
|
|
|
97439
97468
|
// packages/omo-codex/src/install/preserved-agent-settings.ts
|
|
97440
|
-
import { lstat as lstat8, readFile as
|
|
97469
|
+
import { lstat as lstat8, readFile as readFile14, readdir as readdir7, writeFile as writeFile8 } from "node:fs/promises";
|
|
97441
97470
|
import { join as join42 } from "node:path";
|
|
97442
97471
|
|
|
97443
97472
|
// packages/omo-codex/src/install/managed-agent-reasoning-defaults.ts
|
|
@@ -97672,7 +97701,7 @@ async function capturePreservedAgentServiceTier(input) {
|
|
|
97672
97701
|
async function restorePreservedReasoning(input) {
|
|
97673
97702
|
if (input.value === undefined)
|
|
97674
97703
|
return;
|
|
97675
|
-
const content = await
|
|
97704
|
+
const content = await readFile14(input.target, "utf8");
|
|
97676
97705
|
const bundledEffort = extractReasoningEffort(content);
|
|
97677
97706
|
const effort = resolveManagedAgentReasoning({
|
|
97678
97707
|
agentName: input.agentName,
|
|
@@ -97685,33 +97714,33 @@ async function restorePreservedReasoning(input) {
|
|
|
97685
97714
|
const replacement = replaceTopLevelStringSetting(content, "model_reasoning_effort", effort, { insertIfMissing: false });
|
|
97686
97715
|
if (!replacement.replaced)
|
|
97687
97716
|
return;
|
|
97688
|
-
await
|
|
97717
|
+
await writeFile8(input.linkPath, replacement.content);
|
|
97689
97718
|
}
|
|
97690
97719
|
async function restorePreservedServiceTier(input) {
|
|
97691
97720
|
if (!input.preserved)
|
|
97692
97721
|
return;
|
|
97693
|
-
const content = await
|
|
97722
|
+
const content = await readFile14(input.linkPath, "utf8");
|
|
97694
97723
|
if (extractServiceTier(content) === input.value)
|
|
97695
97724
|
return;
|
|
97696
97725
|
const replacement = replaceTopLevelStringSetting(content, "service_tier", input.value, { insertIfMissing: true });
|
|
97697
97726
|
if (!replacement.replaced)
|
|
97698
97727
|
return;
|
|
97699
|
-
await
|
|
97728
|
+
await writeFile8(input.linkPath, replacement.content);
|
|
97700
97729
|
}
|
|
97701
97730
|
async function restorePreservedModel(input) {
|
|
97702
97731
|
if (input.value === null)
|
|
97703
97732
|
return;
|
|
97704
|
-
const content = await
|
|
97733
|
+
const content = await readFile14(input.linkPath, "utf8");
|
|
97705
97734
|
if (extractModel(content) === input.value)
|
|
97706
97735
|
return;
|
|
97707
97736
|
const replacement = replaceTopLevelStringSetting(content, "model", input.value, { insertIfMissing: true });
|
|
97708
97737
|
if (!replacement.replaced)
|
|
97709
97738
|
return;
|
|
97710
|
-
await
|
|
97739
|
+
await writeFile8(input.linkPath, replacement.content);
|
|
97711
97740
|
}
|
|
97712
97741
|
async function readTextIfExists(path) {
|
|
97713
97742
|
try {
|
|
97714
|
-
return await
|
|
97743
|
+
return await readFile14(path, "utf8");
|
|
97715
97744
|
} catch (error) {
|
|
97716
97745
|
if (nodeErrorCode(error) === "ENOENT")
|
|
97717
97746
|
return null;
|
|
@@ -97833,13 +97862,13 @@ async function writeAgentModelReceipts(codexHome, receipts) {
|
|
|
97833
97862
|
await rm9(path, { force: true });
|
|
97834
97863
|
return;
|
|
97835
97864
|
}
|
|
97836
|
-
await
|
|
97865
|
+
await writeFile9(path, `${JSON.stringify(Object.fromEntries(receipts), null, "\t")}
|
|
97837
97866
|
`);
|
|
97838
97867
|
}
|
|
97839
97868
|
async function applyAgentOverride(input) {
|
|
97840
97869
|
if (input.override === undefined)
|
|
97841
97870
|
return;
|
|
97842
|
-
let content = await
|
|
97871
|
+
let content = await readFile15(input.linkPath, "utf8");
|
|
97843
97872
|
if (input.override.model !== undefined) {
|
|
97844
97873
|
content = replaceTopLevelStringSetting(content, "model", input.override.model, { insertIfMissing: true }).content;
|
|
97845
97874
|
}
|
|
@@ -97848,7 +97877,7 @@ async function applyAgentOverride(input) {
|
|
|
97848
97877
|
insertIfMissing: true
|
|
97849
97878
|
}).content;
|
|
97850
97879
|
}
|
|
97851
|
-
await
|
|
97880
|
+
await writeFile9(input.linkPath, content);
|
|
97852
97881
|
}
|
|
97853
97882
|
function receiptPath(codexHome) {
|
|
97854
97883
|
return join43(codexHome, "agents", RECEIPT_FILE);
|
|
@@ -97883,7 +97912,7 @@ function handEditedAgentModel(installedModel, receipt) {
|
|
|
97883
97912
|
}
|
|
97884
97913
|
|
|
97885
97914
|
// packages/omo-codex/src/install/retired-managed-agent-purge.ts
|
|
97886
|
-
import { lstat as lstat9, readFile as
|
|
97915
|
+
import { lstat as lstat9, readFile as readFile16, rm as rm10 } from "node:fs/promises";
|
|
97887
97916
|
import { join as join44 } from "node:path";
|
|
97888
97917
|
var RETIRED_MANAGED_AGENT_FILES = [
|
|
97889
97918
|
{
|
|
@@ -97917,7 +97946,7 @@ function hasRequiredMarkers(content, markers) {
|
|
|
97917
97946
|
}
|
|
97918
97947
|
async function readTextIfExists2(path) {
|
|
97919
97948
|
try {
|
|
97920
|
-
return await
|
|
97949
|
+
return await readFile16(path, "utf8");
|
|
97921
97950
|
} catch (error) {
|
|
97922
97951
|
if (nodeErrorCode2(error) === "ENOENT")
|
|
97923
97952
|
return null;
|
|
@@ -97942,7 +97971,7 @@ function nodeErrorCode2(error) {
|
|
|
97942
97971
|
|
|
97943
97972
|
// packages/omo-codex/src/install/default-agent-role.ts
|
|
97944
97973
|
import { createHash as createHash4 } from "node:crypto";
|
|
97945
|
-
import { lstat as lstat10, readFile as
|
|
97974
|
+
import { lstat as lstat10, readFile as readFile17, rm as rm11 } from "node:fs/promises";
|
|
97946
97975
|
import { join as join45 } from "node:path";
|
|
97947
97976
|
var REGISTRATION = { name: "default", configFile: "./agents/default.toml" };
|
|
97948
97977
|
async function installDefaultAgentRole(input) {
|
|
@@ -97979,7 +98008,7 @@ async function installDefaultAgentRole(input) {
|
|
|
97979
98008
|
if (foreign || existing !== null && !owned) {
|
|
97980
98009
|
throw new Error("Preserved user-owned agents.default / agents/default.toml. Move it aside to install the LazyCodex fallback, or set [codex].agents.default.disable = true in omo.jsonc. Explicit LazyCodex roles remain required.");
|
|
97981
98010
|
}
|
|
97982
|
-
const worker = await
|
|
98011
|
+
const worker = await readFile17(input.worker.path, "utf8");
|
|
97983
98012
|
const content = worker.replace(/^name\s*=\s*["']lazycodex-worker-medium["']\s*$/m, 'name = "default"');
|
|
97984
98013
|
if (content === worker)
|
|
97985
98014
|
throw new Error("Cannot derive default: medium worker has no matching internal name");
|
|
@@ -97989,7 +98018,7 @@ async function installDefaultAgentRole(input) {
|
|
|
97989
98018
|
}
|
|
97990
98019
|
async function readIfPresent(path) {
|
|
97991
98020
|
try {
|
|
97992
|
-
return await
|
|
98021
|
+
return await readFile17(path, "utf8");
|
|
97993
98022
|
} catch (error) {
|
|
97994
98023
|
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
97995
98024
|
return null;
|
|
@@ -98050,7 +98079,7 @@ async function syncAgentFile(input) {
|
|
|
98050
98079
|
value: input.preservedServiceTier?.get(input.agentName) ?? null
|
|
98051
98080
|
});
|
|
98052
98081
|
await applyAgentOverride({ linkPath: input.linkPath, override });
|
|
98053
|
-
const model = override?.model ?? extractModel(await
|
|
98082
|
+
const model = override?.model ?? extractModel(await readFile18(input.agentPath, "utf8"));
|
|
98054
98083
|
return {
|
|
98055
98084
|
...model === null ? {} : { model },
|
|
98056
98085
|
...override?.reasoningEffort === undefined ? {} : { reasoningEffort: override.reasoningEffort }
|
|
@@ -98094,7 +98123,7 @@ async function prepareReplacement(linkPath) {
|
|
|
98094
98123
|
async function writeManifest(pluginRoot, agentPaths) {
|
|
98095
98124
|
const manifestPath = join46(pluginRoot, MANIFEST_FILE);
|
|
98096
98125
|
const payload = { agents: [...agentPaths].sort() };
|
|
98097
|
-
await
|
|
98126
|
+
await writeFile10(manifestPath, `${JSON.stringify(payload, null, "\t")}
|
|
98098
98127
|
`);
|
|
98099
98128
|
}
|
|
98100
98129
|
function agentNameFromToml2(fileName) {
|
|
@@ -98163,12 +98192,12 @@ function agentNameFromToml3(fileName) {
|
|
|
98163
98192
|
}
|
|
98164
98193
|
|
|
98165
98194
|
// packages/omo-codex/src/install/codex-marketplace.ts
|
|
98166
|
-
import { readFile as
|
|
98195
|
+
import { readFile as readFile19 } from "node:fs/promises";
|
|
98167
98196
|
import { join as join47 } from "node:path";
|
|
98168
98197
|
var DEFAULT_MARKETPLACE_PATH = "packages/omo-codex/marketplace.json";
|
|
98169
98198
|
async function readMarketplace(repoRoot, options) {
|
|
98170
98199
|
const marketplacePath = options?.marketplacePath ?? join47(repoRoot, DEFAULT_MARKETPLACE_PATH);
|
|
98171
|
-
const raw = await
|
|
98200
|
+
const raw = await readFile19(marketplacePath, "utf8");
|
|
98172
98201
|
const parsed = JSON.parse(raw);
|
|
98173
98202
|
if (!isPlainRecord4(parsed))
|
|
98174
98203
|
throw new Error("marketplace.json must be an object");
|
|
@@ -98189,7 +98218,7 @@ function resolvePluginSource(repoRoot, plugin, options) {
|
|
|
98189
98218
|
return join47(repoRoot, ...relativePath.split(/[\\/]/));
|
|
98190
98219
|
}
|
|
98191
98220
|
async function readPluginManifest(pluginRoot) {
|
|
98192
|
-
const raw = await
|
|
98221
|
+
const raw = await readFile19(join47(pluginRoot, ".codex-plugin", "plugin.json"), "utf8");
|
|
98193
98222
|
const parsed = JSON.parse(raw);
|
|
98194
98223
|
if (!isPlainRecord4(parsed))
|
|
98195
98224
|
throw new Error(`${pluginRoot} plugin.json must be an object`);
|
|
@@ -98270,11 +98299,11 @@ function validateLocalSourcePath(path) {
|
|
|
98270
98299
|
}
|
|
98271
98300
|
|
|
98272
98301
|
// packages/omo-codex/src/install/lazycodex-version-stamp.ts
|
|
98273
|
-
import { readdir as readdir9, readFile as
|
|
98302
|
+
import { readdir as readdir9, readFile as readFile20, writeFile as writeFile11 } from "node:fs/promises";
|
|
98274
98303
|
import { join as join48 } from "node:path";
|
|
98275
98304
|
async function readDistributionManifest(repoRoot) {
|
|
98276
98305
|
try {
|
|
98277
|
-
const parsed = JSON.parse(await
|
|
98306
|
+
const parsed = JSON.parse(await readFile20(join48(repoRoot, "package.json"), "utf8"));
|
|
98278
98307
|
if (!isPlainRecord4(parsed) || typeof parsed.version !== "string" || parsed.version.trim().length === 0)
|
|
98279
98308
|
return;
|
|
98280
98309
|
return {
|
|
@@ -98310,7 +98339,7 @@ async function stampLazyCodexPluginVersion(input) {
|
|
|
98310
98339
|
async function writeLazyCodexInstallSnapshot(input) {
|
|
98311
98340
|
if (input.distributionManifest === undefined)
|
|
98312
98341
|
return;
|
|
98313
|
-
await
|
|
98342
|
+
await writeFile11(join48(input.pluginRoot, "lazycodex-install.json"), `${JSON.stringify({
|
|
98314
98343
|
packageName: input.distributionManifest.name,
|
|
98315
98344
|
version: input.distributionManifest.version
|
|
98316
98345
|
}, null, "\t")}
|
|
@@ -98318,11 +98347,11 @@ async function writeLazyCodexInstallSnapshot(input) {
|
|
|
98318
98347
|
}
|
|
98319
98348
|
async function stampJsonVersion(path, version) {
|
|
98320
98349
|
try {
|
|
98321
|
-
const parsed = JSON.parse(await
|
|
98350
|
+
const parsed = JSON.parse(await readFile20(path, "utf8"));
|
|
98322
98351
|
if (!isPlainRecord4(parsed))
|
|
98323
98352
|
return;
|
|
98324
98353
|
parsed.version = version;
|
|
98325
|
-
await
|
|
98354
|
+
await writeFile11(path, `${JSON.stringify(parsed, null, "\t")}
|
|
98326
98355
|
`);
|
|
98327
98356
|
} catch (error) {
|
|
98328
98357
|
if (error instanceof Error)
|
|
@@ -98332,7 +98361,7 @@ async function stampJsonVersion(path, version) {
|
|
|
98332
98361
|
}
|
|
98333
98362
|
async function readPluginHookPaths(manifestPath) {
|
|
98334
98363
|
try {
|
|
98335
|
-
const parsed = JSON.parse(await
|
|
98364
|
+
const parsed = JSON.parse(await readFile20(manifestPath, "utf8"));
|
|
98336
98365
|
if (!isPlainRecord4(parsed))
|
|
98337
98366
|
return [];
|
|
98338
98367
|
if (typeof parsed.hooks === "string" && parsed.hooks.trim().length > 0)
|
|
@@ -98352,11 +98381,11 @@ function stripDotSlash3(path) {
|
|
|
98352
98381
|
}
|
|
98353
98382
|
async function stampHookStatusMessages(path, version) {
|
|
98354
98383
|
try {
|
|
98355
|
-
const parsed = JSON.parse(await
|
|
98384
|
+
const parsed = JSON.parse(await readFile20(path, "utf8"));
|
|
98356
98385
|
if (!isPlainRecord4(parsed))
|
|
98357
98386
|
return;
|
|
98358
98387
|
stampHookGroups(parsed.hooks, version);
|
|
98359
|
-
await
|
|
98388
|
+
await writeFile11(path, `${JSON.stringify(parsed, null, "\t")}
|
|
98360
98389
|
`);
|
|
98361
98390
|
} catch (error) {
|
|
98362
98391
|
if (error instanceof Error)
|
|
@@ -98433,7 +98462,7 @@ var defaultRunCommand = async (command, args, options) => {
|
|
|
98433
98462
|
};
|
|
98434
98463
|
|
|
98435
98464
|
// packages/omo-codex/src/install/codex-project-local-cleanup.ts
|
|
98436
|
-
import { copyFile as copyFile2, lstat as lstat12, readFile as
|
|
98465
|
+
import { copyFile as copyFile2, lstat as lstat12, readFile as readFile21, writeFile as writeFile12 } from "node:fs/promises";
|
|
98437
98466
|
import { dirname as dirname17, join as join49, resolve as resolve11 } from "node:path";
|
|
98438
98467
|
var LEGACY_AGENT_CONFLICT_KEYS = ["max_threads"];
|
|
98439
98468
|
var PROJECT_LOCAL_ARTIFACT_PATHS = [
|
|
@@ -98453,7 +98482,7 @@ async function repairNearestProjectLocalCodexArtifacts(input) {
|
|
|
98453
98482
|
const artifacts = await collectProjectLocalArtifacts(project.artifactRoots);
|
|
98454
98483
|
const configs = [];
|
|
98455
98484
|
for (const configPath of project.configPaths) {
|
|
98456
|
-
const original = await
|
|
98485
|
+
const original = await readFile21(configPath, "utf8");
|
|
98457
98486
|
const repair = repairProjectLocalCodexConfigText(original);
|
|
98458
98487
|
if (!repair.changed) {
|
|
98459
98488
|
configs.push({
|
|
@@ -98466,7 +98495,7 @@ async function repairNearestProjectLocalCodexArtifacts(input) {
|
|
|
98466
98495
|
}
|
|
98467
98496
|
const backupPath = `${configPath}.backup-${formatBackupTimestamp(input.now?.() ?? new Date)}`;
|
|
98468
98497
|
await copyFile2(configPath, backupPath);
|
|
98469
|
-
await
|
|
98498
|
+
await writeFile12(configPath, `${repair.config.trimEnd()}
|
|
98470
98499
|
`);
|
|
98471
98500
|
configs.push({
|
|
98472
98501
|
projectRoot: project.projectRoot,
|
|
@@ -98663,13 +98692,13 @@ function formatUnknownError(error) {
|
|
|
98663
98692
|
|
|
98664
98693
|
// packages/omo-codex/src/install/lsp-daemon-reaper.ts
|
|
98665
98694
|
import { createHash as createHash5 } from "node:crypto";
|
|
98666
|
-
import { lstat as lstat13, readFile as
|
|
98695
|
+
import { lstat as lstat13, readFile as readFile23, readdir as readdir11, rm as rm13 } from "node:fs/promises";
|
|
98667
98696
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
98668
98697
|
import { join as join50, posix as posix6 } from "node:path";
|
|
98669
98698
|
|
|
98670
98699
|
// packages/omo-codex/src/install/lsp-daemon-reaper-attestation.ts
|
|
98671
98700
|
import { execFile } from "node:child_process";
|
|
98672
|
-
import { readFile as
|
|
98701
|
+
import { readFile as readFile22, readdir as readdir10, readlink as readlink5 } from "node:fs/promises";
|
|
98673
98702
|
import { connect } from "node:net";
|
|
98674
98703
|
import { basename as basename8 } from "node:path";
|
|
98675
98704
|
var PROBE_TIMEOUT_MS = 500;
|
|
@@ -98711,7 +98740,7 @@ async function attestLegacyDaemonOwnership(input, deps = {}) {
|
|
|
98711
98740
|
return false;
|
|
98712
98741
|
}
|
|
98713
98742
|
async function attestLinuxOwnership(input, deps) {
|
|
98714
|
-
const readFileImpl = deps.readFile ??
|
|
98743
|
+
const readFileImpl = deps.readFile ?? readFile22;
|
|
98715
98744
|
const readDirImpl = deps.readDir ?? readdir10;
|
|
98716
98745
|
const readLinkImpl = deps.readLink ?? readlink5;
|
|
98717
98746
|
const procNetUnix = await readText(readFileImpl, "/proc/net/unix");
|
|
@@ -98936,7 +98965,7 @@ async function readRegularTrimmedFile(path) {
|
|
|
98936
98965
|
return null;
|
|
98937
98966
|
if (!stats.isFile())
|
|
98938
98967
|
return "non_regular";
|
|
98939
|
-
const content = (await
|
|
98968
|
+
const content = (await readFile23(path, "utf8")).trim();
|
|
98940
98969
|
return content.length > 0 ? content : null;
|
|
98941
98970
|
}
|
|
98942
98971
|
function shortDigest(value) {
|
|
@@ -98997,11 +99026,11 @@ function resolveCodexInstallerBinDir(input) {
|
|
|
98997
99026
|
}
|
|
98998
99027
|
|
|
98999
99028
|
// packages/omo-codex/src/install/codex-installed-bin-dir.ts
|
|
99000
|
-
import { readFile as
|
|
99029
|
+
import { readFile as readFile24, readdir as readdir12, writeFile as writeFile13 } from "node:fs/promises";
|
|
99001
99030
|
import { join as join52 } from "node:path";
|
|
99002
99031
|
var INSTALLED_BIN_DIR_MANIFEST = ".installed-bin-dir.json";
|
|
99003
99032
|
async function writeInstalledCodexBinDir(input) {
|
|
99004
|
-
await
|
|
99033
|
+
await writeFile13(join52(input.pluginRoot, INSTALLED_BIN_DIR_MANIFEST), `${JSON.stringify({ binDir: input.binDir }, null, 2)}
|
|
99005
99034
|
`);
|
|
99006
99035
|
}
|
|
99007
99036
|
async function readInstalledCodexBinDir(codexHome) {
|
|
@@ -99027,7 +99056,7 @@ async function installedBinDirManifestPaths(codexHome) {
|
|
|
99027
99056
|
return paths;
|
|
99028
99057
|
}
|
|
99029
99058
|
async function readBinDirFromManifest(manifestPath) {
|
|
99030
|
-
const raw = await
|
|
99059
|
+
const raw = await readFile24(manifestPath, "utf8").catch(() => null);
|
|
99031
99060
|
if (raw === null)
|
|
99032
99061
|
return null;
|
|
99033
99062
|
let parsed;
|
|
@@ -99045,7 +99074,7 @@ async function readBinDirFromManifest(manifestPath) {
|
|
|
99045
99074
|
}
|
|
99046
99075
|
|
|
99047
99076
|
// packages/omo-codex/src/install/codex-git-bash-hooks.ts
|
|
99048
|
-
import { readFile as
|
|
99077
|
+
import { readFile as readFile25, writeFile as writeFile14 } from "node:fs/promises";
|
|
99049
99078
|
import { join as join53 } from "node:path";
|
|
99050
99079
|
var WINDOWS_ONLY_GIT_BASH_HOOKS = new Set([
|
|
99051
99080
|
"./hooks/pre-tool-use-recommending-git-bash-mcp.json",
|
|
@@ -99055,13 +99084,13 @@ async function removeGitBashHooksOffWindows(input) {
|
|
|
99055
99084
|
if (input.platform === "win32")
|
|
99056
99085
|
return;
|
|
99057
99086
|
const manifestPath = join53(input.pluginRoot, ".codex-plugin", "plugin.json");
|
|
99058
|
-
const parsed = JSON.parse(await
|
|
99087
|
+
const parsed = JSON.parse(await readFile25(manifestPath, "utf8"));
|
|
99059
99088
|
if (!isPlainRecord4(parsed) || !Array.isArray(parsed.hooks))
|
|
99060
99089
|
return;
|
|
99061
99090
|
const hooks = parsed.hooks.filter((hook) => typeof hook !== "string" || !WINDOWS_ONLY_GIT_BASH_HOOKS.has(hook));
|
|
99062
99091
|
if (hooks.length === parsed.hooks.length)
|
|
99063
99092
|
return;
|
|
99064
|
-
await
|
|
99093
|
+
await writeFile14(manifestPath, `${JSON.stringify({ ...parsed, hooks }, null, "\t")}
|
|
99065
99094
|
`);
|
|
99066
99095
|
}
|
|
99067
99096
|
|
|
@@ -99432,12 +99461,12 @@ function defaultRunCommand2(command, args) {
|
|
|
99432
99461
|
});
|
|
99433
99462
|
}
|
|
99434
99463
|
// packages/omo-codex/src/install/codex-cleanup.ts
|
|
99435
|
-
import { lstat as lstat16, readFile as
|
|
99464
|
+
import { lstat as lstat16, readFile as readFile28, readdir as readdir14, rm as rm15, rmdir } from "node:fs/promises";
|
|
99436
99465
|
import { homedir as homedir9 } from "node:os";
|
|
99437
99466
|
import { isAbsolute as isAbsolute11, join as join62, relative as relative7, resolve as resolve16 } from "node:path";
|
|
99438
99467
|
|
|
99439
99468
|
// packages/omo-codex/src/install/codex-cleanup-bins.ts
|
|
99440
|
-
import { lstat as lstat14, readFile as
|
|
99469
|
+
import { lstat as lstat14, readFile as readFile26, readdir as readdir13, readlink as readlink6, rm as rm14 } from "node:fs/promises";
|
|
99441
99470
|
import { dirname as dirname20, isAbsolute as isAbsolute9, join as join60, resolve as resolve14 } from "node:path";
|
|
99442
99471
|
var ROOT_RUNTIME_BIN_NAME = "omo";
|
|
99443
99472
|
var MANAGED_CODEX_BIN_NAMES = new Set([
|
|
@@ -99499,12 +99528,12 @@ async function isManagedCodexBin(linkPath, platform, binName) {
|
|
|
99499
99528
|
}
|
|
99500
99529
|
if (!entryStat.isFile())
|
|
99501
99530
|
return false;
|
|
99502
|
-
const content = await
|
|
99531
|
+
const content = await readFile26(linkPath, "utf8");
|
|
99503
99532
|
return content.includes(RUNTIME_WRAPPER_MARKER) || content.includes(COMMAND_SHIM_MARKER);
|
|
99504
99533
|
}
|
|
99505
99534
|
|
|
99506
99535
|
// packages/omo-codex/src/install/codex-cleanup-config.ts
|
|
99507
|
-
import { lstat as lstat15, mkdir as mkdir8, readFile as
|
|
99536
|
+
import { lstat as lstat15, mkdir as mkdir8, readFile as readFile27, writeFile as writeFile15 } from "node:fs/promises";
|
|
99508
99537
|
import { dirname as dirname21 } from "node:path";
|
|
99509
99538
|
var MANAGED_MARKETPLACES = ["sisyphuslabs", "lazycodex", "code-yeongyu-codex-plugins"];
|
|
99510
99539
|
var LEGACY_MANAGED_CODEX_AGENT_NAMES_TO_PURGE2 = ["codex-ultrawork-reviewer"];
|
|
@@ -99537,14 +99566,14 @@ function cleanupCodexLightConfigText(config) {
|
|
|
99537
99566
|
async function cleanupCodexConfig(configPath, now) {
|
|
99538
99567
|
if (!await configExists(configPath))
|
|
99539
99568
|
return { changed: false };
|
|
99540
|
-
const original = await
|
|
99569
|
+
const original = await readFile27(configPath, "utf8");
|
|
99541
99570
|
const next = cleanupCodexLightConfigText(original);
|
|
99542
99571
|
if (next === original)
|
|
99543
99572
|
return { changed: false };
|
|
99544
99573
|
const backupPath = `${configPath}.backup-${formatBackupTimestamp2(now?.() ?? new Date)}`;
|
|
99545
99574
|
await mkdir8(dirname21(configPath), { recursive: true });
|
|
99546
|
-
await
|
|
99547
|
-
await
|
|
99575
|
+
await writeFile15(backupPath, original);
|
|
99576
|
+
await writeFile15(configPath, `${next.trimEnd()}
|
|
99548
99577
|
`);
|
|
99549
99578
|
return { changed: true, backupPath };
|
|
99550
99579
|
}
|
|
@@ -99821,13 +99850,13 @@ async function collectInstalledAgentPaths(codexHome, configPath) {
|
|
|
99821
99850
|
async function readManagedAgentPathsFromConfig(codexHome, configPath) {
|
|
99822
99851
|
if (!await exists6(configPath))
|
|
99823
99852
|
return [];
|
|
99824
|
-
const config = await
|
|
99853
|
+
const config = await readFile28(configPath, "utf8");
|
|
99825
99854
|
return MANAGED_CODEX_AGENT_NAMES2.filter((agentName) => config.includes(`config_file = ${JSON.stringify(`./agents/${agentName}.toml`)}`)).map((agentName) => join62(codexHome, "agents", `${agentName}.toml`));
|
|
99826
99855
|
}
|
|
99827
99856
|
async function readInstalledAgentManifest(manifestPath) {
|
|
99828
99857
|
if (!await exists6(manifestPath))
|
|
99829
99858
|
return [];
|
|
99830
|
-
const parsed = JSON.parse(await
|
|
99859
|
+
const parsed = JSON.parse(await readFile28(manifestPath, "utf8"));
|
|
99831
99860
|
if (!isPlainRecord4(parsed) || !Array.isArray(parsed.agents))
|
|
99832
99861
|
return [];
|
|
99833
99862
|
return parsed.agents.filter((path) => typeof path === "string");
|
|
@@ -100019,7 +100048,7 @@ node "%~dp0omo" %*\r
|
|
|
100019
100048
|
// packages/omo-senpi/src/install/plugin-artifacts.ts
|
|
100020
100049
|
import { createHash as createHash7 } from "node:crypto";
|
|
100021
100050
|
import { constants as constants9 } from "node:fs";
|
|
100022
|
-
import { access as
|
|
100051
|
+
import { access as access3, readFile as readFile30, stat as stat6 } from "node:fs/promises";
|
|
100023
100052
|
import { dirname as dirname25, join as join66 } from "node:path";
|
|
100024
100053
|
|
|
100025
100054
|
// packages/memory-core/src/personas/manifest.ts
|
|
@@ -100038,7 +100067,7 @@ var PERSONA_ASSET_FILES = [
|
|
|
100038
100067
|
|
|
100039
100068
|
// packages/omo-senpi/src/install/senpi-settings.ts
|
|
100040
100069
|
import { constants as constants8 } from "node:fs";
|
|
100041
|
-
import { access, copyFile as copyFile3, mkdir as mkdir9, readFile as
|
|
100070
|
+
import { access as access2, copyFile as copyFile3, mkdir as mkdir9, readFile as readFile29, rename as rename6, writeFile as writeFile16 } from "node:fs/promises";
|
|
100042
100071
|
import { basename as basename10, dirname as dirname24, join as join65, resolve as resolve19 } from "node:path";
|
|
100043
100072
|
var OMO_SENPI_PACKAGE_NAME = "@code-yeongyu/omo-senpi";
|
|
100044
100073
|
var GENERATED_PLUGIN_BASENAME = /^omo-senpi-cli-plugin-[A-Za-z0-9]{6}$/;
|
|
@@ -100049,7 +100078,7 @@ var LEGACY_BUILTIN_SHADOW_PACKAGES = [
|
|
|
100049
100078
|
async function readSettings(settingsPath) {
|
|
100050
100079
|
let raw;
|
|
100051
100080
|
try {
|
|
100052
|
-
raw = await
|
|
100081
|
+
raw = await readFile29(settingsPath, "utf8");
|
|
100053
100082
|
} catch (error) {
|
|
100054
100083
|
if (isErrno(error, "ENOENT"))
|
|
100055
100084
|
return {};
|
|
@@ -100096,11 +100125,11 @@ async function writeSettingsAtomically(settingsPath, settings) {
|
|
|
100096
100125
|
if (await fileExists(settingsPath)) {
|
|
100097
100126
|
await copyFile3(settingsPath, backupPath);
|
|
100098
100127
|
} else {
|
|
100099
|
-
await
|
|
100128
|
+
await writeFile16(backupPath, `{}
|
|
100100
100129
|
`, "utf8");
|
|
100101
100130
|
}
|
|
100102
100131
|
const tempPath = `${settingsPath}.${process.pid}.${Date.now()}.tmp`;
|
|
100103
|
-
await
|
|
100132
|
+
await writeFile16(tempPath, `${JSON.stringify(settings, null, 2)}
|
|
100104
100133
|
`, "utf8");
|
|
100105
100134
|
await rename6(tempPath, settingsPath);
|
|
100106
100135
|
return backupPath;
|
|
@@ -100123,7 +100152,7 @@ function isRecord15(value) {
|
|
|
100123
100152
|
async function readPackageName(packagePath) {
|
|
100124
100153
|
let raw;
|
|
100125
100154
|
try {
|
|
100126
|
-
raw = await
|
|
100155
|
+
raw = await readFile29(join65(packagePath, "package.json"), "utf8");
|
|
100127
100156
|
} catch (error) {
|
|
100128
100157
|
if (isErrno(error, "ENOENT") || isErrno(error, "ENOTDIR"))
|
|
100129
100158
|
return;
|
|
@@ -100141,7 +100170,7 @@ async function readPackageName(packagePath) {
|
|
|
100141
100170
|
}
|
|
100142
100171
|
async function fileExists(path) {
|
|
100143
100172
|
try {
|
|
100144
|
-
await
|
|
100173
|
+
await access2(path, constants8.F_OK);
|
|
100145
100174
|
return true;
|
|
100146
100175
|
} catch (error) {
|
|
100147
100176
|
if (isErrno(error, "ENOENT"))
|
|
@@ -100204,6 +100233,7 @@ var REQUIRED_PLUGIN_ARTIFACTS = [
|
|
|
100204
100233
|
join66("skills", "visual-qa", "SKILL.md"),
|
|
100205
100234
|
join66("skills-conditional", "x-search", "SKILL.md"),
|
|
100206
100235
|
join66("runtime", "agent-toolkit-sdk", "sdk.js"),
|
|
100236
|
+
join66("runtime", "bunshin-ts", "sdk.js"),
|
|
100207
100237
|
join66("runtime", "thread-sdk", "sdk.js"),
|
|
100208
100238
|
join66("runtime", "ast-grep-mcp", "cli.js"),
|
|
100209
100239
|
join66("runtime", "lsp-daemon", "dist", "cli.js"),
|
|
@@ -100246,7 +100276,7 @@ async function verifyAstGrepRuntimeIntegrity(pluginPath, platform) {
|
|
|
100246
100276
|
runtimeStat = await stat6(runtimeEntry);
|
|
100247
100277
|
if (!runtimeStat.isFile())
|
|
100248
100278
|
throw new Error("runtime is not a file");
|
|
100249
|
-
await
|
|
100279
|
+
await access3(runtimeEntry, constants9.R_OK | constants9.X_OK);
|
|
100250
100280
|
} catch (error) {
|
|
100251
100281
|
throw astGrepIntegrityError(runtimeEntry, `runtime is unreadable or non-executable: ${messageOf(error)}`);
|
|
100252
100282
|
}
|
|
@@ -100255,7 +100285,7 @@ async function verifyAstGrepRuntimeIntegrity(pluginPath, platform) {
|
|
|
100255
100285
|
}
|
|
100256
100286
|
let manifest;
|
|
100257
100287
|
try {
|
|
100258
|
-
manifest = JSON.parse(await
|
|
100288
|
+
manifest = JSON.parse(await readFile30(manifestPath, "utf8"));
|
|
100259
100289
|
} catch (error) {
|
|
100260
100290
|
throw astGrepIntegrityError(runtimeEntry, `manifest is unreadable or invalid JSON: ${messageOf(error)}`);
|
|
100261
100291
|
}
|
|
@@ -100264,7 +100294,7 @@ async function verifyAstGrepRuntimeIntegrity(pluginPath, platform) {
|
|
|
100264
100294
|
}
|
|
100265
100295
|
let actualSha256;
|
|
100266
100296
|
try {
|
|
100267
|
-
actualSha256 = createHash7("sha256").update(await
|
|
100297
|
+
actualSha256 = createHash7("sha256").update(await readFile30(runtimeEntry)).digest("hex");
|
|
100268
100298
|
} catch (error) {
|
|
100269
100299
|
throw astGrepIntegrityError(runtimeEntry, `runtime hash could not be computed: ${messageOf(error)}`);
|
|
100270
100300
|
}
|
|
@@ -100289,7 +100319,7 @@ function messageOf(error) {
|
|
|
100289
100319
|
}
|
|
100290
100320
|
async function fileExists2(path) {
|
|
100291
100321
|
try {
|
|
100292
|
-
await
|
|
100322
|
+
await access3(path, constants9.F_OK);
|
|
100293
100323
|
return true;
|
|
100294
100324
|
} catch (error) {
|
|
100295
100325
|
if (isErrno2(error, "ENOENT"))
|
|
@@ -104452,6 +104482,7 @@ var BuiltinSkillNameSchema = _enum([
|
|
|
104452
104482
|
"debugging",
|
|
104453
104483
|
"security-research",
|
|
104454
104484
|
"security-review",
|
|
104485
|
+
"hyperplan",
|
|
104455
104486
|
"visual-qa",
|
|
104456
104487
|
"team-mode"
|
|
104457
104488
|
]);
|
|
@@ -107981,7 +108012,7 @@ function getSuggestedInstallTag(currentVersion) {
|
|
|
107981
108012
|
// packages/omo-opencode/src/cli/doctor/checks/system.ts
|
|
107982
108013
|
init_jsonc_parser2();
|
|
107983
108014
|
init_plugin_identity();
|
|
107984
|
-
var
|
|
108015
|
+
var runtime5 = globalThis;
|
|
107985
108016
|
var defaultDeps5 = {
|
|
107986
108017
|
findOpenCodeBinary,
|
|
107987
108018
|
getOpenCodeVersion: getOpenCodeVersion3,
|
|
@@ -108042,7 +108073,7 @@ async function gatherSystemInfo(deps = defaultDeps5) {
|
|
|
108042
108073
|
opencodePath: binaryInfo?.path ?? null,
|
|
108043
108074
|
pluginVersion,
|
|
108044
108075
|
loadedVersion: loadedInfo.loadedVersion,
|
|
108045
|
-
bunVersion:
|
|
108076
|
+
bunVersion: runtime5.Bun?.version ?? "unavailable",
|
|
108046
108077
|
configPath: pluginInfo.configPath,
|
|
108047
108078
|
configValid: isConfigValid(pluginInfo.configPath, deps),
|
|
108048
108079
|
isLocalDev: pluginInfo.isLocalDev
|
|
@@ -109521,7 +109552,7 @@ async function pathExists2(dir) {
|
|
|
109521
109552
|
// packages/omo-opencode/src/cli/doctor/checks/codex.ts
|
|
109522
109553
|
init_src();
|
|
109523
109554
|
import { existsSync as existsSync61 } from "node:fs";
|
|
109524
|
-
import { lstat as lstat17, readdir as readdir15, readFile as
|
|
109555
|
+
import { lstat as lstat17, readdir as readdir15, readFile as readFile31 } from "node:fs/promises";
|
|
109525
109556
|
import { homedir as homedir26 } from "node:os";
|
|
109526
109557
|
import { basename as basename13, join as join99, resolve as resolve27 } from "node:path";
|
|
109527
109558
|
// packages/omo-opencode/package.json
|
|
@@ -109550,8 +109581,8 @@ var package_default3 = {
|
|
|
109550
109581
|
},
|
|
109551
109582
|
dependencies: {
|
|
109552
109583
|
"@clack/prompts": "^1.8.1",
|
|
109553
|
-
"@code-yeongyu/senpi": "2026.11.
|
|
109554
|
-
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.11.
|
|
109584
|
+
"@code-yeongyu/senpi": "2026.11.5-1",
|
|
109585
|
+
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.11.5-1",
|
|
109555
109586
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
109556
109587
|
"@oh-my-opencode/agents-md-core": "workspace:*",
|
|
109557
109588
|
"@oh-my-opencode/boulder-state": "workspace:*",
|
|
@@ -109746,7 +109777,7 @@ async function readCodexConfigSummary(configPath) {
|
|
|
109746
109777
|
companionLifecycleHookStateEvents: []
|
|
109747
109778
|
};
|
|
109748
109779
|
}
|
|
109749
|
-
const content = await
|
|
109780
|
+
const content = await readFile31(configPath, "utf8");
|
|
109750
109781
|
return {
|
|
109751
109782
|
exists: true,
|
|
109752
109783
|
marketplaceConfigured: content.includes("[marketplaces.sisyphuslabs]"),
|
|
@@ -109774,7 +109805,7 @@ async function readLinkedAgents(codexHome) {
|
|
|
109774
109805
|
}
|
|
109775
109806
|
async function readJson(path) {
|
|
109776
109807
|
try {
|
|
109777
|
-
const parsed = JSON.parse(await
|
|
109808
|
+
const parsed = JSON.parse(await readFile31(path, "utf8"));
|
|
109778
109809
|
return isPlainRecord(parsed) ? parsed : null;
|
|
109779
109810
|
} catch (error) {
|
|
109780
109811
|
if (error instanceof Error)
|
|
@@ -109898,7 +109929,7 @@ function resolveLatestVersion(input) {
|
|
|
109898
109929
|
|
|
109899
109930
|
// packages/omo-opencode/src/cli/doctor/checks/codex-components.ts
|
|
109900
109931
|
init_src();
|
|
109901
|
-
import { readdir as readdir16, readFile as
|
|
109932
|
+
import { readdir as readdir16, readFile as readFile32, stat as stat7 } from "node:fs/promises";
|
|
109902
109933
|
import { homedir as homedir27 } from "node:os";
|
|
109903
109934
|
import { dirname as dirname40, isAbsolute as isAbsolute15, join as join100, relative as relative10, resolve as resolve28, sep as sep11 } from "node:path";
|
|
109904
109935
|
var CODEX_COMPONENTS_CHECK_ID = "codex-components";
|
|
@@ -110151,7 +110182,7 @@ function degradedDetailLines(entries) {
|
|
|
110151
110182
|
}
|
|
110152
110183
|
async function readJson2(path) {
|
|
110153
110184
|
try {
|
|
110154
|
-
const parsed = JSON.parse(await
|
|
110185
|
+
const parsed = JSON.parse(await readFile32(path, "utf8"));
|
|
110155
110186
|
return isRecord18(parsed) ? parsed : null;
|
|
110156
110187
|
} catch (error) {
|
|
110157
110188
|
if (error instanceof Error)
|
|
@@ -110179,7 +110210,7 @@ function isRecord18(value) {
|
|
|
110179
110210
|
|
|
110180
110211
|
// packages/omo-opencode/src/cli/doctor/checks/codex-runtime-wrapper.ts
|
|
110181
110212
|
import { existsSync as existsSync62 } from "node:fs";
|
|
110182
|
-
import { readFile as
|
|
110213
|
+
import { readFile as readFile33 } from "node:fs/promises";
|
|
110183
110214
|
import { homedir as homedir28 } from "node:os";
|
|
110184
110215
|
import { join as join101, resolve as resolve29 } from "node:path";
|
|
110185
110216
|
var RUNTIME_WRAPPER_MARKER2 = "OMO_GENERATED_RUNTIME_WRAPPER";
|
|
@@ -110224,7 +110255,7 @@ async function checkCodexRuntimeWrapper(deps = {}) {
|
|
|
110224
110255
|
}
|
|
110225
110256
|
async function readRuntimeWrapper(path) {
|
|
110226
110257
|
try {
|
|
110227
|
-
return await
|
|
110258
|
+
return await readFile33(path, "utf8");
|
|
110228
110259
|
} catch (error) {
|
|
110229
110260
|
if (error instanceof Error)
|
|
110230
110261
|
return null;
|
|
@@ -112148,6 +112179,73 @@ async function loadDeviceKeyring(store) {
|
|
|
112148
112179
|
import { execFile as execFile5 } from "node:child_process";
|
|
112149
112180
|
import { homedir as homedir30 } from "node:os";
|
|
112150
112181
|
import { join as join105 } from "node:path";
|
|
112182
|
+
|
|
112183
|
+
// packages/omo-opencode/src/shared/bun-ffi-shim.ts
|
|
112184
|
+
async function loadBunFfi() {
|
|
112185
|
+
return import("bun:ffi");
|
|
112186
|
+
}
|
|
112187
|
+
|
|
112188
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/process-state.ts
|
|
112189
|
+
var KEY = Symbol.for("omo.keychain-helper.process.v1");
|
|
112190
|
+
function keychainProcessState() {
|
|
112191
|
+
const holder = globalThis;
|
|
112192
|
+
holder[KEY] ??= {
|
|
112193
|
+
secretsQueue: Promise.resolve(),
|
|
112194
|
+
interactionSwitch: undefined,
|
|
112195
|
+
approvalCache: undefined,
|
|
112196
|
+
entryCandidates: [],
|
|
112197
|
+
helperAccess: undefined,
|
|
112198
|
+
heldPromptLocks: new Set,
|
|
112199
|
+
handOff: undefined
|
|
112200
|
+
};
|
|
112201
|
+
return holder[KEY];
|
|
112202
|
+
}
|
|
112203
|
+
|
|
112204
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/secrets-gate.ts
|
|
112205
|
+
async function loadInteractionSwitch() {
|
|
112206
|
+
const state = keychainProcessState();
|
|
112207
|
+
if (state.interactionSwitch !== undefined)
|
|
112208
|
+
return state.interactionSwitch;
|
|
112209
|
+
if (process.platform !== "darwin")
|
|
112210
|
+
return state.interactionSwitch = null;
|
|
112211
|
+
try {
|
|
112212
|
+
const { dlopen, FFIType } = await loadBunFfi();
|
|
112213
|
+
const security = dlopen("/System/Library/Frameworks/Security.framework/Security", {
|
|
112214
|
+
SecKeychainSetUserInteractionAllowed: { args: [FFIType.u8], returns: FFIType.i32 }
|
|
112215
|
+
});
|
|
112216
|
+
state.interactionSwitch = (allowed) => {
|
|
112217
|
+
security.symbols.SecKeychainSetUserInteractionAllowed(allowed ? 1 : 0);
|
|
112218
|
+
};
|
|
112219
|
+
} catch {
|
|
112220
|
+
state.interactionSwitch = null;
|
|
112221
|
+
}
|
|
112222
|
+
return state.interactionSwitch;
|
|
112223
|
+
}
|
|
112224
|
+
function gatedSecrets(run) {
|
|
112225
|
+
const state = keychainProcessState();
|
|
112226
|
+
const next = state.secretsQueue.then(run, run);
|
|
112227
|
+
state.secretsQueue = next.then(() => {
|
|
112228
|
+
return;
|
|
112229
|
+
}, () => {
|
|
112230
|
+
return;
|
|
112231
|
+
});
|
|
112232
|
+
return next;
|
|
112233
|
+
}
|
|
112234
|
+
function silentSecrets(run) {
|
|
112235
|
+
return gatedSecrets(async () => {
|
|
112236
|
+
const setInteraction = await loadInteractionSwitch();
|
|
112237
|
+
if (setInteraction === null)
|
|
112238
|
+
throw new Error("Keychain interaction cannot be switched off on this host.");
|
|
112239
|
+
setInteraction(false);
|
|
112240
|
+
try {
|
|
112241
|
+
return await run();
|
|
112242
|
+
} finally {
|
|
112243
|
+
setInteraction(true);
|
|
112244
|
+
}
|
|
112245
|
+
});
|
|
112246
|
+
}
|
|
112247
|
+
|
|
112248
|
+
// packages/omo-opencode/src/cli/account-keys/keystore.ts
|
|
112151
112249
|
var DEFAULT_SERVICE = "omo-cli";
|
|
112152
112250
|
function defaultRun(argv, input) {
|
|
112153
112251
|
const [file, ...args] = argv;
|
|
@@ -112171,7 +112269,7 @@ function createOsKeyStore(name, platform = process.platform, run = defaultRun, s
|
|
|
112171
112269
|
const resolved = secrets === undefined ? run === defaultRun && typeof Bun !== "undefined" ? Bun.secrets : null : secrets;
|
|
112172
112270
|
switch (platform) {
|
|
112173
112271
|
case "darwin":
|
|
112174
|
-
return resolved !== null ? createBunSecretsKeyStore(name, resolved) : createMacOsKeychainKeyStore(name, run);
|
|
112272
|
+
return resolved !== null ? createBunSecretsKeyStore(name, gateRealSecrets(resolved)) : createMacOsKeychainKeyStore(name, run);
|
|
112175
112273
|
case "linux":
|
|
112176
112274
|
return resolved !== null ? createBunSecretsKeyStore(name, resolved) : createLibsecretKeyStore(name, run);
|
|
112177
112275
|
case "win32":
|
|
@@ -112190,6 +112288,10 @@ async function guarded(run, fail, argv, input) {
|
|
|
112190
112288
|
throw fail();
|
|
112191
112289
|
}
|
|
112192
112290
|
}
|
|
112291
|
+
var gateRealSecrets = (secrets) => typeof Bun !== "undefined" && secrets === Bun.secrets ? {
|
|
112292
|
+
get: (key) => gatedSecrets(() => secrets.get(key)),
|
|
112293
|
+
set: (entry) => gatedSecrets(() => secrets.set(entry))
|
|
112294
|
+
} : secrets;
|
|
112193
112295
|
function createBunSecretsKeyStore(name, secrets) {
|
|
112194
112296
|
const key = { service: DEFAULT_SERVICE, name };
|
|
112195
112297
|
const unavailable = () => new Error("omo account keys: cannot access the OS credential store. Unlock the login keychain (macOS), the Secret Service keyring (Linux), or DPAPI (Windows), then try again. " + "Private keys are only ever stored through the OS credential facility.");
|
|
@@ -112727,64 +112829,705 @@ async function loginDevice(session, options) {
|
|
|
112727
112829
|
}
|
|
112728
112830
|
|
|
112729
112831
|
// packages/omo-opencode/src/cli/service-auth/keystore.ts
|
|
112730
|
-
import { createHash as createHash12, randomUUID as
|
|
112731
|
-
import { basename as
|
|
112832
|
+
import { createHash as createHash12, randomUUID as randomUUID8 } from "node:crypto";
|
|
112833
|
+
import { basename as basename17 } from "node:path";
|
|
112732
112834
|
|
|
112733
|
-
// packages/omo-opencode/src/cli/service-auth/
|
|
112734
|
-
import {
|
|
112735
|
-
|
|
112736
|
-
|
|
112737
|
-
|
|
112738
|
-
|
|
112739
|
-
|
|
112740
|
-
|
|
112741
|
-
|
|
112835
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/darwin-backend.ts
|
|
112836
|
+
import { homedir as homedir31 } from "node:os";
|
|
112837
|
+
import { join as join109 } from "node:path";
|
|
112838
|
+
|
|
112839
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/client.ts
|
|
112840
|
+
init_zod();
|
|
112841
|
+
init_bun_spawn_shim();
|
|
112842
|
+
var MUTATING = new Set(["write", "stage", "retire", "promote", "remove"]);
|
|
112843
|
+
var helperReplySchema = object({
|
|
112844
|
+
owned: boolean2(),
|
|
112845
|
+
value: string2(),
|
|
112846
|
+
marker: boolean2(),
|
|
112847
|
+
cdat: number2(),
|
|
112848
|
+
mdat: number2(),
|
|
112849
|
+
partition: _enum(["ours", "other", "none", "unknown"]),
|
|
112850
|
+
present: object({ staging: boolean2(), old: boolean2(), oldSlots: array(number2().int().min(0).max(7)).optional() }).strict(),
|
|
112851
|
+
missing: boolean2(),
|
|
112852
|
+
recover: boolean2(),
|
|
112853
|
+
ok: boolean2(),
|
|
112854
|
+
created: boolean2(),
|
|
112855
|
+
skipped: boolean2(),
|
|
112856
|
+
slot: number2().int().min(0).max(7),
|
|
112857
|
+
error: _enum(["locked", "store", "not-owned", "exists", "missing", "denied", "refused"]),
|
|
112858
|
+
reason: string2(),
|
|
112859
|
+
status: number2()
|
|
112860
|
+
}).partial().strict();
|
|
112861
|
+
|
|
112862
|
+
class HelperProtocolError extends Error {
|
|
112863
|
+
}
|
|
112864
|
+
async function firstLine(stream) {
|
|
112865
|
+
const reader = stream.getReader();
|
|
112866
|
+
const decoder = new TextDecoder;
|
|
112867
|
+
let text = "";
|
|
112868
|
+
for (;; ) {
|
|
112869
|
+
const newline = text.indexOf(`
|
|
112870
|
+
`);
|
|
112871
|
+
if (newline !== -1)
|
|
112872
|
+
return text.slice(0, newline);
|
|
112873
|
+
const chunk = await reader.read();
|
|
112874
|
+
if (chunk.done)
|
|
112875
|
+
return null;
|
|
112876
|
+
text += decoder.decode(chunk.value, { stream: true });
|
|
112877
|
+
}
|
|
112878
|
+
}
|
|
112879
|
+
function isFlushable(stream) {
|
|
112880
|
+
return typeof stream.flush === "function";
|
|
112881
|
+
}
|
|
112882
|
+
var spawnDetachedHelper = (path) => {
|
|
112883
|
+
const child = spawn([path], {
|
|
112884
|
+
stdin: "pipe",
|
|
112885
|
+
stdout: "pipe",
|
|
112886
|
+
stderr: "ignore",
|
|
112887
|
+
detached: true,
|
|
112888
|
+
env: process.env.HOME === undefined ? {} : { HOME: process.env.HOME }
|
|
112889
|
+
});
|
|
112890
|
+
const pid = child.pid;
|
|
112891
|
+
if (pid === undefined)
|
|
112892
|
+
throw new HelperProtocolError("The keychain helper did not start.");
|
|
112893
|
+
const stdin = child.stdin;
|
|
112894
|
+
return {
|
|
112895
|
+
pid,
|
|
112896
|
+
send: (line) => {
|
|
112897
|
+
stdin.write(line);
|
|
112898
|
+
if (isFlushable(stdin))
|
|
112899
|
+
stdin.flush();
|
|
112900
|
+
},
|
|
112901
|
+
reply: firstLine(child.stdout),
|
|
112902
|
+
close: () => {
|
|
112903
|
+
stdin.end();
|
|
112904
|
+
}
|
|
112905
|
+
};
|
|
112742
112906
|
};
|
|
112743
|
-
|
|
112744
|
-
const
|
|
112745
|
-
|
|
112746
|
-
|
|
112747
|
-
|
|
112748
|
-
|
|
112749
|
-
|
|
112750
|
-
|
|
112751
|
-
|
|
112752
|
-
|
|
112753
|
-
|
|
112754
|
-
|
|
112755
|
-
|
|
112756
|
-
|
|
112757
|
-
|
|
112758
|
-
|
|
112759
|
-
|
|
112760
|
-
|
|
112761
|
-
|
|
112762
|
-
|
|
112907
|
+
async function callHelper(path, call, options = {}) {
|
|
112908
|
+
const mutates = MUTATING.has(call.verb);
|
|
112909
|
+
if (mutates && options.lease === undefined)
|
|
112910
|
+
throw new HelperProtocolError(`The ${call.verb} helper call needs the session lock.`);
|
|
112911
|
+
const helper = (options.spawn ?? spawnDetachedHelper)(path);
|
|
112912
|
+
let handedOver = false;
|
|
112913
|
+
try {
|
|
112914
|
+
if (mutates && options.lease !== undefined) {
|
|
112915
|
+
await options.lease.handOver(helper.pid);
|
|
112916
|
+
handedOver = true;
|
|
112917
|
+
}
|
|
112918
|
+
helper.send(`${JSON.stringify({ v: 1, verb: call.verb, account: call.account, ...call.value === undefined ? {} : { value: call.value } })}
|
|
112919
|
+
`);
|
|
112920
|
+
const line = await helper.reply;
|
|
112921
|
+
if (handedOver && options.lease !== undefined) {
|
|
112922
|
+
handedOver = false;
|
|
112923
|
+
await options.lease.restore();
|
|
112924
|
+
}
|
|
112925
|
+
if (line === null)
|
|
112926
|
+
throw new HelperProtocolError(`The keychain helper exited without answering ${call.verb}.`);
|
|
112927
|
+
let json;
|
|
112928
|
+
try {
|
|
112929
|
+
json = JSON.parse(line);
|
|
112930
|
+
} catch {
|
|
112931
|
+
throw new HelperProtocolError(`The keychain helper sent a ${call.verb} reply that is not JSON.`);
|
|
112932
|
+
}
|
|
112933
|
+
const parsed = helperReplySchema.safeParse(json);
|
|
112934
|
+
if (!parsed.success)
|
|
112935
|
+
throw new HelperProtocolError(`The keychain helper sent an unexpected ${call.verb} reply.`);
|
|
112936
|
+
return parsed.data;
|
|
112937
|
+
} catch (error) {
|
|
112938
|
+
if (handedOver && options.lease !== undefined) {
|
|
112939
|
+
try {
|
|
112940
|
+
await options.lease.restore();
|
|
112941
|
+
} catch (restoreError) {
|
|
112942
|
+
throw new AggregateError([error, restoreError], `The ${call.verb} helper call failed and the session lock could not be restored.`);
|
|
112943
|
+
}
|
|
112944
|
+
}
|
|
112945
|
+
throw error;
|
|
112946
|
+
} finally {
|
|
112947
|
+
helper.close();
|
|
112948
|
+
}
|
|
112949
|
+
}
|
|
112950
|
+
|
|
112951
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/location.ts
|
|
112952
|
+
import { dirname as dirname42, join as join106, posix as posix13 } from "node:path";
|
|
112953
|
+
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
112954
|
+
function bundleCandidates(moduleUrl) {
|
|
112955
|
+
const root = dirname42(dirname42(dirname42(fileURLToPath8(moduleUrl))));
|
|
112956
|
+
return [join106(root, "bin", "darwin", "omo-keychain"), join106(root, "omo-keychain")];
|
|
112957
|
+
}
|
|
112958
|
+
function machineCandidates(home, arch = process.arch) {
|
|
112959
|
+
const runtimeArch = arch === "arm64" ? "arm64" : "x64";
|
|
112960
|
+
return [
|
|
112961
|
+
`/Applications/OmO.app/Contents/Resources/omo-runtime/darwin-${runtimeArch}/omo-keychain`,
|
|
112962
|
+
posix13.join(home, "Applications", "OmO.app", "Contents", "Resources", "omo-runtime", `darwin-${runtimeArch}`, "omo-keychain"),
|
|
112963
|
+
posix13.join(home, ".bun", "install", "global", "node_modules", "omo-ai", "bin", "darwin", "omo-keychain")
|
|
112964
|
+
];
|
|
112965
|
+
}
|
|
112966
|
+
async function locateHelper(candidates, verify) {
|
|
112967
|
+
const rejected = [];
|
|
112968
|
+
for (const path of candidates) {
|
|
112969
|
+
const verdict = await verify(path);
|
|
112970
|
+
if (verdict === "valid")
|
|
112971
|
+
return { kind: "found", path };
|
|
112972
|
+
if (verdict === "invalid")
|
|
112973
|
+
rejected.push(path);
|
|
112974
|
+
}
|
|
112975
|
+
return rejected.length === 0 ? { kind: "missing" } : { kind: "invalid", rejected };
|
|
112976
|
+
}
|
|
112977
|
+
|
|
112978
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/pin.ts
|
|
112979
|
+
import { readdirSync as readdirSync14, rmSync as rmSync9 } from "node:fs";
|
|
112980
|
+
import { chmod as chmod2, copyFile as copyFile4, constants as constants13, mkdtemp as mkdtemp2, rm as rm16, stat as stat8 } from "node:fs/promises";
|
|
112981
|
+
import { tmpdir as tmpdir6 } from "node:os";
|
|
112982
|
+
import { basename as basename15, join as join107 } from "node:path";
|
|
112983
|
+
var DIR_PREFIX = "omo-keychain-";
|
|
112984
|
+
var OWNED_DIR = new RegExp(`^${DIR_PREFIX}(\\d+)-`);
|
|
112985
|
+
var isAlive = (pid) => {
|
|
112986
|
+
try {
|
|
112987
|
+
process.kill(pid, 0);
|
|
112988
|
+
return true;
|
|
112989
|
+
} catch (error) {
|
|
112990
|
+
return !(error instanceof Error && ("code" in error) && error.code === "ESRCH");
|
|
112991
|
+
}
|
|
112992
|
+
};
|
|
112993
|
+
function sweepDeadPinDirs(root = tmpdir6()) {
|
|
112994
|
+
const removed = [];
|
|
112995
|
+
let entries;
|
|
112996
|
+
try {
|
|
112997
|
+
entries = readdirSync14(root);
|
|
112998
|
+
} catch {
|
|
112999
|
+
return removed;
|
|
113000
|
+
}
|
|
113001
|
+
for (const entry of entries) {
|
|
113002
|
+
const owner = OWNED_DIR.exec(entry)?.[1];
|
|
113003
|
+
if (owner === undefined || Number(owner) === process.pid || isAlive(Number(owner)))
|
|
113004
|
+
continue;
|
|
113005
|
+
try {
|
|
113006
|
+
rmSync9(join107(root, entry), { recursive: true, force: true });
|
|
113007
|
+
} catch {
|
|
113008
|
+
continue;
|
|
113009
|
+
}
|
|
113010
|
+
removed.push(entry);
|
|
113011
|
+
}
|
|
113012
|
+
return removed;
|
|
113013
|
+
}
|
|
113014
|
+
var processDir;
|
|
113015
|
+
async function processPinDir() {
|
|
113016
|
+
if (processDir !== undefined)
|
|
113017
|
+
return processDir;
|
|
113018
|
+
sweepDeadPinDirs();
|
|
113019
|
+
const dir = await mkdtemp2(join107(tmpdir6(), `${DIR_PREFIX}${process.pid}-`));
|
|
113020
|
+
process.once("exit", () => rmSync9(dir, { recursive: true, force: true }));
|
|
113021
|
+
processDir = dir;
|
|
113022
|
+
return dir;
|
|
113023
|
+
}
|
|
113024
|
+
var pinned = new Map;
|
|
113025
|
+
async function sourceIdentity(source) {
|
|
113026
|
+
const info = await stat8(source);
|
|
113027
|
+
return `${source}\x00${info.dev}\x00${info.ino}\x00${info.size}\x00${info.mtimeMs}\x00${info.ctimeMs}`;
|
|
113028
|
+
}
|
|
113029
|
+
async function copyAndVerify(source, verify, dir) {
|
|
113030
|
+
const target = join107(dir, `${crypto.randomUUID()}-${basename15(source)}`);
|
|
113031
|
+
try {
|
|
113032
|
+
await copyFile4(source, target, constants13.COPYFILE_EXCL);
|
|
113033
|
+
await chmod2(target, 320);
|
|
113034
|
+
} catch (error) {
|
|
113035
|
+
await rm16(target, { force: true });
|
|
113036
|
+
return { kind: "unavailable", reason: error instanceof Error ? error.message : String(error) };
|
|
113037
|
+
}
|
|
113038
|
+
let verdict;
|
|
113039
|
+
try {
|
|
113040
|
+
verdict = await verify(target);
|
|
113041
|
+
} catch (error) {
|
|
113042
|
+
await rm16(target, { force: true });
|
|
113043
|
+
return { kind: "unavailable", reason: error instanceof Error ? error.message : String(error) };
|
|
113044
|
+
}
|
|
113045
|
+
if (verdict === "valid")
|
|
113046
|
+
return { kind: "pinned", path: target };
|
|
113047
|
+
await rm16(target, { force: true });
|
|
113048
|
+
return { kind: "invalid" };
|
|
113049
|
+
}
|
|
113050
|
+
async function pinVerifiedCopy(source, verify, dir) {
|
|
113051
|
+
let identity;
|
|
113052
|
+
try {
|
|
113053
|
+
identity = `${dir ?? ""}\x00${await sourceIdentity(source)}`;
|
|
113054
|
+
} catch (error) {
|
|
113055
|
+
return { kind: "unavailable", reason: error instanceof Error ? error.message : String(error) };
|
|
113056
|
+
}
|
|
113057
|
+
const known = pinned.get(identity);
|
|
113058
|
+
if (known !== undefined) {
|
|
113059
|
+
const result = await known;
|
|
113060
|
+
if (result.kind !== "pinned")
|
|
113061
|
+
return result;
|
|
113062
|
+
let verdict;
|
|
113063
|
+
try {
|
|
113064
|
+
verdict = await verify(result.path);
|
|
113065
|
+
} catch (error) {
|
|
113066
|
+
pinned.delete(identity);
|
|
113067
|
+
await rm16(result.path, { force: true });
|
|
113068
|
+
return { kind: "unavailable", reason: error instanceof Error ? error.message : String(error) };
|
|
113069
|
+
}
|
|
113070
|
+
if (verdict === "valid")
|
|
113071
|
+
return result;
|
|
113072
|
+
}
|
|
113073
|
+
const created = Promise.resolve(dir ?? processPinDir()).then((target) => copyAndVerify(source, verify, target), (error) => ({ kind: "unavailable", reason: error instanceof Error ? error.message : String(error) }));
|
|
113074
|
+
pinned.set(identity, created);
|
|
113075
|
+
const result = await created;
|
|
113076
|
+
if (result.kind !== "pinned")
|
|
113077
|
+
pinned.delete(identity);
|
|
113078
|
+
return result;
|
|
113079
|
+
}
|
|
113080
|
+
|
|
113081
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/signature.ts
|
|
113082
|
+
import { stat as stat9 } from "node:fs/promises";
|
|
113083
|
+
init_bun_spawn_shim();
|
|
113084
|
+
var KEYCHAIN_HELPER_REQUIREMENT = 'identifier "com.mengmota.omo-keychain-helper" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] ' + 'and certificate leaf[field.1.2.840.113635.100.6.1.13] and certificate leaf[subject.OU] = "523JNR86LZ"';
|
|
113085
|
+
var STRICT_ALL_ARCHITECTURES = 1 << 4 | 1 << 0;
|
|
113086
|
+
var UTF8 = 134217984;
|
|
113087
|
+
var security;
|
|
113088
|
+
async function loadSecurity() {
|
|
113089
|
+
if (security !== undefined)
|
|
113090
|
+
return security;
|
|
113091
|
+
try {
|
|
113092
|
+
const { dlopen, FFIType, ptr } = await loadBunFfi();
|
|
113093
|
+
const cf = dlopen("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", {
|
|
113094
|
+
CFStringCreateWithCString: { args: [FFIType.u64, FFIType.ptr, FFIType.u32], returns: FFIType.u64 },
|
|
113095
|
+
CFURLCreateFromFileSystemRepresentation: { args: [FFIType.u64, FFIType.ptr, FFIType.i64, FFIType.bool], returns: FFIType.u64 },
|
|
113096
|
+
CFRelease: { args: [FFIType.u64], returns: FFIType.void }
|
|
113097
|
+
});
|
|
113098
|
+
const sec = dlopen("/System/Library/Frameworks/Security.framework/Security", {
|
|
113099
|
+
SecStaticCodeCreateWithPath: { args: [FFIType.u64, FFIType.u32, FFIType.ptr], returns: FFIType.i32 },
|
|
113100
|
+
SecRequirementCreateWithString: { args: [FFIType.u64, FFIType.u32, FFIType.ptr], returns: FFIType.i32 },
|
|
113101
|
+
SecStaticCodeCheckValidityWithErrors: { args: [FFIType.u64, FFIType.u32, FFIType.u64, FFIType.u64], returns: FFIType.i32 }
|
|
113102
|
+
});
|
|
113103
|
+
const cString = (text) => Buffer.from(`${text}\x00`, "utf8");
|
|
113104
|
+
security = {
|
|
113105
|
+
check(path, requirement) {
|
|
113106
|
+
const pathBytes = Buffer.from(path, "utf8");
|
|
113107
|
+
const url = BigInt(cf.symbols.CFURLCreateFromFileSystemRepresentation(0n, ptr(pathBytes), pathBytes.length, false));
|
|
113108
|
+
const text = BigInt(cf.symbols.CFStringCreateWithCString(0n, ptr(cString(requirement)), UTF8));
|
|
113109
|
+
const codeOut = new BigUint64Array(1);
|
|
113110
|
+
const requirementOut = new BigUint64Array(1);
|
|
113111
|
+
try {
|
|
113112
|
+
if (url === 0n || text === 0n)
|
|
113113
|
+
return false;
|
|
113114
|
+
if (sec.symbols.SecStaticCodeCreateWithPath(url, 0, ptr(codeOut)) !== 0)
|
|
113115
|
+
return false;
|
|
113116
|
+
if (sec.symbols.SecRequirementCreateWithString(text, 0, ptr(requirementOut)) !== 0)
|
|
113117
|
+
return false;
|
|
113118
|
+
const code = codeOut[0] ?? 0n;
|
|
113119
|
+
const designated = requirementOut[0] ?? 0n;
|
|
113120
|
+
return sec.symbols.SecStaticCodeCheckValidityWithErrors(code, STRICT_ALL_ARCHITECTURES, designated, 0n) === 0;
|
|
113121
|
+
} finally {
|
|
113122
|
+
for (const ref of [url, text, codeOut[0] ?? 0n, requirementOut[0] ?? 0n])
|
|
113123
|
+
if (ref !== 0n)
|
|
113124
|
+
cf.symbols.CFRelease(ref);
|
|
113125
|
+
}
|
|
113126
|
+
}
|
|
113127
|
+
};
|
|
113128
|
+
} catch {
|
|
113129
|
+
security = null;
|
|
113130
|
+
}
|
|
113131
|
+
return security;
|
|
113132
|
+
}
|
|
113133
|
+
async function verifyWithCodesign(path, requirement) {
|
|
113134
|
+
const child = spawn(["/usr/bin/codesign", "--verify", "--strict", `-R=${requirement}`, path], {
|
|
113135
|
+
stdout: "ignore",
|
|
113136
|
+
stderr: "ignore",
|
|
113137
|
+
env: {}
|
|
112763
113138
|
});
|
|
112764
|
-
child.
|
|
112765
|
-
|
|
112766
|
-
|
|
113139
|
+
return await child.exited === 0;
|
|
113140
|
+
}
|
|
113141
|
+
var verifyWithSecurityFramework = async (path, requirement) => {
|
|
113142
|
+
const loaded = await loadSecurity();
|
|
113143
|
+
return loaded === null ? verifyWithCodesign(path, requirement) : loaded.check(path, requirement);
|
|
113144
|
+
};
|
|
113145
|
+
async function fileIdentity(path) {
|
|
113146
|
+
try {
|
|
113147
|
+
const info = await stat9(path);
|
|
113148
|
+
if (!info.isFile())
|
|
113149
|
+
return null;
|
|
113150
|
+
return `${path}\x00${info.dev}\x00${info.ino}\x00${info.size}\x00${info.mtimeMs}\x00${info.ctimeMs}`;
|
|
113151
|
+
} catch {
|
|
113152
|
+
return null;
|
|
113153
|
+
}
|
|
113154
|
+
}
|
|
113155
|
+
function createSignatureChecker(check = verifyWithSecurityFramework, requirement = KEYCHAIN_HELPER_REQUIREMENT) {
|
|
113156
|
+
const verdicts = new Map;
|
|
113157
|
+
const checker = async (path) => {
|
|
113158
|
+
const before = await fileIdentity(path);
|
|
113159
|
+
if (before === null)
|
|
113160
|
+
return "missing";
|
|
113161
|
+
const known = verdicts.get(before);
|
|
113162
|
+
if (known !== undefined)
|
|
113163
|
+
return known;
|
|
113164
|
+
const passed = await check(path, requirement);
|
|
113165
|
+
if (await fileIdentity(path) !== before)
|
|
113166
|
+
return "invalid";
|
|
113167
|
+
const verdict = passed ? "valid" : "invalid";
|
|
113168
|
+
verdicts.set(before, verdict);
|
|
113169
|
+
return verdict;
|
|
113170
|
+
};
|
|
113171
|
+
return checker;
|
|
113172
|
+
}
|
|
113173
|
+
var processChecker;
|
|
113174
|
+
var processSignatureChecker = () => processChecker ??= createSignatureChecker();
|
|
113175
|
+
|
|
113176
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/access.ts
|
|
113177
|
+
async function resolveHelperAccess(candidates, options = {}) {
|
|
113178
|
+
const verify = options.verify ?? processSignatureChecker();
|
|
113179
|
+
let source;
|
|
113180
|
+
let pin;
|
|
113181
|
+
try {
|
|
113182
|
+
const location = await locateHelper(candidates, verify);
|
|
113183
|
+
if (location.kind !== "found")
|
|
113184
|
+
return location;
|
|
113185
|
+
source = location.path;
|
|
113186
|
+
pin = await (options.pin ?? pinVerifiedCopy)(source, verify);
|
|
113187
|
+
} catch (error) {
|
|
113188
|
+
return { kind: "unavailable", reason: error instanceof Error ? error.message : String(error) };
|
|
113189
|
+
}
|
|
113190
|
+
if (pin.kind === "invalid")
|
|
113191
|
+
return { kind: "invalid", rejected: [source] };
|
|
113192
|
+
if (pin.kind === "unavailable")
|
|
113193
|
+
return { kind: "unavailable", reason: pin.reason };
|
|
113194
|
+
const pinned = pin.path;
|
|
113195
|
+
const spawn = options.spawn ?? spawnDetachedHelper;
|
|
113196
|
+
return {
|
|
113197
|
+
kind: "ready",
|
|
113198
|
+
path: pinned,
|
|
113199
|
+
call: async (call, lease) => {
|
|
113200
|
+
const verdict = await verify(pinned).catch((error) => {
|
|
113201
|
+
throw new HelperProtocolError(`OmO's keychain helper could not be checked before it ran: ${error instanceof Error ? error.message : String(error)}`);
|
|
113202
|
+
});
|
|
113203
|
+
if (verdict !== "valid")
|
|
113204
|
+
throw new HelperProtocolError("OmO's keychain helper changed on disk and failed its signature check; it was not run.");
|
|
113205
|
+
return callHelper(pinned, call, { spawn, ...lease === undefined ? {} : { lease } });
|
|
113206
|
+
}
|
|
113207
|
+
};
|
|
113208
|
+
}
|
|
113209
|
+
|
|
113210
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/approval-cache.ts
|
|
113211
|
+
var systemClock = { nowSeconds: () => Date.now() / 1000, sleepMs: (ms) => new Promise((resolve) => setTimeout(resolve, ms)) };
|
|
113212
|
+
function isEntryValid(entry, current, nowSeconds) {
|
|
113213
|
+
if (nowSeconds < entry.readStartedAt)
|
|
113214
|
+
return false;
|
|
113215
|
+
return current.cdat === entry.cdat && current.mdat === entry.mdat && Math.floor(current.mdat) < Math.floor(entry.readStartedAt);
|
|
113216
|
+
}
|
|
113217
|
+
function createApprovalCache(clock = systemClock) {
|
|
113218
|
+
let entry = null;
|
|
113219
|
+
let deniedForBackground = false;
|
|
113220
|
+
let pending = null;
|
|
113221
|
+
return {
|
|
113222
|
+
consume(current) {
|
|
113223
|
+
if (entry === null)
|
|
113224
|
+
return null;
|
|
113225
|
+
if (!isEntryValid(entry, current, clock.nowSeconds())) {
|
|
113226
|
+
entry = null;
|
|
113227
|
+
return null;
|
|
113228
|
+
}
|
|
113229
|
+
return entry.value;
|
|
113230
|
+
},
|
|
113231
|
+
deniedForBackground: () => deniedForBackground,
|
|
113232
|
+
inFlight: () => pending,
|
|
113233
|
+
approve(run) {
|
|
113234
|
+
if (pending !== null)
|
|
113235
|
+
return pending;
|
|
113236
|
+
const readStartedAt = clock.nowSeconds();
|
|
113237
|
+
const started = run().then((answer) => {
|
|
113238
|
+
if (answer.kind === "approved") {
|
|
113239
|
+
entry = { value: answer.value, ...answer.attributes, readStartedAt };
|
|
113240
|
+
deniedForBackground = false;
|
|
113241
|
+
} else if (answer.kind === "denied")
|
|
113242
|
+
deniedForBackground = true;
|
|
113243
|
+
return answer;
|
|
113244
|
+
});
|
|
113245
|
+
const settled = () => {
|
|
113246
|
+
if (pending === started)
|
|
113247
|
+
pending = null;
|
|
113248
|
+
};
|
|
113249
|
+
started.then(settled, settled);
|
|
113250
|
+
pending = started;
|
|
113251
|
+
return started;
|
|
113252
|
+
},
|
|
113253
|
+
async afterOwnWrite(value, readAttributes) {
|
|
113254
|
+
if (entry === null)
|
|
113255
|
+
return;
|
|
113256
|
+
const written = await readAttributes();
|
|
113257
|
+
if (written === null) {
|
|
113258
|
+
entry = null;
|
|
113259
|
+
return;
|
|
113260
|
+
}
|
|
113261
|
+
while (Math.floor(clock.nowSeconds()) <= Math.floor(written.mdat)) {
|
|
113262
|
+
await clock.sleepMs(Math.max(1, Math.ceil((Math.floor(written.mdat) + 1 - clock.nowSeconds()) * 1000)));
|
|
113263
|
+
}
|
|
113264
|
+
const readStartedAt = clock.nowSeconds();
|
|
113265
|
+
const fresh = await readAttributes();
|
|
113266
|
+
entry = fresh === null ? null : { value, ...fresh, readStartedAt };
|
|
113267
|
+
},
|
|
113268
|
+
drop() {
|
|
113269
|
+
entry = null;
|
|
113270
|
+
}
|
|
113271
|
+
};
|
|
113272
|
+
}
|
|
113273
|
+
var processApprovalCache = () => {
|
|
113274
|
+
const state = keychainProcessState();
|
|
113275
|
+
state.approvalCache ??= createApprovalCache();
|
|
113276
|
+
return state.approvalCache;
|
|
113277
|
+
};
|
|
113278
|
+
|
|
113279
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/darwin-read.ts
|
|
113280
|
+
var ROW_8B_DEFAULT = "re-login";
|
|
113281
|
+
|
|
113282
|
+
class HelperReadError extends Error {
|
|
113283
|
+
failure;
|
|
113284
|
+
constructor(failure, message) {
|
|
113285
|
+
super(message);
|
|
113286
|
+
this.failure = failure;
|
|
113287
|
+
}
|
|
113288
|
+
}
|
|
113289
|
+
function failure2(reply) {
|
|
113290
|
+
if (reply.error === "locked")
|
|
113291
|
+
return new HelperReadError("locked", "The keychain is locked.");
|
|
113292
|
+
return new HelperReadError("store", `The keychain helper answered ${reply.error ?? "unexpectedly"}.`);
|
|
113293
|
+
}
|
|
113294
|
+
async function approveOnce(deps) {
|
|
113295
|
+
const running = deps.cache.inFlight();
|
|
113296
|
+
if (running !== null)
|
|
113297
|
+
return running;
|
|
113298
|
+
const release = await deps.takePromptLock();
|
|
113299
|
+
if (release === null)
|
|
113300
|
+
throw new HelperReadError("pending", "Another omo process is waiting for your keychain approval.");
|
|
113301
|
+
try {
|
|
113302
|
+
return await deps.cache.approve(async () => {
|
|
113303
|
+
const reply = await deps.access.call({ verb: "approve", account: deps.account });
|
|
113304
|
+
if (reply.missing === true)
|
|
113305
|
+
return { kind: "missing" };
|
|
113306
|
+
if (reply.error === "denied")
|
|
113307
|
+
return { kind: "denied" };
|
|
113308
|
+
if (reply.error !== undefined || reply.value === undefined || reply.cdat === undefined || reply.mdat === undefined)
|
|
113309
|
+
throw failure2(reply);
|
|
113310
|
+
return { kind: "approved", value: reply.value, attributes: { cdat: reply.cdat, mdat: reply.mdat } };
|
|
113311
|
+
});
|
|
113312
|
+
} finally {
|
|
113313
|
+
await release();
|
|
113314
|
+
}
|
|
113315
|
+
}
|
|
113316
|
+
async function readThroughHelper(deps, allowPrompt) {
|
|
113317
|
+
const reply = await deps.access.call({ verb: "read", account: deps.account });
|
|
113318
|
+
if (reply.error !== undefined)
|
|
113319
|
+
throw failure2(reply);
|
|
113320
|
+
if (reply.missing === true)
|
|
113321
|
+
return { kind: "missing", reply };
|
|
113322
|
+
if (reply.owned === true && reply.value !== undefined)
|
|
113323
|
+
return { kind: "value", value: reply.value, source: reply.marker === true || reply.recover === true ? "owned" : "owned-unmarked", reply };
|
|
113324
|
+
const own = await deps.ownSilentGet().catch(() => {
|
|
113325
|
+
return;
|
|
112767
113326
|
});
|
|
112768
|
-
|
|
112769
|
-
|
|
112770
|
-
|
|
113327
|
+
if (typeof own === "string")
|
|
113328
|
+
return { kind: "value", value: own, source: "own-identity", reply };
|
|
113329
|
+
if (reply.cdat === undefined || reply.mdat === undefined)
|
|
113330
|
+
throw failure2(reply);
|
|
113331
|
+
const cached = deps.cache.consume({ cdat: reply.cdat, mdat: reply.mdat });
|
|
113332
|
+
if (cached !== null)
|
|
113333
|
+
return { kind: "value", value: cached, source: "approved", reply };
|
|
113334
|
+
const reloginInstead = reply.partition !== "ours" && reply.partition !== "none" && (deps.row8b ?? ROW_8B_DEFAULT) === "re-login";
|
|
113335
|
+
if (!allowPrompt) {
|
|
113336
|
+
if (reloginInstead)
|
|
113337
|
+
return { kind: "missing", reply };
|
|
113338
|
+
throw new HelperReadError("pending", "The keychain needs your approval; run an omo command in a terminal.");
|
|
113339
|
+
}
|
|
113340
|
+
if (deps.background && deps.cache.deniedForBackground())
|
|
113341
|
+
throw new HelperReadError("pending", "Keychain access was denied; run an omo command in a terminal to approve it.");
|
|
113342
|
+
if (reloginInstead)
|
|
113343
|
+
return { kind: "missing", reply };
|
|
113344
|
+
if (deps.noDialog === true)
|
|
113345
|
+
throw new HelperReadError("pending", "The keychain hand-off cannot show a dialog.");
|
|
113346
|
+
if (deps.handOff !== undefined && await deps.handOff()) {
|
|
113347
|
+
const after = await deps.access.call({ verb: "read", account: deps.account });
|
|
113348
|
+
if (after.owned === true && after.value !== undefined)
|
|
113349
|
+
return { kind: "value", value: after.value, source: "owned", reply: after };
|
|
113350
|
+
}
|
|
113351
|
+
const answer = await approveOnce(deps);
|
|
113352
|
+
if (answer.kind === "approved")
|
|
113353
|
+
return { kind: "value", value: answer.value, source: "approved", reply };
|
|
113354
|
+
if (answer.kind === "missing")
|
|
113355
|
+
return { kind: "missing", reply };
|
|
113356
|
+
throw new HelperReadError("denied", "Keychain access was denied.");
|
|
113357
|
+
}
|
|
113358
|
+
|
|
113359
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/recovery.ts
|
|
113360
|
+
var OLD_SLOT_COUNT = 8;
|
|
113361
|
+
var oldSlotName = (account, slot) => slot === 0 ? `${account}.old` : `${account}.old.${slot}`;
|
|
113362
|
+
function recoveryPlan(names) {
|
|
113363
|
+
if (!names.original && names.staging)
|
|
113364
|
+
return names.old ? ["promote", "delete-old"] : ["promote"];
|
|
113365
|
+
if (!names.original && names.old)
|
|
113366
|
+
return ["delete-old"];
|
|
113367
|
+
if (names.original && names.staging)
|
|
113368
|
+
return names.old ? ["remove-staging", "delete-old"] : ["remove-staging"];
|
|
113369
|
+
if (names.original && names.old)
|
|
113370
|
+
return ["delete-old"];
|
|
113371
|
+
return [];
|
|
113372
|
+
}
|
|
113373
|
+
function oldSlotsOf(reply) {
|
|
113374
|
+
return reply.present?.oldSlots ?? (reply.present?.old === true ? [0] : []);
|
|
113375
|
+
}
|
|
113376
|
+
function namesFromRead(reply) {
|
|
113377
|
+
const original = reply.owned === false || reply.owned === true && reply.recover !== true;
|
|
113378
|
+
return { original, staging: reply.present?.staging === true, old: reply.present?.old === true, oldSlots: oldSlotsOf(reply) };
|
|
113379
|
+
}
|
|
113380
|
+
async function deleteOld(name, helper, deleteOwn) {
|
|
113381
|
+
const removed = await helper({ verb: "remove", account: name }).catch(() => null);
|
|
113382
|
+
if (removed?.ok === true)
|
|
113383
|
+
return true;
|
|
113384
|
+
return deleteOwn(name).catch(() => false);
|
|
113385
|
+
}
|
|
113386
|
+
async function deleteOldSlots(account, slots, helper, deleteOwn) {
|
|
113387
|
+
let cleared = true;
|
|
113388
|
+
for (const slot of slots)
|
|
113389
|
+
if (!await deleteOld(oldSlotName(account, slot), helper, deleteOwn))
|
|
113390
|
+
cleared = false;
|
|
113391
|
+
return cleared;
|
|
113392
|
+
}
|
|
113393
|
+
async function runRecovery(account, names, helper, deleteOwnOld) {
|
|
113394
|
+
const applied = [];
|
|
113395
|
+
for (const step of recoveryPlan(names)) {
|
|
113396
|
+
const ok = step === "promote" ? (await helper({ verb: "promote", account })).ok === true : step === "remove-staging" ? (await helper({ verb: "remove", account: `${account}.staging` })).ok === true : await deleteOldSlots(account, names.oldSlots, helper, deleteOwnOld);
|
|
113397
|
+
if (!ok && step !== "delete-old")
|
|
113398
|
+
return { applied, failed: step };
|
|
113399
|
+
if (ok)
|
|
113400
|
+
applied.push(step);
|
|
113401
|
+
}
|
|
113402
|
+
return { applied, failed: null };
|
|
113403
|
+
}
|
|
113404
|
+
|
|
113405
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/migration.ts
|
|
113406
|
+
var MIGRATABLE = new Set(["own-identity", "owned-unmarked", "approved"]);
|
|
113407
|
+
async function migrate(account, value, source, helper, deleteOwnOld) {
|
|
113408
|
+
if (!MIGRATABLE.has(source))
|
|
113409
|
+
return { kind: "skipped", reason: "not-migratable" };
|
|
113410
|
+
if ((await helper({ verb: "stage", account, value })).ok !== true)
|
|
113411
|
+
return { kind: "failed", step: "stage" };
|
|
113412
|
+
const retired = await helper({ verb: "retire", account });
|
|
113413
|
+
if (retired.error === "exists" && retired.reason === "old-slots-full" || retired.ok === true && retired.skipped === true) {
|
|
113414
|
+
await helper({ verb: "remove", account: `${account}.staging` });
|
|
113415
|
+
return { kind: "skipped", reason: "old-slots-full" };
|
|
113416
|
+
}
|
|
113417
|
+
if (retired.ok !== true)
|
|
113418
|
+
return { kind: "failed", step: "retire" };
|
|
113419
|
+
const slot = retired.slot ?? 0;
|
|
113420
|
+
if ((await helper({ verb: "promote", account })).ok !== true)
|
|
113421
|
+
return { kind: "failed", step: "promote" };
|
|
113422
|
+
return { kind: "migrated", oldDeleted: await deleteOld(oldSlotName(account, slot), helper, deleteOwnOld) };
|
|
113423
|
+
}
|
|
113424
|
+
|
|
113425
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/darwin-store.ts
|
|
113426
|
+
class HelperOldSlotsFull extends Error {
|
|
113427
|
+
}
|
|
113428
|
+
var ALL_OLD_SLOTS = Array.from({ length: OLD_SLOT_COUNT }, (_, slot) => slot);
|
|
113429
|
+
var OLD_SLOTS_FULL_MESSAGE = 'The macOS keychain holds 8 earlier OmO sign-ins that cannot be removed automatically. Open Keychain Access, delete the items whose account name ends in ".old" or ".old.1" to ".old.7" for OmO, then sign in again.';
|
|
113430
|
+
var failed = (reply, verb) => new HelperReadError(reply.error === "locked" ? "locked" : "store", `The keychain helper could not ${verb} the sign-in (${reply.error ?? "no answer"}).`);
|
|
113431
|
+
function lockedDarwinStore(deps, lease) {
|
|
113432
|
+
const helper = (call) => deps.access.call(call, lease);
|
|
113433
|
+
const deleteOwnOld = (name) => deps.ownDelete(name);
|
|
113434
|
+
let lastRead = null;
|
|
113435
|
+
const read = async () => {
|
|
113436
|
+
const result = await readThroughHelper(deps, false);
|
|
113437
|
+
lastRead = result.kind === "value" ? result : null;
|
|
113438
|
+
return result.kind === "value" ? result.value : null;
|
|
113439
|
+
};
|
|
113440
|
+
return {
|
|
113441
|
+
async recover() {
|
|
113442
|
+
const reply = await deps.access.call({ verb: "read", account: deps.account });
|
|
113443
|
+
if (reply.error === undefined)
|
|
113444
|
+
await runRecovery(deps.account, namesFromRead(reply), helper, deleteOwnOld);
|
|
113445
|
+
},
|
|
113446
|
+
read,
|
|
113447
|
+
async settle() {
|
|
113448
|
+
if (lastRead === null)
|
|
113449
|
+
return;
|
|
113450
|
+
const outcome = await migrate(deps.account, lastRead.value, lastRead.source, helper, deleteOwnOld);
|
|
113451
|
+
if (outcome.kind === "skipped" && outcome.reason === "old-slots-full")
|
|
113452
|
+
deps.notice(`omo: ${OLD_SLOTS_FULL_MESSAGE}`);
|
|
113453
|
+
if (outcome.kind === "failed")
|
|
113454
|
+
deps.notice(`omo: the macOS keychain item could not be moved to OmO's keychain helper (${outcome.step}); it keeps working as before.`);
|
|
113455
|
+
},
|
|
113456
|
+
async write(value, intent, beforeRetire) {
|
|
113457
|
+
const state = await deps.access.call({ verb: "read", account: deps.account });
|
|
113458
|
+
if (state.error !== undefined)
|
|
113459
|
+
throw failed(state, "check");
|
|
113460
|
+
if (state.owned === false) {
|
|
113461
|
+
const approved = state.cdat !== undefined && state.mdat !== undefined && deps.cache.consume({ cdat: state.cdat, mdat: state.mdat }) !== null;
|
|
113462
|
+
const readable = lastRead !== null || approved || await deps.ownSilentGet().catch(() => {
|
|
113463
|
+
return;
|
|
113464
|
+
}) !== undefined;
|
|
113465
|
+
if (readable || intent !== "fresh-sign-in") {
|
|
113466
|
+
await deps.ownOverwrite(value);
|
|
113467
|
+
if (lastRead?.source === "approved")
|
|
113468
|
+
await deps.cache.afterOwnWrite(value, async () => {
|
|
113469
|
+
const after = await deps.access.call({ verb: "read", account: deps.account });
|
|
113470
|
+
return after.cdat === undefined || after.mdat === undefined ? null : { cdat: after.cdat, mdat: after.mdat };
|
|
113471
|
+
});
|
|
113472
|
+
return;
|
|
113473
|
+
}
|
|
113474
|
+
await beforeRetire?.();
|
|
113475
|
+
const retired = await helper({ verb: "retire", account: deps.account });
|
|
113476
|
+
if (retired.reason === "old-slots-full" || retired.ok === true && retired.skipped === true)
|
|
113477
|
+
throw new HelperOldSlotsFull(OLD_SLOTS_FULL_MESSAGE);
|
|
113478
|
+
if (retired.ok !== true)
|
|
113479
|
+
throw failed(retired, "replace");
|
|
113480
|
+
}
|
|
113481
|
+
const written = await helper({ verb: "write", account: deps.account, value });
|
|
113482
|
+
if (written.ok !== true)
|
|
113483
|
+
throw failed(written, "save");
|
|
113484
|
+
lastRead = { kind: "value", value, source: "owned", reply: written };
|
|
113485
|
+
},
|
|
113486
|
+
async clear() {
|
|
113487
|
+
const removed = await helper({ verb: "remove", account: deps.account });
|
|
113488
|
+
if (removed.error === "not-owned")
|
|
113489
|
+
await deps.ownDelete(deps.account);
|
|
113490
|
+
else if (removed.ok !== true)
|
|
113491
|
+
throw failed(removed, "remove");
|
|
113492
|
+
await helper({ verb: "remove", account: `${deps.account}.staging` });
|
|
113493
|
+
const present = await helper({ verb: "read", account: deps.account });
|
|
113494
|
+
const slots = present.error === undefined ? oldSlotsOf(present) : ALL_OLD_SLOTS;
|
|
113495
|
+
await deleteOldSlots(deps.account, slots, helper, deleteOwnOld);
|
|
113496
|
+
lastRead = null;
|
|
113497
|
+
}
|
|
113498
|
+
};
|
|
113499
|
+
}
|
|
113500
|
+
|
|
113501
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/owner-marker.ts
|
|
113502
|
+
init_bun_spawn_shim();
|
|
113503
|
+
var MARKER_LINE = /^\s*"gena"<blob>="omo-owner\/1"\s*$/m;
|
|
113504
|
+
var ITEM_NOT_FOUND = 44;
|
|
113505
|
+
var probeOwnerMarker = async (service, account, keychain) => {
|
|
113506
|
+
const args = ["find-generic-password", "-s", service, "-a", account, ...keychain === undefined ? [] : [keychain]];
|
|
113507
|
+
const child = spawn(["/usr/bin/security", ...args], {
|
|
113508
|
+
stdout: "pipe",
|
|
113509
|
+
stderr: "ignore",
|
|
113510
|
+
env: process.env.HOME === undefined ? {} : { HOME: process.env.HOME }
|
|
112771
113511
|
});
|
|
112772
|
-
|
|
113512
|
+
const [stdout, code] = await Promise.all([new Response(child.stdout).text(), child.exited]);
|
|
113513
|
+
if (code === ITEM_NOT_FOUND)
|
|
113514
|
+
return "absent";
|
|
113515
|
+
if (code !== 0)
|
|
113516
|
+
return "unknown";
|
|
113517
|
+
return MARKER_LINE.test(stdout) ? "helper-owned" : "other";
|
|
113518
|
+
};
|
|
112773
113519
|
|
|
112774
|
-
// packages/omo-opencode/src/cli/service-auth/
|
|
112775
|
-
import { AsyncLocalStorage as AsyncLocalStorage3 } from "node:async_hooks";
|
|
112776
|
-
import { createHash as createHash11 } from "node:crypto";
|
|
113520
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/prompt-lock.ts
|
|
112777
113521
|
import { mkdir as mkdir11 } from "node:fs/promises";
|
|
112778
|
-
import {
|
|
112779
|
-
import { join as join106 } from "node:path";
|
|
113522
|
+
import { dirname as dirname45 } from "node:path";
|
|
112780
113523
|
|
|
112781
113524
|
// packages/team-core/src/team-state-store/lock-publish.ts
|
|
112782
|
-
import { access as
|
|
112783
|
-
import { dirname as
|
|
113525
|
+
import { access as access5, open as open3, unlink as unlink4 } from "node:fs/promises";
|
|
113526
|
+
import { dirname as dirname43 } from "node:path";
|
|
112784
113527
|
|
|
112785
113528
|
// packages/team-core/src/team-state-store/lock-record.ts
|
|
112786
113529
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
112787
|
-
import { readFile as
|
|
113530
|
+
import { readFile as readFile35, stat as stat11 } from "node:fs/promises";
|
|
112788
113531
|
|
|
112789
113532
|
// packages/memory-core/src/locks/process-identity.ts
|
|
112790
113533
|
import { execFile as execFile7 } from "node:child_process";
|
|
@@ -112823,6 +113566,24 @@ function retryOnEintrSync(operation) {
|
|
|
112823
113566
|
|
|
112824
113567
|
// packages/memory-core/src/fs/rename-contention.ts
|
|
112825
113568
|
var CONTENTION_CODES = new Set(["EPERM", "EBUSY", "EACCES"]);
|
|
113569
|
+
var CONTENTION_DELAYS_MS = [10, 25, 50, 100, 200, 400];
|
|
113570
|
+
var sleepFor = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
113571
|
+
async function renameWithContentionRetry(from, to, deps) {
|
|
113572
|
+
const delays = deps.platform === "win32" ? deps.delaysMs ?? CONTENTION_DELAYS_MS : [];
|
|
113573
|
+
const sleep = deps.sleep ?? sleepFor;
|
|
113574
|
+
for (let attempt = 0;; attempt += 1) {
|
|
113575
|
+
try {
|
|
113576
|
+
await retryOnEintr(() => deps.admit === undefined ? deps.rename(from, to) : deps.admit(() => deps.rename(from, to)));
|
|
113577
|
+
return;
|
|
113578
|
+
} catch (error) {
|
|
113579
|
+
const delay = delays[attempt];
|
|
113580
|
+
const code = fsErrorCode(error);
|
|
113581
|
+
if (delay === undefined || code === undefined || !CONTENTION_CODES.has(code))
|
|
113582
|
+
throw error;
|
|
113583
|
+
await sleep(delay);
|
|
113584
|
+
}
|
|
113585
|
+
}
|
|
113586
|
+
}
|
|
112826
113587
|
|
|
112827
113588
|
// packages/memory-core/src/fs/resilient.ts
|
|
112828
113589
|
function isFunction2(value) {
|
|
@@ -112855,25 +113616,32 @@ function resilientNamespace(namespace, kind) {
|
|
|
112855
113616
|
}
|
|
112856
113617
|
var IDEMPOTENT_HANDLE_METHODS = new Set(["stat", "sync", "datasync", "chmod", "chown", "utimes", "truncate"]);
|
|
112857
113618
|
var promises = resilientNamespace(fsp, "async");
|
|
113619
|
+
function rename8(from, to, admit) {
|
|
113620
|
+
return renameWithContentionRetry(from, to, {
|
|
113621
|
+
rename: (source, target) => fsp.rename(source, target),
|
|
113622
|
+
platform: process.platform,
|
|
113623
|
+
...admit === undefined ? {} : { admit }
|
|
113624
|
+
});
|
|
113625
|
+
}
|
|
112858
113626
|
var sync = resilientNamespace(fsSync, "sync");
|
|
112859
113627
|
var {
|
|
112860
|
-
access:
|
|
112861
|
-
chmod:
|
|
112862
|
-
copyFile:
|
|
113628
|
+
access: access4,
|
|
113629
|
+
chmod: chmod3,
|
|
113630
|
+
copyFile: copyFile5,
|
|
112863
113631
|
cp: cp5,
|
|
112864
113632
|
link,
|
|
112865
113633
|
lstat: lstat18,
|
|
112866
113634
|
mkdir: mkdir10,
|
|
112867
|
-
mkdtemp:
|
|
112868
|
-
readFile:
|
|
113635
|
+
mkdtemp: mkdtemp3,
|
|
113636
|
+
readFile: readFile34,
|
|
112869
113637
|
readdir: readdir17,
|
|
112870
113638
|
readlink: readlink7,
|
|
112871
113639
|
realpath: realpath2,
|
|
112872
|
-
rm:
|
|
113640
|
+
rm: rm17,
|
|
112873
113641
|
rmdir: rmdir2,
|
|
112874
|
-
stat:
|
|
113642
|
+
stat: stat10,
|
|
112875
113643
|
statfs,
|
|
112876
|
-
unlink:
|
|
113644
|
+
unlink: unlink3
|
|
112877
113645
|
} = promises;
|
|
112878
113646
|
var {
|
|
112879
113647
|
accessSync: accessSync5,
|
|
@@ -112883,7 +113651,7 @@ var {
|
|
|
112883
113651
|
lstatSync: lstatSync5,
|
|
112884
113652
|
mkdirSync: mkdirSync19,
|
|
112885
113653
|
readFileSync: readFileSync44,
|
|
112886
|
-
readdirSync:
|
|
113654
|
+
readdirSync: readdirSync15,
|
|
112887
113655
|
realpathSync: realpathSync13,
|
|
112888
113656
|
statSync: statSync8,
|
|
112889
113657
|
unlinkSync: unlinkSync10,
|
|
@@ -112996,7 +113764,7 @@ async function execFileText(command, args) {
|
|
|
112996
113764
|
}
|
|
112997
113765
|
async function readLinuxStartIdentity(pid) {
|
|
112998
113766
|
try {
|
|
112999
|
-
const stat = await
|
|
113767
|
+
const stat = await readFile34(`/proc/${pid}/stat`, "utf8");
|
|
113000
113768
|
const commandEnd = stat.lastIndexOf(")");
|
|
113001
113769
|
if (commandEnd < 0)
|
|
113002
113770
|
return null;
|
|
@@ -113235,14 +114003,17 @@ async function isWorkerLockReleased(incarnation, record) {
|
|
|
113235
114003
|
// packages/team-core/src/team-state-store/lock-record.ts
|
|
113236
114004
|
async function buildLockRecord(ownerTag) {
|
|
113237
114005
|
await registerLockWorker();
|
|
113238
|
-
const processStart = await
|
|
114006
|
+
const processStart = await lockProcessStartLine(process.pid);
|
|
113239
114007
|
return `${ownerTag} ${randomUUID6()}
|
|
113240
114008
|
${process.pid}
|
|
113241
114009
|
${Date.now()}
|
|
113242
114010
|
${lockOwnerInstanceId}
|
|
113243
|
-
${processStart
|
|
114011
|
+
${processStart}
|
|
113244
114012
|
`;
|
|
113245
114013
|
}
|
|
114014
|
+
async function lockProcessStartLine(pid) {
|
|
114015
|
+
return await getProcessStartIdentity(pid) ?? "unavailable";
|
|
114016
|
+
}
|
|
113246
114017
|
function errorCode2(error) {
|
|
113247
114018
|
if (!(error instanceof Error) || !("code" in error))
|
|
113248
114019
|
return null;
|
|
@@ -113271,8 +114042,8 @@ function parseLockOwner(content) {
|
|
|
113271
114042
|
}
|
|
113272
114043
|
async function readLockRecord(lockPath) {
|
|
113273
114044
|
try {
|
|
113274
|
-
const content = await
|
|
113275
|
-
const { mtimeMs } = await
|
|
114045
|
+
const content = await readFile35(lockPath, "utf8");
|
|
114046
|
+
const { mtimeMs } = await stat11(lockPath);
|
|
113276
114047
|
return { content, modifiedAtEpochMs: mtimeMs };
|
|
113277
114048
|
} catch (error) {
|
|
113278
114049
|
if (!(error instanceof Error))
|
|
@@ -113303,7 +114074,7 @@ async function isLockRecordStale(record, staleAfterMs) {
|
|
|
113303
114074
|
|
|
113304
114075
|
// packages/team-core/src/team-state-store/lock-publish.ts
|
|
113305
114076
|
async function pathMayExist(path, deps = {}) {
|
|
113306
|
-
const accessPath = deps.access ??
|
|
114077
|
+
const accessPath = deps.access ?? access5;
|
|
113307
114078
|
try {
|
|
113308
114079
|
await accessPath(path);
|
|
113309
114080
|
return true;
|
|
@@ -113320,7 +114091,7 @@ async function assertRetryableLockOpenError(lockPath, error, deps) {
|
|
|
113320
114091
|
if (code === "EPERM") {
|
|
113321
114092
|
if (await pathMayExist(lockPath, deps))
|
|
113322
114093
|
return;
|
|
113323
|
-
if ((deps?.platform ?? process.platform) === "win32" && await pathMayExist(
|
|
114094
|
+
if ((deps?.platform ?? process.platform) === "win32" && await pathMayExist(dirname43(lockPath), deps))
|
|
113324
114095
|
return;
|
|
113325
114096
|
}
|
|
113326
114097
|
throw error;
|
|
@@ -113340,7 +114111,7 @@ async function publishLockRecord(lockPath, record) {
|
|
|
113340
114111
|
} catch (error) {
|
|
113341
114112
|
markLockRecordReleased(record);
|
|
113342
114113
|
await fileHandle.close();
|
|
113343
|
-
await
|
|
114114
|
+
await unlink4(lockPath).catch(() => {
|
|
113344
114115
|
return;
|
|
113345
114116
|
});
|
|
113346
114117
|
throw error;
|
|
@@ -113349,9 +114120,14 @@ async function publishLockRecord(lockPath, record) {
|
|
|
113349
114120
|
return true;
|
|
113350
114121
|
}
|
|
113351
114122
|
|
|
114123
|
+
// packages/team-core/src/team-state-store/lock-lease.ts
|
|
114124
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
114125
|
+
import { open as open4, readdir as readdir18, readFile as readFile36, rename as rename9, rm as rm18 } from "node:fs/promises";
|
|
114126
|
+
import { basename as basename16, dirname as dirname44, join as join108 } from "node:path";
|
|
114127
|
+
|
|
113352
114128
|
// packages/team-core/src/team-state-store/lock-reclaim.ts
|
|
113353
114129
|
import { createHash as createHash10 } from "node:crypto";
|
|
113354
|
-
import { unlink as
|
|
114130
|
+
import { unlink as unlink5 } from "node:fs/promises";
|
|
113355
114131
|
var RECLAIM_UNLINK_ATTEMPTS = 3;
|
|
113356
114132
|
var RECLAIM_UNLINK_RETRY_MS = 25;
|
|
113357
114133
|
function delay2(ms) {
|
|
@@ -113364,7 +114140,7 @@ function reclaimGuardPath(lockPath, record) {
|
|
|
113364
114140
|
}
|
|
113365
114141
|
async function unlinkWithRetry(path, deps) {
|
|
113366
114142
|
const wait = deps.delay ?? delay2;
|
|
113367
|
-
const unlinkFile = deps.unlink ??
|
|
114143
|
+
const unlinkFile = deps.unlink ?? unlink5;
|
|
113368
114144
|
for (let attempt = 1;; attempt += 1) {
|
|
113369
114145
|
try {
|
|
113370
114146
|
await unlinkFile(path);
|
|
@@ -113382,6 +114158,19 @@ async function unlinkWithRetry(path, deps) {
|
|
|
113382
114158
|
}
|
|
113383
114159
|
}
|
|
113384
114160
|
async function removeLockRecordIfUnchanged(lockPath, expectedRecord, staleAfterMs, deps = {}) {
|
|
114161
|
+
return withRecordGuard(lockPath, expectedRecord, staleAfterMs, deps, async () => {
|
|
114162
|
+
const current = await readLockRecord(lockPath);
|
|
114163
|
+
if (current === null)
|
|
114164
|
+
return "absent";
|
|
114165
|
+
if (current.content !== expectedRecord || !await isLockRecordStale(current, staleAfterMs))
|
|
114166
|
+
return "changed";
|
|
114167
|
+
const unlinked = await unlinkWithRetry(lockPath, deps);
|
|
114168
|
+
if (unlinked !== "stuck")
|
|
114169
|
+
forgetLockRecord(expectedRecord);
|
|
114170
|
+
return unlinked === "absent" ? "absent" : unlinked;
|
|
114171
|
+
});
|
|
114172
|
+
}
|
|
114173
|
+
async function withRecordGuard(lockPath, expectedRecord, staleAfterMs, deps, act) {
|
|
113385
114174
|
const guardPath = reclaimGuardPath(lockPath, expectedRecord);
|
|
113386
114175
|
const guardRecord = await buildLockRecord("lock-reclaim");
|
|
113387
114176
|
if (!await publishLockRecord(guardPath, guardRecord)) {
|
|
@@ -113392,15 +114181,7 @@ async function removeLockRecordIfUnchanged(lockPath, expectedRecord, staleAfterM
|
|
|
113392
114181
|
return "busy";
|
|
113393
114182
|
}
|
|
113394
114183
|
try {
|
|
113395
|
-
|
|
113396
|
-
if (current === null)
|
|
113397
|
-
return "absent";
|
|
113398
|
-
if (current.content !== expectedRecord || !await isLockRecordStale(current, staleAfterMs))
|
|
113399
|
-
return "changed";
|
|
113400
|
-
const unlinked = await unlinkWithRetry(lockPath, deps);
|
|
113401
|
-
if (unlinked !== "stuck")
|
|
113402
|
-
forgetLockRecord(expectedRecord);
|
|
113403
|
-
return unlinked === "absent" ? "absent" : unlinked;
|
|
114184
|
+
return await act();
|
|
113404
114185
|
} finally {
|
|
113405
114186
|
markLockRecordReleased(guardRecord);
|
|
113406
114187
|
if (await unlinkWithRetry(guardPath, deps) !== "stuck")
|
|
@@ -113408,6 +114189,97 @@ async function removeLockRecordIfUnchanged(lockPath, expectedRecord, staleAfterM
|
|
|
113408
114189
|
}
|
|
113409
114190
|
}
|
|
113410
114191
|
|
|
114192
|
+
// packages/team-core/src/team-state-store/lock-lease.ts
|
|
114193
|
+
class LockLeaseLostError extends Error {
|
|
114194
|
+
constructor(lockPath) {
|
|
114195
|
+
super(`The lock at ${lockPath} changed while it was handed over; the critical section was aborted.`);
|
|
114196
|
+
this.name = "LockLeaseLostError";
|
|
114197
|
+
}
|
|
114198
|
+
}
|
|
114199
|
+
var leaseTempPrefix = (lockPath) => `.${basename16(lockPath)}.`;
|
|
114200
|
+
var LEASE_TEMP_SUFFIX = ".lease";
|
|
114201
|
+
var UUID2 = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
|
114202
|
+
var escapeRegExp2 = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
114203
|
+
var leaseTempPattern = (lockPath) => new RegExp(`^\\.${escapeRegExp2(basename16(lockPath))}\\.${UUID2}\\.lease$`);
|
|
114204
|
+
async function replaceRecord(lockPath, content) {
|
|
114205
|
+
const temporary = join108(dirname44(lockPath), `${leaseTempPrefix(lockPath)}${randomUUID7()}${LEASE_TEMP_SUFFIX}`);
|
|
114206
|
+
try {
|
|
114207
|
+
const handle = await open4(temporary, "wx", 384);
|
|
114208
|
+
try {
|
|
114209
|
+
await handle.writeFile(content);
|
|
114210
|
+
} finally {
|
|
114211
|
+
await handle.close();
|
|
114212
|
+
}
|
|
114213
|
+
await rename9(temporary, lockPath);
|
|
114214
|
+
} catch (error) {
|
|
114215
|
+
await rm18(temporary, { force: true });
|
|
114216
|
+
throw error;
|
|
114217
|
+
}
|
|
114218
|
+
}
|
|
114219
|
+
async function removeLeftoverTemps(lockPath) {
|
|
114220
|
+
const pattern = leaseTempPattern(lockPath);
|
|
114221
|
+
let entries;
|
|
114222
|
+
try {
|
|
114223
|
+
entries = await readdir18(dirname44(lockPath));
|
|
114224
|
+
} catch (error) {
|
|
114225
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
114226
|
+
return;
|
|
114227
|
+
throw error;
|
|
114228
|
+
}
|
|
114229
|
+
for (const entry of entries) {
|
|
114230
|
+
if (pattern.test(entry))
|
|
114231
|
+
await rm18(join108(dirname44(lockPath), entry), { force: true });
|
|
114232
|
+
}
|
|
114233
|
+
}
|
|
114234
|
+
async function currentRecord(lockPath) {
|
|
114235
|
+
try {
|
|
114236
|
+
return await readFile36(lockPath, "utf8");
|
|
114237
|
+
} catch (error) {
|
|
114238
|
+
if (error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR"))
|
|
114239
|
+
return null;
|
|
114240
|
+
throw error;
|
|
114241
|
+
}
|
|
114242
|
+
}
|
|
114243
|
+
function createLockLease(lockPath, ownerRecord, ownerTag, options = {}) {
|
|
114244
|
+
const staleAfterMs = options.staleAfterMs ?? Number.POSITIVE_INFINITY;
|
|
114245
|
+
let handedTo = null;
|
|
114246
|
+
return {
|
|
114247
|
+
async handOver(pid) {
|
|
114248
|
+
if (handedTo !== null)
|
|
114249
|
+
throw new Error("The lock is already handed over; restore it first.");
|
|
114250
|
+
if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid)
|
|
114251
|
+
throw new Error(`Cannot hand the lock to pid ${pid}.`);
|
|
114252
|
+
if (await currentRecord(lockPath) !== ownerRecord)
|
|
114253
|
+
throw new LockLeaseLostError(lockPath);
|
|
114254
|
+
await removeLeftoverTemps(lockPath);
|
|
114255
|
+
const processStart = await lockProcessStartLine(pid);
|
|
114256
|
+
const record = `${ownerTag} ${randomUUID7()}
|
|
114257
|
+
${pid}
|
|
114258
|
+
${Date.now()}
|
|
114259
|
+
${randomUUID7()}
|
|
114260
|
+
${processStart}
|
|
114261
|
+
`;
|
|
114262
|
+
await replaceRecord(lockPath, record);
|
|
114263
|
+
handedTo = record;
|
|
114264
|
+
},
|
|
114265
|
+
async restore() {
|
|
114266
|
+
if (handedTo === null)
|
|
114267
|
+
throw new Error("The lock is not handed over.");
|
|
114268
|
+
const expected = handedTo;
|
|
114269
|
+
handedTo = null;
|
|
114270
|
+
const outcome = await withRecordGuard(lockPath, expected, staleAfterMs, {}, async () => {
|
|
114271
|
+
if (await currentRecord(lockPath) !== expected)
|
|
114272
|
+
return "lost";
|
|
114273
|
+
await options.beforeRestoreRename?.();
|
|
114274
|
+
await replaceRecord(lockPath, ownerRecord);
|
|
114275
|
+
return "restored";
|
|
114276
|
+
});
|
|
114277
|
+
if (outcome !== "restored")
|
|
114278
|
+
throw new LockLeaseLostError(lockPath);
|
|
114279
|
+
}
|
|
114280
|
+
};
|
|
114281
|
+
}
|
|
114282
|
+
|
|
113411
114283
|
// packages/team-core/src/team-state-store/locks.ts
|
|
113412
114284
|
var LOCK_RETRY_MS = 50;
|
|
113413
114285
|
var LOCK_WAIT_TIMEOUT_MS = 15000;
|
|
@@ -113437,7 +114309,7 @@ async function withLock(lockPath, fn, opts) {
|
|
|
113437
114309
|
const ownerTag = opts?.ownerTag ?? "owner";
|
|
113438
114310
|
const record = await acquireLock(lockPath, ownerTag, staleAfterMs);
|
|
113439
114311
|
try {
|
|
113440
|
-
return await fn();
|
|
114312
|
+
return await fn(createLockLease(lockPath, record, ownerTag, { staleAfterMs }));
|
|
113441
114313
|
} finally {
|
|
113442
114314
|
markLockRecordReleased(record);
|
|
113443
114315
|
const outcome = await removeLockRecordIfUnchanged(lockPath, record, staleAfterMs);
|
|
@@ -113454,20 +114326,382 @@ async function reapStaleLock(lockPath, staleAfterMs = DEFAULT_STALE_AFTER_MS, de
|
|
|
113454
114326
|
return await removeLockRecordIfUnchanged(lockPath, observed.content, staleAfterMs, deps);
|
|
113455
114327
|
}
|
|
113456
114328
|
|
|
114329
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/prompt-lock.ts
|
|
114330
|
+
function promptLockAt(path, hooks = {}) {
|
|
114331
|
+
return async () => {
|
|
114332
|
+
const held = keychainProcessState().heldPromptLocks;
|
|
114333
|
+
if (held.has(path))
|
|
114334
|
+
return null;
|
|
114335
|
+
held.add(path);
|
|
114336
|
+
let granted = false;
|
|
114337
|
+
try {
|
|
114338
|
+
await mkdir11(dirname45(path), { recursive: true, mode: 448 });
|
|
114339
|
+
await hooks.beforePublish?.();
|
|
114340
|
+
for (let attempt = 0;attempt < 2; attempt++) {
|
|
114341
|
+
const record = await buildLockRecord("keychain-prompt");
|
|
114342
|
+
if (await publishLockRecord(path, record)) {
|
|
114343
|
+
granted = true;
|
|
114344
|
+
return async () => {
|
|
114345
|
+
markLockRecordReleased(record);
|
|
114346
|
+
try {
|
|
114347
|
+
await (hooks.removeRecord ?? ((target, owned) => removeLockRecordIfUnchanged(target, owned, Number.POSITIVE_INFINITY)))(path, record);
|
|
114348
|
+
} finally {
|
|
114349
|
+
held.delete(path);
|
|
114350
|
+
}
|
|
114351
|
+
};
|
|
114352
|
+
}
|
|
114353
|
+
if (await reapStaleLock(path, Number.POSITIVE_INFINITY) !== "removed")
|
|
114354
|
+
return null;
|
|
114355
|
+
}
|
|
114356
|
+
return null;
|
|
114357
|
+
} finally {
|
|
114358
|
+
if (!granted)
|
|
114359
|
+
held.delete(path);
|
|
114360
|
+
}
|
|
114361
|
+
};
|
|
114362
|
+
}
|
|
114363
|
+
|
|
114364
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/darwin-backend.ts
|
|
114365
|
+
var ROW_9B_DEFAULT = "reinstall-notice";
|
|
114366
|
+
var helperAccess = () => sharedHelperAccess(() => {
|
|
114367
|
+
const { entryCandidates } = keychainProcessState();
|
|
114368
|
+
return resolveHelperAccess([...entryCandidates, ...bundleCandidates(import.meta.url), ...machineCandidates(homedir31())]);
|
|
114369
|
+
});
|
|
114370
|
+
function sharedHelperAccess(resolve) {
|
|
114371
|
+
const state = keychainProcessState();
|
|
114372
|
+
if (state.helperAccess !== undefined)
|
|
114373
|
+
return state.helperAccess;
|
|
114374
|
+
const started = resolve();
|
|
114375
|
+
state.helperAccess = started;
|
|
114376
|
+
started.then((access) => {
|
|
114377
|
+
if (access.kind === "unavailable" && state.helperAccess === started)
|
|
114378
|
+
state.helperAccess = undefined;
|
|
114379
|
+
}, () => {
|
|
114380
|
+
if (state.helperAccess === started)
|
|
114381
|
+
state.helperAccess = undefined;
|
|
114382
|
+
});
|
|
114383
|
+
return started;
|
|
114384
|
+
}
|
|
114385
|
+
|
|
114386
|
+
class HelperMissingForOwnedItem extends Error {
|
|
114387
|
+
}
|
|
114388
|
+
function asKeystoreError(error, pending) {
|
|
114389
|
+
if (!(error instanceof HelperReadError))
|
|
114390
|
+
return error;
|
|
114391
|
+
if (error.failure === "pending")
|
|
114392
|
+
return pending(error.message);
|
|
114393
|
+
if (error.failure === "locked")
|
|
114394
|
+
return Object.assign(new Error(error.message), { code: "-25308" });
|
|
114395
|
+
return error;
|
|
114396
|
+
}
|
|
114397
|
+
function createDarwinBackend(options) {
|
|
114398
|
+
const silently = options.silently ?? silentSecrets;
|
|
114399
|
+
const key = { service: options.service, name: options.account };
|
|
114400
|
+
const deps = {
|
|
114401
|
+
account: options.account,
|
|
114402
|
+
access: options.access,
|
|
114403
|
+
cache: options.cache ?? processApprovalCache(),
|
|
114404
|
+
background: options.background,
|
|
114405
|
+
takePromptLock: promptLockAt(join109(options.home ?? homedir31(), ".omo", "session-locks", `${options.account}.keychain-prompt`)),
|
|
114406
|
+
ownSilentGet: () => silently(() => options.secrets.get(key)),
|
|
114407
|
+
ownOverwrite: (value) => silently(() => options.secrets.set({ ...key, value })),
|
|
114408
|
+
ownDelete: (name) => name === options.account ? gatedSecrets(() => options.secrets.delete({ ...key, name })) : silently(() => options.secrets.delete({ ...key, name })),
|
|
114409
|
+
notice: options.notice,
|
|
114410
|
+
...options.row8b === undefined ? {} : { row8b: options.row8b },
|
|
114411
|
+
...options.handOff === undefined ? {} : { handOff: options.handOff },
|
|
114412
|
+
noDialog: options.noDialog === true
|
|
114413
|
+
};
|
|
114414
|
+
let unowned = false;
|
|
114415
|
+
return {
|
|
114416
|
+
read: async () => {
|
|
114417
|
+
const result = await readThroughHelper(deps, true);
|
|
114418
|
+
unowned = result.kind === "value" && result.source !== "owned";
|
|
114419
|
+
return result.kind === "value" ? result.value : null;
|
|
114420
|
+
},
|
|
114421
|
+
underLock: (lease) => lockedDarwinStore(deps, lease),
|
|
114422
|
+
migrationPending: () => unowned
|
|
114423
|
+
};
|
|
114424
|
+
}
|
|
114425
|
+
async function guardHelperlessRead(service, account, choice = ROW_9B_DEFAULT, probe = probeOwnerMarker) {
|
|
114426
|
+
if (choice === "dialog")
|
|
114427
|
+
return;
|
|
114428
|
+
if (await probe(service, account) === "helper-owned")
|
|
114429
|
+
throw new HelperMissingForOwnedItem("OmO's keychain helper is missing or damaged on this Mac. Reinstall omo, then try again.");
|
|
114430
|
+
}
|
|
114431
|
+
|
|
114432
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/store-binding.ts
|
|
114433
|
+
import { homedir as homedir32 } from "node:os";
|
|
114434
|
+
|
|
114435
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/creator-handoff.ts
|
|
114436
|
+
init_bun_file_shim();
|
|
114437
|
+
init_bun_spawn_shim();
|
|
114438
|
+
import { dirname as dirname47, posix as posix14 } from "node:path";
|
|
114439
|
+
|
|
114440
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/runtime-capabilities.ts
|
|
114441
|
+
init_zod();
|
|
114442
|
+
import { readFile as readFile37 } from "node:fs/promises";
|
|
114443
|
+
import { dirname as dirname46, join as join110 } from "node:path";
|
|
114444
|
+
var RUNTIME_CAPABILITIES_FILE = "omo-runtime-capabilities.json";
|
|
114445
|
+
var RUNTIME_CAPABILITIES = { keychainHandoff: 1 };
|
|
114446
|
+
var capabilitiesSchema = object({ keychainHandoff: number2().int() }).passthrough();
|
|
114447
|
+
async function runtimeDeclaresKeychainHandoff(runtime) {
|
|
114448
|
+
const text = await readFile37(join110(dirname46(runtime), RUNTIME_CAPABILITIES_FILE), "utf8").catch(() => null);
|
|
114449
|
+
if (text === null)
|
|
114450
|
+
return false;
|
|
114451
|
+
try {
|
|
114452
|
+
const parsed = capabilitiesSchema.safeParse(JSON.parse(text));
|
|
114453
|
+
return parsed.success && parsed.data.keychainHandoff >= RUNTIME_CAPABILITIES.keychainHandoff;
|
|
114454
|
+
} catch {
|
|
114455
|
+
return false;
|
|
114456
|
+
}
|
|
114457
|
+
}
|
|
114458
|
+
|
|
114459
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/creator-handoff.ts
|
|
114460
|
+
var DEVELOPER_ID_TEAM = 'anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] and certificate leaf[field.1.2.840.113635.100.6.1.13] and certificate leaf[subject.OU] = "523JNR86LZ"';
|
|
114461
|
+
var DESKTOP_RUNTIME_REQUIREMENT = `identifier "com.mengmota.omo-desktop-runtime" and ${DEVELOPER_ID_TEAM}`;
|
|
114462
|
+
var DESKTOP_APP_REQUIREMENT = DEVELOPER_ID_TEAM;
|
|
114463
|
+
var HANDOFF_ENV = "OMO_KEYCHAIN_HANDOFF";
|
|
114464
|
+
var HANDOFF_DEADLINE_MS = 45000;
|
|
114465
|
+
function desktopRuntimeCandidates(home, arch = process.arch) {
|
|
114466
|
+
const runtimeArch = arch === "arm64" ? "arm64" : "x64";
|
|
114467
|
+
return ["/Applications/OmO.app", posix14.join(home, "Applications", "OmO.app")].map((app) => ({
|
|
114468
|
+
app,
|
|
114469
|
+
runtime: posix14.join(app, "Contents", "Resources", "omo-runtime", `darwin-${runtimeArch}`, "omo")
|
|
114470
|
+
}));
|
|
114471
|
+
}
|
|
114472
|
+
var verifyBundle = async (app, requirement) => {
|
|
114473
|
+
const child = spawn(["/usr/bin/codesign", "--verify", "--deep", "--strict", `-R=${requirement}`, app], {
|
|
114474
|
+
stdin: "ignore",
|
|
114475
|
+
stdout: "ignore",
|
|
114476
|
+
stderr: "ignore"
|
|
114477
|
+
});
|
|
114478
|
+
return await child.exited === 0;
|
|
114479
|
+
};
|
|
114480
|
+
var runBounded = async (path, args, env, deadlineMs) => {
|
|
114481
|
+
const child = spawn([path, ...args], { cwd: dirname47(path), stdin: "ignore", stdout: "ignore", stderr: "ignore", env });
|
|
114482
|
+
let killed = false;
|
|
114483
|
+
const timer = setTimeout(() => {
|
|
114484
|
+
killed = true;
|
|
114485
|
+
child.kill("SIGKILL");
|
|
114486
|
+
}, deadlineMs);
|
|
114487
|
+
try {
|
|
114488
|
+
const code = await child.exited;
|
|
114489
|
+
return killed ? null : code;
|
|
114490
|
+
} finally {
|
|
114491
|
+
clearTimeout(timer);
|
|
114492
|
+
}
|
|
114493
|
+
};
|
|
114494
|
+
function createCreatorHandOff(options) {
|
|
114495
|
+
return async () => {
|
|
114496
|
+
const env = options.env ?? process.env;
|
|
114497
|
+
if (env[HANDOFF_ENV] === "1")
|
|
114498
|
+
return false;
|
|
114499
|
+
const checkRuntime = options.checkRuntime ?? verifyWithSecurityFramework;
|
|
114500
|
+
const checkBundle = options.checkBundle ?? verifyBundle;
|
|
114501
|
+
const declaresHandOff = options.declaresHandOff ?? runtimeDeclaresKeychainHandoff;
|
|
114502
|
+
const self = options.selfPath ?? process.execPath;
|
|
114503
|
+
for (const { app, runtime } of options.candidates) {
|
|
114504
|
+
if (runtime === self || !await bunFile(runtime).exists())
|
|
114505
|
+
continue;
|
|
114506
|
+
const verified = await Promise.resolve().then(async () => await checkBundle(app, DESKTOP_APP_REQUIREMENT) && await checkRuntime(runtime, DESKTOP_RUNTIME_REQUIREMENT) && await declaresHandOff(runtime)).catch(() => false);
|
|
114507
|
+
if (!verified)
|
|
114508
|
+
continue;
|
|
114509
|
+
const childEnv = { [HANDOFF_ENV]: "1" };
|
|
114510
|
+
if (env.HOME !== undefined)
|
|
114511
|
+
childEnv.HOME = env.HOME;
|
|
114512
|
+
const origin = options.origin ?? env.OMO_SERVICE_API_URL;
|
|
114513
|
+
if (origin !== undefined)
|
|
114514
|
+
childEnv.OMO_SERVICE_API_URL = origin;
|
|
114515
|
+
try {
|
|
114516
|
+
return await (options.run ?? runBounded)(runtime, ["account", "token"], childEnv, HANDOFF_DEADLINE_MS) === 0;
|
|
114517
|
+
} catch {
|
|
114518
|
+
return false;
|
|
114519
|
+
}
|
|
114520
|
+
}
|
|
114521
|
+
return false;
|
|
114522
|
+
};
|
|
114523
|
+
}
|
|
114524
|
+
|
|
114525
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/store-binding.ts
|
|
114526
|
+
var readers = new Map;
|
|
114527
|
+
var INJECTED_SECRETS = Symbol.for("omo.test.injectedSecrets");
|
|
114528
|
+
var isInjectedSecrets = (api) => api[INJECTED_SECRETS] === true;
|
|
114529
|
+
var backends = new Map;
|
|
114530
|
+
function processHandOff(origin) {
|
|
114531
|
+
return () => {
|
|
114532
|
+
const state = keychainProcessState();
|
|
114533
|
+
state.handOff ??= createCreatorHandOff({ candidates: desktopRuntimeCandidates(homedir32()), origin })();
|
|
114534
|
+
return state.handOff;
|
|
114535
|
+
};
|
|
114536
|
+
}
|
|
114537
|
+
function bindKeychainHelper(input) {
|
|
114538
|
+
const { secrets: real, key, options } = input;
|
|
114539
|
+
const eligible = input.platform === "darwin" && input.namespace === "omo-cli" && (options !== undefined || typeof Bun !== "undefined" && real === Bun.secrets && !isInjectedSecrets(real));
|
|
114540
|
+
const secrets = !eligible ? real : {
|
|
114541
|
+
get: (entry) => gatedSecrets(() => real.get(entry)),
|
|
114542
|
+
set: (entry) => gatedSecrets(() => real.set(entry)),
|
|
114543
|
+
delete: (entry) => gatedSecrets(() => real.delete(entry))
|
|
114544
|
+
};
|
|
114545
|
+
const cacheKey = `${key.service}
|
|
114546
|
+
${key.name}
|
|
114547
|
+
${input.background ? "bounded" : "interactive"}`;
|
|
114548
|
+
let own;
|
|
114549
|
+
const backend = () => {
|
|
114550
|
+
if (!eligible)
|
|
114551
|
+
return Promise.resolve(null);
|
|
114552
|
+
const known = options === undefined ? backends.get(cacheKey) : own;
|
|
114553
|
+
if (known !== undefined)
|
|
114554
|
+
return known;
|
|
114555
|
+
const created = (options?.access ?? helperAccess)().then((access) => access.kind !== "ready" ? null : createDarwinBackend({
|
|
114556
|
+
access,
|
|
114557
|
+
secrets: real,
|
|
114558
|
+
service: key.service,
|
|
114559
|
+
account: key.name,
|
|
114560
|
+
background: input.background,
|
|
114561
|
+
noDialog: options?.noDialog ?? process.env[HANDOFF_ENV] === "1",
|
|
114562
|
+
notice: input.notice,
|
|
114563
|
+
...options?.home === undefined ? {} : { home: options.home },
|
|
114564
|
+
...options?.row8b === undefined ? {} : { row8b: options.row8b },
|
|
114565
|
+
...options?.silently === undefined ? {} : { silently: options.silently },
|
|
114566
|
+
...options?.cache === undefined ? {} : { cache: options.cache },
|
|
114567
|
+
handOff: options === undefined ? processHandOff(input.origin) : options.handOff ?? (async () => false)
|
|
114568
|
+
}));
|
|
114569
|
+
if (options === undefined) {
|
|
114570
|
+
backends.set(cacheKey, created);
|
|
114571
|
+
created.then((found) => {
|
|
114572
|
+
if (found === null && backends.get(cacheKey) === created)
|
|
114573
|
+
backends.delete(cacheKey);
|
|
114574
|
+
});
|
|
114575
|
+
} else
|
|
114576
|
+
own = created;
|
|
114577
|
+
return created;
|
|
114578
|
+
};
|
|
114579
|
+
const reader = (helper) => {
|
|
114580
|
+
const known = readers.get(helper);
|
|
114581
|
+
if (known !== undefined)
|
|
114582
|
+
return known;
|
|
114583
|
+
const refuse = async () => {
|
|
114584
|
+
throw new Error("OmO's keychain helper changes the sign-in only under the session lock.");
|
|
114585
|
+
};
|
|
114586
|
+
const created = {
|
|
114587
|
+
get: async () => {
|
|
114588
|
+
try {
|
|
114589
|
+
return await helper.read();
|
|
114590
|
+
} catch (error) {
|
|
114591
|
+
throw asKeystoreError(error, (message) => input.pending(`${message} Credentials are never saved to a file.`));
|
|
114592
|
+
}
|
|
114593
|
+
},
|
|
114594
|
+
set: refuse,
|
|
114595
|
+
delete: refuse
|
|
114596
|
+
};
|
|
114597
|
+
readers.set(helper, created);
|
|
114598
|
+
return created;
|
|
114599
|
+
};
|
|
114600
|
+
return {
|
|
114601
|
+
secrets,
|
|
114602
|
+
eligible,
|
|
114603
|
+
backend,
|
|
114604
|
+
reader,
|
|
114605
|
+
isHelperReader: (api) => [...readers.values()].includes(api),
|
|
114606
|
+
guardHelperless: async () => {
|
|
114607
|
+
if (!eligible)
|
|
114608
|
+
return;
|
|
114609
|
+
if ((options?.noDialog ?? process.env[HANDOFF_ENV] === "1") === true)
|
|
114610
|
+
throw input.pending("The keychain hand-off cannot show a dialog.");
|
|
114611
|
+
await guardHelperlessRead(key.service, key.name, options?.row9b, options?.ownerMarker);
|
|
114612
|
+
}
|
|
114613
|
+
};
|
|
114614
|
+
}
|
|
114615
|
+
function lockedStoreView(helper, lease, codec, mapError, done) {
|
|
114616
|
+
const locked = helper.underLock(lease);
|
|
114617
|
+
const run = async (step) => {
|
|
114618
|
+
try {
|
|
114619
|
+
return await step();
|
|
114620
|
+
} catch (error) {
|
|
114621
|
+
throw mapError(error);
|
|
114622
|
+
} finally {
|
|
114623
|
+
done();
|
|
114624
|
+
}
|
|
114625
|
+
};
|
|
114626
|
+
return {
|
|
114627
|
+
read: () => run(async () => {
|
|
114628
|
+
const text = await locked.read();
|
|
114629
|
+
return text === null ? null : codec.parse(text);
|
|
114630
|
+
}),
|
|
114631
|
+
write: (value, intent = "update", beforeRetire) => run(async () => {
|
|
114632
|
+
const next = codec.amend === undefined ? value : codec.amend(await locked.read(), value);
|
|
114633
|
+
await locked.write(codec.serialize(next), intent, beforeRetire);
|
|
114634
|
+
}),
|
|
114635
|
+
clear: () => run(() => locked.clear()),
|
|
114636
|
+
recover: () => run(() => locked.recover()),
|
|
114637
|
+
settle: () => run(() => locked.settle())
|
|
114638
|
+
};
|
|
114639
|
+
}
|
|
114640
|
+
|
|
114641
|
+
// packages/omo-opencode/src/cli/service-auth/secret-service-lock.ts
|
|
114642
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
114643
|
+
var DEFAULT_COLLECTION = "/org/freedesktop/secrets/aliases/default";
|
|
114644
|
+
var PROBE_TIMEOUT_MS2 = 1e4;
|
|
114645
|
+
var parseLockedReply = (stdout) => {
|
|
114646
|
+
const match = /<\s*(true|false)\s*>/.exec(stdout);
|
|
114647
|
+
if (match === null)
|
|
114648
|
+
return null;
|
|
114649
|
+
return match[1] === "true" ? "locked" : "unlocked";
|
|
114650
|
+
};
|
|
114651
|
+
var probeSecretServiceLock = () => new Promise((resolve) => {
|
|
114652
|
+
const child = spawn5("gdbus", [
|
|
114653
|
+
"call",
|
|
114654
|
+
"--session",
|
|
114655
|
+
"--dest",
|
|
114656
|
+
"org.freedesktop.secrets",
|
|
114657
|
+
"--object-path",
|
|
114658
|
+
DEFAULT_COLLECTION,
|
|
114659
|
+
"--method",
|
|
114660
|
+
"org.freedesktop.DBus.Properties.Get",
|
|
114661
|
+
"org.freedesktop.Secret.Collection",
|
|
114662
|
+
"Locked"
|
|
114663
|
+
], { stdio: ["ignore", "pipe", "ignore"] });
|
|
114664
|
+
let stdout = "";
|
|
114665
|
+
const timer = setTimeout(() => {
|
|
114666
|
+
child.kill();
|
|
114667
|
+
resolve("unknown");
|
|
114668
|
+
}, PROBE_TIMEOUT_MS2);
|
|
114669
|
+
child.stdout.on("data", (chunk) => {
|
|
114670
|
+
stdout += chunk.toString();
|
|
114671
|
+
});
|
|
114672
|
+
child.on("error", () => {
|
|
114673
|
+
clearTimeout(timer);
|
|
114674
|
+
resolve("unknown");
|
|
114675
|
+
});
|
|
114676
|
+
child.on("close", (code) => {
|
|
114677
|
+
clearTimeout(timer);
|
|
114678
|
+
resolve(code === 0 ? parseLockedReply(stdout) ?? "absent" : "absent");
|
|
114679
|
+
});
|
|
114680
|
+
});
|
|
114681
|
+
|
|
113457
114682
|
// packages/omo-opencode/src/cli/service-auth/credential-lock.ts
|
|
114683
|
+
import { AsyncLocalStorage as AsyncLocalStorage3 } from "node:async_hooks";
|
|
114684
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
114685
|
+
import { mkdir as mkdir12 } from "node:fs/promises";
|
|
114686
|
+
import { homedir as homedir33 } from "node:os";
|
|
114687
|
+
import { join as join112 } from "node:path";
|
|
113458
114688
|
var held = new AsyncLocalStorage3;
|
|
113459
|
-
function credentialLockPaths(api, home =
|
|
114689
|
+
function credentialLockPaths(api, home = homedir33()) {
|
|
113460
114690
|
const id = createHash11("sha256").update(serviceOrigin(api)).digest("hex");
|
|
113461
|
-
const directory =
|
|
113462
|
-
return { directory, lock:
|
|
114691
|
+
const directory = join112(home, ".omo", "session-locks");
|
|
114692
|
+
return { directory, lock: join112(directory, `${id}.lock`), desktopRecord: join112(directory, `${id}.desktop-generation.json`) };
|
|
113463
114693
|
}
|
|
113464
|
-
|
|
114694
|
+
function heldCredentialLease(api, home = homedir33()) {
|
|
114695
|
+
return held.getStore()?.get(credentialLockPaths(api, home).lock);
|
|
114696
|
+
}
|
|
114697
|
+
async function withCredentialLock(api, action, home = homedir33(), ownerTag = "cli-session") {
|
|
113465
114698
|
const { directory, lock } = credentialLockPaths(api, home);
|
|
113466
114699
|
const owned = held.getStore();
|
|
113467
|
-
|
|
113468
|
-
|
|
113469
|
-
|
|
113470
|
-
|
|
114700
|
+
const outer = owned?.get(lock);
|
|
114701
|
+
if (outer !== undefined)
|
|
114702
|
+
return action(outer);
|
|
114703
|
+
await mkdir12(directory, { recursive: true, mode: 448 });
|
|
114704
|
+
return withLock(lock, (lease) => held.run(new Map([...owned ?? [], [lock, lease]]), () => action(lease)), {
|
|
113471
114705
|
ownerTag,
|
|
113472
114706
|
staleAfterMs: Number.POSITIVE_INFINITY
|
|
113473
114707
|
});
|
|
@@ -113519,17 +114753,51 @@ function createCredentialStore(api, options = {}) {
|
|
|
113519
114753
|
return {
|
|
113520
114754
|
...value,
|
|
113521
114755
|
...accountId === undefined ? {} : { accountId },
|
|
113522
|
-
credentialGeneration: sameIdentity ? current?.credentialGeneration ??
|
|
114756
|
+
credentialGeneration: sameIdentity ? current?.credentialGeneration ?? randomUUID8() : randomUUID8()
|
|
113523
114757
|
};
|
|
113524
|
-
});
|
|
114758
|
+
}, options.keychainHelper);
|
|
114759
|
+
const sections = new WeakMap;
|
|
114760
|
+
const underLock = (lease) => {
|
|
114761
|
+
const known = sections.get(lease);
|
|
114762
|
+
if (known !== undefined)
|
|
114763
|
+
return known;
|
|
114764
|
+
const view = (async () => {
|
|
114765
|
+
const opened = await store.underLock?.(lease) ?? null;
|
|
114766
|
+
await opened?.recover();
|
|
114767
|
+
return opened;
|
|
114768
|
+
})();
|
|
114769
|
+
sections.set(lease, view);
|
|
114770
|
+
return view;
|
|
114771
|
+
};
|
|
114772
|
+
const held = async () => {
|
|
114773
|
+
const lease = heldCredentialLease(api, options.home);
|
|
114774
|
+
return lease === undefined ? null : underLock(lease);
|
|
114775
|
+
};
|
|
114776
|
+
const locked = async (helper, plain) => {
|
|
114777
|
+
if (heldCredentialLease(api, options.home) === undefined)
|
|
114778
|
+
await store.prepare?.();
|
|
114779
|
+
await withCredentialLock(api, async (lease) => {
|
|
114780
|
+
const view = await underLock(lease);
|
|
114781
|
+
await (view === null ? plain() : helper(view));
|
|
114782
|
+
}, options.home);
|
|
114783
|
+
};
|
|
113525
114784
|
return {
|
|
113526
|
-
read:
|
|
113527
|
-
|
|
113528
|
-
|
|
113529
|
-
|
|
114785
|
+
read: async () => {
|
|
114786
|
+
const view = await held();
|
|
114787
|
+
return view === null ? store.read() : view.read();
|
|
114788
|
+
},
|
|
114789
|
+
readAuthoritative: async () => {
|
|
114790
|
+
const view = await held();
|
|
114791
|
+
return view === null ? store.readAuthoritative() : view.read();
|
|
114792
|
+
},
|
|
114793
|
+
write: (value, intent, beforeRetire) => locked((view) => view.write(value, intent, beforeRetire), () => store.write(value)),
|
|
114794
|
+
clear: () => locked((view) => view.clear(), store.clear),
|
|
114795
|
+
...store.prepare === undefined ? {} : { prepare: store.prepare },
|
|
114796
|
+
underLock,
|
|
114797
|
+
...store.migrationPending === undefined ? {} : { migrationPending: store.migrationPending }
|
|
113530
114798
|
};
|
|
113531
114799
|
}
|
|
113532
|
-
function createSealedStore(api, namespace, schema, secrets = typeof Bun === "undefined" ? null : Bun.secrets, platform = process.platform, lockProbe = probeSecretServiceLock, notice = stderrNoticeOncePerProcess, wait = SESSION_READ_WAIT, amendWrite) {
|
|
114800
|
+
function createSealedStore(api, namespace, schema, secrets = typeof Bun === "undefined" ? null : Bun.secrets, platform = process.platform, lockProbe = probeSecretServiceLock, notice = stderrNoticeOncePerProcess, wait = SESSION_READ_WAIT, amendWrite, keychainHelper) {
|
|
113533
114801
|
if (!secrets)
|
|
113534
114802
|
throw new SignInError("OmO sign-in needs Bun 1.4 or newer with OS credential storage. No file fallback is available.");
|
|
113535
114803
|
const platformName = platform === "darwin" ? "macOS Keychain" : platform === "linux" ? "Linux Secret Service (libsecret and an unlocked keyring)" : platform === "win32" ? "Windows Credential Manager" : null;
|
|
@@ -113538,6 +114806,18 @@ function createSealedStore(api, namespace, schema, secrets = typeof Bun === "und
|
|
|
113538
114806
|
const key = { service: namespace, name: credentialId(api) };
|
|
113539
114807
|
const slot = `${key.service}
|
|
113540
114808
|
${key.name}`;
|
|
114809
|
+
const helper = bindKeychainHelper({
|
|
114810
|
+
platform,
|
|
114811
|
+
namespace,
|
|
114812
|
+
secrets,
|
|
114813
|
+
key,
|
|
114814
|
+
background: wait.kind === "bounded",
|
|
114815
|
+
origin: api,
|
|
114816
|
+
notice,
|
|
114817
|
+
pending: (message) => new KeychainApprovalPendingError(message),
|
|
114818
|
+
...keychainHelper === undefined ? {} : { options: keychainHelper }
|
|
114819
|
+
});
|
|
114820
|
+
secrets = helper.secrets;
|
|
113541
114821
|
const readsOf = (api) => {
|
|
113542
114822
|
const known = processReads.get(api);
|
|
113543
114823
|
if (known !== undefined)
|
|
@@ -113563,17 +114843,19 @@ ${key.name}`;
|
|
|
113563
114843
|
reads.set(slot, read);
|
|
113564
114844
|
return read;
|
|
113565
114845
|
};
|
|
113566
|
-
const waiting = platform === "darwin" ? `macOS Keychain is waiting for your approval: answer the "${
|
|
114846
|
+
const waiting = platform === "darwin" ? `macOS Keychain is waiting for your approval: answer the "${basename17(process.execPath)} wants to access key ${namespace}" dialog ("Always Allow" stops it asking again)` : `${platformName} has not answered; it may be waiting for your approval or an unlock in a system dialog`;
|
|
114847
|
+
const helperWaiting = `macOS Keychain is waiting for your approval: answer the "OmO's keychain helper wants to access key ${namespace}" dialog`;
|
|
113567
114848
|
const answered = async (api, fresh = false) => {
|
|
114849
|
+
const waitingFor = helper.isHelperReader(api) ? helperWaiting : waiting;
|
|
113568
114850
|
const read = fresh ? Promise.resolve().then(() => api.get(key)) : sharedRead(api);
|
|
113569
114851
|
let timer;
|
|
113570
114852
|
try {
|
|
113571
114853
|
if (wait.kind === "interactive") {
|
|
113572
|
-
timer = setTimeout(() => wait.notice(`omo: ${
|
|
114854
|
+
timer = setTimeout(() => wait.notice(`omo: ${waitingFor}.`), wait.noticeAfterMs);
|
|
113573
114855
|
return await read;
|
|
113574
114856
|
}
|
|
113575
114857
|
const expired = new Promise((_, reject) => {
|
|
113576
|
-
timer = setTimeout(() => reject(new KeychainApprovalPendingError(`${
|
|
114858
|
+
timer = setTimeout(() => reject(new KeychainApprovalPendingError(`${waitingFor}, then try again. Credentials are never saved to a file.`)), wait.deadlineMs);
|
|
113577
114859
|
});
|
|
113578
114860
|
return await Promise.race([read, expired]);
|
|
113579
114861
|
} finally {
|
|
@@ -113598,41 +114880,76 @@ ${key.name}`;
|
|
|
113598
114880
|
notice("omo: could not check whether the keyring is locked (gdbus or the Secret Service did not answer); using libsecret directly.");
|
|
113599
114881
|
}
|
|
113600
114882
|
};
|
|
113601
|
-
const
|
|
114883
|
+
const parseStored = (value) => {
|
|
114884
|
+
try {
|
|
114885
|
+
return schema.parse(JSON.parse(value));
|
|
114886
|
+
} catch {
|
|
114887
|
+
throw new InvalidCredentialState(signInRoute() === "cli" ? "Stored sign-in data is invalid. Run omo account forget, then omo login." : "The OmO sign-in saved on this computer can't be read. Run omo account forget to remove it, then sign in again in the desktop app.");
|
|
114888
|
+
}
|
|
114889
|
+
};
|
|
114890
|
+
const previousOf = (raw) => {
|
|
114891
|
+
if (raw === null)
|
|
114892
|
+
return null;
|
|
114893
|
+
try {
|
|
114894
|
+
return schema.parse(JSON.parse(raw));
|
|
114895
|
+
} catch {
|
|
114896
|
+
return null;
|
|
114897
|
+
}
|
|
114898
|
+
};
|
|
114899
|
+
const rawRead = async (fresh) => {
|
|
113602
114900
|
await assertUsable();
|
|
113603
|
-
|
|
114901
|
+
const backend = await helper.backend();
|
|
113604
114902
|
try {
|
|
113605
|
-
|
|
114903
|
+
if (backend === null)
|
|
114904
|
+
await helper.guardHelperless();
|
|
114905
|
+
return await answered(backend === null ? secrets : helper.reader(backend), fresh);
|
|
113606
114906
|
} catch (error) {
|
|
113607
114907
|
if (error instanceof KeychainApprovalPendingError)
|
|
113608
114908
|
throw error;
|
|
114909
|
+
if (error instanceof HelperMissingForOwnedItem)
|
|
114910
|
+
throw new CredentialStoreError(error.message);
|
|
113609
114911
|
throw unavailable(error);
|
|
113610
114912
|
}
|
|
113611
|
-
|
|
113612
|
-
|
|
113613
|
-
|
|
113614
|
-
|
|
113615
|
-
|
|
113616
|
-
|
|
113617
|
-
|
|
114913
|
+
};
|
|
114914
|
+
const parsedRead = async (fresh) => {
|
|
114915
|
+
const value = await rawRead(fresh);
|
|
114916
|
+
return value === null ? null : parseStored(value);
|
|
114917
|
+
};
|
|
114918
|
+
const lockedFailure = (error) => {
|
|
114919
|
+
const mapped = asKeystoreError(error, (message) => new KeychainApprovalPendingError(message));
|
|
114920
|
+
if (error instanceof HelperOldSlotsFull)
|
|
114921
|
+
return new CredentialStoreError(error.message);
|
|
114922
|
+
if (mapped instanceof KeychainApprovalPendingError || mapped instanceof SignInError)
|
|
114923
|
+
return mapped;
|
|
114924
|
+
if (mapped instanceof Error && mapped.name === "LockLeaseLostError")
|
|
114925
|
+
return mapped;
|
|
114926
|
+
return unavailable(mapped);
|
|
113618
114927
|
};
|
|
113619
114928
|
return {
|
|
113620
114929
|
read: () => parsedRead(false),
|
|
113621
114930
|
readAuthoritative: () => parsedRead(true),
|
|
114931
|
+
async prepare() {
|
|
114932
|
+
if (await helper.backend() !== null)
|
|
114933
|
+
await rawRead(false);
|
|
114934
|
+
},
|
|
114935
|
+
async underLock(lease) {
|
|
114936
|
+
const backend = await helper.backend();
|
|
114937
|
+
if (backend === null)
|
|
114938
|
+
return null;
|
|
114939
|
+
const codec = {
|
|
114940
|
+
parse: parseStored,
|
|
114941
|
+
serialize: (value) => JSON.stringify(schema.parse(value)),
|
|
114942
|
+
...amendWrite === undefined ? {} : { amend: (raw, next) => amendWrite(previousOf(raw), next) }
|
|
114943
|
+
};
|
|
114944
|
+
return lockedStoreView(backend, lease, codec, lockedFailure, () => forget(helper.reader(backend)));
|
|
114945
|
+
},
|
|
114946
|
+
migrationPending: async () => (await helper.backend())?.migrationPending() ?? false,
|
|
113622
114947
|
async write(value) {
|
|
113623
114948
|
await assertUsable();
|
|
114949
|
+
if (await helper.backend() !== null)
|
|
114950
|
+
throw new Error("OmO's keychain helper writes only under the session lock.");
|
|
113624
114951
|
try {
|
|
113625
|
-
|
|
113626
|
-
if (amendWrite !== undefined) {
|
|
113627
|
-
const raw = await answered(secrets, true);
|
|
113628
|
-
let previous = null;
|
|
113629
|
-
if (raw !== null) {
|
|
113630
|
-
try {
|
|
113631
|
-
previous = schema.parse(JSON.parse(raw));
|
|
113632
|
-
} catch {}
|
|
113633
|
-
}
|
|
113634
|
-
next = amendWrite(previous, value);
|
|
113635
|
-
}
|
|
114952
|
+
const next = amendWrite === undefined ? value : amendWrite(previousOf(await answered(secrets, true)), value);
|
|
113636
114953
|
await secrets.set({ ...key, value: JSON.stringify(schema.parse(next)) });
|
|
113637
114954
|
} catch (error) {
|
|
113638
114955
|
throw unavailable(error);
|
|
@@ -113641,6 +114958,8 @@ ${key.name}`;
|
|
|
113641
114958
|
},
|
|
113642
114959
|
async clear() {
|
|
113643
114960
|
await assertUsable();
|
|
114961
|
+
if (await helper.backend() !== null)
|
|
114962
|
+
throw new Error("OmO's keychain helper deletes only under the session lock.");
|
|
113644
114963
|
try {
|
|
113645
114964
|
await secrets.delete(key);
|
|
113646
114965
|
} catch (error) {
|
|
@@ -113750,17 +115069,62 @@ async function loginLoopback(session, options) {
|
|
|
113750
115069
|
}
|
|
113751
115070
|
}
|
|
113752
115071
|
|
|
115072
|
+
// packages/memory-core/src/sync/device-retire.ts
|
|
115073
|
+
import { createHash as createHash14, randomBytes as randomBytes6 } from "node:crypto";
|
|
115074
|
+
import { join as join115 } from "node:path";
|
|
115075
|
+
|
|
115076
|
+
// packages/memory-core/src/identity/layout.ts
|
|
115077
|
+
import { homedir as homedir34 } from "node:os";
|
|
115078
|
+
import { join as join113, resolve as resolve31 } from "node:path";
|
|
115079
|
+
var MEMORY_ROOT_ENV_VAR = "OMO_MEMORY_HOME";
|
|
115080
|
+
function defaultMemoryRoot() {
|
|
115081
|
+
return join113(homedir34(), ".omo", "memory");
|
|
115082
|
+
}
|
|
115083
|
+
function resolveMemoryRoot(env, cwd) {
|
|
115084
|
+
const override = env[MEMORY_ROOT_ENV_VAR];
|
|
115085
|
+
if (override === undefined || override.trim() === "") {
|
|
115086
|
+
return defaultMemoryRoot();
|
|
115087
|
+
}
|
|
115088
|
+
return resolve31(cwd, override);
|
|
115089
|
+
}
|
|
115090
|
+
// packages/memory-core/src/sync/pin-dir.ts
|
|
115091
|
+
import { join as join114 } from "node:path";
|
|
115092
|
+
var syncPinDir = (memoryRoot) => join114(memoryRoot, "sync-device");
|
|
115093
|
+
|
|
115094
|
+
// packages/memory-core/src/sync/device-retire.ts
|
|
115095
|
+
var trustAnchorRoot = (pinDir) => join115(pinDir, "trust-anchor");
|
|
115096
|
+
var trustAnchorKey = (account) => createHash14("sha256").update(account, "utf8").digest("base64url");
|
|
115097
|
+
var trustAnchorDir = (pinDir, account) => join115(trustAnchorRoot(pinDir), trustAnchorKey(account));
|
|
115098
|
+
var hasLiveTrustAnchor = async (pinDir) => {
|
|
115099
|
+
try {
|
|
115100
|
+
return (await readdir17(trustAnchorRoot(pinDir))).some((name) => !name.includes(".retired-"));
|
|
115101
|
+
} catch (error) {
|
|
115102
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
115103
|
+
return false;
|
|
115104
|
+
throw error;
|
|
115105
|
+
}
|
|
115106
|
+
};
|
|
115107
|
+
var retireSyncDevice = async (input) => {
|
|
115108
|
+
const dir = trustAnchorDir(input.pinDir, input.account);
|
|
115109
|
+
try {
|
|
115110
|
+
await rename8(dir, `${dir}.retired-${Date.now()}-${randomBytes6(4).toString("hex")}`);
|
|
115111
|
+
} catch (error) {
|
|
115112
|
+
if (!(error instanceof Error && ("code" in error) && error.code === "ENOENT"))
|
|
115113
|
+
throw error;
|
|
115114
|
+
}
|
|
115115
|
+
};
|
|
115116
|
+
|
|
113753
115117
|
// packages/omo-opencode/src/cli/service-auth/session.ts
|
|
113754
|
-
import { homedir as
|
|
115118
|
+
import { homedir as homedir35 } from "node:os";
|
|
113755
115119
|
|
|
113756
115120
|
// packages/omo-opencode/src/cli/service-auth/signed-out-marker.ts
|
|
113757
115121
|
init_zod();
|
|
113758
|
-
import { mkdir as
|
|
113759
|
-
import { dirname as
|
|
115122
|
+
import { mkdir as mkdir13, readFile as readFile38, rename as rename10, rm as rm19, writeFile as writeFile18 } from "node:fs/promises";
|
|
115123
|
+
import { dirname as dirname48, join as join116 } from "node:path";
|
|
113760
115124
|
var markerSchema = object({ device: string2().nullable(), at: string2() });
|
|
113761
|
-
var signedOutMarkerPath = (home, credential) =>
|
|
115125
|
+
var signedOutMarkerPath = (home, credential) => join116(home, ".omo", "account-state", `${credential}.signed-out.json`);
|
|
113762
115126
|
async function readSignedOutMarker(path) {
|
|
113763
|
-
const text = await
|
|
115127
|
+
const text = await readFile38(path, "utf8").catch(() => null);
|
|
113764
115128
|
if (text === null)
|
|
113765
115129
|
return null;
|
|
113766
115130
|
let value;
|
|
@@ -113773,12 +115137,12 @@ async function readSignedOutMarker(path) {
|
|
|
113773
115137
|
return parsed.success ? parsed.data : null;
|
|
113774
115138
|
}
|
|
113775
115139
|
async function writeSignedOutMarker(path, device) {
|
|
113776
|
-
await
|
|
115140
|
+
await mkdir13(dirname48(path), { recursive: true, mode: 448 });
|
|
113777
115141
|
const staging = `${path}.${process.pid}.tmp`;
|
|
113778
|
-
await
|
|
113779
|
-
await
|
|
115142
|
+
await writeFile18(staging, JSON.stringify({ device, at: new Date().toISOString() }), { mode: 384 });
|
|
115143
|
+
await rename10(staging, path);
|
|
113780
115144
|
}
|
|
113781
|
-
var clearSignedOutMarker = (path) =>
|
|
115145
|
+
var clearSignedOutMarker = (path) => rm19(path, { force: true });
|
|
113782
115146
|
|
|
113783
115147
|
// packages/omo-opencode/src/cli/service-auth/session.ts
|
|
113784
115148
|
class SessionEnded extends SignInError {
|
|
@@ -113791,19 +115155,33 @@ class SessionEnded extends SignInError {
|
|
|
113791
115155
|
}
|
|
113792
115156
|
}
|
|
113793
115157
|
var DEVICE_REVOKING_REFUSALS = new Set(["account_deleted", "reauth_required", "device_revoked"]);
|
|
115158
|
+
var discardedOf = (credentials, cause) => ({
|
|
115159
|
+
kind: "credential",
|
|
115160
|
+
deviceId: credentials.device.id,
|
|
115161
|
+
accountId: credentials.accountId,
|
|
115162
|
+
owner: credentials.owner,
|
|
115163
|
+
cause
|
|
115164
|
+
});
|
|
113794
115165
|
function createSession(options) {
|
|
113795
115166
|
const api = serviceOrigin(options.api);
|
|
113796
115167
|
const now = options.now ?? Date.now;
|
|
113797
|
-
const { store, signal } = options;
|
|
113798
|
-
const markerPath = signedOutMarkerPath(options.home ??
|
|
115168
|
+
const { store, signal, beforeKeysDiscarded } = options;
|
|
115169
|
+
const markerPath = signedOutMarkerPath(options.home ?? homedir35(), credentialId(api));
|
|
113799
115170
|
async function locked(action) {
|
|
113800
115171
|
signal?.throwIfAborted();
|
|
113801
|
-
|
|
115172
|
+
if (heldCredentialLease(api, options.home) === undefined)
|
|
115173
|
+
await store.prepare?.();
|
|
115174
|
+
return withCredentialLock(api, async (lease) => {
|
|
113802
115175
|
signal?.throwIfAborted();
|
|
113803
|
-
return action();
|
|
115176
|
+
return action(await store.underLock?.(lease) ?? null);
|
|
113804
115177
|
}, options.home);
|
|
113805
115178
|
}
|
|
113806
115179
|
const request = (path, init) => requestApi(api, path, init, signal);
|
|
115180
|
+
const accountOf = async (access) => {
|
|
115181
|
+
const body = await request("/v1/me", { headers: { authorization: `Bearer ${access}` } }).catch(() => null);
|
|
115182
|
+
const id = typeof body === "object" && body !== null && "account" in body && typeof body.account === "object" && body.account !== null && "id" in body.account ? body.account.id : undefined;
|
|
115183
|
+
return typeof id === "string" && id !== "" ? id : undefined;
|
|
115184
|
+
};
|
|
113807
115185
|
async function refreshed(current) {
|
|
113808
115186
|
if (current.refreshState === "uncertain" || current.refreshAttempt !== undefined) {
|
|
113809
115187
|
throw new SessionEnded(`Refresh recovery can no longer be proved safe. ${signInHint("again")}`, false, "refresh_recovery_expired");
|
|
@@ -113820,6 +115198,7 @@ function createSession(options) {
|
|
|
113820
115198
|
if (error instanceof CredentialStoreError)
|
|
113821
115199
|
throw error;
|
|
113822
115200
|
if (error instanceof ApiRefusal && error.status < 500 && ["unauthorized", "account_deleted", "reauth_required", "invalid_grant", "device_revoked"].includes(error.code)) {
|
|
115201
|
+
await beforeKeysDiscarded(discardedOf(current, "refused"));
|
|
113823
115202
|
await store.clear();
|
|
113824
115203
|
throw new SessionEnded(error.code === "reauth_required" ? `This session was ended because its refresh token was reused. ${signInHint("again")}` : refusalMessage(refusalGuidance(error.code, error.status)), DEVICE_REVOKING_REFUSALS.has(error.code), error.code);
|
|
113825
115204
|
}
|
|
@@ -113831,9 +115210,12 @@ function createSession(options) {
|
|
|
113831
115210
|
}
|
|
113832
115211
|
}
|
|
113833
115212
|
async function snapshot() {
|
|
113834
|
-
return locked(async () => {
|
|
115213
|
+
return locked(async (view) => {
|
|
113835
115214
|
const current = await store.read();
|
|
113836
|
-
|
|
115215
|
+
if (current === null)
|
|
115216
|
+
return null;
|
|
115217
|
+
await view?.settle();
|
|
115218
|
+
return refreshed(current);
|
|
113837
115219
|
});
|
|
113838
115220
|
}
|
|
113839
115221
|
return {
|
|
@@ -113845,7 +115227,18 @@ function createSession(options) {
|
|
|
113845
115227
|
},
|
|
113846
115228
|
async save(value) {
|
|
113847
115229
|
await locked(async () => {
|
|
113848
|
-
|
|
115230
|
+
let stored;
|
|
115231
|
+
try {
|
|
115232
|
+
stored = await store.readAuthoritative();
|
|
115233
|
+
} catch (error) {
|
|
115234
|
+
if (!(error instanceof InvalidCredentialState))
|
|
115235
|
+
throw error;
|
|
115236
|
+
await beforeKeysDiscarded({ kind: "unreadable" });
|
|
115237
|
+
stored = null;
|
|
115238
|
+
}
|
|
115239
|
+
if (stored !== null && stored.device.id !== value.device.id)
|
|
115240
|
+
await beforeKeysDiscarded(discardedOf(stored, "replaced"));
|
|
115241
|
+
await store.write(value, "fresh-sign-in", () => beforeKeysDiscarded({ kind: "unreadable" }));
|
|
113849
115242
|
await clearSignedOutMarker(markerPath);
|
|
113850
115243
|
});
|
|
113851
115244
|
},
|
|
@@ -113871,12 +115264,16 @@ function createSession(options) {
|
|
|
113871
115264
|
async logout() {
|
|
113872
115265
|
return locked(async () => {
|
|
113873
115266
|
let current = null;
|
|
115267
|
+
let account;
|
|
113874
115268
|
try {
|
|
113875
115269
|
current = await store.readAuthoritative();
|
|
113876
115270
|
if (current !== null) {
|
|
113877
115271
|
if (current.refreshState === "uncertain")
|
|
113878
115272
|
return false;
|
|
113879
115273
|
const access = Date.parse(current.accessTokenExpiresAt) <= now() ? (await refreshed(current)).accessToken : current.accessToken;
|
|
115274
|
+
if (current.accountId === undefined && current.owner === undefined && await beforeKeysDiscarded.wantsAccount?.() === true) {
|
|
115275
|
+
account = await accountOf(access);
|
|
115276
|
+
}
|
|
113880
115277
|
await request(`/v1/devices/${encodeURIComponent(current.device.id)}`, {
|
|
113881
115278
|
method: "DELETE",
|
|
113882
115279
|
headers: { authorization: `Bearer ${access}` }
|
|
@@ -113891,6 +115288,9 @@ function createSession(options) {
|
|
|
113891
115288
|
throw error;
|
|
113892
115289
|
} finally {
|
|
113893
115290
|
await writeSignedOutMarker(markerPath, current?.device.id ?? null);
|
|
115291
|
+
const stored = current === null ? null : await store.read().catch(() => current);
|
|
115292
|
+
if (stored !== null)
|
|
115293
|
+
await beforeKeysDiscarded(discardedOf(stored.accountId === undefined && account !== undefined ? { ...stored, accountId: account } : stored, "logout"));
|
|
113894
115294
|
await store.clear();
|
|
113895
115295
|
}
|
|
113896
115296
|
});
|
|
@@ -113899,14 +115299,15 @@ function createSession(options) {
|
|
|
113899
115299
|
signal?.throwIfAborted();
|
|
113900
115300
|
const snapshot = await store.read();
|
|
113901
115301
|
signal?.throwIfAborted();
|
|
113902
|
-
if (snapshot !== null && snapshot.refreshState !== "uncertain" && snapshot.refreshAttempt === undefined && Date.parse(snapshot.accessTokenExpiresAt) > now() + 30000 && (expect === undefined || expect(snapshot)))
|
|
115302
|
+
if (snapshot !== null && snapshot.refreshState !== "uncertain" && snapshot.refreshAttempt === undefined && Date.parse(snapshot.accessTokenExpiresAt) > now() + 30000 && (expect === undefined || expect(snapshot)) && !await store.migrationPending?.())
|
|
113903
115303
|
return snapshot.accessToken;
|
|
113904
|
-
return locked(async () => {
|
|
115304
|
+
return locked(async (view) => {
|
|
113905
115305
|
const current = await store.readAuthoritative();
|
|
113906
115306
|
if (current === null)
|
|
113907
115307
|
throw new SignInError(`Not signed in. ${signInHint("first")}`);
|
|
113908
115308
|
if (expect !== undefined && !expect(current))
|
|
113909
115309
|
throw new CredentialIdentityChanged;
|
|
115310
|
+
await view?.settle();
|
|
113910
115311
|
return (await refreshed(current)).accessToken;
|
|
113911
115312
|
});
|
|
113912
115313
|
},
|
|
@@ -113927,6 +115328,26 @@ function createSession(options) {
|
|
|
113927
115328
|
};
|
|
113928
115329
|
}
|
|
113929
115330
|
|
|
115331
|
+
// packages/omo-opencode/src/cli/service-auth/sync-pin-retire.ts
|
|
115332
|
+
var reason = (error) => error instanceof Error && ("code" in error) && typeof error.code === "string" ? error.code : "unknown";
|
|
115333
|
+
function retireSyncPinOnDiscard(options) {
|
|
115334
|
+
const hook = async (discarded) => {
|
|
115335
|
+
if (discarded.kind === "unreadable") {
|
|
115336
|
+
options.log("memory sync: a stored sign-in could not be read while it was replaced; its sync pin was left in place");
|
|
115337
|
+
return;
|
|
115338
|
+
}
|
|
115339
|
+
const account = discarded.owner?.accountId ?? discarded.accountId;
|
|
115340
|
+
if (account === undefined)
|
|
115341
|
+
return;
|
|
115342
|
+
try {
|
|
115343
|
+
await retireSyncDevice({ pinDir: options.pinDir(), account });
|
|
115344
|
+
} catch (error) {
|
|
115345
|
+
options.log(`memory sync: the sync pin could not be retired (${reason(error)}); it was left in place`);
|
|
115346
|
+
}
|
|
115347
|
+
};
|
|
115348
|
+
return Object.assign(hook, { wantsAccount: () => hasLiveTrustAnchor(options.pinDir()).catch(() => false) });
|
|
115349
|
+
}
|
|
115350
|
+
|
|
113930
115351
|
// packages/omo-opencode/src/cli/service-auth/commands.ts
|
|
113931
115352
|
async function ensureServiceAvailable(session, api) {
|
|
113932
115353
|
try {
|
|
@@ -113969,7 +115390,12 @@ async function run2(action, options) {
|
|
|
113969
115390
|
try {
|
|
113970
115391
|
const api = serviceOrigin(options.api ?? process.env.OMO_SERVICE_API_URL ?? "https://api.omo.dev");
|
|
113971
115392
|
const store = createCredentialStore(api, { wait: INTERACTIVE_READ_WAIT });
|
|
113972
|
-
const session = createSession({
|
|
115393
|
+
const session = createSession({
|
|
115394
|
+
api,
|
|
115395
|
+
store,
|
|
115396
|
+
signal: controller.signal,
|
|
115397
|
+
beforeKeysDiscarded: retireSyncPinOnDiscard({ pinDir: () => syncPinDir(resolveMemoryRoot(process.env, process.cwd())), log: (line) => console.error(line) })
|
|
115398
|
+
});
|
|
113973
115399
|
if (action === "logout") {
|
|
113974
115400
|
const revoked = await session.logout();
|
|
113975
115401
|
console.log("Signed out of OmO. Stored credentials and device keys were removed.");
|
|
@@ -114029,6 +115455,10 @@ function refuseClosedServiceAuth() {
|
|
|
114029
115455
|
}
|
|
114030
115456
|
function configureClosedServiceAuthCommands(program) {
|
|
114031
115457
|
for (const name of SERVICE_AUTH_COMMANDS) {
|
|
115458
|
+
if (name === "login") {
|
|
115459
|
+
configureClosedDeviceLogin(program);
|
|
115460
|
+
continue;
|
|
115461
|
+
}
|
|
114032
115462
|
const command = program.command(name, { hidden: true }).helpOption(false).allowUnknownOption().allowExcessArguments().action(() => {
|
|
114033
115463
|
console.error(SERVICE_ACCOUNTS_CLOSED_MESSAGE);
|
|
114034
115464
|
process.exitCode = 1;
|
|
@@ -114036,6 +115466,17 @@ function configureClosedServiceAuthCommands(program) {
|
|
|
114036
115466
|
command.help = refuseClosedServiceAuth;
|
|
114037
115467
|
}
|
|
114038
115468
|
}
|
|
115469
|
+
function configureClosedDeviceLogin(program) {
|
|
115470
|
+
const command = program.command("login", { hidden: true }).helpOption(false).allowUnknownOption().allowExcessArguments().option("--device").option("--no-browser").option("--api <url>").action((options) => {
|
|
115471
|
+
if (options.device !== true && options.browser !== false || command.args.length > 0) {
|
|
115472
|
+
console.error(SERVICE_ACCOUNTS_CLOSED_MESSAGE);
|
|
115473
|
+
process.exitCode = 1;
|
|
115474
|
+
return;
|
|
115475
|
+
}
|
|
115476
|
+
return run2("login", { ...options, device: true });
|
|
115477
|
+
});
|
|
115478
|
+
command.help = refuseClosedServiceAuth;
|
|
115479
|
+
}
|
|
114039
115480
|
function configureServiceAuthCommands(program, open = serviceAccountsOpen()) {
|
|
114040
115481
|
if (!open) {
|
|
114041
115482
|
configureClosedServiceAuthCommands(program);
|
|
@@ -114237,11 +115678,11 @@ async function boulder(options) {
|
|
|
114237
115678
|
// packages/omo-opencode/src/cli/codex-ulw-loop.ts
|
|
114238
115679
|
import { spawn as spawn6 } from "node:child_process";
|
|
114239
115680
|
import { existsSync as existsSync67, readFileSync as readFileSync45, realpathSync as realpathSync14 } from "node:fs";
|
|
114240
|
-
import { homedir as
|
|
115681
|
+
import { homedir as homedir36 } from "node:os";
|
|
114241
115682
|
var ULW_LOOP_DELEGATION_SENTINEL = "OMO_ULW_LOOP_DELEGATED";
|
|
114242
115683
|
function resolveCodexUlwLoopCommand(input = {}) {
|
|
114243
115684
|
const env = input.env ?? process.env;
|
|
114244
|
-
const homeDir = input.homeDir ??
|
|
115685
|
+
const homeDir = input.homeDir ?? homedir36();
|
|
114245
115686
|
const localComponentBin = resolveLocalUlwLoopBin(env, homeDir);
|
|
114246
115687
|
if (localComponentBin !== null)
|
|
114247
115688
|
return { executable: localComponentBin, argsPrefix: [] };
|
|
@@ -114484,7 +115925,7 @@ function linkedWorktrees(records) {
|
|
|
114484
115925
|
}
|
|
114485
115926
|
// packages/omo-opencode/src/cli/worktree-sweep/sweep.ts
|
|
114486
115927
|
import { existsSync as existsSync68 } from "node:fs";
|
|
114487
|
-
import { stat as
|
|
115928
|
+
import { stat as stat12 } from "node:fs/promises";
|
|
114488
115929
|
import os7 from "node:os";
|
|
114489
115930
|
import { normalize as normalize2 } from "node:path";
|
|
114490
115931
|
|
|
@@ -114567,7 +116008,7 @@ async function isOlderThan(worktreePath, days, now) {
|
|
|
114567
116008
|
if (days <= 0)
|
|
114568
116009
|
return false;
|
|
114569
116010
|
try {
|
|
114570
|
-
const stats = await
|
|
116011
|
+
const stats = await stat12(worktreePath);
|
|
114571
116012
|
return now - stats.mtimeMs > days * DAY_MS;
|
|
114572
116013
|
} catch {
|
|
114573
116014
|
return false;
|
|
@@ -114732,7 +116173,7 @@ prunes.
|
|
|
114732
116173
|
|
|
114733
116174
|
// packages/omo-opencode/src/cli/config-migrate.ts
|
|
114734
116175
|
init_startup_migration();
|
|
114735
|
-
import { posix as
|
|
116176
|
+
import { posix as posix15 } from "node:path";
|
|
114736
116177
|
function reports(result) {
|
|
114737
116178
|
return result.results.map((entry) => ({
|
|
114738
116179
|
diagnostics: entry.diagnostics,
|
|
@@ -114766,7 +116207,7 @@ function runConfigMigrate(options = {}) {
|
|
|
114766
116207
|
dryRun: options.dryRun ?? false,
|
|
114767
116208
|
environment,
|
|
114768
116209
|
...homeDir === undefined ? {} : { env: { HOME: homeDir }, homeDir },
|
|
114769
|
-
pathOperations:
|
|
116210
|
+
pathOperations: posix15
|
|
114770
116211
|
});
|
|
114771
116212
|
const report = reports(result);
|
|
114772
116213
|
const response = {
|