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/index.js
CHANGED
|
@@ -2132,7 +2132,7 @@ var package_default;
|
|
|
2132
2132
|
var init_package = __esm(() => {
|
|
2133
2133
|
package_default = {
|
|
2134
2134
|
name: "oh-my-opencode",
|
|
2135
|
-
version: "5.1.
|
|
2135
|
+
version: "5.1.63",
|
|
2136
2136
|
description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
|
|
2137
2137
|
main: "./dist/index.js",
|
|
2138
2138
|
types: "dist/index.d.ts",
|
|
@@ -2319,7 +2319,7 @@ var init_package = __esm(() => {
|
|
|
2319
2319
|
},
|
|
2320
2320
|
devDependencies: {
|
|
2321
2321
|
"@clack/prompts": "^1.8.1",
|
|
2322
|
-
"@code-yeongyu/senpi": "2026.11.
|
|
2322
|
+
"@code-yeongyu/senpi": "2026.11.5-1",
|
|
2323
2323
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
2324
2324
|
"@oh-my-opencode/agents-md-core": "workspace:*",
|
|
2325
2325
|
"@oh-my-opencode/ast-grep-mcp": "workspace:*",
|
|
@@ -2384,18 +2384,18 @@ var init_package = __esm(() => {
|
|
|
2384
2384
|
typescript: "^7.0.2"
|
|
2385
2385
|
},
|
|
2386
2386
|
optionalDependencies: {
|
|
2387
|
-
"oh-my-opencode-darwin-arm64": "5.1.
|
|
2388
|
-
"oh-my-opencode-darwin-x64": "5.1.
|
|
2389
|
-
"oh-my-opencode-darwin-x64-baseline": "5.1.
|
|
2390
|
-
"oh-my-opencode-linux-arm64": "5.1.
|
|
2391
|
-
"oh-my-opencode-linux-arm64-musl": "5.1.
|
|
2392
|
-
"oh-my-opencode-linux-x64": "5.1.
|
|
2393
|
-
"oh-my-opencode-linux-x64-baseline": "5.1.
|
|
2394
|
-
"oh-my-opencode-linux-x64-musl": "5.1.
|
|
2395
|
-
"oh-my-opencode-linux-x64-musl-baseline": "5.1.
|
|
2396
|
-
"oh-my-opencode-windows-arm64": "5.1.
|
|
2397
|
-
"oh-my-opencode-windows-x64": "5.1.
|
|
2398
|
-
"oh-my-opencode-windows-x64-baseline": "5.1.
|
|
2387
|
+
"oh-my-opencode-darwin-arm64": "5.1.63",
|
|
2388
|
+
"oh-my-opencode-darwin-x64": "5.1.63",
|
|
2389
|
+
"oh-my-opencode-darwin-x64-baseline": "5.1.63",
|
|
2390
|
+
"oh-my-opencode-linux-arm64": "5.1.63",
|
|
2391
|
+
"oh-my-opencode-linux-arm64-musl": "5.1.63",
|
|
2392
|
+
"oh-my-opencode-linux-x64": "5.1.63",
|
|
2393
|
+
"oh-my-opencode-linux-x64-baseline": "5.1.63",
|
|
2394
|
+
"oh-my-opencode-linux-x64-musl": "5.1.63",
|
|
2395
|
+
"oh-my-opencode-linux-x64-musl-baseline": "5.1.63",
|
|
2396
|
+
"oh-my-opencode-windows-arm64": "5.1.63",
|
|
2397
|
+
"oh-my-opencode-windows-x64": "5.1.63",
|
|
2398
|
+
"oh-my-opencode-windows-x64-baseline": "5.1.63"
|
|
2399
2399
|
},
|
|
2400
2400
|
overrides: {
|
|
2401
2401
|
hono: "^4.13.8",
|
|
@@ -7339,7 +7339,34 @@ var init_which = __esm(() => {
|
|
|
7339
7339
|
});
|
|
7340
7340
|
|
|
7341
7341
|
// packages/utils/src/runtime/file.ts
|
|
7342
|
-
|
|
7342
|
+
import { access, readFile, unlink, writeFile } from "fs/promises";
|
|
7343
|
+
function createNodeFile(path) {
|
|
7344
|
+
return {
|
|
7345
|
+
text() {
|
|
7346
|
+
return readFile(path, "utf8");
|
|
7347
|
+
},
|
|
7348
|
+
async arrayBuffer() {
|
|
7349
|
+
const buffer = await readFile(path);
|
|
7350
|
+
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
7351
|
+
},
|
|
7352
|
+
exists() {
|
|
7353
|
+
return access(path).then(() => true, () => false);
|
|
7354
|
+
},
|
|
7355
|
+
delete() {
|
|
7356
|
+
return unlink(path);
|
|
7357
|
+
}
|
|
7358
|
+
};
|
|
7359
|
+
}
|
|
7360
|
+
function bunFile(path) {
|
|
7361
|
+
const bun = runtime3.Bun;
|
|
7362
|
+
if (bun)
|
|
7363
|
+
return bun.file(path);
|
|
7364
|
+
return createNodeFile(path);
|
|
7365
|
+
}
|
|
7366
|
+
var runtime3;
|
|
7367
|
+
var init_file = __esm(() => {
|
|
7368
|
+
runtime3 = globalThis;
|
|
7369
|
+
});
|
|
7343
7370
|
|
|
7344
7371
|
// packages/utils/src/runtime/git-bash.ts
|
|
7345
7372
|
import { execFileSync } from "child_process";
|
|
@@ -12283,7 +12310,9 @@ var init_zip_extractor = __esm(() => {
|
|
|
12283
12310
|
});
|
|
12284
12311
|
|
|
12285
12312
|
// packages/omo-opencode/src/shared/bun-file-shim.ts
|
|
12286
|
-
var init_bun_file_shim = () => {
|
|
12313
|
+
var init_bun_file_shim = __esm(() => {
|
|
12314
|
+
init_runtime();
|
|
12315
|
+
});
|
|
12287
12316
|
|
|
12288
12317
|
// packages/omo-opencode/src/shared/binary-downloader.ts
|
|
12289
12318
|
import { chmodSync, existsSync as existsSync9, mkdirSync as mkdirSync4, unlinkSync as unlinkSync3 } from "fs";
|
|
@@ -92710,7 +92739,7 @@ var package_default2;
|
|
|
92710
92739
|
var init_package2 = __esm(() => {
|
|
92711
92740
|
package_default2 = {
|
|
92712
92741
|
name: "@oh-my-opencode/omo-codex",
|
|
92713
|
-
version: "5.1.
|
|
92742
|
+
version: "5.1.63",
|
|
92714
92743
|
type: "module",
|
|
92715
92744
|
private: true,
|
|
92716
92745
|
description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
|
|
@@ -93326,7 +93355,7 @@ var init_check_for_update = __esm(() => {
|
|
|
93326
93355
|
});
|
|
93327
93356
|
|
|
93328
93357
|
// packages/omo-opencode/src/hooks/auto-update-checker/checker/sync-package-json.ts
|
|
93329
|
-
import * as
|
|
93358
|
+
import * as crypto2 from "crypto";
|
|
93330
93359
|
import * as fs8 from "fs";
|
|
93331
93360
|
import * as path11 from "path";
|
|
93332
93361
|
function safeUnlink(filePath) {
|
|
@@ -93350,7 +93379,7 @@ function getPackageNameFromIntent(pluginInfo) {
|
|
|
93350
93379
|
return ACCEPTED_PACKAGE_NAMES2.find((packageName) => pluginInfo.entry === packageName || pluginInfo.entry.startsWith(`${packageName}@`)) ?? PACKAGE_NAME3;
|
|
93351
93380
|
}
|
|
93352
93381
|
function writeCachePackageJson(cachePackageJsonPath, pkgJson) {
|
|
93353
|
-
const tmpPath = `${cachePackageJsonPath}.${
|
|
93382
|
+
const tmpPath = `${cachePackageJsonPath}.${crypto2.randomUUID()}`;
|
|
93354
93383
|
try {
|
|
93355
93384
|
fs8.mkdirSync(path11.dirname(cachePackageJsonPath), { recursive: true });
|
|
93356
93385
|
fs8.writeFileSync(tmpPath, JSON.stringify(pkgJson, null, 2));
|
|
@@ -94271,7 +94300,7 @@ import { existsSync as existsSync27 } from "fs";
|
|
|
94271
94300
|
import { homedir as homedir7 } from "os";
|
|
94272
94301
|
|
|
94273
94302
|
// packages/omo-codex/src/install/codex-cache-bins.ts
|
|
94274
|
-
import { chmod, lstat as lstat4, mkdir, readFile as
|
|
94303
|
+
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 "fs/promises";
|
|
94275
94304
|
import { basename as basename4, isAbsolute as isAbsolute2, join as join26, relative, resolve as resolve6, sep } from "path";
|
|
94276
94305
|
|
|
94277
94306
|
// packages/omo-codex/src/install/codex-cache-command-shim.ts
|
|
@@ -94315,7 +94344,7 @@ function windowsCommandShim(targetPath) {
|
|
|
94315
94344
|
}
|
|
94316
94345
|
|
|
94317
94346
|
// packages/omo-codex/src/install/codex-cache-dangling-bins.ts
|
|
94318
|
-
import { lstat as lstat2, readFile, readdir, readlink, rm, stat } from "fs/promises";
|
|
94347
|
+
import { lstat as lstat2, readFile as readFile2, readdir, readlink, rm, stat } from "fs/promises";
|
|
94319
94348
|
import { dirname as dirname10, isAbsolute, join as join23, resolve as resolve5 } from "path";
|
|
94320
94349
|
|
|
94321
94350
|
// packages/omo-codex/src/install/codex-cache-fs.ts
|
|
@@ -94377,7 +94406,7 @@ async function removeDanglingGeneratedCommandShim(linkPath) {
|
|
|
94377
94406
|
const linkStat = await lstat2(linkPath);
|
|
94378
94407
|
if (!linkStat.isFile())
|
|
94379
94408
|
return;
|
|
94380
|
-
const content = await
|
|
94409
|
+
const content = await readFile2(linkPath, "utf8");
|
|
94381
94410
|
if (!content.includes(COMMAND_SHIM_MARKER))
|
|
94382
94411
|
return;
|
|
94383
94412
|
const target = extractCommandShimTarget(content);
|
|
@@ -94425,7 +94454,7 @@ function hasOmoCodexPluginPrefix(parts, endExclusive) {
|
|
|
94425
94454
|
}
|
|
94426
94455
|
|
|
94427
94456
|
// packages/omo-codex/src/install/codex-cache-legacy-bins.ts
|
|
94428
|
-
import { lstat as lstat3, readFile as
|
|
94457
|
+
import { lstat as lstat3, readFile as readFile3, readlink as readlink2, rm as rm2 } from "fs/promises";
|
|
94429
94458
|
import { join as join24 } from "path";
|
|
94430
94459
|
var LEGACY_CODEX_COMPONENT_BINS = [
|
|
94431
94460
|
{ name: "omo", component: "ulw-loop" },
|
|
@@ -94460,7 +94489,7 @@ async function removeLegacyCodexComponentBin(linkPath, component, platform) {
|
|
|
94460
94489
|
}
|
|
94461
94490
|
if (!stat.isFile())
|
|
94462
94491
|
return;
|
|
94463
|
-
const content = await
|
|
94492
|
+
const content = await readFile3(linkPath, "utf8");
|
|
94464
94493
|
if (content.includes(COMMAND_SHIM_MARKER))
|
|
94465
94494
|
await rm2(linkPath, { force: true });
|
|
94466
94495
|
} catch (error) {
|
|
@@ -94697,7 +94726,7 @@ async function collectPackageBins(directory, root, links) {
|
|
|
94697
94726
|
}
|
|
94698
94727
|
}
|
|
94699
94728
|
async function appendPackageBinLinks(packageJsonPath, packageRoot, root, links) {
|
|
94700
|
-
const packageJson = JSON.parse(await
|
|
94729
|
+
const packageJson = JSON.parse(await readFile4(packageJsonPath, "utf8"));
|
|
94701
94730
|
if (!isPlainRecord4(packageJson))
|
|
94702
94731
|
return;
|
|
94703
94732
|
const packageName = packageJson.name;
|
|
@@ -94749,13 +94778,13 @@ async function replaceSymlink(linkPath, targetPath) {
|
|
|
94749
94778
|
async function replaceCommandShim(linkPath, targetPath) {
|
|
94750
94779
|
if (await existingNonShim(linkPath))
|
|
94751
94780
|
throw new Error(`${linkPath} already exists and is not a command shim`);
|
|
94752
|
-
await
|
|
94781
|
+
await writeFile2(linkPath, windowsCommandShim(targetPath));
|
|
94753
94782
|
}
|
|
94754
94783
|
async function replaceRuntimeWrapper(linkPath, content) {
|
|
94755
94784
|
if (await existingNonRuntimeWrapper(linkPath))
|
|
94756
94785
|
throw new Error(`${linkPath} already exists and is not a generated OMO runtime wrapper`);
|
|
94757
94786
|
await rm3(linkPath, { force: true });
|
|
94758
|
-
await
|
|
94787
|
+
await writeFile2(linkPath, content);
|
|
94759
94788
|
}
|
|
94760
94789
|
async function removeGeneratedRuntimeWrapper(path) {
|
|
94761
94790
|
try {
|
|
@@ -94773,7 +94802,7 @@ async function removeGeneratedRuntimeWrapper(path) {
|
|
|
94773
94802
|
}
|
|
94774
94803
|
async function readGeneratedWrapperContent(path) {
|
|
94775
94804
|
try {
|
|
94776
|
-
return await
|
|
94805
|
+
return await readFile4(path, "utf8");
|
|
94777
94806
|
} catch (error) {
|
|
94778
94807
|
if (isNodeErrorWithCode(error) && (error.code === "ENOENT" || error.code === "EISDIR"))
|
|
94779
94808
|
return "";
|
|
@@ -94787,7 +94816,7 @@ async function existingNonRuntimeWrapper(path) {
|
|
|
94787
94816
|
return false;
|
|
94788
94817
|
if (!stat.isFile())
|
|
94789
94818
|
return true;
|
|
94790
|
-
const content = await
|
|
94819
|
+
const content = await readFile4(path, "utf8");
|
|
94791
94820
|
return !content.includes(RUNTIME_WRAPPER_MARKER);
|
|
94792
94821
|
} catch (error) {
|
|
94793
94822
|
if (isNodeErrorWithCode(error) && error.code === "ENOENT")
|
|
@@ -94800,7 +94829,7 @@ async function existingNonShim(path) {
|
|
|
94800
94829
|
const stat = await lstat4(path);
|
|
94801
94830
|
if (!stat.isFile())
|
|
94802
94831
|
return true;
|
|
94803
|
-
const content = await
|
|
94832
|
+
const content = await readFile4(path, "utf8");
|
|
94804
94833
|
if (content.includes(COMMAND_SHIM_MARKER))
|
|
94805
94834
|
return false;
|
|
94806
94835
|
throw new Error(`${path} already exists and is not a generated command shim`);
|
|
@@ -94824,11 +94853,11 @@ async function existingNonSymlink(path) {
|
|
|
94824
94853
|
}
|
|
94825
94854
|
}
|
|
94826
94855
|
// packages/omo-codex/src/install/codex-cache-install.ts
|
|
94827
|
-
import { cp as cp3, mkdir as mkdir3, readFile as
|
|
94856
|
+
import { cp as cp3, mkdir as mkdir3, readFile as readFile9, readdir as readdir5, rename as rename2, rm as rm5 } from "fs/promises";
|
|
94828
94857
|
import { basename as basename5, dirname as dirname13, join as join33, sep as sep6 } from "path";
|
|
94829
94858
|
|
|
94830
94859
|
// packages/omo-codex/src/install/codex-cache-bundled-mcps.ts
|
|
94831
|
-
import { cp, mkdir as mkdir2, readFile as
|
|
94860
|
+
import { cp, mkdir as mkdir2, readFile as readFile5, stat as stat3 } from "fs/promises";
|
|
94832
94861
|
import { dirname as dirname11, join as join27, resolve as resolve7 } from "path";
|
|
94833
94862
|
var BUNDLED_MCP_RUNTIMES = [
|
|
94834
94863
|
{
|
|
@@ -94870,7 +94899,7 @@ async function copyBundledMcpRuntimeDist(pluginRoot, sourceRoot, runtime) {
|
|
|
94870
94899
|
async function readSourceMcpArgs(path) {
|
|
94871
94900
|
let parsed;
|
|
94872
94901
|
try {
|
|
94873
|
-
parsed = JSON.parse(await
|
|
94902
|
+
parsed = JSON.parse(await readFile5(path, "utf8"));
|
|
94874
94903
|
} catch (error) {
|
|
94875
94904
|
if (error instanceof Error)
|
|
94876
94905
|
return new Set;
|
|
@@ -94901,7 +94930,7 @@ async function isDirectory(path) {
|
|
|
94901
94930
|
|
|
94902
94931
|
// packages/omo-codex/src/install/codex-cache-local-dependencies.ts
|
|
94903
94932
|
import { realpathSync as realpathSync7 } from "fs";
|
|
94904
|
-
import { readFile as
|
|
94933
|
+
import { readFile as readFile6, readdir as readdir3, writeFile as writeFile3 } from "fs/promises";
|
|
94905
94934
|
import { dirname as dirname12, isAbsolute as isAbsolute4, join as join29, relative as relative3, resolve as resolve9, sep as sep2 } from "path";
|
|
94906
94935
|
|
|
94907
94936
|
// packages/omo-codex/src/install/codex-cache-paths.ts
|
|
@@ -94967,7 +94996,7 @@ async function rewriteCachedPackageLocalFileDependencies(pluginRoot, sourceRoot)
|
|
|
94967
94996
|
const packageLock = await readPackageLock(pluginRoot);
|
|
94968
94997
|
let rewroteAnyPackageJson = false;
|
|
94969
94998
|
for (const packageJsonPath of packageJsonPaths) {
|
|
94970
|
-
const raw = await
|
|
94999
|
+
const raw = await readFile6(packageJsonPath, "utf8");
|
|
94971
95000
|
const parsed = JSON.parse(raw);
|
|
94972
95001
|
if (!isPlainRecord4(parsed))
|
|
94973
95002
|
continue;
|
|
@@ -95002,20 +95031,20 @@ async function rewriteCachedPackageLocalFileDependencies(pluginRoot, sourceRoot)
|
|
|
95002
95031
|
}
|
|
95003
95032
|
}
|
|
95004
95033
|
if (changed) {
|
|
95005
|
-
await
|
|
95034
|
+
await writeFile3(packageJsonPath, `${JSON.stringify(parsed, null, "\t")}
|
|
95006
95035
|
`);
|
|
95007
95036
|
rewroteAnyPackageJson = true;
|
|
95008
95037
|
}
|
|
95009
95038
|
}
|
|
95010
95039
|
if (packageLock.changed)
|
|
95011
|
-
await
|
|
95040
|
+
await writeFile3(packageLock.path, `${JSON.stringify(packageLock.value, null, "\t")}
|
|
95012
95041
|
`);
|
|
95013
95042
|
return rewroteAnyPackageJson;
|
|
95014
95043
|
}
|
|
95015
95044
|
async function readPackageLock(pluginRoot) {
|
|
95016
95045
|
const path = join29(pluginRoot, "package-lock.json");
|
|
95017
95046
|
try {
|
|
95018
|
-
const parsed = JSON.parse(await
|
|
95047
|
+
const parsed = JSON.parse(await readFile6(path, "utf8"));
|
|
95019
95048
|
return { path, value: isPlainRecord4(parsed) ? parsed : null, changed: false };
|
|
95020
95049
|
} catch (error) {
|
|
95021
95050
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
@@ -95089,14 +95118,14 @@ async function collectPackageJsonPaths(directory, root, paths) {
|
|
|
95089
95118
|
}
|
|
95090
95119
|
|
|
95091
95120
|
// packages/omo-codex/src/install/codex-cache-mcp-manifest.ts
|
|
95092
|
-
import { readFile as
|
|
95121
|
+
import { readFile as readFile7, writeFile as writeFile4 } from "fs/promises";
|
|
95093
95122
|
import { join as join30, sep as sep3 } from "path";
|
|
95094
95123
|
var CONTEXT7_API_KEY_ENV = "CONTEXT7_API_KEY";
|
|
95095
95124
|
async function rewriteCachedMcpManifest(pluginRoot, sourceRoot = pluginRoot) {
|
|
95096
95125
|
const manifestPath = join30(pluginRoot, ".mcp.json");
|
|
95097
95126
|
if (!await fileExistsStrict(manifestPath))
|
|
95098
95127
|
return;
|
|
95099
|
-
const raw = await
|
|
95128
|
+
const raw = await readFile7(manifestPath, "utf8");
|
|
95100
95129
|
const parsed = JSON.parse(raw);
|
|
95101
95130
|
if (!isPlainRecord4(parsed) || !isPlainRecord4(parsed.mcpServers))
|
|
95102
95131
|
return;
|
|
@@ -95130,7 +95159,7 @@ async function rewriteCachedMcpManifest(pluginRoot, sourceRoot = pluginRoot) {
|
|
|
95130
95159
|
}
|
|
95131
95160
|
}
|
|
95132
95161
|
if (changed)
|
|
95133
|
-
await
|
|
95162
|
+
await writeFile4(manifestPath, `${JSON.stringify(parsed, null, "\t")}
|
|
95134
95163
|
`);
|
|
95135
95164
|
}
|
|
95136
95165
|
function sanitizeContext7Auth(server) {
|
|
@@ -95189,7 +95218,7 @@ async function rewriteCachedManifestRoot(pluginRoot, fromRoot, toRoot) {
|
|
|
95189
95218
|
const manifestPath = join30(pluginRoot, ".mcp.json");
|
|
95190
95219
|
if (!await fileExistsStrict(manifestPath))
|
|
95191
95220
|
return;
|
|
95192
|
-
const raw = await
|
|
95221
|
+
const raw = await readFile7(manifestPath, "utf8");
|
|
95193
95222
|
const parsed = JSON.parse(raw);
|
|
95194
95223
|
if (!isPlainRecord4(parsed) || !isPlainRecord4(parsed.mcpServers))
|
|
95195
95224
|
return;
|
|
@@ -95216,7 +95245,7 @@ async function rewriteCachedManifestRoot(pluginRoot, fromRoot, toRoot) {
|
|
|
95216
95245
|
}
|
|
95217
95246
|
}
|
|
95218
95247
|
if (changed)
|
|
95219
|
-
await
|
|
95248
|
+
await writeFile4(manifestPath, `${JSON.stringify(parsed, null, "\t")}
|
|
95220
95249
|
`);
|
|
95221
95250
|
}
|
|
95222
95251
|
|
|
@@ -95278,7 +95307,7 @@ async function unsupportedEntries(root, directory) {
|
|
|
95278
95307
|
}
|
|
95279
95308
|
|
|
95280
95309
|
// packages/omo-codex/src/install/codex-hook-targets.ts
|
|
95281
|
-
import { readFile as
|
|
95310
|
+
import { readFile as readFile8 } from "fs/promises";
|
|
95282
95311
|
import { join as join32, sep as sep5 } from "path";
|
|
95283
95312
|
var PLUGIN_ROOT_TARGET_PATTERN = /\$\{PLUGIN_ROOT\}[\\/]+([^"']+)/g;
|
|
95284
95313
|
async function findMissingHookCommandTargets(pluginRoot) {
|
|
@@ -95286,7 +95315,7 @@ async function findMissingHookCommandTargets(pluginRoot) {
|
|
|
95286
95315
|
for (const manifestPath of await hookManifestPaths(pluginRoot)) {
|
|
95287
95316
|
if (!await fileExistsStrict(manifestPath))
|
|
95288
95317
|
continue;
|
|
95289
|
-
const parsed = JSON.parse(await
|
|
95318
|
+
const parsed = JSON.parse(await readFile8(manifestPath, "utf8"));
|
|
95290
95319
|
collectCommands(parsed, commands);
|
|
95291
95320
|
}
|
|
95292
95321
|
const missing = [];
|
|
@@ -95310,7 +95339,7 @@ async function hookManifestPaths(pluginRoot) {
|
|
|
95310
95339
|
const pluginManifestPath = join32(pluginRoot, ".codex-plugin", "plugin.json");
|
|
95311
95340
|
if (!await fileExistsStrict(pluginManifestPath))
|
|
95312
95341
|
return [join32(pluginRoot, "hooks", "hooks.json")];
|
|
95313
|
-
const parsed = JSON.parse(await
|
|
95342
|
+
const parsed = JSON.parse(await readFile8(pluginManifestPath, "utf8"));
|
|
95314
95343
|
if (!isPlainRecord4(parsed))
|
|
95315
95344
|
return [];
|
|
95316
95345
|
if (typeof parsed.hooks === "string" && parsed.hooks.trim() !== "") {
|
|
@@ -95397,7 +95426,7 @@ async function maybeRunNpmInstall(cwd, runCommand, env, args = ["install"]) {
|
|
|
95397
95426
|
async function maybeRunNpmBuild(cwd, runCommand, env) {
|
|
95398
95427
|
if (!await fileExistsStrict(join33(cwd, "package.json")))
|
|
95399
95428
|
return;
|
|
95400
|
-
const packageJson = JSON.parse(await
|
|
95429
|
+
const packageJson = JSON.parse(await readFile9(join33(cwd, "package.json"), "utf8"));
|
|
95401
95430
|
if (!isPlainRecord4(packageJson))
|
|
95402
95431
|
return;
|
|
95403
95432
|
const scripts = packageJson.scripts;
|
|
@@ -95408,7 +95437,7 @@ async function maybeRunNpmBuild(cwd, runCommand, env) {
|
|
|
95408
95437
|
async function maybeRunNpmSyncSkills(cwd, runCommand, env) {
|
|
95409
95438
|
if (!await fileExistsStrict(join33(cwd, "package.json")))
|
|
95410
95439
|
return;
|
|
95411
|
-
const packageJson = JSON.parse(await
|
|
95440
|
+
const packageJson = JSON.parse(await readFile9(join33(cwd, "package.json"), "utf8"));
|
|
95412
95441
|
if (!isPlainRecord4(packageJson))
|
|
95413
95442
|
return;
|
|
95414
95443
|
const scripts = packageJson.scripts;
|
|
@@ -95471,7 +95500,7 @@ var removedSparkshellPromptSurfaceFiles = new Set(["directive.md", "plugin.json"
|
|
|
95471
95500
|
var removedSparkshellTextFilePattern = /\.(?:json|md|toml|ya?ml)$/i;
|
|
95472
95501
|
async function assertNoRemovedSparkshellPromptReferences(pluginRoot) {
|
|
95473
95502
|
for (const filePath of await listRemovedSparkshellPromptSurfaceFiles(pluginRoot, "")) {
|
|
95474
|
-
const content = await
|
|
95503
|
+
const content = await readFile9(join33(pluginRoot, filePath), "utf8");
|
|
95475
95504
|
if (!removedSparkshellReferencePattern.test(content))
|
|
95476
95505
|
continue;
|
|
95477
95506
|
throw new Error(`removed sparkshell reference found in Codex plugin prompt surface: ${filePath}`);
|
|
@@ -95620,7 +95649,7 @@ async function isBrokenCacheSymlink(path) {
|
|
|
95620
95649
|
}
|
|
95621
95650
|
}
|
|
95622
95651
|
// packages/omo-codex/src/install/codex-cached-marketplace-manifest.ts
|
|
95623
|
-
import { mkdir as mkdir4, rename as rename3, rm as rm7, stat as stat5, writeFile as
|
|
95652
|
+
import { mkdir as mkdir4, rename as rename3, rm as rm7, stat as stat5, writeFile as writeFile5 } from "fs/promises";
|
|
95624
95653
|
import { join as join35 } from "path";
|
|
95625
95654
|
async function writeCachedMarketplaceManifest(input) {
|
|
95626
95655
|
const marketplaceDir = join35(input.marketplaceRoot, ".agents", "plugins");
|
|
@@ -95633,7 +95662,7 @@ async function writeCachedMarketplaceManifest(input) {
|
|
|
95633
95662
|
const manifestPath = join35(marketplaceDir, "marketplace.json");
|
|
95634
95663
|
const tempPath = join35(marketplaceDir, `.marketplace.json.tmp-${process.pid}-${Date.now()}`);
|
|
95635
95664
|
try {
|
|
95636
|
-
await
|
|
95665
|
+
await writeFile5(tempPath, `${JSON.stringify({
|
|
95637
95666
|
name: input.marketplaceName,
|
|
95638
95667
|
plugins: input.plugins.map((plugin) => ({
|
|
95639
95668
|
name: plugin.name,
|
|
@@ -95659,7 +95688,7 @@ async function isDirectory2(path) {
|
|
|
95659
95688
|
|
|
95660
95689
|
// packages/omo-codex/src/install/codex-package-layout.ts
|
|
95661
95690
|
import { existsSync as existsSync24 } from "fs";
|
|
95662
|
-
import { readFile as
|
|
95691
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
95663
95692
|
import { join as join36 } from "path";
|
|
95664
95693
|
var PACKAGED_CODEX_INSTALLER_NAMES = new Set([
|
|
95665
95694
|
"@code-yeongyu/lazycodex",
|
|
@@ -95675,14 +95704,14 @@ async function shouldBuildSourcePackages(repoRoot) {
|
|
|
95675
95704
|
const packageJsonPath = join36(repoRoot, "package.json");
|
|
95676
95705
|
if (!existsSync24(packageJsonPath))
|
|
95677
95706
|
return true;
|
|
95678
|
-
const packageJson = JSON.parse(await
|
|
95707
|
+
const packageJson = JSON.parse(await readFile10(packageJsonPath, "utf8"));
|
|
95679
95708
|
if (!isPlainRecord4(packageJson) || typeof packageJson.name !== "string")
|
|
95680
95709
|
return true;
|
|
95681
95710
|
return !PACKAGED_CODEX_INSTALLER_NAMES.has(packageJson.name);
|
|
95682
95711
|
}
|
|
95683
95712
|
|
|
95684
95713
|
// packages/omo-codex/src/install/codex-config-toml.ts
|
|
95685
|
-
import { mkdir as mkdir5, readFile as
|
|
95714
|
+
import { mkdir as mkdir5, readFile as readFile12 } from "fs/promises";
|
|
95686
95715
|
import { dirname as dirname16 } from "path";
|
|
95687
95716
|
|
|
95688
95717
|
// packages/omo-codex/src/install/toml-section-editor.ts
|
|
@@ -96279,18 +96308,18 @@ function tomlKeySegment(value) {
|
|
|
96279
96308
|
}
|
|
96280
96309
|
|
|
96281
96310
|
// packages/omo-codex/src/install/codex-config-atomic-write.ts
|
|
96282
|
-
import { lstat as lstat7, readlink as readlink4, realpath, rename as rename4, unlink, writeFile as
|
|
96311
|
+
import { lstat as lstat7, readlink as readlink4, realpath, rename as rename4, unlink as unlink2, writeFile as writeFile6 } from "fs/promises";
|
|
96283
96312
|
import { basename as basename6, dirname as dirname14, isAbsolute as isAbsolute5, join as join37, resolve as resolve10 } from "path";
|
|
96284
96313
|
var RENAME_RETRY_DELAYS_MS = [10, 25, 50];
|
|
96285
96314
|
var RETRIABLE_RENAME_CODES = new Set(["EPERM", "EBUSY"]);
|
|
96286
96315
|
async function writeFileAtomic(targetPath, data) {
|
|
96287
96316
|
const writeTarget = await resolveSymlinkTarget(targetPath);
|
|
96288
96317
|
const temporaryPath = join37(dirname14(writeTarget), `.tmp-${basename6(writeTarget)}-${process.pid}-${Date.now()}`);
|
|
96289
|
-
await
|
|
96318
|
+
await writeFile6(temporaryPath, data);
|
|
96290
96319
|
try {
|
|
96291
96320
|
await renameWithRetry(temporaryPath, writeTarget);
|
|
96292
96321
|
} catch (error) {
|
|
96293
|
-
await
|
|
96322
|
+
await unlink2(temporaryPath).catch((unlinkError) => {
|
|
96294
96323
|
if (unlinkError instanceof Error)
|
|
96295
96324
|
return;
|
|
96296
96325
|
return;
|
|
@@ -96785,7 +96814,7 @@ function isRootSetting(line, key) {
|
|
|
96785
96814
|
|
|
96786
96815
|
// packages/omo-codex/src/install/codex-model-catalog.ts
|
|
96787
96816
|
init_latest_models();
|
|
96788
|
-
import { readFile as
|
|
96817
|
+
import { readFile as readFile11 } from "fs/promises";
|
|
96789
96818
|
import { join as join38 } from "path";
|
|
96790
96819
|
var FALLBACK_CODEX_MODEL_CATALOG = {
|
|
96791
96820
|
current: {
|
|
@@ -96819,7 +96848,7 @@ var FALLBACK_CODEX_MODEL_CATALOG = {
|
|
|
96819
96848
|
async function readCodexModelCatalog(codexPackageRoot) {
|
|
96820
96849
|
const catalogPath = join38(codexPackageRoot, "plugin", "model-catalog.json");
|
|
96821
96850
|
try {
|
|
96822
|
-
const parsed = JSON.parse(await
|
|
96851
|
+
const parsed = JSON.parse(await readFile11(catalogPath, "utf8"));
|
|
96823
96852
|
return parseCodexModelCatalog(parsed) ?? FALLBACK_CODEX_MODEL_CATALOG;
|
|
96824
96853
|
} catch (error) {
|
|
96825
96854
|
if (error instanceof Error)
|
|
@@ -97044,7 +97073,7 @@ async function updateCodexConfig(input) {
|
|
|
97044
97073
|
await mkdir5(dirname16(input.configPath), { recursive: true });
|
|
97045
97074
|
let config;
|
|
97046
97075
|
try {
|
|
97047
|
-
config = await
|
|
97076
|
+
config = await readFile12(input.configPath, "utf8");
|
|
97048
97077
|
} catch (error) {
|
|
97049
97078
|
if (!isMissingFileError(error))
|
|
97050
97079
|
throw error;
|
|
@@ -97092,7 +97121,7 @@ function isMissingFileError(error) {
|
|
|
97092
97121
|
|
|
97093
97122
|
// packages/omo-codex/src/install/codex-hook-trust.ts
|
|
97094
97123
|
import { createHash as createHash3 } from "crypto";
|
|
97095
|
-
import { readFile as
|
|
97124
|
+
import { readFile as readFile13 } from "fs/promises";
|
|
97096
97125
|
import { join as join40 } from "path";
|
|
97097
97126
|
var EVENT_LABELS = new Map([
|
|
97098
97127
|
["PreToolUse", "pre_tool_use"],
|
|
@@ -97110,7 +97139,7 @@ async function trustedHookStatesForPlugin(input) {
|
|
|
97110
97139
|
const manifestPath = join40(input.pluginRoot, ".codex-plugin", "plugin.json");
|
|
97111
97140
|
if (!await exists(manifestPath))
|
|
97112
97141
|
return [];
|
|
97113
|
-
const manifest = JSON.parse(await
|
|
97142
|
+
const manifest = JSON.parse(await readFile13(manifestPath, "utf8"));
|
|
97114
97143
|
if (!isPlainRecord4(manifest))
|
|
97115
97144
|
return [];
|
|
97116
97145
|
const states = [];
|
|
@@ -97118,7 +97147,7 @@ async function trustedHookStatesForPlugin(input) {
|
|
|
97118
97147
|
const hooksPath = join40(input.pluginRoot, hookPath);
|
|
97119
97148
|
if (!await exists(hooksPath))
|
|
97120
97149
|
continue;
|
|
97121
|
-
const parsed = JSON.parse(await
|
|
97150
|
+
const parsed = JSON.parse(await readFile13(hooksPath, "utf8"));
|
|
97122
97151
|
if (!isPlainRecord4(parsed) || !isPlainRecord4(parsed.hooks))
|
|
97123
97152
|
continue;
|
|
97124
97153
|
states.push(...trustedHookStatesForHooksFile({
|
|
@@ -97201,7 +97230,7 @@ function stripDotSlash2(value) {
|
|
|
97201
97230
|
}
|
|
97202
97231
|
async function exists(path) {
|
|
97203
97232
|
try {
|
|
97204
|
-
await
|
|
97233
|
+
await readFile13(path, "utf8");
|
|
97205
97234
|
return true;
|
|
97206
97235
|
} catch (error) {
|
|
97207
97236
|
if (error instanceof Error)
|
|
@@ -97301,7 +97330,7 @@ function recordAt2(value, key) {
|
|
|
97301
97330
|
}
|
|
97302
97331
|
|
|
97303
97332
|
// packages/omo-codex/src/install/codex-marketplace-snapshot.ts
|
|
97304
|
-
import { cp as cp4, mkdir as mkdir6, rename as rename5, rm as rm8, writeFile as
|
|
97333
|
+
import { cp as cp4, mkdir as mkdir6, rename as rename5, rm as rm8, writeFile as writeFile7 } from "fs/promises";
|
|
97305
97334
|
import { join as join41, sep as sep7 } from "path";
|
|
97306
97335
|
var INSTALLED_MARKETPLACES_DIR = ".tmp/marketplaces";
|
|
97307
97336
|
async function writeInstalledMarketplaceSnapshot(input) {
|
|
@@ -97321,7 +97350,7 @@ async function writeMarketplaceManifest(marketplaceRoot, marketplace) {
|
|
|
97321
97350
|
const manifestDir = join41(marketplaceRoot, ".agents", "plugins");
|
|
97322
97351
|
await mkdir6(manifestDir, { recursive: true });
|
|
97323
97352
|
const tempPath = join41(manifestDir, `.marketplace-${process.pid}-${Date.now()}.json.tmp`);
|
|
97324
|
-
await
|
|
97353
|
+
await writeFile7(tempPath, `${JSON.stringify(marketplace, null, "\t")}
|
|
97325
97354
|
`);
|
|
97326
97355
|
await rename5(tempPath, join41(manifestDir, "marketplace.json"));
|
|
97327
97356
|
}
|
|
@@ -97350,15 +97379,15 @@ function shouldCopyMarketplaceSourcePath(path, root) {
|
|
|
97350
97379
|
}
|
|
97351
97380
|
|
|
97352
97381
|
// packages/omo-codex/src/install/link-cached-plugin-agents.ts
|
|
97353
|
-
import { copyFile, lstat as lstat11, mkdir as mkdir7, readdir as readdir8, readFile as
|
|
97382
|
+
import { copyFile, lstat as lstat11, mkdir as mkdir7, readdir as readdir8, readFile as readFile18, rm as rm12, writeFile as writeFile10 } from "fs/promises";
|
|
97354
97383
|
import { basename as basename7, join as join46 } from "path";
|
|
97355
97384
|
|
|
97356
97385
|
// packages/omo-codex/src/install/agent-model-overrides.ts
|
|
97357
|
-
import { readFile as
|
|
97386
|
+
import { readFile as readFile15, rm as rm9, writeFile as writeFile9 } from "fs/promises";
|
|
97358
97387
|
import { join as join43 } from "path";
|
|
97359
97388
|
|
|
97360
97389
|
// packages/omo-codex/src/install/preserved-agent-settings.ts
|
|
97361
|
-
import { lstat as lstat8, readFile as
|
|
97390
|
+
import { lstat as lstat8, readFile as readFile14, readdir as readdir7, writeFile as writeFile8 } from "fs/promises";
|
|
97362
97391
|
import { join as join42 } from "path";
|
|
97363
97392
|
|
|
97364
97393
|
// packages/omo-codex/src/install/managed-agent-reasoning-defaults.ts
|
|
@@ -97593,7 +97622,7 @@ async function capturePreservedAgentServiceTier(input) {
|
|
|
97593
97622
|
async function restorePreservedReasoning(input) {
|
|
97594
97623
|
if (input.value === undefined)
|
|
97595
97624
|
return;
|
|
97596
|
-
const content = await
|
|
97625
|
+
const content = await readFile14(input.target, "utf8");
|
|
97597
97626
|
const bundledEffort = extractReasoningEffort(content);
|
|
97598
97627
|
const effort = resolveManagedAgentReasoning({
|
|
97599
97628
|
agentName: input.agentName,
|
|
@@ -97606,33 +97635,33 @@ async function restorePreservedReasoning(input) {
|
|
|
97606
97635
|
const replacement = replaceTopLevelStringSetting(content, "model_reasoning_effort", effort, { insertIfMissing: false });
|
|
97607
97636
|
if (!replacement.replaced)
|
|
97608
97637
|
return;
|
|
97609
|
-
await
|
|
97638
|
+
await writeFile8(input.linkPath, replacement.content);
|
|
97610
97639
|
}
|
|
97611
97640
|
async function restorePreservedServiceTier(input) {
|
|
97612
97641
|
if (!input.preserved)
|
|
97613
97642
|
return;
|
|
97614
|
-
const content = await
|
|
97643
|
+
const content = await readFile14(input.linkPath, "utf8");
|
|
97615
97644
|
if (extractServiceTier(content) === input.value)
|
|
97616
97645
|
return;
|
|
97617
97646
|
const replacement = replaceTopLevelStringSetting(content, "service_tier", input.value, { insertIfMissing: true });
|
|
97618
97647
|
if (!replacement.replaced)
|
|
97619
97648
|
return;
|
|
97620
|
-
await
|
|
97649
|
+
await writeFile8(input.linkPath, replacement.content);
|
|
97621
97650
|
}
|
|
97622
97651
|
async function restorePreservedModel(input) {
|
|
97623
97652
|
if (input.value === null)
|
|
97624
97653
|
return;
|
|
97625
|
-
const content = await
|
|
97654
|
+
const content = await readFile14(input.linkPath, "utf8");
|
|
97626
97655
|
if (extractModel(content) === input.value)
|
|
97627
97656
|
return;
|
|
97628
97657
|
const replacement = replaceTopLevelStringSetting(content, "model", input.value, { insertIfMissing: true });
|
|
97629
97658
|
if (!replacement.replaced)
|
|
97630
97659
|
return;
|
|
97631
|
-
await
|
|
97660
|
+
await writeFile8(input.linkPath, replacement.content);
|
|
97632
97661
|
}
|
|
97633
97662
|
async function readTextIfExists(path) {
|
|
97634
97663
|
try {
|
|
97635
|
-
return await
|
|
97664
|
+
return await readFile14(path, "utf8");
|
|
97636
97665
|
} catch (error) {
|
|
97637
97666
|
if (nodeErrorCode(error) === "ENOENT")
|
|
97638
97667
|
return null;
|
|
@@ -97754,13 +97783,13 @@ async function writeAgentModelReceipts(codexHome, receipts) {
|
|
|
97754
97783
|
await rm9(path, { force: true });
|
|
97755
97784
|
return;
|
|
97756
97785
|
}
|
|
97757
|
-
await
|
|
97786
|
+
await writeFile9(path, `${JSON.stringify(Object.fromEntries(receipts), null, "\t")}
|
|
97758
97787
|
`);
|
|
97759
97788
|
}
|
|
97760
97789
|
async function applyAgentOverride(input) {
|
|
97761
97790
|
if (input.override === undefined)
|
|
97762
97791
|
return;
|
|
97763
|
-
let content = await
|
|
97792
|
+
let content = await readFile15(input.linkPath, "utf8");
|
|
97764
97793
|
if (input.override.model !== undefined) {
|
|
97765
97794
|
content = replaceTopLevelStringSetting(content, "model", input.override.model, { insertIfMissing: true }).content;
|
|
97766
97795
|
}
|
|
@@ -97769,7 +97798,7 @@ async function applyAgentOverride(input) {
|
|
|
97769
97798
|
insertIfMissing: true
|
|
97770
97799
|
}).content;
|
|
97771
97800
|
}
|
|
97772
|
-
await
|
|
97801
|
+
await writeFile9(input.linkPath, content);
|
|
97773
97802
|
}
|
|
97774
97803
|
function receiptPath(codexHome) {
|
|
97775
97804
|
return join43(codexHome, "agents", RECEIPT_FILE);
|
|
@@ -97804,7 +97833,7 @@ function handEditedAgentModel(installedModel, receipt) {
|
|
|
97804
97833
|
}
|
|
97805
97834
|
|
|
97806
97835
|
// packages/omo-codex/src/install/retired-managed-agent-purge.ts
|
|
97807
|
-
import { lstat as lstat9, readFile as
|
|
97836
|
+
import { lstat as lstat9, readFile as readFile16, rm as rm10 } from "fs/promises";
|
|
97808
97837
|
import { join as join44 } from "path";
|
|
97809
97838
|
var RETIRED_MANAGED_AGENT_FILES = [
|
|
97810
97839
|
{
|
|
@@ -97838,7 +97867,7 @@ function hasRequiredMarkers(content, markers) {
|
|
|
97838
97867
|
}
|
|
97839
97868
|
async function readTextIfExists2(path) {
|
|
97840
97869
|
try {
|
|
97841
|
-
return await
|
|
97870
|
+
return await readFile16(path, "utf8");
|
|
97842
97871
|
} catch (error) {
|
|
97843
97872
|
if (nodeErrorCode2(error) === "ENOENT")
|
|
97844
97873
|
return null;
|
|
@@ -97863,7 +97892,7 @@ function nodeErrorCode2(error) {
|
|
|
97863
97892
|
|
|
97864
97893
|
// packages/omo-codex/src/install/default-agent-role.ts
|
|
97865
97894
|
import { createHash as createHash4 } from "crypto";
|
|
97866
|
-
import { lstat as lstat10, readFile as
|
|
97895
|
+
import { lstat as lstat10, readFile as readFile17, rm as rm11 } from "fs/promises";
|
|
97867
97896
|
import { join as join45 } from "path";
|
|
97868
97897
|
var REGISTRATION = { name: "default", configFile: "./agents/default.toml" };
|
|
97869
97898
|
async function installDefaultAgentRole(input) {
|
|
@@ -97900,7 +97929,7 @@ async function installDefaultAgentRole(input) {
|
|
|
97900
97929
|
if (foreign || existing !== null && !owned) {
|
|
97901
97930
|
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.");
|
|
97902
97931
|
}
|
|
97903
|
-
const worker = await
|
|
97932
|
+
const worker = await readFile17(input.worker.path, "utf8");
|
|
97904
97933
|
const content = worker.replace(/^name\s*=\s*["']lazycodex-worker-medium["']\s*$/m, 'name = "default"');
|
|
97905
97934
|
if (content === worker)
|
|
97906
97935
|
throw new Error("Cannot derive default: medium worker has no matching internal name");
|
|
@@ -97910,7 +97939,7 @@ async function installDefaultAgentRole(input) {
|
|
|
97910
97939
|
}
|
|
97911
97940
|
async function readIfPresent(path) {
|
|
97912
97941
|
try {
|
|
97913
|
-
return await
|
|
97942
|
+
return await readFile17(path, "utf8");
|
|
97914
97943
|
} catch (error) {
|
|
97915
97944
|
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
97916
97945
|
return null;
|
|
@@ -97971,7 +98000,7 @@ async function syncAgentFile(input) {
|
|
|
97971
98000
|
value: input.preservedServiceTier?.get(input.agentName) ?? null
|
|
97972
98001
|
});
|
|
97973
98002
|
await applyAgentOverride({ linkPath: input.linkPath, override });
|
|
97974
|
-
const model = override?.model ?? extractModel(await
|
|
98003
|
+
const model = override?.model ?? extractModel(await readFile18(input.agentPath, "utf8"));
|
|
97975
98004
|
return {
|
|
97976
98005
|
...model === null ? {} : { model },
|
|
97977
98006
|
...override?.reasoningEffort === undefined ? {} : { reasoningEffort: override.reasoningEffort }
|
|
@@ -98015,7 +98044,7 @@ async function prepareReplacement(linkPath) {
|
|
|
98015
98044
|
async function writeManifest(pluginRoot, agentPaths) {
|
|
98016
98045
|
const manifestPath = join46(pluginRoot, MANIFEST_FILE);
|
|
98017
98046
|
const payload = { agents: [...agentPaths].sort() };
|
|
98018
|
-
await
|
|
98047
|
+
await writeFile10(manifestPath, `${JSON.stringify(payload, null, "\t")}
|
|
98019
98048
|
`);
|
|
98020
98049
|
}
|
|
98021
98050
|
function agentNameFromToml2(fileName) {
|
|
@@ -98084,12 +98113,12 @@ function agentNameFromToml3(fileName) {
|
|
|
98084
98113
|
}
|
|
98085
98114
|
|
|
98086
98115
|
// packages/omo-codex/src/install/codex-marketplace.ts
|
|
98087
|
-
import { readFile as
|
|
98116
|
+
import { readFile as readFile19 } from "fs/promises";
|
|
98088
98117
|
import { join as join47 } from "path";
|
|
98089
98118
|
var DEFAULT_MARKETPLACE_PATH = "packages/omo-codex/marketplace.json";
|
|
98090
98119
|
async function readMarketplace(repoRoot, options) {
|
|
98091
98120
|
const marketplacePath = options?.marketplacePath ?? join47(repoRoot, DEFAULT_MARKETPLACE_PATH);
|
|
98092
|
-
const raw = await
|
|
98121
|
+
const raw = await readFile19(marketplacePath, "utf8");
|
|
98093
98122
|
const parsed = JSON.parse(raw);
|
|
98094
98123
|
if (!isPlainRecord4(parsed))
|
|
98095
98124
|
throw new Error("marketplace.json must be an object");
|
|
@@ -98110,7 +98139,7 @@ function resolvePluginSource(repoRoot, plugin, options) {
|
|
|
98110
98139
|
return join47(repoRoot, ...relativePath.split(/[\\/]/));
|
|
98111
98140
|
}
|
|
98112
98141
|
async function readPluginManifest(pluginRoot) {
|
|
98113
|
-
const raw = await
|
|
98142
|
+
const raw = await readFile19(join47(pluginRoot, ".codex-plugin", "plugin.json"), "utf8");
|
|
98114
98143
|
const parsed = JSON.parse(raw);
|
|
98115
98144
|
if (!isPlainRecord4(parsed))
|
|
98116
98145
|
throw new Error(`${pluginRoot} plugin.json must be an object`);
|
|
@@ -98191,11 +98220,11 @@ function validateLocalSourcePath(path) {
|
|
|
98191
98220
|
}
|
|
98192
98221
|
|
|
98193
98222
|
// packages/omo-codex/src/install/lazycodex-version-stamp.ts
|
|
98194
|
-
import { readdir as readdir9, readFile as
|
|
98223
|
+
import { readdir as readdir9, readFile as readFile20, writeFile as writeFile11 } from "fs/promises";
|
|
98195
98224
|
import { join as join48 } from "path";
|
|
98196
98225
|
async function readDistributionManifest(repoRoot) {
|
|
98197
98226
|
try {
|
|
98198
|
-
const parsed = JSON.parse(await
|
|
98227
|
+
const parsed = JSON.parse(await readFile20(join48(repoRoot, "package.json"), "utf8"));
|
|
98199
98228
|
if (!isPlainRecord4(parsed) || typeof parsed.version !== "string" || parsed.version.trim().length === 0)
|
|
98200
98229
|
return;
|
|
98201
98230
|
return {
|
|
@@ -98231,7 +98260,7 @@ async function stampLazyCodexPluginVersion(input) {
|
|
|
98231
98260
|
async function writeLazyCodexInstallSnapshot(input) {
|
|
98232
98261
|
if (input.distributionManifest === undefined)
|
|
98233
98262
|
return;
|
|
98234
|
-
await
|
|
98263
|
+
await writeFile11(join48(input.pluginRoot, "lazycodex-install.json"), `${JSON.stringify({
|
|
98235
98264
|
packageName: input.distributionManifest.name,
|
|
98236
98265
|
version: input.distributionManifest.version
|
|
98237
98266
|
}, null, "\t")}
|
|
@@ -98239,11 +98268,11 @@ async function writeLazyCodexInstallSnapshot(input) {
|
|
|
98239
98268
|
}
|
|
98240
98269
|
async function stampJsonVersion(path, version) {
|
|
98241
98270
|
try {
|
|
98242
|
-
const parsed = JSON.parse(await
|
|
98271
|
+
const parsed = JSON.parse(await readFile20(path, "utf8"));
|
|
98243
98272
|
if (!isPlainRecord4(parsed))
|
|
98244
98273
|
return;
|
|
98245
98274
|
parsed.version = version;
|
|
98246
|
-
await
|
|
98275
|
+
await writeFile11(path, `${JSON.stringify(parsed, null, "\t")}
|
|
98247
98276
|
`);
|
|
98248
98277
|
} catch (error) {
|
|
98249
98278
|
if (error instanceof Error)
|
|
@@ -98253,7 +98282,7 @@ async function stampJsonVersion(path, version) {
|
|
|
98253
98282
|
}
|
|
98254
98283
|
async function readPluginHookPaths(manifestPath) {
|
|
98255
98284
|
try {
|
|
98256
|
-
const parsed = JSON.parse(await
|
|
98285
|
+
const parsed = JSON.parse(await readFile20(manifestPath, "utf8"));
|
|
98257
98286
|
if (!isPlainRecord4(parsed))
|
|
98258
98287
|
return [];
|
|
98259
98288
|
if (typeof parsed.hooks === "string" && parsed.hooks.trim().length > 0)
|
|
@@ -98273,11 +98302,11 @@ function stripDotSlash3(path) {
|
|
|
98273
98302
|
}
|
|
98274
98303
|
async function stampHookStatusMessages(path, version) {
|
|
98275
98304
|
try {
|
|
98276
|
-
const parsed = JSON.parse(await
|
|
98305
|
+
const parsed = JSON.parse(await readFile20(path, "utf8"));
|
|
98277
98306
|
if (!isPlainRecord4(parsed))
|
|
98278
98307
|
return;
|
|
98279
98308
|
stampHookGroups(parsed.hooks, version);
|
|
98280
|
-
await
|
|
98309
|
+
await writeFile11(path, `${JSON.stringify(parsed, null, "\t")}
|
|
98281
98310
|
`);
|
|
98282
98311
|
} catch (error) {
|
|
98283
98312
|
if (error instanceof Error)
|
|
@@ -98354,7 +98383,7 @@ var defaultRunCommand = async (command, args, options) => {
|
|
|
98354
98383
|
};
|
|
98355
98384
|
|
|
98356
98385
|
// packages/omo-codex/src/install/codex-project-local-cleanup.ts
|
|
98357
|
-
import { copyFile as copyFile2, lstat as lstat12, readFile as
|
|
98386
|
+
import { copyFile as copyFile2, lstat as lstat12, readFile as readFile21, writeFile as writeFile12 } from "fs/promises";
|
|
98358
98387
|
import { dirname as dirname17, join as join49, resolve as resolve11 } from "path";
|
|
98359
98388
|
var LEGACY_AGENT_CONFLICT_KEYS = ["max_threads"];
|
|
98360
98389
|
var PROJECT_LOCAL_ARTIFACT_PATHS = [
|
|
@@ -98374,7 +98403,7 @@ async function repairNearestProjectLocalCodexArtifacts(input) {
|
|
|
98374
98403
|
const artifacts = await collectProjectLocalArtifacts(project.artifactRoots);
|
|
98375
98404
|
const configs = [];
|
|
98376
98405
|
for (const configPath of project.configPaths) {
|
|
98377
|
-
const original = await
|
|
98406
|
+
const original = await readFile21(configPath, "utf8");
|
|
98378
98407
|
const repair = repairProjectLocalCodexConfigText(original);
|
|
98379
98408
|
if (!repair.changed) {
|
|
98380
98409
|
configs.push({
|
|
@@ -98387,7 +98416,7 @@ async function repairNearestProjectLocalCodexArtifacts(input) {
|
|
|
98387
98416
|
}
|
|
98388
98417
|
const backupPath = `${configPath}.backup-${formatBackupTimestamp(input.now?.() ?? new Date)}`;
|
|
98389
98418
|
await copyFile2(configPath, backupPath);
|
|
98390
|
-
await
|
|
98419
|
+
await writeFile12(configPath, `${repair.config.trimEnd()}
|
|
98391
98420
|
`);
|
|
98392
98421
|
configs.push({
|
|
98393
98422
|
projectRoot: project.projectRoot,
|
|
@@ -98584,13 +98613,13 @@ function formatUnknownError(error) {
|
|
|
98584
98613
|
|
|
98585
98614
|
// packages/omo-codex/src/install/lsp-daemon-reaper.ts
|
|
98586
98615
|
import { createHash as createHash5 } from "crypto";
|
|
98587
|
-
import { lstat as lstat13, readFile as
|
|
98616
|
+
import { lstat as lstat13, readFile as readFile23, readdir as readdir11, rm as rm13 } from "fs/promises";
|
|
98588
98617
|
import { tmpdir as tmpdir4 } from "os";
|
|
98589
98618
|
import { join as join50, posix as posix6 } from "path";
|
|
98590
98619
|
|
|
98591
98620
|
// packages/omo-codex/src/install/lsp-daemon-reaper-attestation.ts
|
|
98592
98621
|
import { execFile } from "child_process";
|
|
98593
|
-
import { readFile as
|
|
98622
|
+
import { readFile as readFile22, readdir as readdir10, readlink as readlink5 } from "fs/promises";
|
|
98594
98623
|
import { connect } from "net";
|
|
98595
98624
|
import { basename as basename8 } from "path";
|
|
98596
98625
|
var PROBE_TIMEOUT_MS = 500;
|
|
@@ -98632,7 +98661,7 @@ async function attestLegacyDaemonOwnership(input, deps = {}) {
|
|
|
98632
98661
|
return false;
|
|
98633
98662
|
}
|
|
98634
98663
|
async function attestLinuxOwnership(input, deps) {
|
|
98635
|
-
const readFileImpl = deps.readFile ??
|
|
98664
|
+
const readFileImpl = deps.readFile ?? readFile22;
|
|
98636
98665
|
const readDirImpl = deps.readDir ?? readdir10;
|
|
98637
98666
|
const readLinkImpl = deps.readLink ?? readlink5;
|
|
98638
98667
|
const procNetUnix = await readText(readFileImpl, "/proc/net/unix");
|
|
@@ -98857,7 +98886,7 @@ async function readRegularTrimmedFile(path) {
|
|
|
98857
98886
|
return null;
|
|
98858
98887
|
if (!stats.isFile())
|
|
98859
98888
|
return "non_regular";
|
|
98860
|
-
const content = (await
|
|
98889
|
+
const content = (await readFile23(path, "utf8")).trim();
|
|
98861
98890
|
return content.length > 0 ? content : null;
|
|
98862
98891
|
}
|
|
98863
98892
|
function shortDigest(value) {
|
|
@@ -98918,11 +98947,11 @@ function resolveCodexInstallerBinDir(input) {
|
|
|
98918
98947
|
}
|
|
98919
98948
|
|
|
98920
98949
|
// packages/omo-codex/src/install/codex-installed-bin-dir.ts
|
|
98921
|
-
import { readFile as
|
|
98950
|
+
import { readFile as readFile24, readdir as readdir12, writeFile as writeFile13 } from "fs/promises";
|
|
98922
98951
|
import { join as join52 } from "path";
|
|
98923
98952
|
var INSTALLED_BIN_DIR_MANIFEST = ".installed-bin-dir.json";
|
|
98924
98953
|
async function writeInstalledCodexBinDir(input) {
|
|
98925
|
-
await
|
|
98954
|
+
await writeFile13(join52(input.pluginRoot, INSTALLED_BIN_DIR_MANIFEST), `${JSON.stringify({ binDir: input.binDir }, null, 2)}
|
|
98926
98955
|
`);
|
|
98927
98956
|
}
|
|
98928
98957
|
async function readInstalledCodexBinDir(codexHome) {
|
|
@@ -98948,7 +98977,7 @@ async function installedBinDirManifestPaths(codexHome) {
|
|
|
98948
98977
|
return paths;
|
|
98949
98978
|
}
|
|
98950
98979
|
async function readBinDirFromManifest(manifestPath) {
|
|
98951
|
-
const raw = await
|
|
98980
|
+
const raw = await readFile24(manifestPath, "utf8").catch(() => null);
|
|
98952
98981
|
if (raw === null)
|
|
98953
98982
|
return null;
|
|
98954
98983
|
let parsed;
|
|
@@ -98966,7 +98995,7 @@ async function readBinDirFromManifest(manifestPath) {
|
|
|
98966
98995
|
}
|
|
98967
98996
|
|
|
98968
98997
|
// packages/omo-codex/src/install/codex-git-bash-hooks.ts
|
|
98969
|
-
import { readFile as
|
|
98998
|
+
import { readFile as readFile25, writeFile as writeFile14 } from "fs/promises";
|
|
98970
98999
|
import { join as join53 } from "path";
|
|
98971
99000
|
var WINDOWS_ONLY_GIT_BASH_HOOKS = new Set([
|
|
98972
99001
|
"./hooks/pre-tool-use-recommending-git-bash-mcp.json",
|
|
@@ -98976,13 +99005,13 @@ async function removeGitBashHooksOffWindows(input) {
|
|
|
98976
99005
|
if (input.platform === "win32")
|
|
98977
99006
|
return;
|
|
98978
99007
|
const manifestPath = join53(input.pluginRoot, ".codex-plugin", "plugin.json");
|
|
98979
|
-
const parsed = JSON.parse(await
|
|
99008
|
+
const parsed = JSON.parse(await readFile25(manifestPath, "utf8"));
|
|
98980
99009
|
if (!isPlainRecord4(parsed) || !Array.isArray(parsed.hooks))
|
|
98981
99010
|
return;
|
|
98982
99011
|
const hooks = parsed.hooks.filter((hook) => typeof hook !== "string" || !WINDOWS_ONLY_GIT_BASH_HOOKS.has(hook));
|
|
98983
99012
|
if (hooks.length === parsed.hooks.length)
|
|
98984
99013
|
return;
|
|
98985
|
-
await
|
|
99014
|
+
await writeFile14(manifestPath, `${JSON.stringify({ ...parsed, hooks }, null, "\t")}
|
|
98986
99015
|
`);
|
|
98987
99016
|
}
|
|
98988
99017
|
|
|
@@ -99353,12 +99382,12 @@ function defaultRunCommand2(command, args) {
|
|
|
99353
99382
|
});
|
|
99354
99383
|
}
|
|
99355
99384
|
// packages/omo-codex/src/install/codex-cleanup.ts
|
|
99356
|
-
import { lstat as lstat16, readFile as
|
|
99385
|
+
import { lstat as lstat16, readFile as readFile28, readdir as readdir14, rm as rm15, rmdir } from "fs/promises";
|
|
99357
99386
|
import { homedir as homedir9 } from "os";
|
|
99358
99387
|
import { isAbsolute as isAbsolute11, join as join62, relative as relative7, resolve as resolve16 } from "path";
|
|
99359
99388
|
|
|
99360
99389
|
// packages/omo-codex/src/install/codex-cleanup-bins.ts
|
|
99361
|
-
import { lstat as lstat14, readFile as
|
|
99390
|
+
import { lstat as lstat14, readFile as readFile26, readdir as readdir13, readlink as readlink6, rm as rm14 } from "fs/promises";
|
|
99362
99391
|
import { dirname as dirname20, isAbsolute as isAbsolute9, join as join60, resolve as resolve14 } from "path";
|
|
99363
99392
|
var ROOT_RUNTIME_BIN_NAME = "omo";
|
|
99364
99393
|
var MANAGED_CODEX_BIN_NAMES = new Set([
|
|
@@ -99420,12 +99449,12 @@ async function isManagedCodexBin(linkPath, platform, binName) {
|
|
|
99420
99449
|
}
|
|
99421
99450
|
if (!entryStat.isFile())
|
|
99422
99451
|
return false;
|
|
99423
|
-
const content = await
|
|
99452
|
+
const content = await readFile26(linkPath, "utf8");
|
|
99424
99453
|
return content.includes(RUNTIME_WRAPPER_MARKER) || content.includes(COMMAND_SHIM_MARKER);
|
|
99425
99454
|
}
|
|
99426
99455
|
|
|
99427
99456
|
// packages/omo-codex/src/install/codex-cleanup-config.ts
|
|
99428
|
-
import { lstat as lstat15, mkdir as mkdir8, readFile as
|
|
99457
|
+
import { lstat as lstat15, mkdir as mkdir8, readFile as readFile27, writeFile as writeFile15 } from "fs/promises";
|
|
99429
99458
|
import { dirname as dirname21 } from "path";
|
|
99430
99459
|
var MANAGED_MARKETPLACES = ["sisyphuslabs", "lazycodex", "code-yeongyu-codex-plugins"];
|
|
99431
99460
|
var LEGACY_MANAGED_CODEX_AGENT_NAMES_TO_PURGE2 = ["codex-ultrawork-reviewer"];
|
|
@@ -99458,14 +99487,14 @@ function cleanupCodexLightConfigText(config) {
|
|
|
99458
99487
|
async function cleanupCodexConfig(configPath, now) {
|
|
99459
99488
|
if (!await configExists(configPath))
|
|
99460
99489
|
return { changed: false };
|
|
99461
|
-
const original = await
|
|
99490
|
+
const original = await readFile27(configPath, "utf8");
|
|
99462
99491
|
const next = cleanupCodexLightConfigText(original);
|
|
99463
99492
|
if (next === original)
|
|
99464
99493
|
return { changed: false };
|
|
99465
99494
|
const backupPath = `${configPath}.backup-${formatBackupTimestamp2(now?.() ?? new Date)}`;
|
|
99466
99495
|
await mkdir8(dirname21(configPath), { recursive: true });
|
|
99467
|
-
await
|
|
99468
|
-
await
|
|
99496
|
+
await writeFile15(backupPath, original);
|
|
99497
|
+
await writeFile15(configPath, `${next.trimEnd()}
|
|
99469
99498
|
`);
|
|
99470
99499
|
return { changed: true, backupPath };
|
|
99471
99500
|
}
|
|
@@ -99742,13 +99771,13 @@ async function collectInstalledAgentPaths(codexHome, configPath) {
|
|
|
99742
99771
|
async function readManagedAgentPathsFromConfig(codexHome, configPath) {
|
|
99743
99772
|
if (!await exists6(configPath))
|
|
99744
99773
|
return [];
|
|
99745
|
-
const config = await
|
|
99774
|
+
const config = await readFile28(configPath, "utf8");
|
|
99746
99775
|
return MANAGED_CODEX_AGENT_NAMES2.filter((agentName) => config.includes(`config_file = ${JSON.stringify(`./agents/${agentName}.toml`)}`)).map((agentName) => join62(codexHome, "agents", `${agentName}.toml`));
|
|
99747
99776
|
}
|
|
99748
99777
|
async function readInstalledAgentManifest(manifestPath) {
|
|
99749
99778
|
if (!await exists6(manifestPath))
|
|
99750
99779
|
return [];
|
|
99751
|
-
const parsed = JSON.parse(await
|
|
99780
|
+
const parsed = JSON.parse(await readFile28(manifestPath, "utf8"));
|
|
99752
99781
|
if (!isPlainRecord4(parsed) || !Array.isArray(parsed.agents))
|
|
99753
99782
|
return [];
|
|
99754
99783
|
return parsed.agents.filter((path) => typeof path === "string");
|
|
@@ -99940,7 +99969,7 @@ node "%~dp0omo" %*\r
|
|
|
99940
99969
|
// packages/omo-senpi/src/install/plugin-artifacts.ts
|
|
99941
99970
|
import { createHash as createHash7 } from "crypto";
|
|
99942
99971
|
import { constants as constants9 } from "fs";
|
|
99943
|
-
import { access as
|
|
99972
|
+
import { access as access3, readFile as readFile30, stat as stat6 } from "fs/promises";
|
|
99944
99973
|
import { dirname as dirname25, join as join66 } from "path";
|
|
99945
99974
|
|
|
99946
99975
|
// packages/memory-core/src/personas/manifest.ts
|
|
@@ -99959,7 +99988,7 @@ var PERSONA_ASSET_FILES = [
|
|
|
99959
99988
|
|
|
99960
99989
|
// packages/omo-senpi/src/install/senpi-settings.ts
|
|
99961
99990
|
import { constants as constants8 } from "fs";
|
|
99962
|
-
import { access, copyFile as copyFile3, mkdir as mkdir9, readFile as
|
|
99991
|
+
import { access as access2, copyFile as copyFile3, mkdir as mkdir9, readFile as readFile29, rename as rename6, writeFile as writeFile16 } from "fs/promises";
|
|
99963
99992
|
import { basename as basename10, dirname as dirname24, join as join65, resolve as resolve19 } from "path";
|
|
99964
99993
|
var OMO_SENPI_PACKAGE_NAME = "@code-yeongyu/omo-senpi";
|
|
99965
99994
|
var GENERATED_PLUGIN_BASENAME = /^omo-senpi-cli-plugin-[A-Za-z0-9]{6}$/;
|
|
@@ -99970,7 +99999,7 @@ var LEGACY_BUILTIN_SHADOW_PACKAGES = [
|
|
|
99970
99999
|
async function readSettings(settingsPath) {
|
|
99971
100000
|
let raw;
|
|
99972
100001
|
try {
|
|
99973
|
-
raw = await
|
|
100002
|
+
raw = await readFile29(settingsPath, "utf8");
|
|
99974
100003
|
} catch (error) {
|
|
99975
100004
|
if (isErrno(error, "ENOENT"))
|
|
99976
100005
|
return {};
|
|
@@ -100017,11 +100046,11 @@ async function writeSettingsAtomically(settingsPath, settings) {
|
|
|
100017
100046
|
if (await fileExists(settingsPath)) {
|
|
100018
100047
|
await copyFile3(settingsPath, backupPath);
|
|
100019
100048
|
} else {
|
|
100020
|
-
await
|
|
100049
|
+
await writeFile16(backupPath, `{}
|
|
100021
100050
|
`, "utf8");
|
|
100022
100051
|
}
|
|
100023
100052
|
const tempPath = `${settingsPath}.${process.pid}.${Date.now()}.tmp`;
|
|
100024
|
-
await
|
|
100053
|
+
await writeFile16(tempPath, `${JSON.stringify(settings, null, 2)}
|
|
100025
100054
|
`, "utf8");
|
|
100026
100055
|
await rename6(tempPath, settingsPath);
|
|
100027
100056
|
return backupPath;
|
|
@@ -100044,7 +100073,7 @@ function isRecord15(value) {
|
|
|
100044
100073
|
async function readPackageName(packagePath) {
|
|
100045
100074
|
let raw;
|
|
100046
100075
|
try {
|
|
100047
|
-
raw = await
|
|
100076
|
+
raw = await readFile29(join65(packagePath, "package.json"), "utf8");
|
|
100048
100077
|
} catch (error) {
|
|
100049
100078
|
if (isErrno(error, "ENOENT") || isErrno(error, "ENOTDIR"))
|
|
100050
100079
|
return;
|
|
@@ -100062,7 +100091,7 @@ async function readPackageName(packagePath) {
|
|
|
100062
100091
|
}
|
|
100063
100092
|
async function fileExists(path) {
|
|
100064
100093
|
try {
|
|
100065
|
-
await
|
|
100094
|
+
await access2(path, constants8.F_OK);
|
|
100066
100095
|
return true;
|
|
100067
100096
|
} catch (error) {
|
|
100068
100097
|
if (isErrno(error, "ENOENT"))
|
|
@@ -100125,6 +100154,7 @@ var REQUIRED_PLUGIN_ARTIFACTS = [
|
|
|
100125
100154
|
join66("skills", "visual-qa", "SKILL.md"),
|
|
100126
100155
|
join66("skills-conditional", "x-search", "SKILL.md"),
|
|
100127
100156
|
join66("runtime", "agent-toolkit-sdk", "sdk.js"),
|
|
100157
|
+
join66("runtime", "bunshin-ts", "sdk.js"),
|
|
100128
100158
|
join66("runtime", "thread-sdk", "sdk.js"),
|
|
100129
100159
|
join66("runtime", "ast-grep-mcp", "cli.js"),
|
|
100130
100160
|
join66("runtime", "lsp-daemon", "dist", "cli.js"),
|
|
@@ -100167,7 +100197,7 @@ async function verifyAstGrepRuntimeIntegrity(pluginPath, platform) {
|
|
|
100167
100197
|
runtimeStat = await stat6(runtimeEntry);
|
|
100168
100198
|
if (!runtimeStat.isFile())
|
|
100169
100199
|
throw new Error("runtime is not a file");
|
|
100170
|
-
await
|
|
100200
|
+
await access3(runtimeEntry, constants9.R_OK | constants9.X_OK);
|
|
100171
100201
|
} catch (error) {
|
|
100172
100202
|
throw astGrepIntegrityError(runtimeEntry, `runtime is unreadable or non-executable: ${messageOf(error)}`);
|
|
100173
100203
|
}
|
|
@@ -100176,7 +100206,7 @@ async function verifyAstGrepRuntimeIntegrity(pluginPath, platform) {
|
|
|
100176
100206
|
}
|
|
100177
100207
|
let manifest;
|
|
100178
100208
|
try {
|
|
100179
|
-
manifest = JSON.parse(await
|
|
100209
|
+
manifest = JSON.parse(await readFile30(manifestPath, "utf8"));
|
|
100180
100210
|
} catch (error) {
|
|
100181
100211
|
throw astGrepIntegrityError(runtimeEntry, `manifest is unreadable or invalid JSON: ${messageOf(error)}`);
|
|
100182
100212
|
}
|
|
@@ -100185,7 +100215,7 @@ async function verifyAstGrepRuntimeIntegrity(pluginPath, platform) {
|
|
|
100185
100215
|
}
|
|
100186
100216
|
let actualSha256;
|
|
100187
100217
|
try {
|
|
100188
|
-
actualSha256 = createHash7("sha256").update(await
|
|
100218
|
+
actualSha256 = createHash7("sha256").update(await readFile30(runtimeEntry)).digest("hex");
|
|
100189
100219
|
} catch (error) {
|
|
100190
100220
|
throw astGrepIntegrityError(runtimeEntry, `runtime hash could not be computed: ${messageOf(error)}`);
|
|
100191
100221
|
}
|
|
@@ -100210,7 +100240,7 @@ function messageOf(error) {
|
|
|
100210
100240
|
}
|
|
100211
100241
|
async function fileExists2(path) {
|
|
100212
100242
|
try {
|
|
100213
|
-
await
|
|
100243
|
+
await access3(path, constants9.F_OK);
|
|
100214
100244
|
return true;
|
|
100215
100245
|
} catch (error) {
|
|
100216
100246
|
if (isErrno2(error, "ENOENT"))
|
|
@@ -104373,6 +104403,7 @@ var BuiltinSkillNameSchema = _enum([
|
|
|
104373
104403
|
"debugging",
|
|
104374
104404
|
"security-research",
|
|
104375
104405
|
"security-review",
|
|
104406
|
+
"hyperplan",
|
|
104376
104407
|
"visual-qa",
|
|
104377
104408
|
"team-mode"
|
|
104378
104409
|
]);
|
|
@@ -107902,7 +107933,7 @@ function getSuggestedInstallTag(currentVersion) {
|
|
|
107902
107933
|
// packages/omo-opencode/src/cli/doctor/checks/system.ts
|
|
107903
107934
|
init_jsonc_parser2();
|
|
107904
107935
|
init_plugin_identity();
|
|
107905
|
-
var
|
|
107936
|
+
var runtime5 = globalThis;
|
|
107906
107937
|
var defaultDeps5 = {
|
|
107907
107938
|
findOpenCodeBinary,
|
|
107908
107939
|
getOpenCodeVersion: getOpenCodeVersion3,
|
|
@@ -107963,7 +107994,7 @@ async function gatherSystemInfo(deps = defaultDeps5) {
|
|
|
107963
107994
|
opencodePath: binaryInfo?.path ?? null,
|
|
107964
107995
|
pluginVersion,
|
|
107965
107996
|
loadedVersion: loadedInfo.loadedVersion,
|
|
107966
|
-
bunVersion:
|
|
107997
|
+
bunVersion: runtime5.Bun?.version ?? "unavailable",
|
|
107967
107998
|
configPath: pluginInfo.configPath,
|
|
107968
107999
|
configValid: isConfigValid(pluginInfo.configPath, deps),
|
|
107969
108000
|
isLocalDev: pluginInfo.isLocalDev
|
|
@@ -109442,7 +109473,7 @@ async function pathExists2(dir) {
|
|
|
109442
109473
|
// packages/omo-opencode/src/cli/doctor/checks/codex.ts
|
|
109443
109474
|
init_src();
|
|
109444
109475
|
import { existsSync as existsSync61 } from "fs";
|
|
109445
|
-
import { lstat as lstat17, readdir as readdir15, readFile as
|
|
109476
|
+
import { lstat as lstat17, readdir as readdir15, readFile as readFile31 } from "fs/promises";
|
|
109446
109477
|
import { homedir as homedir26 } from "os";
|
|
109447
109478
|
import { basename as basename13, join as join99, resolve as resolve27 } from "path";
|
|
109448
109479
|
// packages/omo-opencode/package.json
|
|
@@ -109471,8 +109502,8 @@ var package_default3 = {
|
|
|
109471
109502
|
},
|
|
109472
109503
|
dependencies: {
|
|
109473
109504
|
"@clack/prompts": "^1.8.1",
|
|
109474
|
-
"@code-yeongyu/senpi": "2026.11.
|
|
109475
|
-
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.11.
|
|
109505
|
+
"@code-yeongyu/senpi": "2026.11.5-1",
|
|
109506
|
+
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.11.5-1",
|
|
109476
109507
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
109477
109508
|
"@oh-my-opencode/agents-md-core": "workspace:*",
|
|
109478
109509
|
"@oh-my-opencode/boulder-state": "workspace:*",
|
|
@@ -109667,7 +109698,7 @@ async function readCodexConfigSummary(configPath) {
|
|
|
109667
109698
|
companionLifecycleHookStateEvents: []
|
|
109668
109699
|
};
|
|
109669
109700
|
}
|
|
109670
|
-
const content = await
|
|
109701
|
+
const content = await readFile31(configPath, "utf8");
|
|
109671
109702
|
return {
|
|
109672
109703
|
exists: true,
|
|
109673
109704
|
marketplaceConfigured: content.includes("[marketplaces.sisyphuslabs]"),
|
|
@@ -109695,7 +109726,7 @@ async function readLinkedAgents(codexHome) {
|
|
|
109695
109726
|
}
|
|
109696
109727
|
async function readJson(path) {
|
|
109697
109728
|
try {
|
|
109698
|
-
const parsed = JSON.parse(await
|
|
109729
|
+
const parsed = JSON.parse(await readFile31(path, "utf8"));
|
|
109699
109730
|
return isPlainRecord(parsed) ? parsed : null;
|
|
109700
109731
|
} catch (error) {
|
|
109701
109732
|
if (error instanceof Error)
|
|
@@ -109819,7 +109850,7 @@ function resolveLatestVersion(input) {
|
|
|
109819
109850
|
|
|
109820
109851
|
// packages/omo-opencode/src/cli/doctor/checks/codex-components.ts
|
|
109821
109852
|
init_src();
|
|
109822
|
-
import { readdir as readdir16, readFile as
|
|
109853
|
+
import { readdir as readdir16, readFile as readFile32, stat as stat7 } from "fs/promises";
|
|
109823
109854
|
import { homedir as homedir27 } from "os";
|
|
109824
109855
|
import { dirname as dirname40, isAbsolute as isAbsolute15, join as join100, relative as relative10, resolve as resolve28, sep as sep11 } from "path";
|
|
109825
109856
|
var CODEX_COMPONENTS_CHECK_ID = "codex-components";
|
|
@@ -110072,7 +110103,7 @@ function degradedDetailLines(entries) {
|
|
|
110072
110103
|
}
|
|
110073
110104
|
async function readJson2(path) {
|
|
110074
110105
|
try {
|
|
110075
|
-
const parsed = JSON.parse(await
|
|
110106
|
+
const parsed = JSON.parse(await readFile32(path, "utf8"));
|
|
110076
110107
|
return isRecord18(parsed) ? parsed : null;
|
|
110077
110108
|
} catch (error) {
|
|
110078
110109
|
if (error instanceof Error)
|
|
@@ -110100,7 +110131,7 @@ function isRecord18(value) {
|
|
|
110100
110131
|
|
|
110101
110132
|
// packages/omo-opencode/src/cli/doctor/checks/codex-runtime-wrapper.ts
|
|
110102
110133
|
import { existsSync as existsSync62 } from "fs";
|
|
110103
|
-
import { readFile as
|
|
110134
|
+
import { readFile as readFile33 } from "fs/promises";
|
|
110104
110135
|
import { homedir as homedir28 } from "os";
|
|
110105
110136
|
import { join as join101, resolve as resolve29 } from "path";
|
|
110106
110137
|
var RUNTIME_WRAPPER_MARKER2 = "OMO_GENERATED_RUNTIME_WRAPPER";
|
|
@@ -110145,7 +110176,7 @@ async function checkCodexRuntimeWrapper(deps = {}) {
|
|
|
110145
110176
|
}
|
|
110146
110177
|
async function readRuntimeWrapper(path) {
|
|
110147
110178
|
try {
|
|
110148
|
-
return await
|
|
110179
|
+
return await readFile33(path, "utf8");
|
|
110149
110180
|
} catch (error) {
|
|
110150
110181
|
if (error instanceof Error)
|
|
110151
110182
|
return null;
|
|
@@ -112069,6 +112100,73 @@ async function loadDeviceKeyring(store) {
|
|
|
112069
112100
|
import { execFile as execFile5 } from "child_process";
|
|
112070
112101
|
import { homedir as homedir30 } from "os";
|
|
112071
112102
|
import { join as join105 } from "path";
|
|
112103
|
+
|
|
112104
|
+
// packages/omo-opencode/src/shared/bun-ffi-shim.ts
|
|
112105
|
+
async function loadBunFfi() {
|
|
112106
|
+
return import("bun:ffi");
|
|
112107
|
+
}
|
|
112108
|
+
|
|
112109
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/process-state.ts
|
|
112110
|
+
var KEY = Symbol.for("omo.keychain-helper.process.v1");
|
|
112111
|
+
function keychainProcessState() {
|
|
112112
|
+
const holder = globalThis;
|
|
112113
|
+
holder[KEY] ??= {
|
|
112114
|
+
secretsQueue: Promise.resolve(),
|
|
112115
|
+
interactionSwitch: undefined,
|
|
112116
|
+
approvalCache: undefined,
|
|
112117
|
+
entryCandidates: [],
|
|
112118
|
+
helperAccess: undefined,
|
|
112119
|
+
heldPromptLocks: new Set,
|
|
112120
|
+
handOff: undefined
|
|
112121
|
+
};
|
|
112122
|
+
return holder[KEY];
|
|
112123
|
+
}
|
|
112124
|
+
|
|
112125
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/secrets-gate.ts
|
|
112126
|
+
async function loadInteractionSwitch() {
|
|
112127
|
+
const state = keychainProcessState();
|
|
112128
|
+
if (state.interactionSwitch !== undefined)
|
|
112129
|
+
return state.interactionSwitch;
|
|
112130
|
+
if (process.platform !== "darwin")
|
|
112131
|
+
return state.interactionSwitch = null;
|
|
112132
|
+
try {
|
|
112133
|
+
const { dlopen, FFIType } = await loadBunFfi();
|
|
112134
|
+
const security = dlopen("/System/Library/Frameworks/Security.framework/Security", {
|
|
112135
|
+
SecKeychainSetUserInteractionAllowed: { args: [FFIType.u8], returns: FFIType.i32 }
|
|
112136
|
+
});
|
|
112137
|
+
state.interactionSwitch = (allowed) => {
|
|
112138
|
+
security.symbols.SecKeychainSetUserInteractionAllowed(allowed ? 1 : 0);
|
|
112139
|
+
};
|
|
112140
|
+
} catch {
|
|
112141
|
+
state.interactionSwitch = null;
|
|
112142
|
+
}
|
|
112143
|
+
return state.interactionSwitch;
|
|
112144
|
+
}
|
|
112145
|
+
function gatedSecrets(run) {
|
|
112146
|
+
const state = keychainProcessState();
|
|
112147
|
+
const next = state.secretsQueue.then(run, run);
|
|
112148
|
+
state.secretsQueue = next.then(() => {
|
|
112149
|
+
return;
|
|
112150
|
+
}, () => {
|
|
112151
|
+
return;
|
|
112152
|
+
});
|
|
112153
|
+
return next;
|
|
112154
|
+
}
|
|
112155
|
+
function silentSecrets(run) {
|
|
112156
|
+
return gatedSecrets(async () => {
|
|
112157
|
+
const setInteraction = await loadInteractionSwitch();
|
|
112158
|
+
if (setInteraction === null)
|
|
112159
|
+
throw new Error("Keychain interaction cannot be switched off on this host.");
|
|
112160
|
+
setInteraction(false);
|
|
112161
|
+
try {
|
|
112162
|
+
return await run();
|
|
112163
|
+
} finally {
|
|
112164
|
+
setInteraction(true);
|
|
112165
|
+
}
|
|
112166
|
+
});
|
|
112167
|
+
}
|
|
112168
|
+
|
|
112169
|
+
// packages/omo-opencode/src/cli/account-keys/keystore.ts
|
|
112072
112170
|
var DEFAULT_SERVICE = "omo-cli";
|
|
112073
112171
|
function defaultRun(argv, input) {
|
|
112074
112172
|
const [file, ...args] = argv;
|
|
@@ -112092,7 +112190,7 @@ function createOsKeyStore(name, platform = process.platform, run = defaultRun, s
|
|
|
112092
112190
|
const resolved = secrets === undefined ? run === defaultRun && typeof Bun !== "undefined" ? Bun.secrets : null : secrets;
|
|
112093
112191
|
switch (platform) {
|
|
112094
112192
|
case "darwin":
|
|
112095
|
-
return resolved !== null ? createBunSecretsKeyStore(name, resolved) : createMacOsKeychainKeyStore(name, run);
|
|
112193
|
+
return resolved !== null ? createBunSecretsKeyStore(name, gateRealSecrets(resolved)) : createMacOsKeychainKeyStore(name, run);
|
|
112096
112194
|
case "linux":
|
|
112097
112195
|
return resolved !== null ? createBunSecretsKeyStore(name, resolved) : createLibsecretKeyStore(name, run);
|
|
112098
112196
|
case "win32":
|
|
@@ -112111,6 +112209,10 @@ async function guarded(run, fail, argv, input) {
|
|
|
112111
112209
|
throw fail();
|
|
112112
112210
|
}
|
|
112113
112211
|
}
|
|
112212
|
+
var gateRealSecrets = (secrets) => typeof Bun !== "undefined" && secrets === Bun.secrets ? {
|
|
112213
|
+
get: (key) => gatedSecrets(() => secrets.get(key)),
|
|
112214
|
+
set: (entry) => gatedSecrets(() => secrets.set(entry))
|
|
112215
|
+
} : secrets;
|
|
112114
112216
|
function createBunSecretsKeyStore(name, secrets) {
|
|
112115
112217
|
const key = { service: DEFAULT_SERVICE, name };
|
|
112116
112218
|
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.");
|
|
@@ -112648,64 +112750,705 @@ async function loginDevice(session, options) {
|
|
|
112648
112750
|
}
|
|
112649
112751
|
|
|
112650
112752
|
// packages/omo-opencode/src/cli/service-auth/keystore.ts
|
|
112651
|
-
import { createHash as createHash12, randomUUID as
|
|
112652
|
-
import { basename as
|
|
112753
|
+
import { createHash as createHash12, randomUUID as randomUUID8 } from "crypto";
|
|
112754
|
+
import { basename as basename17 } from "path";
|
|
112653
112755
|
|
|
112654
|
-
// packages/omo-opencode/src/cli/service-auth/
|
|
112655
|
-
import {
|
|
112656
|
-
|
|
112657
|
-
|
|
112658
|
-
|
|
112659
|
-
|
|
112660
|
-
|
|
112661
|
-
|
|
112662
|
-
|
|
112756
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/darwin-backend.ts
|
|
112757
|
+
import { homedir as homedir31 } from "os";
|
|
112758
|
+
import { join as join109 } from "path";
|
|
112759
|
+
|
|
112760
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/client.ts
|
|
112761
|
+
init_zod();
|
|
112762
|
+
init_bun_spawn_shim();
|
|
112763
|
+
var MUTATING = new Set(["write", "stage", "retire", "promote", "remove"]);
|
|
112764
|
+
var helperReplySchema = object({
|
|
112765
|
+
owned: boolean2(),
|
|
112766
|
+
value: string2(),
|
|
112767
|
+
marker: boolean2(),
|
|
112768
|
+
cdat: number2(),
|
|
112769
|
+
mdat: number2(),
|
|
112770
|
+
partition: _enum(["ours", "other", "none", "unknown"]),
|
|
112771
|
+
present: object({ staging: boolean2(), old: boolean2(), oldSlots: array(number2().int().min(0).max(7)).optional() }).strict(),
|
|
112772
|
+
missing: boolean2(),
|
|
112773
|
+
recover: boolean2(),
|
|
112774
|
+
ok: boolean2(),
|
|
112775
|
+
created: boolean2(),
|
|
112776
|
+
skipped: boolean2(),
|
|
112777
|
+
slot: number2().int().min(0).max(7),
|
|
112778
|
+
error: _enum(["locked", "store", "not-owned", "exists", "missing", "denied", "refused"]),
|
|
112779
|
+
reason: string2(),
|
|
112780
|
+
status: number2()
|
|
112781
|
+
}).partial().strict();
|
|
112782
|
+
|
|
112783
|
+
class HelperProtocolError extends Error {
|
|
112784
|
+
}
|
|
112785
|
+
async function firstLine(stream) {
|
|
112786
|
+
const reader = stream.getReader();
|
|
112787
|
+
const decoder = new TextDecoder;
|
|
112788
|
+
let text = "";
|
|
112789
|
+
for (;; ) {
|
|
112790
|
+
const newline = text.indexOf(`
|
|
112791
|
+
`);
|
|
112792
|
+
if (newline !== -1)
|
|
112793
|
+
return text.slice(0, newline);
|
|
112794
|
+
const chunk = await reader.read();
|
|
112795
|
+
if (chunk.done)
|
|
112796
|
+
return null;
|
|
112797
|
+
text += decoder.decode(chunk.value, { stream: true });
|
|
112798
|
+
}
|
|
112799
|
+
}
|
|
112800
|
+
function isFlushable(stream) {
|
|
112801
|
+
return typeof stream.flush === "function";
|
|
112802
|
+
}
|
|
112803
|
+
var spawnDetachedHelper = (path) => {
|
|
112804
|
+
const child = spawn([path], {
|
|
112805
|
+
stdin: "pipe",
|
|
112806
|
+
stdout: "pipe",
|
|
112807
|
+
stderr: "ignore",
|
|
112808
|
+
detached: true,
|
|
112809
|
+
env: process.env.HOME === undefined ? {} : { HOME: process.env.HOME }
|
|
112810
|
+
});
|
|
112811
|
+
const pid = child.pid;
|
|
112812
|
+
if (pid === undefined)
|
|
112813
|
+
throw new HelperProtocolError("The keychain helper did not start.");
|
|
112814
|
+
const stdin = child.stdin;
|
|
112815
|
+
return {
|
|
112816
|
+
pid,
|
|
112817
|
+
send: (line) => {
|
|
112818
|
+
stdin.write(line);
|
|
112819
|
+
if (isFlushable(stdin))
|
|
112820
|
+
stdin.flush();
|
|
112821
|
+
},
|
|
112822
|
+
reply: firstLine(child.stdout),
|
|
112823
|
+
close: () => {
|
|
112824
|
+
stdin.end();
|
|
112825
|
+
}
|
|
112826
|
+
};
|
|
112663
112827
|
};
|
|
112664
|
-
|
|
112665
|
-
const
|
|
112666
|
-
|
|
112667
|
-
|
|
112668
|
-
|
|
112669
|
-
|
|
112670
|
-
|
|
112671
|
-
|
|
112672
|
-
|
|
112673
|
-
|
|
112674
|
-
|
|
112675
|
-
|
|
112676
|
-
|
|
112677
|
-
|
|
112678
|
-
|
|
112679
|
-
|
|
112680
|
-
|
|
112681
|
-
|
|
112682
|
-
|
|
112683
|
-
|
|
112828
|
+
async function callHelper(path, call, options = {}) {
|
|
112829
|
+
const mutates = MUTATING.has(call.verb);
|
|
112830
|
+
if (mutates && options.lease === undefined)
|
|
112831
|
+
throw new HelperProtocolError(`The ${call.verb} helper call needs the session lock.`);
|
|
112832
|
+
const helper = (options.spawn ?? spawnDetachedHelper)(path);
|
|
112833
|
+
let handedOver = false;
|
|
112834
|
+
try {
|
|
112835
|
+
if (mutates && options.lease !== undefined) {
|
|
112836
|
+
await options.lease.handOver(helper.pid);
|
|
112837
|
+
handedOver = true;
|
|
112838
|
+
}
|
|
112839
|
+
helper.send(`${JSON.stringify({ v: 1, verb: call.verb, account: call.account, ...call.value === undefined ? {} : { value: call.value } })}
|
|
112840
|
+
`);
|
|
112841
|
+
const line = await helper.reply;
|
|
112842
|
+
if (handedOver && options.lease !== undefined) {
|
|
112843
|
+
handedOver = false;
|
|
112844
|
+
await options.lease.restore();
|
|
112845
|
+
}
|
|
112846
|
+
if (line === null)
|
|
112847
|
+
throw new HelperProtocolError(`The keychain helper exited without answering ${call.verb}.`);
|
|
112848
|
+
let json;
|
|
112849
|
+
try {
|
|
112850
|
+
json = JSON.parse(line);
|
|
112851
|
+
} catch {
|
|
112852
|
+
throw new HelperProtocolError(`The keychain helper sent a ${call.verb} reply that is not JSON.`);
|
|
112853
|
+
}
|
|
112854
|
+
const parsed = helperReplySchema.safeParse(json);
|
|
112855
|
+
if (!parsed.success)
|
|
112856
|
+
throw new HelperProtocolError(`The keychain helper sent an unexpected ${call.verb} reply.`);
|
|
112857
|
+
return parsed.data;
|
|
112858
|
+
} catch (error) {
|
|
112859
|
+
if (handedOver && options.lease !== undefined) {
|
|
112860
|
+
try {
|
|
112861
|
+
await options.lease.restore();
|
|
112862
|
+
} catch (restoreError) {
|
|
112863
|
+
throw new AggregateError([error, restoreError], `The ${call.verb} helper call failed and the session lock could not be restored.`);
|
|
112864
|
+
}
|
|
112865
|
+
}
|
|
112866
|
+
throw error;
|
|
112867
|
+
} finally {
|
|
112868
|
+
helper.close();
|
|
112869
|
+
}
|
|
112870
|
+
}
|
|
112871
|
+
|
|
112872
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/location.ts
|
|
112873
|
+
import { dirname as dirname42, join as join106, posix as posix13 } from "path";
|
|
112874
|
+
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
112875
|
+
function bundleCandidates(moduleUrl) {
|
|
112876
|
+
const root = dirname42(dirname42(dirname42(fileURLToPath8(moduleUrl))));
|
|
112877
|
+
return [join106(root, "bin", "darwin", "omo-keychain"), join106(root, "omo-keychain")];
|
|
112878
|
+
}
|
|
112879
|
+
function machineCandidates(home, arch = process.arch) {
|
|
112880
|
+
const runtimeArch = arch === "arm64" ? "arm64" : "x64";
|
|
112881
|
+
return [
|
|
112882
|
+
`/Applications/OmO.app/Contents/Resources/omo-runtime/darwin-${runtimeArch}/omo-keychain`,
|
|
112883
|
+
posix13.join(home, "Applications", "OmO.app", "Contents", "Resources", "omo-runtime", `darwin-${runtimeArch}`, "omo-keychain"),
|
|
112884
|
+
posix13.join(home, ".bun", "install", "global", "node_modules", "omo-ai", "bin", "darwin", "omo-keychain")
|
|
112885
|
+
];
|
|
112886
|
+
}
|
|
112887
|
+
async function locateHelper(candidates, verify) {
|
|
112888
|
+
const rejected = [];
|
|
112889
|
+
for (const path of candidates) {
|
|
112890
|
+
const verdict = await verify(path);
|
|
112891
|
+
if (verdict === "valid")
|
|
112892
|
+
return { kind: "found", path };
|
|
112893
|
+
if (verdict === "invalid")
|
|
112894
|
+
rejected.push(path);
|
|
112895
|
+
}
|
|
112896
|
+
return rejected.length === 0 ? { kind: "missing" } : { kind: "invalid", rejected };
|
|
112897
|
+
}
|
|
112898
|
+
|
|
112899
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/pin.ts
|
|
112900
|
+
import { readdirSync as readdirSync14, rmSync as rmSync9 } from "fs";
|
|
112901
|
+
import { chmod as chmod2, copyFile as copyFile4, constants as constants13, mkdtemp as mkdtemp2, rm as rm16, stat as stat8 } from "fs/promises";
|
|
112902
|
+
import { tmpdir as tmpdir6 } from "os";
|
|
112903
|
+
import { basename as basename15, join as join107 } from "path";
|
|
112904
|
+
var DIR_PREFIX = "omo-keychain-";
|
|
112905
|
+
var OWNED_DIR = new RegExp(`^${DIR_PREFIX}(\\d+)-`);
|
|
112906
|
+
var isAlive = (pid) => {
|
|
112907
|
+
try {
|
|
112908
|
+
process.kill(pid, 0);
|
|
112909
|
+
return true;
|
|
112910
|
+
} catch (error) {
|
|
112911
|
+
return !(error instanceof Error && ("code" in error) && error.code === "ESRCH");
|
|
112912
|
+
}
|
|
112913
|
+
};
|
|
112914
|
+
function sweepDeadPinDirs(root = tmpdir6()) {
|
|
112915
|
+
const removed = [];
|
|
112916
|
+
let entries;
|
|
112917
|
+
try {
|
|
112918
|
+
entries = readdirSync14(root);
|
|
112919
|
+
} catch {
|
|
112920
|
+
return removed;
|
|
112921
|
+
}
|
|
112922
|
+
for (const entry of entries) {
|
|
112923
|
+
const owner = OWNED_DIR.exec(entry)?.[1];
|
|
112924
|
+
if (owner === undefined || Number(owner) === process.pid || isAlive(Number(owner)))
|
|
112925
|
+
continue;
|
|
112926
|
+
try {
|
|
112927
|
+
rmSync9(join107(root, entry), { recursive: true, force: true });
|
|
112928
|
+
} catch {
|
|
112929
|
+
continue;
|
|
112930
|
+
}
|
|
112931
|
+
removed.push(entry);
|
|
112932
|
+
}
|
|
112933
|
+
return removed;
|
|
112934
|
+
}
|
|
112935
|
+
var processDir;
|
|
112936
|
+
async function processPinDir() {
|
|
112937
|
+
if (processDir !== undefined)
|
|
112938
|
+
return processDir;
|
|
112939
|
+
sweepDeadPinDirs();
|
|
112940
|
+
const dir = await mkdtemp2(join107(tmpdir6(), `${DIR_PREFIX}${process.pid}-`));
|
|
112941
|
+
process.once("exit", () => rmSync9(dir, { recursive: true, force: true }));
|
|
112942
|
+
processDir = dir;
|
|
112943
|
+
return dir;
|
|
112944
|
+
}
|
|
112945
|
+
var pinned = new Map;
|
|
112946
|
+
async function sourceIdentity(source) {
|
|
112947
|
+
const info = await stat8(source);
|
|
112948
|
+
return `${source}\x00${info.dev}\x00${info.ino}\x00${info.size}\x00${info.mtimeMs}\x00${info.ctimeMs}`;
|
|
112949
|
+
}
|
|
112950
|
+
async function copyAndVerify(source, verify, dir) {
|
|
112951
|
+
const target = join107(dir, `${crypto.randomUUID()}-${basename15(source)}`);
|
|
112952
|
+
try {
|
|
112953
|
+
await copyFile4(source, target, constants13.COPYFILE_EXCL);
|
|
112954
|
+
await chmod2(target, 320);
|
|
112955
|
+
} catch (error) {
|
|
112956
|
+
await rm16(target, { force: true });
|
|
112957
|
+
return { kind: "unavailable", reason: error instanceof Error ? error.message : String(error) };
|
|
112958
|
+
}
|
|
112959
|
+
let verdict;
|
|
112960
|
+
try {
|
|
112961
|
+
verdict = await verify(target);
|
|
112962
|
+
} catch (error) {
|
|
112963
|
+
await rm16(target, { force: true });
|
|
112964
|
+
return { kind: "unavailable", reason: error instanceof Error ? error.message : String(error) };
|
|
112965
|
+
}
|
|
112966
|
+
if (verdict === "valid")
|
|
112967
|
+
return { kind: "pinned", path: target };
|
|
112968
|
+
await rm16(target, { force: true });
|
|
112969
|
+
return { kind: "invalid" };
|
|
112970
|
+
}
|
|
112971
|
+
async function pinVerifiedCopy(source, verify, dir) {
|
|
112972
|
+
let identity;
|
|
112973
|
+
try {
|
|
112974
|
+
identity = `${dir ?? ""}\x00${await sourceIdentity(source)}`;
|
|
112975
|
+
} catch (error) {
|
|
112976
|
+
return { kind: "unavailable", reason: error instanceof Error ? error.message : String(error) };
|
|
112977
|
+
}
|
|
112978
|
+
const known = pinned.get(identity);
|
|
112979
|
+
if (known !== undefined) {
|
|
112980
|
+
const result = await known;
|
|
112981
|
+
if (result.kind !== "pinned")
|
|
112982
|
+
return result;
|
|
112983
|
+
let verdict;
|
|
112984
|
+
try {
|
|
112985
|
+
verdict = await verify(result.path);
|
|
112986
|
+
} catch (error) {
|
|
112987
|
+
pinned.delete(identity);
|
|
112988
|
+
await rm16(result.path, { force: true });
|
|
112989
|
+
return { kind: "unavailable", reason: error instanceof Error ? error.message : String(error) };
|
|
112990
|
+
}
|
|
112991
|
+
if (verdict === "valid")
|
|
112992
|
+
return result;
|
|
112993
|
+
}
|
|
112994
|
+
const created = Promise.resolve(dir ?? processPinDir()).then((target) => copyAndVerify(source, verify, target), (error) => ({ kind: "unavailable", reason: error instanceof Error ? error.message : String(error) }));
|
|
112995
|
+
pinned.set(identity, created);
|
|
112996
|
+
const result = await created;
|
|
112997
|
+
if (result.kind !== "pinned")
|
|
112998
|
+
pinned.delete(identity);
|
|
112999
|
+
return result;
|
|
113000
|
+
}
|
|
113001
|
+
|
|
113002
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/signature.ts
|
|
113003
|
+
import { stat as stat9 } from "fs/promises";
|
|
113004
|
+
init_bun_spawn_shim();
|
|
113005
|
+
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"';
|
|
113006
|
+
var STRICT_ALL_ARCHITECTURES = 1 << 4 | 1 << 0;
|
|
113007
|
+
var UTF8 = 134217984;
|
|
113008
|
+
var security;
|
|
113009
|
+
async function loadSecurity() {
|
|
113010
|
+
if (security !== undefined)
|
|
113011
|
+
return security;
|
|
113012
|
+
try {
|
|
113013
|
+
const { dlopen, FFIType, ptr } = await loadBunFfi();
|
|
113014
|
+
const cf = dlopen("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", {
|
|
113015
|
+
CFStringCreateWithCString: { args: [FFIType.u64, FFIType.ptr, FFIType.u32], returns: FFIType.u64 },
|
|
113016
|
+
CFURLCreateFromFileSystemRepresentation: { args: [FFIType.u64, FFIType.ptr, FFIType.i64, FFIType.bool], returns: FFIType.u64 },
|
|
113017
|
+
CFRelease: { args: [FFIType.u64], returns: FFIType.void }
|
|
113018
|
+
});
|
|
113019
|
+
const sec = dlopen("/System/Library/Frameworks/Security.framework/Security", {
|
|
113020
|
+
SecStaticCodeCreateWithPath: { args: [FFIType.u64, FFIType.u32, FFIType.ptr], returns: FFIType.i32 },
|
|
113021
|
+
SecRequirementCreateWithString: { args: [FFIType.u64, FFIType.u32, FFIType.ptr], returns: FFIType.i32 },
|
|
113022
|
+
SecStaticCodeCheckValidityWithErrors: { args: [FFIType.u64, FFIType.u32, FFIType.u64, FFIType.u64], returns: FFIType.i32 }
|
|
113023
|
+
});
|
|
113024
|
+
const cString = (text) => Buffer.from(`${text}\x00`, "utf8");
|
|
113025
|
+
security = {
|
|
113026
|
+
check(path, requirement) {
|
|
113027
|
+
const pathBytes = Buffer.from(path, "utf8");
|
|
113028
|
+
const url = BigInt(cf.symbols.CFURLCreateFromFileSystemRepresentation(0n, ptr(pathBytes), pathBytes.length, false));
|
|
113029
|
+
const text = BigInt(cf.symbols.CFStringCreateWithCString(0n, ptr(cString(requirement)), UTF8));
|
|
113030
|
+
const codeOut = new BigUint64Array(1);
|
|
113031
|
+
const requirementOut = new BigUint64Array(1);
|
|
113032
|
+
try {
|
|
113033
|
+
if (url === 0n || text === 0n)
|
|
113034
|
+
return false;
|
|
113035
|
+
if (sec.symbols.SecStaticCodeCreateWithPath(url, 0, ptr(codeOut)) !== 0)
|
|
113036
|
+
return false;
|
|
113037
|
+
if (sec.symbols.SecRequirementCreateWithString(text, 0, ptr(requirementOut)) !== 0)
|
|
113038
|
+
return false;
|
|
113039
|
+
const code = codeOut[0] ?? 0n;
|
|
113040
|
+
const designated = requirementOut[0] ?? 0n;
|
|
113041
|
+
return sec.symbols.SecStaticCodeCheckValidityWithErrors(code, STRICT_ALL_ARCHITECTURES, designated, 0n) === 0;
|
|
113042
|
+
} finally {
|
|
113043
|
+
for (const ref of [url, text, codeOut[0] ?? 0n, requirementOut[0] ?? 0n])
|
|
113044
|
+
if (ref !== 0n)
|
|
113045
|
+
cf.symbols.CFRelease(ref);
|
|
113046
|
+
}
|
|
113047
|
+
}
|
|
113048
|
+
};
|
|
113049
|
+
} catch {
|
|
113050
|
+
security = null;
|
|
113051
|
+
}
|
|
113052
|
+
return security;
|
|
113053
|
+
}
|
|
113054
|
+
async function verifyWithCodesign(path, requirement) {
|
|
113055
|
+
const child = spawn(["/usr/bin/codesign", "--verify", "--strict", `-R=${requirement}`, path], {
|
|
113056
|
+
stdout: "ignore",
|
|
113057
|
+
stderr: "ignore",
|
|
113058
|
+
env: {}
|
|
112684
113059
|
});
|
|
112685
|
-
child.
|
|
112686
|
-
|
|
112687
|
-
|
|
113060
|
+
return await child.exited === 0;
|
|
113061
|
+
}
|
|
113062
|
+
var verifyWithSecurityFramework = async (path, requirement) => {
|
|
113063
|
+
const loaded = await loadSecurity();
|
|
113064
|
+
return loaded === null ? verifyWithCodesign(path, requirement) : loaded.check(path, requirement);
|
|
113065
|
+
};
|
|
113066
|
+
async function fileIdentity(path) {
|
|
113067
|
+
try {
|
|
113068
|
+
const info = await stat9(path);
|
|
113069
|
+
if (!info.isFile())
|
|
113070
|
+
return null;
|
|
113071
|
+
return `${path}\x00${info.dev}\x00${info.ino}\x00${info.size}\x00${info.mtimeMs}\x00${info.ctimeMs}`;
|
|
113072
|
+
} catch {
|
|
113073
|
+
return null;
|
|
113074
|
+
}
|
|
113075
|
+
}
|
|
113076
|
+
function createSignatureChecker(check = verifyWithSecurityFramework, requirement = KEYCHAIN_HELPER_REQUIREMENT) {
|
|
113077
|
+
const verdicts = new Map;
|
|
113078
|
+
const checker = async (path) => {
|
|
113079
|
+
const before = await fileIdentity(path);
|
|
113080
|
+
if (before === null)
|
|
113081
|
+
return "missing";
|
|
113082
|
+
const known = verdicts.get(before);
|
|
113083
|
+
if (known !== undefined)
|
|
113084
|
+
return known;
|
|
113085
|
+
const passed = await check(path, requirement);
|
|
113086
|
+
if (await fileIdentity(path) !== before)
|
|
113087
|
+
return "invalid";
|
|
113088
|
+
const verdict = passed ? "valid" : "invalid";
|
|
113089
|
+
verdicts.set(before, verdict);
|
|
113090
|
+
return verdict;
|
|
113091
|
+
};
|
|
113092
|
+
return checker;
|
|
113093
|
+
}
|
|
113094
|
+
var processChecker;
|
|
113095
|
+
var processSignatureChecker = () => processChecker ??= createSignatureChecker();
|
|
113096
|
+
|
|
113097
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/access.ts
|
|
113098
|
+
async function resolveHelperAccess(candidates, options = {}) {
|
|
113099
|
+
const verify = options.verify ?? processSignatureChecker();
|
|
113100
|
+
let source;
|
|
113101
|
+
let pin;
|
|
113102
|
+
try {
|
|
113103
|
+
const location = await locateHelper(candidates, verify);
|
|
113104
|
+
if (location.kind !== "found")
|
|
113105
|
+
return location;
|
|
113106
|
+
source = location.path;
|
|
113107
|
+
pin = await (options.pin ?? pinVerifiedCopy)(source, verify);
|
|
113108
|
+
} catch (error) {
|
|
113109
|
+
return { kind: "unavailable", reason: error instanceof Error ? error.message : String(error) };
|
|
113110
|
+
}
|
|
113111
|
+
if (pin.kind === "invalid")
|
|
113112
|
+
return { kind: "invalid", rejected: [source] };
|
|
113113
|
+
if (pin.kind === "unavailable")
|
|
113114
|
+
return { kind: "unavailable", reason: pin.reason };
|
|
113115
|
+
const pinned = pin.path;
|
|
113116
|
+
const spawn = options.spawn ?? spawnDetachedHelper;
|
|
113117
|
+
return {
|
|
113118
|
+
kind: "ready",
|
|
113119
|
+
path: pinned,
|
|
113120
|
+
call: async (call, lease) => {
|
|
113121
|
+
const verdict = await verify(pinned).catch((error) => {
|
|
113122
|
+
throw new HelperProtocolError(`OmO's keychain helper could not be checked before it ran: ${error instanceof Error ? error.message : String(error)}`);
|
|
113123
|
+
});
|
|
113124
|
+
if (verdict !== "valid")
|
|
113125
|
+
throw new HelperProtocolError("OmO's keychain helper changed on disk and failed its signature check; it was not run.");
|
|
113126
|
+
return callHelper(pinned, call, { spawn, ...lease === undefined ? {} : { lease } });
|
|
113127
|
+
}
|
|
113128
|
+
};
|
|
113129
|
+
}
|
|
113130
|
+
|
|
113131
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/approval-cache.ts
|
|
113132
|
+
var systemClock = { nowSeconds: () => Date.now() / 1000, sleepMs: (ms) => new Promise((resolve) => setTimeout(resolve, ms)) };
|
|
113133
|
+
function isEntryValid(entry, current, nowSeconds) {
|
|
113134
|
+
if (nowSeconds < entry.readStartedAt)
|
|
113135
|
+
return false;
|
|
113136
|
+
return current.cdat === entry.cdat && current.mdat === entry.mdat && Math.floor(current.mdat) < Math.floor(entry.readStartedAt);
|
|
113137
|
+
}
|
|
113138
|
+
function createApprovalCache(clock = systemClock) {
|
|
113139
|
+
let entry = null;
|
|
113140
|
+
let deniedForBackground = false;
|
|
113141
|
+
let pending = null;
|
|
113142
|
+
return {
|
|
113143
|
+
consume(current) {
|
|
113144
|
+
if (entry === null)
|
|
113145
|
+
return null;
|
|
113146
|
+
if (!isEntryValid(entry, current, clock.nowSeconds())) {
|
|
113147
|
+
entry = null;
|
|
113148
|
+
return null;
|
|
113149
|
+
}
|
|
113150
|
+
return entry.value;
|
|
113151
|
+
},
|
|
113152
|
+
deniedForBackground: () => deniedForBackground,
|
|
113153
|
+
inFlight: () => pending,
|
|
113154
|
+
approve(run) {
|
|
113155
|
+
if (pending !== null)
|
|
113156
|
+
return pending;
|
|
113157
|
+
const readStartedAt = clock.nowSeconds();
|
|
113158
|
+
const started = run().then((answer) => {
|
|
113159
|
+
if (answer.kind === "approved") {
|
|
113160
|
+
entry = { value: answer.value, ...answer.attributes, readStartedAt };
|
|
113161
|
+
deniedForBackground = false;
|
|
113162
|
+
} else if (answer.kind === "denied")
|
|
113163
|
+
deniedForBackground = true;
|
|
113164
|
+
return answer;
|
|
113165
|
+
});
|
|
113166
|
+
const settled = () => {
|
|
113167
|
+
if (pending === started)
|
|
113168
|
+
pending = null;
|
|
113169
|
+
};
|
|
113170
|
+
started.then(settled, settled);
|
|
113171
|
+
pending = started;
|
|
113172
|
+
return started;
|
|
113173
|
+
},
|
|
113174
|
+
async afterOwnWrite(value, readAttributes) {
|
|
113175
|
+
if (entry === null)
|
|
113176
|
+
return;
|
|
113177
|
+
const written = await readAttributes();
|
|
113178
|
+
if (written === null) {
|
|
113179
|
+
entry = null;
|
|
113180
|
+
return;
|
|
113181
|
+
}
|
|
113182
|
+
while (Math.floor(clock.nowSeconds()) <= Math.floor(written.mdat)) {
|
|
113183
|
+
await clock.sleepMs(Math.max(1, Math.ceil((Math.floor(written.mdat) + 1 - clock.nowSeconds()) * 1000)));
|
|
113184
|
+
}
|
|
113185
|
+
const readStartedAt = clock.nowSeconds();
|
|
113186
|
+
const fresh = await readAttributes();
|
|
113187
|
+
entry = fresh === null ? null : { value, ...fresh, readStartedAt };
|
|
113188
|
+
},
|
|
113189
|
+
drop() {
|
|
113190
|
+
entry = null;
|
|
113191
|
+
}
|
|
113192
|
+
};
|
|
113193
|
+
}
|
|
113194
|
+
var processApprovalCache = () => {
|
|
113195
|
+
const state = keychainProcessState();
|
|
113196
|
+
state.approvalCache ??= createApprovalCache();
|
|
113197
|
+
return state.approvalCache;
|
|
113198
|
+
};
|
|
113199
|
+
|
|
113200
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/darwin-read.ts
|
|
113201
|
+
var ROW_8B_DEFAULT = "re-login";
|
|
113202
|
+
|
|
113203
|
+
class HelperReadError extends Error {
|
|
113204
|
+
failure;
|
|
113205
|
+
constructor(failure, message) {
|
|
113206
|
+
super(message);
|
|
113207
|
+
this.failure = failure;
|
|
113208
|
+
}
|
|
113209
|
+
}
|
|
113210
|
+
function failure2(reply) {
|
|
113211
|
+
if (reply.error === "locked")
|
|
113212
|
+
return new HelperReadError("locked", "The keychain is locked.");
|
|
113213
|
+
return new HelperReadError("store", `The keychain helper answered ${reply.error ?? "unexpectedly"}.`);
|
|
113214
|
+
}
|
|
113215
|
+
async function approveOnce(deps) {
|
|
113216
|
+
const running = deps.cache.inFlight();
|
|
113217
|
+
if (running !== null)
|
|
113218
|
+
return running;
|
|
113219
|
+
const release = await deps.takePromptLock();
|
|
113220
|
+
if (release === null)
|
|
113221
|
+
throw new HelperReadError("pending", "Another omo process is waiting for your keychain approval.");
|
|
113222
|
+
try {
|
|
113223
|
+
return await deps.cache.approve(async () => {
|
|
113224
|
+
const reply = await deps.access.call({ verb: "approve", account: deps.account });
|
|
113225
|
+
if (reply.missing === true)
|
|
113226
|
+
return { kind: "missing" };
|
|
113227
|
+
if (reply.error === "denied")
|
|
113228
|
+
return { kind: "denied" };
|
|
113229
|
+
if (reply.error !== undefined || reply.value === undefined || reply.cdat === undefined || reply.mdat === undefined)
|
|
113230
|
+
throw failure2(reply);
|
|
113231
|
+
return { kind: "approved", value: reply.value, attributes: { cdat: reply.cdat, mdat: reply.mdat } };
|
|
113232
|
+
});
|
|
113233
|
+
} finally {
|
|
113234
|
+
await release();
|
|
113235
|
+
}
|
|
113236
|
+
}
|
|
113237
|
+
async function readThroughHelper(deps, allowPrompt) {
|
|
113238
|
+
const reply = await deps.access.call({ verb: "read", account: deps.account });
|
|
113239
|
+
if (reply.error !== undefined)
|
|
113240
|
+
throw failure2(reply);
|
|
113241
|
+
if (reply.missing === true)
|
|
113242
|
+
return { kind: "missing", reply };
|
|
113243
|
+
if (reply.owned === true && reply.value !== undefined)
|
|
113244
|
+
return { kind: "value", value: reply.value, source: reply.marker === true || reply.recover === true ? "owned" : "owned-unmarked", reply };
|
|
113245
|
+
const own = await deps.ownSilentGet().catch(() => {
|
|
113246
|
+
return;
|
|
112688
113247
|
});
|
|
112689
|
-
|
|
112690
|
-
|
|
112691
|
-
|
|
113248
|
+
if (typeof own === "string")
|
|
113249
|
+
return { kind: "value", value: own, source: "own-identity", reply };
|
|
113250
|
+
if (reply.cdat === undefined || reply.mdat === undefined)
|
|
113251
|
+
throw failure2(reply);
|
|
113252
|
+
const cached = deps.cache.consume({ cdat: reply.cdat, mdat: reply.mdat });
|
|
113253
|
+
if (cached !== null)
|
|
113254
|
+
return { kind: "value", value: cached, source: "approved", reply };
|
|
113255
|
+
const reloginInstead = reply.partition !== "ours" && reply.partition !== "none" && (deps.row8b ?? ROW_8B_DEFAULT) === "re-login";
|
|
113256
|
+
if (!allowPrompt) {
|
|
113257
|
+
if (reloginInstead)
|
|
113258
|
+
return { kind: "missing", reply };
|
|
113259
|
+
throw new HelperReadError("pending", "The keychain needs your approval; run an omo command in a terminal.");
|
|
113260
|
+
}
|
|
113261
|
+
if (deps.background && deps.cache.deniedForBackground())
|
|
113262
|
+
throw new HelperReadError("pending", "Keychain access was denied; run an omo command in a terminal to approve it.");
|
|
113263
|
+
if (reloginInstead)
|
|
113264
|
+
return { kind: "missing", reply };
|
|
113265
|
+
if (deps.noDialog === true)
|
|
113266
|
+
throw new HelperReadError("pending", "The keychain hand-off cannot show a dialog.");
|
|
113267
|
+
if (deps.handOff !== undefined && await deps.handOff()) {
|
|
113268
|
+
const after = await deps.access.call({ verb: "read", account: deps.account });
|
|
113269
|
+
if (after.owned === true && after.value !== undefined)
|
|
113270
|
+
return { kind: "value", value: after.value, source: "owned", reply: after };
|
|
113271
|
+
}
|
|
113272
|
+
const answer = await approveOnce(deps);
|
|
113273
|
+
if (answer.kind === "approved")
|
|
113274
|
+
return { kind: "value", value: answer.value, source: "approved", reply };
|
|
113275
|
+
if (answer.kind === "missing")
|
|
113276
|
+
return { kind: "missing", reply };
|
|
113277
|
+
throw new HelperReadError("denied", "Keychain access was denied.");
|
|
113278
|
+
}
|
|
113279
|
+
|
|
113280
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/recovery.ts
|
|
113281
|
+
var OLD_SLOT_COUNT = 8;
|
|
113282
|
+
var oldSlotName = (account, slot) => slot === 0 ? `${account}.old` : `${account}.old.${slot}`;
|
|
113283
|
+
function recoveryPlan(names) {
|
|
113284
|
+
if (!names.original && names.staging)
|
|
113285
|
+
return names.old ? ["promote", "delete-old"] : ["promote"];
|
|
113286
|
+
if (!names.original && names.old)
|
|
113287
|
+
return ["delete-old"];
|
|
113288
|
+
if (names.original && names.staging)
|
|
113289
|
+
return names.old ? ["remove-staging", "delete-old"] : ["remove-staging"];
|
|
113290
|
+
if (names.original && names.old)
|
|
113291
|
+
return ["delete-old"];
|
|
113292
|
+
return [];
|
|
113293
|
+
}
|
|
113294
|
+
function oldSlotsOf(reply) {
|
|
113295
|
+
return reply.present?.oldSlots ?? (reply.present?.old === true ? [0] : []);
|
|
113296
|
+
}
|
|
113297
|
+
function namesFromRead(reply) {
|
|
113298
|
+
const original = reply.owned === false || reply.owned === true && reply.recover !== true;
|
|
113299
|
+
return { original, staging: reply.present?.staging === true, old: reply.present?.old === true, oldSlots: oldSlotsOf(reply) };
|
|
113300
|
+
}
|
|
113301
|
+
async function deleteOld(name, helper, deleteOwn) {
|
|
113302
|
+
const removed = await helper({ verb: "remove", account: name }).catch(() => null);
|
|
113303
|
+
if (removed?.ok === true)
|
|
113304
|
+
return true;
|
|
113305
|
+
return deleteOwn(name).catch(() => false);
|
|
113306
|
+
}
|
|
113307
|
+
async function deleteOldSlots(account, slots, helper, deleteOwn) {
|
|
113308
|
+
let cleared = true;
|
|
113309
|
+
for (const slot of slots)
|
|
113310
|
+
if (!await deleteOld(oldSlotName(account, slot), helper, deleteOwn))
|
|
113311
|
+
cleared = false;
|
|
113312
|
+
return cleared;
|
|
113313
|
+
}
|
|
113314
|
+
async function runRecovery(account, names, helper, deleteOwnOld) {
|
|
113315
|
+
const applied = [];
|
|
113316
|
+
for (const step of recoveryPlan(names)) {
|
|
113317
|
+
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);
|
|
113318
|
+
if (!ok && step !== "delete-old")
|
|
113319
|
+
return { applied, failed: step };
|
|
113320
|
+
if (ok)
|
|
113321
|
+
applied.push(step);
|
|
113322
|
+
}
|
|
113323
|
+
return { applied, failed: null };
|
|
113324
|
+
}
|
|
113325
|
+
|
|
113326
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/migration.ts
|
|
113327
|
+
var MIGRATABLE = new Set(["own-identity", "owned-unmarked", "approved"]);
|
|
113328
|
+
async function migrate(account, value, source, helper, deleteOwnOld) {
|
|
113329
|
+
if (!MIGRATABLE.has(source))
|
|
113330
|
+
return { kind: "skipped", reason: "not-migratable" };
|
|
113331
|
+
if ((await helper({ verb: "stage", account, value })).ok !== true)
|
|
113332
|
+
return { kind: "failed", step: "stage" };
|
|
113333
|
+
const retired = await helper({ verb: "retire", account });
|
|
113334
|
+
if (retired.error === "exists" && retired.reason === "old-slots-full" || retired.ok === true && retired.skipped === true) {
|
|
113335
|
+
await helper({ verb: "remove", account: `${account}.staging` });
|
|
113336
|
+
return { kind: "skipped", reason: "old-slots-full" };
|
|
113337
|
+
}
|
|
113338
|
+
if (retired.ok !== true)
|
|
113339
|
+
return { kind: "failed", step: "retire" };
|
|
113340
|
+
const slot = retired.slot ?? 0;
|
|
113341
|
+
if ((await helper({ verb: "promote", account })).ok !== true)
|
|
113342
|
+
return { kind: "failed", step: "promote" };
|
|
113343
|
+
return { kind: "migrated", oldDeleted: await deleteOld(oldSlotName(account, slot), helper, deleteOwnOld) };
|
|
113344
|
+
}
|
|
113345
|
+
|
|
113346
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/darwin-store.ts
|
|
113347
|
+
class HelperOldSlotsFull extends Error {
|
|
113348
|
+
}
|
|
113349
|
+
var ALL_OLD_SLOTS = Array.from({ length: OLD_SLOT_COUNT }, (_, slot) => slot);
|
|
113350
|
+
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.';
|
|
113351
|
+
var failed = (reply, verb) => new HelperReadError(reply.error === "locked" ? "locked" : "store", `The keychain helper could not ${verb} the sign-in (${reply.error ?? "no answer"}).`);
|
|
113352
|
+
function lockedDarwinStore(deps, lease) {
|
|
113353
|
+
const helper = (call) => deps.access.call(call, lease);
|
|
113354
|
+
const deleteOwnOld = (name) => deps.ownDelete(name);
|
|
113355
|
+
let lastRead = null;
|
|
113356
|
+
const read = async () => {
|
|
113357
|
+
const result = await readThroughHelper(deps, false);
|
|
113358
|
+
lastRead = result.kind === "value" ? result : null;
|
|
113359
|
+
return result.kind === "value" ? result.value : null;
|
|
113360
|
+
};
|
|
113361
|
+
return {
|
|
113362
|
+
async recover() {
|
|
113363
|
+
const reply = await deps.access.call({ verb: "read", account: deps.account });
|
|
113364
|
+
if (reply.error === undefined)
|
|
113365
|
+
await runRecovery(deps.account, namesFromRead(reply), helper, deleteOwnOld);
|
|
113366
|
+
},
|
|
113367
|
+
read,
|
|
113368
|
+
async settle() {
|
|
113369
|
+
if (lastRead === null)
|
|
113370
|
+
return;
|
|
113371
|
+
const outcome = await migrate(deps.account, lastRead.value, lastRead.source, helper, deleteOwnOld);
|
|
113372
|
+
if (outcome.kind === "skipped" && outcome.reason === "old-slots-full")
|
|
113373
|
+
deps.notice(`omo: ${OLD_SLOTS_FULL_MESSAGE}`);
|
|
113374
|
+
if (outcome.kind === "failed")
|
|
113375
|
+
deps.notice(`omo: the macOS keychain item could not be moved to OmO's keychain helper (${outcome.step}); it keeps working as before.`);
|
|
113376
|
+
},
|
|
113377
|
+
async write(value, intent, beforeRetire) {
|
|
113378
|
+
const state = await deps.access.call({ verb: "read", account: deps.account });
|
|
113379
|
+
if (state.error !== undefined)
|
|
113380
|
+
throw failed(state, "check");
|
|
113381
|
+
if (state.owned === false) {
|
|
113382
|
+
const approved = state.cdat !== undefined && state.mdat !== undefined && deps.cache.consume({ cdat: state.cdat, mdat: state.mdat }) !== null;
|
|
113383
|
+
const readable = lastRead !== null || approved || await deps.ownSilentGet().catch(() => {
|
|
113384
|
+
return;
|
|
113385
|
+
}) !== undefined;
|
|
113386
|
+
if (readable || intent !== "fresh-sign-in") {
|
|
113387
|
+
await deps.ownOverwrite(value);
|
|
113388
|
+
if (lastRead?.source === "approved")
|
|
113389
|
+
await deps.cache.afterOwnWrite(value, async () => {
|
|
113390
|
+
const after = await deps.access.call({ verb: "read", account: deps.account });
|
|
113391
|
+
return after.cdat === undefined || after.mdat === undefined ? null : { cdat: after.cdat, mdat: after.mdat };
|
|
113392
|
+
});
|
|
113393
|
+
return;
|
|
113394
|
+
}
|
|
113395
|
+
await beforeRetire?.();
|
|
113396
|
+
const retired = await helper({ verb: "retire", account: deps.account });
|
|
113397
|
+
if (retired.reason === "old-slots-full" || retired.ok === true && retired.skipped === true)
|
|
113398
|
+
throw new HelperOldSlotsFull(OLD_SLOTS_FULL_MESSAGE);
|
|
113399
|
+
if (retired.ok !== true)
|
|
113400
|
+
throw failed(retired, "replace");
|
|
113401
|
+
}
|
|
113402
|
+
const written = await helper({ verb: "write", account: deps.account, value });
|
|
113403
|
+
if (written.ok !== true)
|
|
113404
|
+
throw failed(written, "save");
|
|
113405
|
+
lastRead = { kind: "value", value, source: "owned", reply: written };
|
|
113406
|
+
},
|
|
113407
|
+
async clear() {
|
|
113408
|
+
const removed = await helper({ verb: "remove", account: deps.account });
|
|
113409
|
+
if (removed.error === "not-owned")
|
|
113410
|
+
await deps.ownDelete(deps.account);
|
|
113411
|
+
else if (removed.ok !== true)
|
|
113412
|
+
throw failed(removed, "remove");
|
|
113413
|
+
await helper({ verb: "remove", account: `${deps.account}.staging` });
|
|
113414
|
+
const present = await helper({ verb: "read", account: deps.account });
|
|
113415
|
+
const slots = present.error === undefined ? oldSlotsOf(present) : ALL_OLD_SLOTS;
|
|
113416
|
+
await deleteOldSlots(deps.account, slots, helper, deleteOwnOld);
|
|
113417
|
+
lastRead = null;
|
|
113418
|
+
}
|
|
113419
|
+
};
|
|
113420
|
+
}
|
|
113421
|
+
|
|
113422
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/owner-marker.ts
|
|
113423
|
+
init_bun_spawn_shim();
|
|
113424
|
+
var MARKER_LINE = /^\s*"gena"<blob>="omo-owner\/1"\s*$/m;
|
|
113425
|
+
var ITEM_NOT_FOUND = 44;
|
|
113426
|
+
var probeOwnerMarker = async (service, account, keychain) => {
|
|
113427
|
+
const args = ["find-generic-password", "-s", service, "-a", account, ...keychain === undefined ? [] : [keychain]];
|
|
113428
|
+
const child = spawn(["/usr/bin/security", ...args], {
|
|
113429
|
+
stdout: "pipe",
|
|
113430
|
+
stderr: "ignore",
|
|
113431
|
+
env: process.env.HOME === undefined ? {} : { HOME: process.env.HOME }
|
|
112692
113432
|
});
|
|
112693
|
-
|
|
113433
|
+
const [stdout, code] = await Promise.all([new Response(child.stdout).text(), child.exited]);
|
|
113434
|
+
if (code === ITEM_NOT_FOUND)
|
|
113435
|
+
return "absent";
|
|
113436
|
+
if (code !== 0)
|
|
113437
|
+
return "unknown";
|
|
113438
|
+
return MARKER_LINE.test(stdout) ? "helper-owned" : "other";
|
|
113439
|
+
};
|
|
112694
113440
|
|
|
112695
|
-
// packages/omo-opencode/src/cli/service-auth/
|
|
112696
|
-
import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
|
|
112697
|
-
import { createHash as createHash11 } from "crypto";
|
|
113441
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/prompt-lock.ts
|
|
112698
113442
|
import { mkdir as mkdir11 } from "fs/promises";
|
|
112699
|
-
import {
|
|
112700
|
-
import { join as join106 } from "path";
|
|
113443
|
+
import { dirname as dirname45 } from "path";
|
|
112701
113444
|
|
|
112702
113445
|
// packages/team-core/src/team-state-store/lock-publish.ts
|
|
112703
|
-
import { access as
|
|
112704
|
-
import { dirname as
|
|
113446
|
+
import { access as access5, open as open3, unlink as unlink4 } from "fs/promises";
|
|
113447
|
+
import { dirname as dirname43 } from "path";
|
|
112705
113448
|
|
|
112706
113449
|
// packages/team-core/src/team-state-store/lock-record.ts
|
|
112707
113450
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
112708
|
-
import { readFile as
|
|
113451
|
+
import { readFile as readFile35, stat as stat11 } from "fs/promises";
|
|
112709
113452
|
|
|
112710
113453
|
// packages/memory-core/src/locks/process-identity.ts
|
|
112711
113454
|
import { execFile as execFile7 } from "child_process";
|
|
@@ -112744,6 +113487,24 @@ function retryOnEintrSync(operation) {
|
|
|
112744
113487
|
|
|
112745
113488
|
// packages/memory-core/src/fs/rename-contention.ts
|
|
112746
113489
|
var CONTENTION_CODES = new Set(["EPERM", "EBUSY", "EACCES"]);
|
|
113490
|
+
var CONTENTION_DELAYS_MS = [10, 25, 50, 100, 200, 400];
|
|
113491
|
+
var sleepFor = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
113492
|
+
async function renameWithContentionRetry(from, to, deps) {
|
|
113493
|
+
const delays = deps.platform === "win32" ? deps.delaysMs ?? CONTENTION_DELAYS_MS : [];
|
|
113494
|
+
const sleep = deps.sleep ?? sleepFor;
|
|
113495
|
+
for (let attempt = 0;; attempt += 1) {
|
|
113496
|
+
try {
|
|
113497
|
+
await retryOnEintr(() => deps.admit === undefined ? deps.rename(from, to) : deps.admit(() => deps.rename(from, to)));
|
|
113498
|
+
return;
|
|
113499
|
+
} catch (error) {
|
|
113500
|
+
const delay = delays[attempt];
|
|
113501
|
+
const code = fsErrorCode(error);
|
|
113502
|
+
if (delay === undefined || code === undefined || !CONTENTION_CODES.has(code))
|
|
113503
|
+
throw error;
|
|
113504
|
+
await sleep(delay);
|
|
113505
|
+
}
|
|
113506
|
+
}
|
|
113507
|
+
}
|
|
112747
113508
|
|
|
112748
113509
|
// packages/memory-core/src/fs/resilient.ts
|
|
112749
113510
|
function isFunction2(value) {
|
|
@@ -112776,25 +113537,32 @@ function resilientNamespace(namespace, kind) {
|
|
|
112776
113537
|
}
|
|
112777
113538
|
var IDEMPOTENT_HANDLE_METHODS = new Set(["stat", "sync", "datasync", "chmod", "chown", "utimes", "truncate"]);
|
|
112778
113539
|
var promises = resilientNamespace(fsp, "async");
|
|
113540
|
+
function rename8(from, to, admit) {
|
|
113541
|
+
return renameWithContentionRetry(from, to, {
|
|
113542
|
+
rename: (source, target) => fsp.rename(source, target),
|
|
113543
|
+
platform: process.platform,
|
|
113544
|
+
...admit === undefined ? {} : { admit }
|
|
113545
|
+
});
|
|
113546
|
+
}
|
|
112779
113547
|
var sync = resilientNamespace(fsSync, "sync");
|
|
112780
113548
|
var {
|
|
112781
|
-
access:
|
|
112782
|
-
chmod:
|
|
112783
|
-
copyFile:
|
|
113549
|
+
access: access4,
|
|
113550
|
+
chmod: chmod3,
|
|
113551
|
+
copyFile: copyFile5,
|
|
112784
113552
|
cp: cp5,
|
|
112785
113553
|
link,
|
|
112786
113554
|
lstat: lstat18,
|
|
112787
113555
|
mkdir: mkdir10,
|
|
112788
|
-
mkdtemp:
|
|
112789
|
-
readFile:
|
|
113556
|
+
mkdtemp: mkdtemp3,
|
|
113557
|
+
readFile: readFile34,
|
|
112790
113558
|
readdir: readdir17,
|
|
112791
113559
|
readlink: readlink7,
|
|
112792
113560
|
realpath: realpath2,
|
|
112793
|
-
rm:
|
|
113561
|
+
rm: rm17,
|
|
112794
113562
|
rmdir: rmdir2,
|
|
112795
|
-
stat:
|
|
113563
|
+
stat: stat10,
|
|
112796
113564
|
statfs,
|
|
112797
|
-
unlink:
|
|
113565
|
+
unlink: unlink3
|
|
112798
113566
|
} = promises;
|
|
112799
113567
|
var {
|
|
112800
113568
|
accessSync: accessSync5,
|
|
@@ -112804,7 +113572,7 @@ var {
|
|
|
112804
113572
|
lstatSync: lstatSync5,
|
|
112805
113573
|
mkdirSync: mkdirSync19,
|
|
112806
113574
|
readFileSync: readFileSync44,
|
|
112807
|
-
readdirSync:
|
|
113575
|
+
readdirSync: readdirSync15,
|
|
112808
113576
|
realpathSync: realpathSync13,
|
|
112809
113577
|
statSync: statSync8,
|
|
112810
113578
|
unlinkSync: unlinkSync10,
|
|
@@ -112917,7 +113685,7 @@ async function execFileText(command, args) {
|
|
|
112917
113685
|
}
|
|
112918
113686
|
async function readLinuxStartIdentity(pid) {
|
|
112919
113687
|
try {
|
|
112920
|
-
const stat = await
|
|
113688
|
+
const stat = await readFile34(`/proc/${pid}/stat`, "utf8");
|
|
112921
113689
|
const commandEnd = stat.lastIndexOf(")");
|
|
112922
113690
|
if (commandEnd < 0)
|
|
112923
113691
|
return null;
|
|
@@ -113156,14 +113924,17 @@ async function isWorkerLockReleased(incarnation, record) {
|
|
|
113156
113924
|
// packages/team-core/src/team-state-store/lock-record.ts
|
|
113157
113925
|
async function buildLockRecord(ownerTag) {
|
|
113158
113926
|
await registerLockWorker();
|
|
113159
|
-
const processStart = await
|
|
113927
|
+
const processStart = await lockProcessStartLine(process.pid);
|
|
113160
113928
|
return `${ownerTag} ${randomUUID6()}
|
|
113161
113929
|
${process.pid}
|
|
113162
113930
|
${Date.now()}
|
|
113163
113931
|
${lockOwnerInstanceId}
|
|
113164
|
-
${processStart
|
|
113932
|
+
${processStart}
|
|
113165
113933
|
`;
|
|
113166
113934
|
}
|
|
113935
|
+
async function lockProcessStartLine(pid) {
|
|
113936
|
+
return await getProcessStartIdentity(pid) ?? "unavailable";
|
|
113937
|
+
}
|
|
113167
113938
|
function errorCode2(error) {
|
|
113168
113939
|
if (!(error instanceof Error) || !("code" in error))
|
|
113169
113940
|
return null;
|
|
@@ -113192,8 +113963,8 @@ function parseLockOwner(content) {
|
|
|
113192
113963
|
}
|
|
113193
113964
|
async function readLockRecord(lockPath) {
|
|
113194
113965
|
try {
|
|
113195
|
-
const content = await
|
|
113196
|
-
const { mtimeMs } = await
|
|
113966
|
+
const content = await readFile35(lockPath, "utf8");
|
|
113967
|
+
const { mtimeMs } = await stat11(lockPath);
|
|
113197
113968
|
return { content, modifiedAtEpochMs: mtimeMs };
|
|
113198
113969
|
} catch (error) {
|
|
113199
113970
|
if (!(error instanceof Error))
|
|
@@ -113224,7 +113995,7 @@ async function isLockRecordStale(record, staleAfterMs) {
|
|
|
113224
113995
|
|
|
113225
113996
|
// packages/team-core/src/team-state-store/lock-publish.ts
|
|
113226
113997
|
async function pathMayExist(path, deps = {}) {
|
|
113227
|
-
const accessPath = deps.access ??
|
|
113998
|
+
const accessPath = deps.access ?? access5;
|
|
113228
113999
|
try {
|
|
113229
114000
|
await accessPath(path);
|
|
113230
114001
|
return true;
|
|
@@ -113241,7 +114012,7 @@ async function assertRetryableLockOpenError(lockPath, error, deps) {
|
|
|
113241
114012
|
if (code === "EPERM") {
|
|
113242
114013
|
if (await pathMayExist(lockPath, deps))
|
|
113243
114014
|
return;
|
|
113244
|
-
if ((deps?.platform ?? process.platform) === "win32" && await pathMayExist(
|
|
114015
|
+
if ((deps?.platform ?? process.platform) === "win32" && await pathMayExist(dirname43(lockPath), deps))
|
|
113245
114016
|
return;
|
|
113246
114017
|
}
|
|
113247
114018
|
throw error;
|
|
@@ -113261,7 +114032,7 @@ async function publishLockRecord(lockPath, record) {
|
|
|
113261
114032
|
} catch (error) {
|
|
113262
114033
|
markLockRecordReleased(record);
|
|
113263
114034
|
await fileHandle.close();
|
|
113264
|
-
await
|
|
114035
|
+
await unlink4(lockPath).catch(() => {
|
|
113265
114036
|
return;
|
|
113266
114037
|
});
|
|
113267
114038
|
throw error;
|
|
@@ -113270,9 +114041,14 @@ async function publishLockRecord(lockPath, record) {
|
|
|
113270
114041
|
return true;
|
|
113271
114042
|
}
|
|
113272
114043
|
|
|
114044
|
+
// packages/team-core/src/team-state-store/lock-lease.ts
|
|
114045
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
114046
|
+
import { open as open4, readdir as readdir18, readFile as readFile36, rename as rename9, rm as rm18 } from "fs/promises";
|
|
114047
|
+
import { basename as basename16, dirname as dirname44, join as join108 } from "path";
|
|
114048
|
+
|
|
113273
114049
|
// packages/team-core/src/team-state-store/lock-reclaim.ts
|
|
113274
114050
|
import { createHash as createHash10 } from "crypto";
|
|
113275
|
-
import { unlink as
|
|
114051
|
+
import { unlink as unlink5 } from "fs/promises";
|
|
113276
114052
|
var RECLAIM_UNLINK_ATTEMPTS = 3;
|
|
113277
114053
|
var RECLAIM_UNLINK_RETRY_MS = 25;
|
|
113278
114054
|
function delay2(ms) {
|
|
@@ -113285,7 +114061,7 @@ function reclaimGuardPath(lockPath, record) {
|
|
|
113285
114061
|
}
|
|
113286
114062
|
async function unlinkWithRetry(path, deps) {
|
|
113287
114063
|
const wait = deps.delay ?? delay2;
|
|
113288
|
-
const unlinkFile = deps.unlink ??
|
|
114064
|
+
const unlinkFile = deps.unlink ?? unlink5;
|
|
113289
114065
|
for (let attempt = 1;; attempt += 1) {
|
|
113290
114066
|
try {
|
|
113291
114067
|
await unlinkFile(path);
|
|
@@ -113303,6 +114079,19 @@ async function unlinkWithRetry(path, deps) {
|
|
|
113303
114079
|
}
|
|
113304
114080
|
}
|
|
113305
114081
|
async function removeLockRecordIfUnchanged(lockPath, expectedRecord, staleAfterMs, deps = {}) {
|
|
114082
|
+
return withRecordGuard(lockPath, expectedRecord, staleAfterMs, deps, async () => {
|
|
114083
|
+
const current = await readLockRecord(lockPath);
|
|
114084
|
+
if (current === null)
|
|
114085
|
+
return "absent";
|
|
114086
|
+
if (current.content !== expectedRecord || !await isLockRecordStale(current, staleAfterMs))
|
|
114087
|
+
return "changed";
|
|
114088
|
+
const unlinked = await unlinkWithRetry(lockPath, deps);
|
|
114089
|
+
if (unlinked !== "stuck")
|
|
114090
|
+
forgetLockRecord(expectedRecord);
|
|
114091
|
+
return unlinked === "absent" ? "absent" : unlinked;
|
|
114092
|
+
});
|
|
114093
|
+
}
|
|
114094
|
+
async function withRecordGuard(lockPath, expectedRecord, staleAfterMs, deps, act) {
|
|
113306
114095
|
const guardPath = reclaimGuardPath(lockPath, expectedRecord);
|
|
113307
114096
|
const guardRecord = await buildLockRecord("lock-reclaim");
|
|
113308
114097
|
if (!await publishLockRecord(guardPath, guardRecord)) {
|
|
@@ -113313,15 +114102,7 @@ async function removeLockRecordIfUnchanged(lockPath, expectedRecord, staleAfterM
|
|
|
113313
114102
|
return "busy";
|
|
113314
114103
|
}
|
|
113315
114104
|
try {
|
|
113316
|
-
|
|
113317
|
-
if (current === null)
|
|
113318
|
-
return "absent";
|
|
113319
|
-
if (current.content !== expectedRecord || !await isLockRecordStale(current, staleAfterMs))
|
|
113320
|
-
return "changed";
|
|
113321
|
-
const unlinked = await unlinkWithRetry(lockPath, deps);
|
|
113322
|
-
if (unlinked !== "stuck")
|
|
113323
|
-
forgetLockRecord(expectedRecord);
|
|
113324
|
-
return unlinked === "absent" ? "absent" : unlinked;
|
|
114105
|
+
return await act();
|
|
113325
114106
|
} finally {
|
|
113326
114107
|
markLockRecordReleased(guardRecord);
|
|
113327
114108
|
if (await unlinkWithRetry(guardPath, deps) !== "stuck")
|
|
@@ -113329,6 +114110,97 @@ async function removeLockRecordIfUnchanged(lockPath, expectedRecord, staleAfterM
|
|
|
113329
114110
|
}
|
|
113330
114111
|
}
|
|
113331
114112
|
|
|
114113
|
+
// packages/team-core/src/team-state-store/lock-lease.ts
|
|
114114
|
+
class LockLeaseLostError extends Error {
|
|
114115
|
+
constructor(lockPath) {
|
|
114116
|
+
super(`The lock at ${lockPath} changed while it was handed over; the critical section was aborted.`);
|
|
114117
|
+
this.name = "LockLeaseLostError";
|
|
114118
|
+
}
|
|
114119
|
+
}
|
|
114120
|
+
var leaseTempPrefix = (lockPath) => `.${basename16(lockPath)}.`;
|
|
114121
|
+
var LEASE_TEMP_SUFFIX = ".lease";
|
|
114122
|
+
var UUID2 = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
|
114123
|
+
var escapeRegExp2 = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
114124
|
+
var leaseTempPattern = (lockPath) => new RegExp(`^\\.${escapeRegExp2(basename16(lockPath))}\\.${UUID2}\\.lease$`);
|
|
114125
|
+
async function replaceRecord(lockPath, content) {
|
|
114126
|
+
const temporary = join108(dirname44(lockPath), `${leaseTempPrefix(lockPath)}${randomUUID7()}${LEASE_TEMP_SUFFIX}`);
|
|
114127
|
+
try {
|
|
114128
|
+
const handle = await open4(temporary, "wx", 384);
|
|
114129
|
+
try {
|
|
114130
|
+
await handle.writeFile(content);
|
|
114131
|
+
} finally {
|
|
114132
|
+
await handle.close();
|
|
114133
|
+
}
|
|
114134
|
+
await rename9(temporary, lockPath);
|
|
114135
|
+
} catch (error) {
|
|
114136
|
+
await rm18(temporary, { force: true });
|
|
114137
|
+
throw error;
|
|
114138
|
+
}
|
|
114139
|
+
}
|
|
114140
|
+
async function removeLeftoverTemps(lockPath) {
|
|
114141
|
+
const pattern = leaseTempPattern(lockPath);
|
|
114142
|
+
let entries;
|
|
114143
|
+
try {
|
|
114144
|
+
entries = await readdir18(dirname44(lockPath));
|
|
114145
|
+
} catch (error) {
|
|
114146
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
114147
|
+
return;
|
|
114148
|
+
throw error;
|
|
114149
|
+
}
|
|
114150
|
+
for (const entry of entries) {
|
|
114151
|
+
if (pattern.test(entry))
|
|
114152
|
+
await rm18(join108(dirname44(lockPath), entry), { force: true });
|
|
114153
|
+
}
|
|
114154
|
+
}
|
|
114155
|
+
async function currentRecord(lockPath) {
|
|
114156
|
+
try {
|
|
114157
|
+
return await readFile36(lockPath, "utf8");
|
|
114158
|
+
} catch (error) {
|
|
114159
|
+
if (error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR"))
|
|
114160
|
+
return null;
|
|
114161
|
+
throw error;
|
|
114162
|
+
}
|
|
114163
|
+
}
|
|
114164
|
+
function createLockLease(lockPath, ownerRecord, ownerTag, options = {}) {
|
|
114165
|
+
const staleAfterMs = options.staleAfterMs ?? Number.POSITIVE_INFINITY;
|
|
114166
|
+
let handedTo = null;
|
|
114167
|
+
return {
|
|
114168
|
+
async handOver(pid) {
|
|
114169
|
+
if (handedTo !== null)
|
|
114170
|
+
throw new Error("The lock is already handed over; restore it first.");
|
|
114171
|
+
if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid)
|
|
114172
|
+
throw new Error(`Cannot hand the lock to pid ${pid}.`);
|
|
114173
|
+
if (await currentRecord(lockPath) !== ownerRecord)
|
|
114174
|
+
throw new LockLeaseLostError(lockPath);
|
|
114175
|
+
await removeLeftoverTemps(lockPath);
|
|
114176
|
+
const processStart = await lockProcessStartLine(pid);
|
|
114177
|
+
const record = `${ownerTag} ${randomUUID7()}
|
|
114178
|
+
${pid}
|
|
114179
|
+
${Date.now()}
|
|
114180
|
+
${randomUUID7()}
|
|
114181
|
+
${processStart}
|
|
114182
|
+
`;
|
|
114183
|
+
await replaceRecord(lockPath, record);
|
|
114184
|
+
handedTo = record;
|
|
114185
|
+
},
|
|
114186
|
+
async restore() {
|
|
114187
|
+
if (handedTo === null)
|
|
114188
|
+
throw new Error("The lock is not handed over.");
|
|
114189
|
+
const expected = handedTo;
|
|
114190
|
+
handedTo = null;
|
|
114191
|
+
const outcome = await withRecordGuard(lockPath, expected, staleAfterMs, {}, async () => {
|
|
114192
|
+
if (await currentRecord(lockPath) !== expected)
|
|
114193
|
+
return "lost";
|
|
114194
|
+
await options.beforeRestoreRename?.();
|
|
114195
|
+
await replaceRecord(lockPath, ownerRecord);
|
|
114196
|
+
return "restored";
|
|
114197
|
+
});
|
|
114198
|
+
if (outcome !== "restored")
|
|
114199
|
+
throw new LockLeaseLostError(lockPath);
|
|
114200
|
+
}
|
|
114201
|
+
};
|
|
114202
|
+
}
|
|
114203
|
+
|
|
113332
114204
|
// packages/team-core/src/team-state-store/locks.ts
|
|
113333
114205
|
var LOCK_RETRY_MS = 50;
|
|
113334
114206
|
var LOCK_WAIT_TIMEOUT_MS = 15000;
|
|
@@ -113358,7 +114230,7 @@ async function withLock(lockPath, fn, opts) {
|
|
|
113358
114230
|
const ownerTag = opts?.ownerTag ?? "owner";
|
|
113359
114231
|
const record = await acquireLock(lockPath, ownerTag, staleAfterMs);
|
|
113360
114232
|
try {
|
|
113361
|
-
return await fn();
|
|
114233
|
+
return await fn(createLockLease(lockPath, record, ownerTag, { staleAfterMs }));
|
|
113362
114234
|
} finally {
|
|
113363
114235
|
markLockRecordReleased(record);
|
|
113364
114236
|
const outcome = await removeLockRecordIfUnchanged(lockPath, record, staleAfterMs);
|
|
@@ -113375,20 +114247,382 @@ async function reapStaleLock(lockPath, staleAfterMs = DEFAULT_STALE_AFTER_MS, de
|
|
|
113375
114247
|
return await removeLockRecordIfUnchanged(lockPath, observed.content, staleAfterMs, deps);
|
|
113376
114248
|
}
|
|
113377
114249
|
|
|
114250
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/prompt-lock.ts
|
|
114251
|
+
function promptLockAt(path, hooks = {}) {
|
|
114252
|
+
return async () => {
|
|
114253
|
+
const held = keychainProcessState().heldPromptLocks;
|
|
114254
|
+
if (held.has(path))
|
|
114255
|
+
return null;
|
|
114256
|
+
held.add(path);
|
|
114257
|
+
let granted = false;
|
|
114258
|
+
try {
|
|
114259
|
+
await mkdir11(dirname45(path), { recursive: true, mode: 448 });
|
|
114260
|
+
await hooks.beforePublish?.();
|
|
114261
|
+
for (let attempt = 0;attempt < 2; attempt++) {
|
|
114262
|
+
const record = await buildLockRecord("keychain-prompt");
|
|
114263
|
+
if (await publishLockRecord(path, record)) {
|
|
114264
|
+
granted = true;
|
|
114265
|
+
return async () => {
|
|
114266
|
+
markLockRecordReleased(record);
|
|
114267
|
+
try {
|
|
114268
|
+
await (hooks.removeRecord ?? ((target, owned) => removeLockRecordIfUnchanged(target, owned, Number.POSITIVE_INFINITY)))(path, record);
|
|
114269
|
+
} finally {
|
|
114270
|
+
held.delete(path);
|
|
114271
|
+
}
|
|
114272
|
+
};
|
|
114273
|
+
}
|
|
114274
|
+
if (await reapStaleLock(path, Number.POSITIVE_INFINITY) !== "removed")
|
|
114275
|
+
return null;
|
|
114276
|
+
}
|
|
114277
|
+
return null;
|
|
114278
|
+
} finally {
|
|
114279
|
+
if (!granted)
|
|
114280
|
+
held.delete(path);
|
|
114281
|
+
}
|
|
114282
|
+
};
|
|
114283
|
+
}
|
|
114284
|
+
|
|
114285
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/darwin-backend.ts
|
|
114286
|
+
var ROW_9B_DEFAULT = "reinstall-notice";
|
|
114287
|
+
var helperAccess = () => sharedHelperAccess(() => {
|
|
114288
|
+
const { entryCandidates } = keychainProcessState();
|
|
114289
|
+
return resolveHelperAccess([...entryCandidates, ...bundleCandidates(import.meta.url), ...machineCandidates(homedir31())]);
|
|
114290
|
+
});
|
|
114291
|
+
function sharedHelperAccess(resolve) {
|
|
114292
|
+
const state = keychainProcessState();
|
|
114293
|
+
if (state.helperAccess !== undefined)
|
|
114294
|
+
return state.helperAccess;
|
|
114295
|
+
const started = resolve();
|
|
114296
|
+
state.helperAccess = started;
|
|
114297
|
+
started.then((access) => {
|
|
114298
|
+
if (access.kind === "unavailable" && state.helperAccess === started)
|
|
114299
|
+
state.helperAccess = undefined;
|
|
114300
|
+
}, () => {
|
|
114301
|
+
if (state.helperAccess === started)
|
|
114302
|
+
state.helperAccess = undefined;
|
|
114303
|
+
});
|
|
114304
|
+
return started;
|
|
114305
|
+
}
|
|
114306
|
+
|
|
114307
|
+
class HelperMissingForOwnedItem extends Error {
|
|
114308
|
+
}
|
|
114309
|
+
function asKeystoreError(error, pending) {
|
|
114310
|
+
if (!(error instanceof HelperReadError))
|
|
114311
|
+
return error;
|
|
114312
|
+
if (error.failure === "pending")
|
|
114313
|
+
return pending(error.message);
|
|
114314
|
+
if (error.failure === "locked")
|
|
114315
|
+
return Object.assign(new Error(error.message), { code: "-25308" });
|
|
114316
|
+
return error;
|
|
114317
|
+
}
|
|
114318
|
+
function createDarwinBackend(options) {
|
|
114319
|
+
const silently = options.silently ?? silentSecrets;
|
|
114320
|
+
const key = { service: options.service, name: options.account };
|
|
114321
|
+
const deps = {
|
|
114322
|
+
account: options.account,
|
|
114323
|
+
access: options.access,
|
|
114324
|
+
cache: options.cache ?? processApprovalCache(),
|
|
114325
|
+
background: options.background,
|
|
114326
|
+
takePromptLock: promptLockAt(join109(options.home ?? homedir31(), ".omo", "session-locks", `${options.account}.keychain-prompt`)),
|
|
114327
|
+
ownSilentGet: () => silently(() => options.secrets.get(key)),
|
|
114328
|
+
ownOverwrite: (value) => silently(() => options.secrets.set({ ...key, value })),
|
|
114329
|
+
ownDelete: (name) => name === options.account ? gatedSecrets(() => options.secrets.delete({ ...key, name })) : silently(() => options.secrets.delete({ ...key, name })),
|
|
114330
|
+
notice: options.notice,
|
|
114331
|
+
...options.row8b === undefined ? {} : { row8b: options.row8b },
|
|
114332
|
+
...options.handOff === undefined ? {} : { handOff: options.handOff },
|
|
114333
|
+
noDialog: options.noDialog === true
|
|
114334
|
+
};
|
|
114335
|
+
let unowned = false;
|
|
114336
|
+
return {
|
|
114337
|
+
read: async () => {
|
|
114338
|
+
const result = await readThroughHelper(deps, true);
|
|
114339
|
+
unowned = result.kind === "value" && result.source !== "owned";
|
|
114340
|
+
return result.kind === "value" ? result.value : null;
|
|
114341
|
+
},
|
|
114342
|
+
underLock: (lease) => lockedDarwinStore(deps, lease),
|
|
114343
|
+
migrationPending: () => unowned
|
|
114344
|
+
};
|
|
114345
|
+
}
|
|
114346
|
+
async function guardHelperlessRead(service, account, choice = ROW_9B_DEFAULT, probe = probeOwnerMarker) {
|
|
114347
|
+
if (choice === "dialog")
|
|
114348
|
+
return;
|
|
114349
|
+
if (await probe(service, account) === "helper-owned")
|
|
114350
|
+
throw new HelperMissingForOwnedItem("OmO's keychain helper is missing or damaged on this Mac. Reinstall omo, then try again.");
|
|
114351
|
+
}
|
|
114352
|
+
|
|
114353
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/store-binding.ts
|
|
114354
|
+
import { homedir as homedir32 } from "os";
|
|
114355
|
+
|
|
114356
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/creator-handoff.ts
|
|
114357
|
+
init_bun_file_shim();
|
|
114358
|
+
init_bun_spawn_shim();
|
|
114359
|
+
import { dirname as dirname47, posix as posix14 } from "path";
|
|
114360
|
+
|
|
114361
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/runtime-capabilities.ts
|
|
114362
|
+
init_zod();
|
|
114363
|
+
import { readFile as readFile37 } from "fs/promises";
|
|
114364
|
+
import { dirname as dirname46, join as join110 } from "path";
|
|
114365
|
+
var RUNTIME_CAPABILITIES_FILE = "omo-runtime-capabilities.json";
|
|
114366
|
+
var RUNTIME_CAPABILITIES = { keychainHandoff: 1 };
|
|
114367
|
+
var capabilitiesSchema = object({ keychainHandoff: number2().int() }).passthrough();
|
|
114368
|
+
async function runtimeDeclaresKeychainHandoff(runtime) {
|
|
114369
|
+
const text = await readFile37(join110(dirname46(runtime), RUNTIME_CAPABILITIES_FILE), "utf8").catch(() => null);
|
|
114370
|
+
if (text === null)
|
|
114371
|
+
return false;
|
|
114372
|
+
try {
|
|
114373
|
+
const parsed = capabilitiesSchema.safeParse(JSON.parse(text));
|
|
114374
|
+
return parsed.success && parsed.data.keychainHandoff >= RUNTIME_CAPABILITIES.keychainHandoff;
|
|
114375
|
+
} catch {
|
|
114376
|
+
return false;
|
|
114377
|
+
}
|
|
114378
|
+
}
|
|
114379
|
+
|
|
114380
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/creator-handoff.ts
|
|
114381
|
+
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"';
|
|
114382
|
+
var DESKTOP_RUNTIME_REQUIREMENT = `identifier "com.mengmota.omo-desktop-runtime" and ${DEVELOPER_ID_TEAM}`;
|
|
114383
|
+
var DESKTOP_APP_REQUIREMENT = DEVELOPER_ID_TEAM;
|
|
114384
|
+
var HANDOFF_ENV = "OMO_KEYCHAIN_HANDOFF";
|
|
114385
|
+
var HANDOFF_DEADLINE_MS = 45000;
|
|
114386
|
+
function desktopRuntimeCandidates(home, arch = process.arch) {
|
|
114387
|
+
const runtimeArch = arch === "arm64" ? "arm64" : "x64";
|
|
114388
|
+
return ["/Applications/OmO.app", posix14.join(home, "Applications", "OmO.app")].map((app) => ({
|
|
114389
|
+
app,
|
|
114390
|
+
runtime: posix14.join(app, "Contents", "Resources", "omo-runtime", `darwin-${runtimeArch}`, "omo")
|
|
114391
|
+
}));
|
|
114392
|
+
}
|
|
114393
|
+
var verifyBundle = async (app, requirement) => {
|
|
114394
|
+
const child = spawn(["/usr/bin/codesign", "--verify", "--deep", "--strict", `-R=${requirement}`, app], {
|
|
114395
|
+
stdin: "ignore",
|
|
114396
|
+
stdout: "ignore",
|
|
114397
|
+
stderr: "ignore"
|
|
114398
|
+
});
|
|
114399
|
+
return await child.exited === 0;
|
|
114400
|
+
};
|
|
114401
|
+
var runBounded = async (path, args, env, deadlineMs) => {
|
|
114402
|
+
const child = spawn([path, ...args], { cwd: dirname47(path), stdin: "ignore", stdout: "ignore", stderr: "ignore", env });
|
|
114403
|
+
let killed = false;
|
|
114404
|
+
const timer = setTimeout(() => {
|
|
114405
|
+
killed = true;
|
|
114406
|
+
child.kill("SIGKILL");
|
|
114407
|
+
}, deadlineMs);
|
|
114408
|
+
try {
|
|
114409
|
+
const code = await child.exited;
|
|
114410
|
+
return killed ? null : code;
|
|
114411
|
+
} finally {
|
|
114412
|
+
clearTimeout(timer);
|
|
114413
|
+
}
|
|
114414
|
+
};
|
|
114415
|
+
function createCreatorHandOff(options) {
|
|
114416
|
+
return async () => {
|
|
114417
|
+
const env = options.env ?? process.env;
|
|
114418
|
+
if (env[HANDOFF_ENV] === "1")
|
|
114419
|
+
return false;
|
|
114420
|
+
const checkRuntime = options.checkRuntime ?? verifyWithSecurityFramework;
|
|
114421
|
+
const checkBundle = options.checkBundle ?? verifyBundle;
|
|
114422
|
+
const declaresHandOff = options.declaresHandOff ?? runtimeDeclaresKeychainHandoff;
|
|
114423
|
+
const self = options.selfPath ?? process.execPath;
|
|
114424
|
+
for (const { app, runtime } of options.candidates) {
|
|
114425
|
+
if (runtime === self || !await bunFile(runtime).exists())
|
|
114426
|
+
continue;
|
|
114427
|
+
const verified = await Promise.resolve().then(async () => await checkBundle(app, DESKTOP_APP_REQUIREMENT) && await checkRuntime(runtime, DESKTOP_RUNTIME_REQUIREMENT) && await declaresHandOff(runtime)).catch(() => false);
|
|
114428
|
+
if (!verified)
|
|
114429
|
+
continue;
|
|
114430
|
+
const childEnv = { [HANDOFF_ENV]: "1" };
|
|
114431
|
+
if (env.HOME !== undefined)
|
|
114432
|
+
childEnv.HOME = env.HOME;
|
|
114433
|
+
const origin = options.origin ?? env.OMO_SERVICE_API_URL;
|
|
114434
|
+
if (origin !== undefined)
|
|
114435
|
+
childEnv.OMO_SERVICE_API_URL = origin;
|
|
114436
|
+
try {
|
|
114437
|
+
return await (options.run ?? runBounded)(runtime, ["account", "token"], childEnv, HANDOFF_DEADLINE_MS) === 0;
|
|
114438
|
+
} catch {
|
|
114439
|
+
return false;
|
|
114440
|
+
}
|
|
114441
|
+
}
|
|
114442
|
+
return false;
|
|
114443
|
+
};
|
|
114444
|
+
}
|
|
114445
|
+
|
|
114446
|
+
// packages/omo-opencode/src/cli/service-auth/keychain-helper/store-binding.ts
|
|
114447
|
+
var readers = new Map;
|
|
114448
|
+
var INJECTED_SECRETS = Symbol.for("omo.test.injectedSecrets");
|
|
114449
|
+
var isInjectedSecrets = (api) => api[INJECTED_SECRETS] === true;
|
|
114450
|
+
var backends = new Map;
|
|
114451
|
+
function processHandOff(origin) {
|
|
114452
|
+
return () => {
|
|
114453
|
+
const state = keychainProcessState();
|
|
114454
|
+
state.handOff ??= createCreatorHandOff({ candidates: desktopRuntimeCandidates(homedir32()), origin })();
|
|
114455
|
+
return state.handOff;
|
|
114456
|
+
};
|
|
114457
|
+
}
|
|
114458
|
+
function bindKeychainHelper(input) {
|
|
114459
|
+
const { secrets: real, key, options } = input;
|
|
114460
|
+
const eligible = input.platform === "darwin" && input.namespace === "omo-cli" && (options !== undefined || typeof Bun !== "undefined" && real === Bun.secrets && !isInjectedSecrets(real));
|
|
114461
|
+
const secrets = !eligible ? real : {
|
|
114462
|
+
get: (entry) => gatedSecrets(() => real.get(entry)),
|
|
114463
|
+
set: (entry) => gatedSecrets(() => real.set(entry)),
|
|
114464
|
+
delete: (entry) => gatedSecrets(() => real.delete(entry))
|
|
114465
|
+
};
|
|
114466
|
+
const cacheKey = `${key.service}
|
|
114467
|
+
${key.name}
|
|
114468
|
+
${input.background ? "bounded" : "interactive"}`;
|
|
114469
|
+
let own;
|
|
114470
|
+
const backend = () => {
|
|
114471
|
+
if (!eligible)
|
|
114472
|
+
return Promise.resolve(null);
|
|
114473
|
+
const known = options === undefined ? backends.get(cacheKey) : own;
|
|
114474
|
+
if (known !== undefined)
|
|
114475
|
+
return known;
|
|
114476
|
+
const created = (options?.access ?? helperAccess)().then((access) => access.kind !== "ready" ? null : createDarwinBackend({
|
|
114477
|
+
access,
|
|
114478
|
+
secrets: real,
|
|
114479
|
+
service: key.service,
|
|
114480
|
+
account: key.name,
|
|
114481
|
+
background: input.background,
|
|
114482
|
+
noDialog: options?.noDialog ?? process.env[HANDOFF_ENV] === "1",
|
|
114483
|
+
notice: input.notice,
|
|
114484
|
+
...options?.home === undefined ? {} : { home: options.home },
|
|
114485
|
+
...options?.row8b === undefined ? {} : { row8b: options.row8b },
|
|
114486
|
+
...options?.silently === undefined ? {} : { silently: options.silently },
|
|
114487
|
+
...options?.cache === undefined ? {} : { cache: options.cache },
|
|
114488
|
+
handOff: options === undefined ? processHandOff(input.origin) : options.handOff ?? (async () => false)
|
|
114489
|
+
}));
|
|
114490
|
+
if (options === undefined) {
|
|
114491
|
+
backends.set(cacheKey, created);
|
|
114492
|
+
created.then((found) => {
|
|
114493
|
+
if (found === null && backends.get(cacheKey) === created)
|
|
114494
|
+
backends.delete(cacheKey);
|
|
114495
|
+
});
|
|
114496
|
+
} else
|
|
114497
|
+
own = created;
|
|
114498
|
+
return created;
|
|
114499
|
+
};
|
|
114500
|
+
const reader = (helper) => {
|
|
114501
|
+
const known = readers.get(helper);
|
|
114502
|
+
if (known !== undefined)
|
|
114503
|
+
return known;
|
|
114504
|
+
const refuse = async () => {
|
|
114505
|
+
throw new Error("OmO's keychain helper changes the sign-in only under the session lock.");
|
|
114506
|
+
};
|
|
114507
|
+
const created = {
|
|
114508
|
+
get: async () => {
|
|
114509
|
+
try {
|
|
114510
|
+
return await helper.read();
|
|
114511
|
+
} catch (error) {
|
|
114512
|
+
throw asKeystoreError(error, (message) => input.pending(`${message} Credentials are never saved to a file.`));
|
|
114513
|
+
}
|
|
114514
|
+
},
|
|
114515
|
+
set: refuse,
|
|
114516
|
+
delete: refuse
|
|
114517
|
+
};
|
|
114518
|
+
readers.set(helper, created);
|
|
114519
|
+
return created;
|
|
114520
|
+
};
|
|
114521
|
+
return {
|
|
114522
|
+
secrets,
|
|
114523
|
+
eligible,
|
|
114524
|
+
backend,
|
|
114525
|
+
reader,
|
|
114526
|
+
isHelperReader: (api) => [...readers.values()].includes(api),
|
|
114527
|
+
guardHelperless: async () => {
|
|
114528
|
+
if (!eligible)
|
|
114529
|
+
return;
|
|
114530
|
+
if ((options?.noDialog ?? process.env[HANDOFF_ENV] === "1") === true)
|
|
114531
|
+
throw input.pending("The keychain hand-off cannot show a dialog.");
|
|
114532
|
+
await guardHelperlessRead(key.service, key.name, options?.row9b, options?.ownerMarker);
|
|
114533
|
+
}
|
|
114534
|
+
};
|
|
114535
|
+
}
|
|
114536
|
+
function lockedStoreView(helper, lease, codec, mapError, done) {
|
|
114537
|
+
const locked = helper.underLock(lease);
|
|
114538
|
+
const run = async (step) => {
|
|
114539
|
+
try {
|
|
114540
|
+
return await step();
|
|
114541
|
+
} catch (error) {
|
|
114542
|
+
throw mapError(error);
|
|
114543
|
+
} finally {
|
|
114544
|
+
done();
|
|
114545
|
+
}
|
|
114546
|
+
};
|
|
114547
|
+
return {
|
|
114548
|
+
read: () => run(async () => {
|
|
114549
|
+
const text = await locked.read();
|
|
114550
|
+
return text === null ? null : codec.parse(text);
|
|
114551
|
+
}),
|
|
114552
|
+
write: (value, intent = "update", beforeRetire) => run(async () => {
|
|
114553
|
+
const next = codec.amend === undefined ? value : codec.amend(await locked.read(), value);
|
|
114554
|
+
await locked.write(codec.serialize(next), intent, beforeRetire);
|
|
114555
|
+
}),
|
|
114556
|
+
clear: () => run(() => locked.clear()),
|
|
114557
|
+
recover: () => run(() => locked.recover()),
|
|
114558
|
+
settle: () => run(() => locked.settle())
|
|
114559
|
+
};
|
|
114560
|
+
}
|
|
114561
|
+
|
|
114562
|
+
// packages/omo-opencode/src/cli/service-auth/secret-service-lock.ts
|
|
114563
|
+
import { spawn as spawn5 } from "child_process";
|
|
114564
|
+
var DEFAULT_COLLECTION = "/org/freedesktop/secrets/aliases/default";
|
|
114565
|
+
var PROBE_TIMEOUT_MS2 = 1e4;
|
|
114566
|
+
var parseLockedReply = (stdout) => {
|
|
114567
|
+
const match = /<\s*(true|false)\s*>/.exec(stdout);
|
|
114568
|
+
if (match === null)
|
|
114569
|
+
return null;
|
|
114570
|
+
return match[1] === "true" ? "locked" : "unlocked";
|
|
114571
|
+
};
|
|
114572
|
+
var probeSecretServiceLock = () => new Promise((resolve) => {
|
|
114573
|
+
const child = spawn5("gdbus", [
|
|
114574
|
+
"call",
|
|
114575
|
+
"--session",
|
|
114576
|
+
"--dest",
|
|
114577
|
+
"org.freedesktop.secrets",
|
|
114578
|
+
"--object-path",
|
|
114579
|
+
DEFAULT_COLLECTION,
|
|
114580
|
+
"--method",
|
|
114581
|
+
"org.freedesktop.DBus.Properties.Get",
|
|
114582
|
+
"org.freedesktop.Secret.Collection",
|
|
114583
|
+
"Locked"
|
|
114584
|
+
], { stdio: ["ignore", "pipe", "ignore"] });
|
|
114585
|
+
let stdout = "";
|
|
114586
|
+
const timer = setTimeout(() => {
|
|
114587
|
+
child.kill();
|
|
114588
|
+
resolve("unknown");
|
|
114589
|
+
}, PROBE_TIMEOUT_MS2);
|
|
114590
|
+
child.stdout.on("data", (chunk) => {
|
|
114591
|
+
stdout += chunk.toString();
|
|
114592
|
+
});
|
|
114593
|
+
child.on("error", () => {
|
|
114594
|
+
clearTimeout(timer);
|
|
114595
|
+
resolve("unknown");
|
|
114596
|
+
});
|
|
114597
|
+
child.on("close", (code) => {
|
|
114598
|
+
clearTimeout(timer);
|
|
114599
|
+
resolve(code === 0 ? parseLockedReply(stdout) ?? "absent" : "absent");
|
|
114600
|
+
});
|
|
114601
|
+
});
|
|
114602
|
+
|
|
113378
114603
|
// packages/omo-opencode/src/cli/service-auth/credential-lock.ts
|
|
114604
|
+
import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
|
|
114605
|
+
import { createHash as createHash11 } from "crypto";
|
|
114606
|
+
import { mkdir as mkdir12 } from "fs/promises";
|
|
114607
|
+
import { homedir as homedir33 } from "os";
|
|
114608
|
+
import { join as join112 } from "path";
|
|
113379
114609
|
var held = new AsyncLocalStorage3;
|
|
113380
|
-
function credentialLockPaths(api, home =
|
|
114610
|
+
function credentialLockPaths(api, home = homedir33()) {
|
|
113381
114611
|
const id = createHash11("sha256").update(serviceOrigin(api)).digest("hex");
|
|
113382
|
-
const directory =
|
|
113383
|
-
return { directory, lock:
|
|
114612
|
+
const directory = join112(home, ".omo", "session-locks");
|
|
114613
|
+
return { directory, lock: join112(directory, `${id}.lock`), desktopRecord: join112(directory, `${id}.desktop-generation.json`) };
|
|
113384
114614
|
}
|
|
113385
|
-
|
|
114615
|
+
function heldCredentialLease(api, home = homedir33()) {
|
|
114616
|
+
return held.getStore()?.get(credentialLockPaths(api, home).lock);
|
|
114617
|
+
}
|
|
114618
|
+
async function withCredentialLock(api, action, home = homedir33(), ownerTag = "cli-session") {
|
|
113386
114619
|
const { directory, lock } = credentialLockPaths(api, home);
|
|
113387
114620
|
const owned = held.getStore();
|
|
113388
|
-
|
|
113389
|
-
|
|
113390
|
-
|
|
113391
|
-
|
|
114621
|
+
const outer = owned?.get(lock);
|
|
114622
|
+
if (outer !== undefined)
|
|
114623
|
+
return action(outer);
|
|
114624
|
+
await mkdir12(directory, { recursive: true, mode: 448 });
|
|
114625
|
+
return withLock(lock, (lease) => held.run(new Map([...owned ?? [], [lock, lease]]), () => action(lease)), {
|
|
113392
114626
|
ownerTag,
|
|
113393
114627
|
staleAfterMs: Number.POSITIVE_INFINITY
|
|
113394
114628
|
});
|
|
@@ -113440,17 +114674,51 @@ function createCredentialStore(api, options = {}) {
|
|
|
113440
114674
|
return {
|
|
113441
114675
|
...value,
|
|
113442
114676
|
...accountId === undefined ? {} : { accountId },
|
|
113443
|
-
credentialGeneration: sameIdentity ? current?.credentialGeneration ??
|
|
114677
|
+
credentialGeneration: sameIdentity ? current?.credentialGeneration ?? randomUUID8() : randomUUID8()
|
|
113444
114678
|
};
|
|
113445
|
-
});
|
|
114679
|
+
}, options.keychainHelper);
|
|
114680
|
+
const sections = new WeakMap;
|
|
114681
|
+
const underLock = (lease) => {
|
|
114682
|
+
const known = sections.get(lease);
|
|
114683
|
+
if (known !== undefined)
|
|
114684
|
+
return known;
|
|
114685
|
+
const view = (async () => {
|
|
114686
|
+
const opened = await store.underLock?.(lease) ?? null;
|
|
114687
|
+
await opened?.recover();
|
|
114688
|
+
return opened;
|
|
114689
|
+
})();
|
|
114690
|
+
sections.set(lease, view);
|
|
114691
|
+
return view;
|
|
114692
|
+
};
|
|
114693
|
+
const held = async () => {
|
|
114694
|
+
const lease = heldCredentialLease(api, options.home);
|
|
114695
|
+
return lease === undefined ? null : underLock(lease);
|
|
114696
|
+
};
|
|
114697
|
+
const locked = async (helper, plain) => {
|
|
114698
|
+
if (heldCredentialLease(api, options.home) === undefined)
|
|
114699
|
+
await store.prepare?.();
|
|
114700
|
+
await withCredentialLock(api, async (lease) => {
|
|
114701
|
+
const view = await underLock(lease);
|
|
114702
|
+
await (view === null ? plain() : helper(view));
|
|
114703
|
+
}, options.home);
|
|
114704
|
+
};
|
|
113446
114705
|
return {
|
|
113447
|
-
read:
|
|
113448
|
-
|
|
113449
|
-
|
|
113450
|
-
|
|
114706
|
+
read: async () => {
|
|
114707
|
+
const view = await held();
|
|
114708
|
+
return view === null ? store.read() : view.read();
|
|
114709
|
+
},
|
|
114710
|
+
readAuthoritative: async () => {
|
|
114711
|
+
const view = await held();
|
|
114712
|
+
return view === null ? store.readAuthoritative() : view.read();
|
|
114713
|
+
},
|
|
114714
|
+
write: (value, intent, beforeRetire) => locked((view) => view.write(value, intent, beforeRetire), () => store.write(value)),
|
|
114715
|
+
clear: () => locked((view) => view.clear(), store.clear),
|
|
114716
|
+
...store.prepare === undefined ? {} : { prepare: store.prepare },
|
|
114717
|
+
underLock,
|
|
114718
|
+
...store.migrationPending === undefined ? {} : { migrationPending: store.migrationPending }
|
|
113451
114719
|
};
|
|
113452
114720
|
}
|
|
113453
|
-
function createSealedStore(api, namespace, schema, secrets = typeof Bun === "undefined" ? null : Bun.secrets, platform = process.platform, lockProbe = probeSecretServiceLock, notice = stderrNoticeOncePerProcess, wait = SESSION_READ_WAIT, amendWrite) {
|
|
114721
|
+
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) {
|
|
113454
114722
|
if (!secrets)
|
|
113455
114723
|
throw new SignInError("OmO sign-in needs Bun 1.4 or newer with OS credential storage. No file fallback is available.");
|
|
113456
114724
|
const platformName = platform === "darwin" ? "macOS Keychain" : platform === "linux" ? "Linux Secret Service (libsecret and an unlocked keyring)" : platform === "win32" ? "Windows Credential Manager" : null;
|
|
@@ -113459,6 +114727,18 @@ function createSealedStore(api, namespace, schema, secrets = typeof Bun === "und
|
|
|
113459
114727
|
const key = { service: namespace, name: credentialId(api) };
|
|
113460
114728
|
const slot = `${key.service}
|
|
113461
114729
|
${key.name}`;
|
|
114730
|
+
const helper = bindKeychainHelper({
|
|
114731
|
+
platform,
|
|
114732
|
+
namespace,
|
|
114733
|
+
secrets,
|
|
114734
|
+
key,
|
|
114735
|
+
background: wait.kind === "bounded",
|
|
114736
|
+
origin: api,
|
|
114737
|
+
notice,
|
|
114738
|
+
pending: (message) => new KeychainApprovalPendingError(message),
|
|
114739
|
+
...keychainHelper === undefined ? {} : { options: keychainHelper }
|
|
114740
|
+
});
|
|
114741
|
+
secrets = helper.secrets;
|
|
113462
114742
|
const readsOf = (api) => {
|
|
113463
114743
|
const known = processReads.get(api);
|
|
113464
114744
|
if (known !== undefined)
|
|
@@ -113484,17 +114764,19 @@ ${key.name}`;
|
|
|
113484
114764
|
reads.set(slot, read);
|
|
113485
114765
|
return read;
|
|
113486
114766
|
};
|
|
113487
|
-
const waiting = platform === "darwin" ? `macOS Keychain is waiting for your approval: answer the "${
|
|
114767
|
+
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`;
|
|
114768
|
+
const helperWaiting = `macOS Keychain is waiting for your approval: answer the "OmO's keychain helper wants to access key ${namespace}" dialog`;
|
|
113488
114769
|
const answered = async (api, fresh = false) => {
|
|
114770
|
+
const waitingFor = helper.isHelperReader(api) ? helperWaiting : waiting;
|
|
113489
114771
|
const read = fresh ? Promise.resolve().then(() => api.get(key)) : sharedRead(api);
|
|
113490
114772
|
let timer;
|
|
113491
114773
|
try {
|
|
113492
114774
|
if (wait.kind === "interactive") {
|
|
113493
|
-
timer = setTimeout(() => wait.notice(`omo: ${
|
|
114775
|
+
timer = setTimeout(() => wait.notice(`omo: ${waitingFor}.`), wait.noticeAfterMs);
|
|
113494
114776
|
return await read;
|
|
113495
114777
|
}
|
|
113496
114778
|
const expired = new Promise((_, reject) => {
|
|
113497
|
-
timer = setTimeout(() => reject(new KeychainApprovalPendingError(`${
|
|
114779
|
+
timer = setTimeout(() => reject(new KeychainApprovalPendingError(`${waitingFor}, then try again. Credentials are never saved to a file.`)), wait.deadlineMs);
|
|
113498
114780
|
});
|
|
113499
114781
|
return await Promise.race([read, expired]);
|
|
113500
114782
|
} finally {
|
|
@@ -113519,41 +114801,76 @@ ${key.name}`;
|
|
|
113519
114801
|
notice("omo: could not check whether the keyring is locked (gdbus or the Secret Service did not answer); using libsecret directly.");
|
|
113520
114802
|
}
|
|
113521
114803
|
};
|
|
113522
|
-
const
|
|
114804
|
+
const parseStored = (value) => {
|
|
114805
|
+
try {
|
|
114806
|
+
return schema.parse(JSON.parse(value));
|
|
114807
|
+
} catch {
|
|
114808
|
+
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.");
|
|
114809
|
+
}
|
|
114810
|
+
};
|
|
114811
|
+
const previousOf = (raw) => {
|
|
114812
|
+
if (raw === null)
|
|
114813
|
+
return null;
|
|
114814
|
+
try {
|
|
114815
|
+
return schema.parse(JSON.parse(raw));
|
|
114816
|
+
} catch {
|
|
114817
|
+
return null;
|
|
114818
|
+
}
|
|
114819
|
+
};
|
|
114820
|
+
const rawRead = async (fresh) => {
|
|
113523
114821
|
await assertUsable();
|
|
113524
|
-
|
|
114822
|
+
const backend = await helper.backend();
|
|
113525
114823
|
try {
|
|
113526
|
-
|
|
114824
|
+
if (backend === null)
|
|
114825
|
+
await helper.guardHelperless();
|
|
114826
|
+
return await answered(backend === null ? secrets : helper.reader(backend), fresh);
|
|
113527
114827
|
} catch (error) {
|
|
113528
114828
|
if (error instanceof KeychainApprovalPendingError)
|
|
113529
114829
|
throw error;
|
|
114830
|
+
if (error instanceof HelperMissingForOwnedItem)
|
|
114831
|
+
throw new CredentialStoreError(error.message);
|
|
113530
114832
|
throw unavailable(error);
|
|
113531
114833
|
}
|
|
113532
|
-
|
|
113533
|
-
|
|
113534
|
-
|
|
113535
|
-
|
|
113536
|
-
|
|
113537
|
-
|
|
113538
|
-
|
|
114834
|
+
};
|
|
114835
|
+
const parsedRead = async (fresh) => {
|
|
114836
|
+
const value = await rawRead(fresh);
|
|
114837
|
+
return value === null ? null : parseStored(value);
|
|
114838
|
+
};
|
|
114839
|
+
const lockedFailure = (error) => {
|
|
114840
|
+
const mapped = asKeystoreError(error, (message) => new KeychainApprovalPendingError(message));
|
|
114841
|
+
if (error instanceof HelperOldSlotsFull)
|
|
114842
|
+
return new CredentialStoreError(error.message);
|
|
114843
|
+
if (mapped instanceof KeychainApprovalPendingError || mapped instanceof SignInError)
|
|
114844
|
+
return mapped;
|
|
114845
|
+
if (mapped instanceof Error && mapped.name === "LockLeaseLostError")
|
|
114846
|
+
return mapped;
|
|
114847
|
+
return unavailable(mapped);
|
|
113539
114848
|
};
|
|
113540
114849
|
return {
|
|
113541
114850
|
read: () => parsedRead(false),
|
|
113542
114851
|
readAuthoritative: () => parsedRead(true),
|
|
114852
|
+
async prepare() {
|
|
114853
|
+
if (await helper.backend() !== null)
|
|
114854
|
+
await rawRead(false);
|
|
114855
|
+
},
|
|
114856
|
+
async underLock(lease) {
|
|
114857
|
+
const backend = await helper.backend();
|
|
114858
|
+
if (backend === null)
|
|
114859
|
+
return null;
|
|
114860
|
+
const codec = {
|
|
114861
|
+
parse: parseStored,
|
|
114862
|
+
serialize: (value) => JSON.stringify(schema.parse(value)),
|
|
114863
|
+
...amendWrite === undefined ? {} : { amend: (raw, next) => amendWrite(previousOf(raw), next) }
|
|
114864
|
+
};
|
|
114865
|
+
return lockedStoreView(backend, lease, codec, lockedFailure, () => forget(helper.reader(backend)));
|
|
114866
|
+
},
|
|
114867
|
+
migrationPending: async () => (await helper.backend())?.migrationPending() ?? false,
|
|
113543
114868
|
async write(value) {
|
|
113544
114869
|
await assertUsable();
|
|
114870
|
+
if (await helper.backend() !== null)
|
|
114871
|
+
throw new Error("OmO's keychain helper writes only under the session lock.");
|
|
113545
114872
|
try {
|
|
113546
|
-
|
|
113547
|
-
if (amendWrite !== undefined) {
|
|
113548
|
-
const raw = await answered(secrets, true);
|
|
113549
|
-
let previous = null;
|
|
113550
|
-
if (raw !== null) {
|
|
113551
|
-
try {
|
|
113552
|
-
previous = schema.parse(JSON.parse(raw));
|
|
113553
|
-
} catch {}
|
|
113554
|
-
}
|
|
113555
|
-
next = amendWrite(previous, value);
|
|
113556
|
-
}
|
|
114873
|
+
const next = amendWrite === undefined ? value : amendWrite(previousOf(await answered(secrets, true)), value);
|
|
113557
114874
|
await secrets.set({ ...key, value: JSON.stringify(schema.parse(next)) });
|
|
113558
114875
|
} catch (error) {
|
|
113559
114876
|
throw unavailable(error);
|
|
@@ -113562,6 +114879,8 @@ ${key.name}`;
|
|
|
113562
114879
|
},
|
|
113563
114880
|
async clear() {
|
|
113564
114881
|
await assertUsable();
|
|
114882
|
+
if (await helper.backend() !== null)
|
|
114883
|
+
throw new Error("OmO's keychain helper deletes only under the session lock.");
|
|
113565
114884
|
try {
|
|
113566
114885
|
await secrets.delete(key);
|
|
113567
114886
|
} catch (error) {
|
|
@@ -113671,17 +114990,62 @@ async function loginLoopback(session, options) {
|
|
|
113671
114990
|
}
|
|
113672
114991
|
}
|
|
113673
114992
|
|
|
114993
|
+
// packages/memory-core/src/sync/device-retire.ts
|
|
114994
|
+
import { createHash as createHash14, randomBytes as randomBytes6 } from "crypto";
|
|
114995
|
+
import { join as join115 } from "path";
|
|
114996
|
+
|
|
114997
|
+
// packages/memory-core/src/identity/layout.ts
|
|
114998
|
+
import { homedir as homedir34 } from "os";
|
|
114999
|
+
import { join as join113, resolve as resolve31 } from "path";
|
|
115000
|
+
var MEMORY_ROOT_ENV_VAR = "OMO_MEMORY_HOME";
|
|
115001
|
+
function defaultMemoryRoot() {
|
|
115002
|
+
return join113(homedir34(), ".omo", "memory");
|
|
115003
|
+
}
|
|
115004
|
+
function resolveMemoryRoot(env, cwd) {
|
|
115005
|
+
const override = env[MEMORY_ROOT_ENV_VAR];
|
|
115006
|
+
if (override === undefined || override.trim() === "") {
|
|
115007
|
+
return defaultMemoryRoot();
|
|
115008
|
+
}
|
|
115009
|
+
return resolve31(cwd, override);
|
|
115010
|
+
}
|
|
115011
|
+
// packages/memory-core/src/sync/pin-dir.ts
|
|
115012
|
+
import { join as join114 } from "path";
|
|
115013
|
+
var syncPinDir = (memoryRoot) => join114(memoryRoot, "sync-device");
|
|
115014
|
+
|
|
115015
|
+
// packages/memory-core/src/sync/device-retire.ts
|
|
115016
|
+
var trustAnchorRoot = (pinDir) => join115(pinDir, "trust-anchor");
|
|
115017
|
+
var trustAnchorKey = (account) => createHash14("sha256").update(account, "utf8").digest("base64url");
|
|
115018
|
+
var trustAnchorDir = (pinDir, account) => join115(trustAnchorRoot(pinDir), trustAnchorKey(account));
|
|
115019
|
+
var hasLiveTrustAnchor = async (pinDir) => {
|
|
115020
|
+
try {
|
|
115021
|
+
return (await readdir17(trustAnchorRoot(pinDir))).some((name) => !name.includes(".retired-"));
|
|
115022
|
+
} catch (error) {
|
|
115023
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
115024
|
+
return false;
|
|
115025
|
+
throw error;
|
|
115026
|
+
}
|
|
115027
|
+
};
|
|
115028
|
+
var retireSyncDevice = async (input) => {
|
|
115029
|
+
const dir = trustAnchorDir(input.pinDir, input.account);
|
|
115030
|
+
try {
|
|
115031
|
+
await rename8(dir, `${dir}.retired-${Date.now()}-${randomBytes6(4).toString("hex")}`);
|
|
115032
|
+
} catch (error) {
|
|
115033
|
+
if (!(error instanceof Error && ("code" in error) && error.code === "ENOENT"))
|
|
115034
|
+
throw error;
|
|
115035
|
+
}
|
|
115036
|
+
};
|
|
115037
|
+
|
|
113674
115038
|
// packages/omo-opencode/src/cli/service-auth/session.ts
|
|
113675
|
-
import { homedir as
|
|
115039
|
+
import { homedir as homedir35 } from "os";
|
|
113676
115040
|
|
|
113677
115041
|
// packages/omo-opencode/src/cli/service-auth/signed-out-marker.ts
|
|
113678
115042
|
init_zod();
|
|
113679
|
-
import { mkdir as
|
|
113680
|
-
import { dirname as
|
|
115043
|
+
import { mkdir as mkdir13, readFile as readFile38, rename as rename10, rm as rm19, writeFile as writeFile18 } from "fs/promises";
|
|
115044
|
+
import { dirname as dirname48, join as join116 } from "path";
|
|
113681
115045
|
var markerSchema = object({ device: string2().nullable(), at: string2() });
|
|
113682
|
-
var signedOutMarkerPath = (home, credential) =>
|
|
115046
|
+
var signedOutMarkerPath = (home, credential) => join116(home, ".omo", "account-state", `${credential}.signed-out.json`);
|
|
113683
115047
|
async function readSignedOutMarker(path) {
|
|
113684
|
-
const text = await
|
|
115048
|
+
const text = await readFile38(path, "utf8").catch(() => null);
|
|
113685
115049
|
if (text === null)
|
|
113686
115050
|
return null;
|
|
113687
115051
|
let value;
|
|
@@ -113694,12 +115058,12 @@ async function readSignedOutMarker(path) {
|
|
|
113694
115058
|
return parsed.success ? parsed.data : null;
|
|
113695
115059
|
}
|
|
113696
115060
|
async function writeSignedOutMarker(path, device) {
|
|
113697
|
-
await
|
|
115061
|
+
await mkdir13(dirname48(path), { recursive: true, mode: 448 });
|
|
113698
115062
|
const staging = `${path}.${process.pid}.tmp`;
|
|
113699
|
-
await
|
|
113700
|
-
await
|
|
115063
|
+
await writeFile18(staging, JSON.stringify({ device, at: new Date().toISOString() }), { mode: 384 });
|
|
115064
|
+
await rename10(staging, path);
|
|
113701
115065
|
}
|
|
113702
|
-
var clearSignedOutMarker = (path) =>
|
|
115066
|
+
var clearSignedOutMarker = (path) => rm19(path, { force: true });
|
|
113703
115067
|
|
|
113704
115068
|
// packages/omo-opencode/src/cli/service-auth/session.ts
|
|
113705
115069
|
class SessionEnded extends SignInError {
|
|
@@ -113712,19 +115076,33 @@ class SessionEnded extends SignInError {
|
|
|
113712
115076
|
}
|
|
113713
115077
|
}
|
|
113714
115078
|
var DEVICE_REVOKING_REFUSALS = new Set(["account_deleted", "reauth_required", "device_revoked"]);
|
|
115079
|
+
var discardedOf = (credentials, cause) => ({
|
|
115080
|
+
kind: "credential",
|
|
115081
|
+
deviceId: credentials.device.id,
|
|
115082
|
+
accountId: credentials.accountId,
|
|
115083
|
+
owner: credentials.owner,
|
|
115084
|
+
cause
|
|
115085
|
+
});
|
|
113715
115086
|
function createSession(options) {
|
|
113716
115087
|
const api = serviceOrigin(options.api);
|
|
113717
115088
|
const now = options.now ?? Date.now;
|
|
113718
|
-
const { store, signal } = options;
|
|
113719
|
-
const markerPath = signedOutMarkerPath(options.home ??
|
|
115089
|
+
const { store, signal, beforeKeysDiscarded } = options;
|
|
115090
|
+
const markerPath = signedOutMarkerPath(options.home ?? homedir35(), credentialId(api));
|
|
113720
115091
|
async function locked(action) {
|
|
113721
115092
|
signal?.throwIfAborted();
|
|
113722
|
-
|
|
115093
|
+
if (heldCredentialLease(api, options.home) === undefined)
|
|
115094
|
+
await store.prepare?.();
|
|
115095
|
+
return withCredentialLock(api, async (lease) => {
|
|
113723
115096
|
signal?.throwIfAborted();
|
|
113724
|
-
return action();
|
|
115097
|
+
return action(await store.underLock?.(lease) ?? null);
|
|
113725
115098
|
}, options.home);
|
|
113726
115099
|
}
|
|
113727
115100
|
const request = (path, init) => requestApi(api, path, init, signal);
|
|
115101
|
+
const accountOf = async (access) => {
|
|
115102
|
+
const body = await request("/v1/me", { headers: { authorization: `Bearer ${access}` } }).catch(() => null);
|
|
115103
|
+
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;
|
|
115104
|
+
return typeof id === "string" && id !== "" ? id : undefined;
|
|
115105
|
+
};
|
|
113728
115106
|
async function refreshed(current) {
|
|
113729
115107
|
if (current.refreshState === "uncertain" || current.refreshAttempt !== undefined) {
|
|
113730
115108
|
throw new SessionEnded(`Refresh recovery can no longer be proved safe. ${signInHint("again")}`, false, "refresh_recovery_expired");
|
|
@@ -113741,6 +115119,7 @@ function createSession(options) {
|
|
|
113741
115119
|
if (error instanceof CredentialStoreError)
|
|
113742
115120
|
throw error;
|
|
113743
115121
|
if (error instanceof ApiRefusal && error.status < 500 && ["unauthorized", "account_deleted", "reauth_required", "invalid_grant", "device_revoked"].includes(error.code)) {
|
|
115122
|
+
await beforeKeysDiscarded(discardedOf(current, "refused"));
|
|
113744
115123
|
await store.clear();
|
|
113745
115124
|
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);
|
|
113746
115125
|
}
|
|
@@ -113752,9 +115131,12 @@ function createSession(options) {
|
|
|
113752
115131
|
}
|
|
113753
115132
|
}
|
|
113754
115133
|
async function snapshot() {
|
|
113755
|
-
return locked(async () => {
|
|
115134
|
+
return locked(async (view) => {
|
|
113756
115135
|
const current = await store.read();
|
|
113757
|
-
|
|
115136
|
+
if (current === null)
|
|
115137
|
+
return null;
|
|
115138
|
+
await view?.settle();
|
|
115139
|
+
return refreshed(current);
|
|
113758
115140
|
});
|
|
113759
115141
|
}
|
|
113760
115142
|
return {
|
|
@@ -113766,7 +115148,18 @@ function createSession(options) {
|
|
|
113766
115148
|
},
|
|
113767
115149
|
async save(value) {
|
|
113768
115150
|
await locked(async () => {
|
|
113769
|
-
|
|
115151
|
+
let stored;
|
|
115152
|
+
try {
|
|
115153
|
+
stored = await store.readAuthoritative();
|
|
115154
|
+
} catch (error) {
|
|
115155
|
+
if (!(error instanceof InvalidCredentialState))
|
|
115156
|
+
throw error;
|
|
115157
|
+
await beforeKeysDiscarded({ kind: "unreadable" });
|
|
115158
|
+
stored = null;
|
|
115159
|
+
}
|
|
115160
|
+
if (stored !== null && stored.device.id !== value.device.id)
|
|
115161
|
+
await beforeKeysDiscarded(discardedOf(stored, "replaced"));
|
|
115162
|
+
await store.write(value, "fresh-sign-in", () => beforeKeysDiscarded({ kind: "unreadable" }));
|
|
113770
115163
|
await clearSignedOutMarker(markerPath);
|
|
113771
115164
|
});
|
|
113772
115165
|
},
|
|
@@ -113792,12 +115185,16 @@ function createSession(options) {
|
|
|
113792
115185
|
async logout() {
|
|
113793
115186
|
return locked(async () => {
|
|
113794
115187
|
let current = null;
|
|
115188
|
+
let account;
|
|
113795
115189
|
try {
|
|
113796
115190
|
current = await store.readAuthoritative();
|
|
113797
115191
|
if (current !== null) {
|
|
113798
115192
|
if (current.refreshState === "uncertain")
|
|
113799
115193
|
return false;
|
|
113800
115194
|
const access = Date.parse(current.accessTokenExpiresAt) <= now() ? (await refreshed(current)).accessToken : current.accessToken;
|
|
115195
|
+
if (current.accountId === undefined && current.owner === undefined && await beforeKeysDiscarded.wantsAccount?.() === true) {
|
|
115196
|
+
account = await accountOf(access);
|
|
115197
|
+
}
|
|
113801
115198
|
await request(`/v1/devices/${encodeURIComponent(current.device.id)}`, {
|
|
113802
115199
|
method: "DELETE",
|
|
113803
115200
|
headers: { authorization: `Bearer ${access}` }
|
|
@@ -113812,6 +115209,9 @@ function createSession(options) {
|
|
|
113812
115209
|
throw error;
|
|
113813
115210
|
} finally {
|
|
113814
115211
|
await writeSignedOutMarker(markerPath, current?.device.id ?? null);
|
|
115212
|
+
const stored = current === null ? null : await store.read().catch(() => current);
|
|
115213
|
+
if (stored !== null)
|
|
115214
|
+
await beforeKeysDiscarded(discardedOf(stored.accountId === undefined && account !== undefined ? { ...stored, accountId: account } : stored, "logout"));
|
|
113815
115215
|
await store.clear();
|
|
113816
115216
|
}
|
|
113817
115217
|
});
|
|
@@ -113820,14 +115220,15 @@ function createSession(options) {
|
|
|
113820
115220
|
signal?.throwIfAborted();
|
|
113821
115221
|
const snapshot = await store.read();
|
|
113822
115222
|
signal?.throwIfAborted();
|
|
113823
|
-
if (snapshot !== null && snapshot.refreshState !== "uncertain" && snapshot.refreshAttempt === undefined && Date.parse(snapshot.accessTokenExpiresAt) > now() + 30000 && (expect === undefined || expect(snapshot)))
|
|
115223
|
+
if (snapshot !== null && snapshot.refreshState !== "uncertain" && snapshot.refreshAttempt === undefined && Date.parse(snapshot.accessTokenExpiresAt) > now() + 30000 && (expect === undefined || expect(snapshot)) && !await store.migrationPending?.())
|
|
113824
115224
|
return snapshot.accessToken;
|
|
113825
|
-
return locked(async () => {
|
|
115225
|
+
return locked(async (view) => {
|
|
113826
115226
|
const current = await store.readAuthoritative();
|
|
113827
115227
|
if (current === null)
|
|
113828
115228
|
throw new SignInError(`Not signed in. ${signInHint("first")}`);
|
|
113829
115229
|
if (expect !== undefined && !expect(current))
|
|
113830
115230
|
throw new CredentialIdentityChanged;
|
|
115231
|
+
await view?.settle();
|
|
113831
115232
|
return (await refreshed(current)).accessToken;
|
|
113832
115233
|
});
|
|
113833
115234
|
},
|
|
@@ -113848,6 +115249,26 @@ function createSession(options) {
|
|
|
113848
115249
|
};
|
|
113849
115250
|
}
|
|
113850
115251
|
|
|
115252
|
+
// packages/omo-opencode/src/cli/service-auth/sync-pin-retire.ts
|
|
115253
|
+
var reason = (error) => error instanceof Error && ("code" in error) && typeof error.code === "string" ? error.code : "unknown";
|
|
115254
|
+
function retireSyncPinOnDiscard(options) {
|
|
115255
|
+
const hook = async (discarded) => {
|
|
115256
|
+
if (discarded.kind === "unreadable") {
|
|
115257
|
+
options.log("memory sync: a stored sign-in could not be read while it was replaced; its sync pin was left in place");
|
|
115258
|
+
return;
|
|
115259
|
+
}
|
|
115260
|
+
const account = discarded.owner?.accountId ?? discarded.accountId;
|
|
115261
|
+
if (account === undefined)
|
|
115262
|
+
return;
|
|
115263
|
+
try {
|
|
115264
|
+
await retireSyncDevice({ pinDir: options.pinDir(), account });
|
|
115265
|
+
} catch (error) {
|
|
115266
|
+
options.log(`memory sync: the sync pin could not be retired (${reason(error)}); it was left in place`);
|
|
115267
|
+
}
|
|
115268
|
+
};
|
|
115269
|
+
return Object.assign(hook, { wantsAccount: () => hasLiveTrustAnchor(options.pinDir()).catch(() => false) });
|
|
115270
|
+
}
|
|
115271
|
+
|
|
113851
115272
|
// packages/omo-opencode/src/cli/service-auth/commands.ts
|
|
113852
115273
|
async function ensureServiceAvailable(session, api) {
|
|
113853
115274
|
try {
|
|
@@ -113890,7 +115311,12 @@ async function run2(action, options) {
|
|
|
113890
115311
|
try {
|
|
113891
115312
|
const api = serviceOrigin(options.api ?? process.env.OMO_SERVICE_API_URL ?? "https://api.omo.dev");
|
|
113892
115313
|
const store = createCredentialStore(api, { wait: INTERACTIVE_READ_WAIT });
|
|
113893
|
-
const session = createSession({
|
|
115314
|
+
const session = createSession({
|
|
115315
|
+
api,
|
|
115316
|
+
store,
|
|
115317
|
+
signal: controller.signal,
|
|
115318
|
+
beforeKeysDiscarded: retireSyncPinOnDiscard({ pinDir: () => syncPinDir(resolveMemoryRoot(process.env, process.cwd())), log: (line) => console.error(line) })
|
|
115319
|
+
});
|
|
113894
115320
|
if (action === "logout") {
|
|
113895
115321
|
const revoked = await session.logout();
|
|
113896
115322
|
console.log("Signed out of OmO. Stored credentials and device keys were removed.");
|
|
@@ -113950,6 +115376,10 @@ function refuseClosedServiceAuth() {
|
|
|
113950
115376
|
}
|
|
113951
115377
|
function configureClosedServiceAuthCommands(program) {
|
|
113952
115378
|
for (const name of SERVICE_AUTH_COMMANDS) {
|
|
115379
|
+
if (name === "login") {
|
|
115380
|
+
configureClosedDeviceLogin(program);
|
|
115381
|
+
continue;
|
|
115382
|
+
}
|
|
113953
115383
|
const command = program.command(name, { hidden: true }).helpOption(false).allowUnknownOption().allowExcessArguments().action(() => {
|
|
113954
115384
|
console.error(SERVICE_ACCOUNTS_CLOSED_MESSAGE);
|
|
113955
115385
|
process.exitCode = 1;
|
|
@@ -113957,6 +115387,17 @@ function configureClosedServiceAuthCommands(program) {
|
|
|
113957
115387
|
command.help = refuseClosedServiceAuth;
|
|
113958
115388
|
}
|
|
113959
115389
|
}
|
|
115390
|
+
function configureClosedDeviceLogin(program) {
|
|
115391
|
+
const command = program.command("login", { hidden: true }).helpOption(false).allowUnknownOption().allowExcessArguments().option("--device").option("--no-browser").option("--api <url>").action((options) => {
|
|
115392
|
+
if (options.device !== true && options.browser !== false || command.args.length > 0) {
|
|
115393
|
+
console.error(SERVICE_ACCOUNTS_CLOSED_MESSAGE);
|
|
115394
|
+
process.exitCode = 1;
|
|
115395
|
+
return;
|
|
115396
|
+
}
|
|
115397
|
+
return run2("login", { ...options, device: true });
|
|
115398
|
+
});
|
|
115399
|
+
command.help = refuseClosedServiceAuth;
|
|
115400
|
+
}
|
|
113960
115401
|
function configureServiceAuthCommands(program, open = serviceAccountsOpen()) {
|
|
113961
115402
|
if (!open) {
|
|
113962
115403
|
configureClosedServiceAuthCommands(program);
|
|
@@ -114158,11 +115599,11 @@ async function boulder(options) {
|
|
|
114158
115599
|
// packages/omo-opencode/src/cli/codex-ulw-loop.ts
|
|
114159
115600
|
import { spawn as spawn6 } from "child_process";
|
|
114160
115601
|
import { existsSync as existsSync67, readFileSync as readFileSync45, realpathSync as realpathSync14 } from "fs";
|
|
114161
|
-
import { homedir as
|
|
115602
|
+
import { homedir as homedir36 } from "os";
|
|
114162
115603
|
var ULW_LOOP_DELEGATION_SENTINEL = "OMO_ULW_LOOP_DELEGATED";
|
|
114163
115604
|
function resolveCodexUlwLoopCommand(input = {}) {
|
|
114164
115605
|
const env = input.env ?? process.env;
|
|
114165
|
-
const homeDir = input.homeDir ??
|
|
115606
|
+
const homeDir = input.homeDir ?? homedir36();
|
|
114166
115607
|
const localComponentBin = resolveLocalUlwLoopBin(env, homeDir);
|
|
114167
115608
|
if (localComponentBin !== null)
|
|
114168
115609
|
return { executable: localComponentBin, argsPrefix: [] };
|
|
@@ -114405,7 +115846,7 @@ function linkedWorktrees(records) {
|
|
|
114405
115846
|
}
|
|
114406
115847
|
// packages/omo-opencode/src/cli/worktree-sweep/sweep.ts
|
|
114407
115848
|
import { existsSync as existsSync68 } from "fs";
|
|
114408
|
-
import { stat as
|
|
115849
|
+
import { stat as stat12 } from "fs/promises";
|
|
114409
115850
|
import os7 from "os";
|
|
114410
115851
|
import { normalize as normalize2 } from "path";
|
|
114411
115852
|
|
|
@@ -114488,7 +115929,7 @@ async function isOlderThan(worktreePath, days, now) {
|
|
|
114488
115929
|
if (days <= 0)
|
|
114489
115930
|
return false;
|
|
114490
115931
|
try {
|
|
114491
|
-
const stats = await
|
|
115932
|
+
const stats = await stat12(worktreePath);
|
|
114492
115933
|
return now - stats.mtimeMs > days * DAY_MS;
|
|
114493
115934
|
} catch {
|
|
114494
115935
|
return false;
|
|
@@ -114653,7 +116094,7 @@ prunes.
|
|
|
114653
116094
|
|
|
114654
116095
|
// packages/omo-opencode/src/cli/config-migrate.ts
|
|
114655
116096
|
init_startup_migration();
|
|
114656
|
-
import { posix as
|
|
116097
|
+
import { posix as posix15 } from "path";
|
|
114657
116098
|
function reports(result) {
|
|
114658
116099
|
return result.results.map((entry) => ({
|
|
114659
116100
|
diagnostics: entry.diagnostics,
|
|
@@ -114687,7 +116128,7 @@ function runConfigMigrate(options = {}) {
|
|
|
114687
116128
|
dryRun: options.dryRun ?? false,
|
|
114688
116129
|
environment,
|
|
114689
116130
|
...homeDir === undefined ? {} : { env: { HOME: homeDir }, homeDir },
|
|
114690
|
-
pathOperations:
|
|
116131
|
+
pathOperations: posix15
|
|
114691
116132
|
});
|
|
114692
116133
|
const report = reports(result);
|
|
114693
116134
|
const response = {
|