voratiq 0.1.0-beta.0
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/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/auth/providers/claude/constants.d.ts +7 -0
- package/dist/auth/providers/claude/constants.js +9 -0
- package/dist/auth/providers/claude/credentials.d.ts +5 -0
- package/dist/auth/providers/claude/credentials.js +112 -0
- package/dist/auth/providers/claude/error.d.ts +5 -0
- package/dist/auth/providers/claude/error.js +6 -0
- package/dist/auth/providers/claude/keychain.d.ts +4 -0
- package/dist/auth/providers/claude/keychain.js +158 -0
- package/dist/auth/providers/claude.d.ts +2 -0
- package/dist/auth/providers/claude.js +124 -0
- package/dist/auth/providers/codex.d.ts +2 -0
- package/dist/auth/providers/codex.js +93 -0
- package/dist/auth/providers/gemini.d.ts +2 -0
- package/dist/auth/providers/gemini.js +159 -0
- package/dist/auth/providers/index.d.ts +2 -0
- package/dist/auth/providers/index.js +16 -0
- package/dist/auth/providers/messages.d.ts +1 -0
- package/dist/auth/providers/messages.js +3 -0
- package/dist/auth/providers/secret-staging.d.ts +14 -0
- package/dist/auth/providers/secret-staging.js +72 -0
- package/dist/auth/providers/teardown.d.ts +2 -0
- package/dist/auth/providers/teardown.js +6 -0
- package/dist/auth/providers/types.d.ts +31 -0
- package/dist/auth/providers/types.js +1 -0
- package/dist/auth/providers/utils.d.ts +20 -0
- package/dist/auth/providers/utils.js +148 -0
- package/dist/auth/runtime.d.ts +2 -0
- package/dist/auth/runtime.js +17 -0
- package/dist/auth/staging.d.ts +8 -0
- package/dist/auth/staging.js +7 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +142 -0
- package/dist/cli/apply.d.ts +14 -0
- package/dist/cli/apply.js +38 -0
- package/dist/cli/commander-utils.d.ts +3 -0
- package/dist/cli/commander-utils.js +27 -0
- package/dist/cli/confirmation.d.ts +14 -0
- package/dist/cli/confirmation.js +16 -0
- package/dist/cli/errors.d.ts +5 -0
- package/dist/cli/errors.js +16 -0
- package/dist/cli/init.d.ts +10 -0
- package/dist/cli/init.js +41 -0
- package/dist/cli/list.d.ts +14 -0
- package/dist/cli/list.js +48 -0
- package/dist/cli/output.d.ts +14 -0
- package/dist/cli/output.js +62 -0
- package/dist/cli/prune.d.ts +14 -0
- package/dist/cli/prune.js +54 -0
- package/dist/cli/review.d.ts +12 -0
- package/dist/cli/review.js +33 -0
- package/dist/cli/run.d.ts +13 -0
- package/dist/cli/run.js +51 -0
- package/dist/commands/apply/command.d.ts +9 -0
- package/dist/commands/apply/command.js +135 -0
- package/dist/commands/apply/errors.d.ts +35 -0
- package/dist/commands/apply/errors.js +73 -0
- package/dist/commands/apply/types.d.ts +13 -0
- package/dist/commands/apply/types.js +1 -0
- package/dist/commands/errors.d.ts +4 -0
- package/dist/commands/errors.js +7 -0
- package/dist/commands/fetch.d.ts +8 -0
- package/dist/commands/fetch.js +25 -0
- package/dist/commands/init/agents.d.ts +3 -0
- package/dist/commands/init/agents.js +159 -0
- package/dist/commands/init/command.d.ts +2 -0
- package/dist/commands/init/command.js +40 -0
- package/dist/commands/init/environment.d.ts +2 -0
- package/dist/commands/init/environment.js +76 -0
- package/dist/commands/init/evals.d.ts +4 -0
- package/dist/commands/init/evals.js +219 -0
- package/dist/commands/init/types.d.ts +48 -0
- package/dist/commands/init/types.js +1 -0
- package/dist/commands/list/command.d.ts +13 -0
- package/dist/commands/list/command.js +60 -0
- package/dist/commands/prune/command.d.ts +2 -0
- package/dist/commands/prune/command.js +336 -0
- package/dist/commands/prune/errors.d.ts +20 -0
- package/dist/commands/prune/errors.js +39 -0
- package/dist/commands/prune/types.d.ts +42 -0
- package/dist/commands/prune/types.js +1 -0
- package/dist/commands/review/command.d.ts +10 -0
- package/dist/commands/review/command.js +26 -0
- package/dist/commands/run/agent-execution.d.ts +19 -0
- package/dist/commands/run/agent-execution.js +63 -0
- package/dist/commands/run/agents/auth-stage.d.ts +23 -0
- package/dist/commands/run/agents/auth-stage.js +108 -0
- package/dist/commands/run/agents/chat-preserver.d.ts +9 -0
- package/dist/commands/run/agents/chat-preserver.js +35 -0
- package/dist/commands/run/agents/eval-runner.d.ts +19 -0
- package/dist/commands/run/agents/eval-runner.js +27 -0
- package/dist/commands/run/agents/failures.d.ts +7 -0
- package/dist/commands/run/agents/failures.js +32 -0
- package/dist/commands/run/agents/lifecycle.d.ts +9 -0
- package/dist/commands/run/agents/lifecycle.js +157 -0
- package/dist/commands/run/agents/preparation.d.ts +2 -0
- package/dist/commands/run/agents/preparation.js +123 -0
- package/dist/commands/run/agents/run-context.d.ts +46 -0
- package/dist/commands/run/agents/run-context.js +193 -0
- package/dist/commands/run/agents/sandbox-launcher.d.ts +44 -0
- package/dist/commands/run/agents/sandbox-launcher.js +211 -0
- package/dist/commands/run/agents/types.d.ts +47 -0
- package/dist/commands/run/agents/types.js +1 -0
- package/dist/commands/run/agents/watchdog.d.ts +39 -0
- package/dist/commands/run/agents/watchdog.js +172 -0
- package/dist/commands/run/agents/workspace-prep.d.ts +17 -0
- package/dist/commands/run/agents/workspace-prep.js +78 -0
- package/dist/commands/run/agents.d.ts +14 -0
- package/dist/commands/run/agents.js +47 -0
- package/dist/commands/run/argv.d.ts +1 -0
- package/dist/commands/run/argv.js +19 -0
- package/dist/commands/run/command.d.ts +14 -0
- package/dist/commands/run/command.js +170 -0
- package/dist/commands/run/errors.d.ts +61 -0
- package/dist/commands/run/errors.js +86 -0
- package/dist/commands/run/id.d.ts +1 -0
- package/dist/commands/run/id.js +22 -0
- package/dist/commands/run/lifecycle.d.ts +19 -0
- package/dist/commands/run/lifecycle.js +186 -0
- package/dist/commands/run/phases.d.ts +11 -0
- package/dist/commands/run/phases.js +1 -0
- package/dist/commands/run/prompts.d.ts +4 -0
- package/dist/commands/run/prompts.js +16 -0
- package/dist/commands/run/record-init.d.ts +15 -0
- package/dist/commands/run/record-init.js +29 -0
- package/dist/commands/run/reports.d.ts +14 -0
- package/dist/commands/run/reports.js +63 -0
- package/dist/commands/run/sandbox-registry.d.ts +4 -0
- package/dist/commands/run/sandbox-registry.js +54 -0
- package/dist/commands/run/sandbox.d.ts +16 -0
- package/dist/commands/run/sandbox.js +96 -0
- package/dist/commands/run/shim/agent-manifest.d.ts +7 -0
- package/dist/commands/run/shim/agent-manifest.js +1 -0
- package/dist/commands/run/shim/run-agent-shim.d.ts +1 -0
- package/dist/commands/run/shim/run-agent-shim.js +232 -0
- package/dist/commands/run/shim/run-agent-shim.mjs +10 -0
- package/dist/commands/run/validation.d.ts +20 -0
- package/dist/commands/run/validation.js +60 -0
- package/dist/configs/agents/defaults.d.ts +9 -0
- package/dist/configs/agents/defaults.js +55 -0
- package/dist/configs/agents/errors.d.ts +40 -0
- package/dist/configs/agents/errors.js +78 -0
- package/dist/configs/agents/loader.d.ts +8 -0
- package/dist/configs/agents/loader.js +137 -0
- package/dist/configs/agents/types.d.ts +39 -0
- package/dist/configs/agents/types.js +31 -0
- package/dist/configs/environment/detect.d.ts +17 -0
- package/dist/configs/environment/detect.js +79 -0
- package/dist/configs/environment/errors.d.ts +12 -0
- package/dist/configs/environment/errors.js +26 -0
- package/dist/configs/environment/loader.d.ts +10 -0
- package/dist/configs/environment/loader.js +80 -0
- package/dist/configs/environment/types.d.ts +21 -0
- package/dist/configs/environment/types.js +98 -0
- package/dist/configs/evals/defaults.d.ts +8 -0
- package/dist/configs/evals/defaults.js +28 -0
- package/dist/configs/evals/detect.d.ts +10 -0
- package/dist/configs/evals/detect.js +224 -0
- package/dist/configs/evals/errors.d.ts +16 -0
- package/dist/configs/evals/errors.js +29 -0
- package/dist/configs/evals/loader.d.ts +9 -0
- package/dist/configs/evals/loader.js +46 -0
- package/dist/configs/evals/types.d.ts +42 -0
- package/dist/configs/evals/types.js +74 -0
- package/dist/configs/sandbox/defaults.d.ts +14 -0
- package/dist/configs/sandbox/defaults.js +54 -0
- package/dist/configs/sandbox/errors.d.ts +5 -0
- package/dist/configs/sandbox/errors.js +8 -0
- package/dist/configs/sandbox/loader.d.ts +6 -0
- package/dist/configs/sandbox/loader.js +192 -0
- package/dist/configs/sandbox/merge.d.ts +9 -0
- package/dist/configs/sandbox/merge.js +94 -0
- package/dist/configs/sandbox/schemas.d.ts +58 -0
- package/dist/configs/sandbox/schemas.js +72 -0
- package/dist/configs/sandbox/types.d.ts +34 -0
- package/dist/configs/sandbox/types.js +1 -0
- package/dist/configs/shared/loader-factory.d.ts +19 -0
- package/dist/configs/shared/loader-factory.js +33 -0
- package/dist/configs/shared/yaml-error-formatter.d.ts +40 -0
- package/dist/configs/shared/yaml-error-formatter.js +41 -0
- package/dist/evals/runner.d.ts +16 -0
- package/dist/evals/runner.js +132 -0
- package/dist/preflight/errors.d.ts +10 -0
- package/dist/preflight/errors.js +21 -0
- package/dist/preflight/index.d.ts +30 -0
- package/dist/preflight/index.js +157 -0
- package/dist/records/enhanced.d.ts +38 -0
- package/dist/records/enhanced.js +139 -0
- package/dist/records/errors.d.ts +23 -0
- package/dist/records/errors.js +43 -0
- package/dist/records/history-lock.d.ts +27 -0
- package/dist/records/history-lock.js +184 -0
- package/dist/records/mutators.d.ts +17 -0
- package/dist/records/mutators.js +144 -0
- package/dist/records/persistence.d.ts +95 -0
- package/dist/records/persistence.js +459 -0
- package/dist/records/types.d.ts +238 -0
- package/dist/records/types.js +131 -0
- package/dist/render/interactions/confirmation.d.ts +19 -0
- package/dist/render/interactions/confirmation.js +63 -0
- package/dist/render/transcripts/apply.d.ts +2 -0
- package/dist/render/transcripts/apply.js +52 -0
- package/dist/render/transcripts/init.d.ts +18 -0
- package/dist/render/transcripts/init.js +84 -0
- package/dist/render/transcripts/list.d.ts +3 -0
- package/dist/render/transcripts/list.js +44 -0
- package/dist/render/transcripts/prune.d.ts +16 -0
- package/dist/render/transcripts/prune.js +50 -0
- package/dist/render/transcripts/review.d.ts +2 -0
- package/dist/render/transcripts/review.js +36 -0
- package/dist/render/transcripts/run.d.ts +25 -0
- package/dist/render/transcripts/run.js +295 -0
- package/dist/render/transcripts/shared.d.ts +12 -0
- package/dist/render/transcripts/shared.js +41 -0
- package/dist/render/utils/agents.d.ts +28 -0
- package/dist/render/utils/agents.js +261 -0
- package/dist/render/utils/badges.d.ts +20 -0
- package/dist/render/utils/badges.js +37 -0
- package/dist/render/utils/errors.d.ts +2 -0
- package/dist/render/utils/errors.js +14 -0
- package/dist/render/utils/records.d.ts +1 -0
- package/dist/render/utils/records.js +32 -0
- package/dist/render/utils/runs.d.ts +16 -0
- package/dist/render/utils/runs.js +50 -0
- package/dist/render/utils/table.d.ts +12 -0
- package/dist/render/utils/table.js +32 -0
- package/dist/render/utils/transcript.d.ts +14 -0
- package/dist/render/utils/transcript.js +44 -0
- package/dist/status/colors.d.ts +10 -0
- package/dist/status/colors.js +33 -0
- package/dist/status/index.d.ts +37 -0
- package/dist/status/index.js +30 -0
- package/dist/testing/test-hooks.d.ts +7 -0
- package/dist/testing/test-hooks.js +16 -0
- package/dist/utils/binaries.d.ts +1 -0
- package/dist/utils/binaries.js +13 -0
- package/dist/utils/cli-root.d.ts +2 -0
- package/dist/utils/cli-root.js +42 -0
- package/dist/utils/colors.d.ts +2 -0
- package/dist/utils/colors.js +23 -0
- package/dist/utils/diff.d.ts +9 -0
- package/dist/utils/diff.js +61 -0
- package/dist/utils/env.d.ts +10 -0
- package/dist/utils/env.js +56 -0
- package/dist/utils/errors.d.ts +31 -0
- package/dist/utils/errors.js +53 -0
- package/dist/utils/fs.d.ts +13 -0
- package/dist/utils/fs.js +70 -0
- package/dist/utils/git.d.ts +40 -0
- package/dist/utils/git.js +126 -0
- package/dist/utils/output.d.ts +4 -0
- package/dist/utils/output.js +12 -0
- package/dist/utils/path.d.ts +11 -0
- package/dist/utils/path.js +84 -0
- package/dist/utils/process.d.ts +37 -0
- package/dist/utils/process.js +152 -0
- package/dist/utils/terminal.d.ts +5 -0
- package/dist/utils/terminal.js +5 -0
- package/dist/utils/validators.d.ts +1 -0
- package/dist/utils/validators.js +15 -0
- package/dist/utils/version.d.ts +1 -0
- package/dist/utils/version.js +25 -0
- package/dist/utils/yaml-reader.d.ts +14 -0
- package/dist/utils/yaml-reader.js +41 -0
- package/dist/utils/yaml.d.ts +33 -0
- package/dist/utils/yaml.js +75 -0
- package/dist/workspace/agents.d.ts +33 -0
- package/dist/workspace/agents.js +189 -0
- package/dist/workspace/chat/artifacts.d.ts +14 -0
- package/dist/workspace/chat/artifacts.js +157 -0
- package/dist/workspace/chat/sources.d.ts +5 -0
- package/dist/workspace/chat/sources.js +80 -0
- package/dist/workspace/chat/types.d.ts +1 -0
- package/dist/workspace/chat/types.js +1 -0
- package/dist/workspace/cleanup.d.ts +4 -0
- package/dist/workspace/cleanup.js +12 -0
- package/dist/workspace/credential-guard.d.ts +4 -0
- package/dist/workspace/credential-guard.js +71 -0
- package/dist/workspace/dependencies.d.ts +23 -0
- package/dist/workspace/dependencies.js +190 -0
- package/dist/workspace/errors.d.ts +16 -0
- package/dist/workspace/errors.js +43 -0
- package/dist/workspace/layout.d.ts +30 -0
- package/dist/workspace/layout.js +124 -0
- package/dist/workspace/prune.d.ts +8 -0
- package/dist/workspace/prune.js +29 -0
- package/dist/workspace/run.d.ts +14 -0
- package/dist/workspace/run.js +28 -0
- package/dist/workspace/sandbox-requirements.d.ts +17 -0
- package/dist/workspace/sandbox-requirements.js +69 -0
- package/dist/workspace/setup.d.ts +3 -0
- package/dist/workspace/setup.js +81 -0
- package/dist/workspace/shim.d.ts +4 -0
- package/dist/workspace/shim.js +65 -0
- package/dist/workspace/structure.d.ts +77 -0
- package/dist/workspace/structure.js +134 -0
- package/dist/workspace/templates.d.ts +9 -0
- package/dist/workspace/templates.js +66 -0
- package/dist/workspace/types.d.ts +4 -0
- package/dist/workspace/types.js +1 -0
- package/package.json +82 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Voratiq
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Voratiq
|
|
2
|
+
|
|
3
|
+
Run multiple AI coding agents in parallel, compare their results, and apply the best solution.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Voratiq is in public beta. Install via npm:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g voratiq@beta
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Requirements
|
|
16
|
+
|
|
17
|
+
Core:
|
|
18
|
+
|
|
19
|
+
- Node 20+
|
|
20
|
+
- git
|
|
21
|
+
- 1+ AI coding agent (Claude [(>=2.0.55)](https://github.com/anthropics/claude-code?tab=readme-ov-file#get-started), Codex [(>=0.66.0)](https://github.com/openai/codex?tab=readme-ov-file#quickstart), or Gemini [(>=0.19.4)](https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#quick-install))
|
|
22
|
+
|
|
23
|
+
Platform-specific:
|
|
24
|
+
|
|
25
|
+
- macOS: `ripgrep`
|
|
26
|
+
- Linux (Debian/Ubuntu): `bubblewrap`, `socat`, `ripgrep`
|
|
27
|
+
|
|
28
|
+
See the [sandbox runtime docs](https://github.com/anthropic-experimental/sandbox-runtime/blob/1bafa66a2c3ebc52569fc0c1a868e85e778f66a0/README.md#platform-specific-dependencies) for installation instructions.
|
|
29
|
+
|
|
30
|
+
Note: Windows is not currently supported.
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Initialize workspace
|
|
36
|
+
voratiq init
|
|
37
|
+
|
|
38
|
+
# Write a spec
|
|
39
|
+
cat > specs/fix-auth.md <<EOF
|
|
40
|
+
# Fix Session Timeout Bug
|
|
41
|
+
Users are logged out after 5 minutes instead of 30.
|
|
42
|
+
Sessions should honor SESSION_TIMEOUT_MS (default 30 minutes).
|
|
43
|
+
EOF
|
|
44
|
+
|
|
45
|
+
# Run agents in parallel
|
|
46
|
+
voratiq run --spec specs/fix-auth.md
|
|
47
|
+
|
|
48
|
+
# Review results
|
|
49
|
+
voratiq review --run <run-id>
|
|
50
|
+
|
|
51
|
+
# Apply the best solution
|
|
52
|
+
voratiq apply --run <run-id> --agent <agent-id>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
See the [docs](https://github.com/voratiq/voratiq/blob/main/docs/index.md) for core concepts, CLI reference, and guides on configuring agents, evals, runtime environments, and sandbox restrictions.
|
|
56
|
+
|
|
57
|
+
## License
|
|
58
|
+
|
|
59
|
+
Voratiq is available under the [MIT License](https://github.com/voratiq/voratiq/blob/main/LICENSE).
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const CLAUDE_PROVIDER_ID: "claude";
|
|
2
|
+
export declare const CLAUDE_SERVICE_NAME: "Claude Code-credentials";
|
|
3
|
+
export declare const CLAUDE_CREDENTIAL_FILENAME: ".credentials.json";
|
|
4
|
+
export declare const CLAUDE_CONFIG_DIRNAME: ".claude";
|
|
5
|
+
export declare const CLAUDE_LOGIN_HINT: string;
|
|
6
|
+
export declare const MAC_LOGIN_KEYCHAIN_HINT: string;
|
|
7
|
+
export declare const CLAUDE_OAUTH_RELOGIN_HINT: string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { buildAuthFailedMessage } from "../messages.js";
|
|
2
|
+
export const CLAUDE_PROVIDER_ID = "claude";
|
|
3
|
+
export const CLAUDE_SERVICE_NAME = "Claude Code-credentials";
|
|
4
|
+
export const CLAUDE_CREDENTIAL_FILENAME = ".credentials.json";
|
|
5
|
+
export const CLAUDE_CONFIG_DIRNAME = ".claude";
|
|
6
|
+
const CLAUDE_REAUTH_MESSAGE = buildAuthFailedMessage("Claude");
|
|
7
|
+
export const CLAUDE_LOGIN_HINT = CLAUDE_REAUTH_MESSAGE;
|
|
8
|
+
export const MAC_LOGIN_KEYCHAIN_HINT = CLAUDE_REAUTH_MESSAGE;
|
|
9
|
+
export const CLAUDE_OAUTH_RELOGIN_HINT = CLAUDE_REAUTH_MESSAGE;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { StageOptions, VerifyOptions } from "../types.js";
|
|
2
|
+
export declare function locateClaudeCredentials(options: VerifyOptions | StageOptions): Promise<string | undefined>;
|
|
3
|
+
export declare function locateClaudeApiKey(options: VerifyOptions | StageOptions): Promise<string | undefined>;
|
|
4
|
+
export declare function parseApiKeyFromClaudeConfig(content: string): string | undefined;
|
|
5
|
+
export declare function validateClaudeCredentialSecret(secret: string): void;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { resolve as resolvePathNative } from "node:path";
|
|
4
|
+
import { isMissing, resolveChildPath } from "../utils.js";
|
|
5
|
+
import { CLAUDE_CONFIG_DIRNAME, CLAUDE_CREDENTIAL_FILENAME, CLAUDE_LOGIN_HINT, CLAUDE_OAUTH_RELOGIN_HINT, } from "./constants.js";
|
|
6
|
+
import { ClaudeAuthProviderError } from "./error.js";
|
|
7
|
+
export async function locateClaudeCredentials(options) {
|
|
8
|
+
for (const candidate of resolveClaudeConfigCandidates(options)) {
|
|
9
|
+
const credentialsPath = resolveChildPath(candidate, CLAUDE_CREDENTIAL_FILENAME);
|
|
10
|
+
try {
|
|
11
|
+
await access(credentialsPath);
|
|
12
|
+
return credentialsPath;
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
if (!isMissing(error)) {
|
|
16
|
+
throw new ClaudeAuthProviderError(CLAUDE_LOGIN_HINT, { cause: error });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
export async function locateClaudeApiKey(options) {
|
|
23
|
+
const { runtime: { homeDir }, } = options;
|
|
24
|
+
if (!homeDir) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
const configPath = resolveChildPath(homeDir, ".claude.json");
|
|
28
|
+
try {
|
|
29
|
+
const content = await readFile(configPath, "utf8");
|
|
30
|
+
return parseApiKeyFromClaudeConfig(content);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (isMissing(error)) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
throw new ClaudeAuthProviderError(CLAUDE_LOGIN_HINT, { cause: error });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function parseApiKeyFromClaudeConfig(content) {
|
|
40
|
+
let parsed;
|
|
41
|
+
try {
|
|
42
|
+
parsed = JSON.parse(content);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
throw new ClaudeAuthProviderError(CLAUDE_LOGIN_HINT, { cause: error });
|
|
46
|
+
}
|
|
47
|
+
const key = parsed.primaryApiKey;
|
|
48
|
+
if (typeof key === "string" && key.trim().length > 0) {
|
|
49
|
+
return key.trim();
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
export function validateClaudeCredentialSecret(secret) {
|
|
54
|
+
const trimmed = secret?.trim();
|
|
55
|
+
if (!trimmed) {
|
|
56
|
+
throw new ClaudeAuthProviderError(buildMissingOauthMessage("empty secret"));
|
|
57
|
+
}
|
|
58
|
+
let parsed;
|
|
59
|
+
try {
|
|
60
|
+
parsed = JSON.parse(trimmed);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
throw new ClaudeAuthProviderError(CLAUDE_LOGIN_HINT, { cause: error });
|
|
64
|
+
}
|
|
65
|
+
const oauth = parsed.claudeAiOauth;
|
|
66
|
+
if (!oauth || typeof oauth !== "object") {
|
|
67
|
+
throw new ClaudeAuthProviderError(buildMissingOauthMessage("oauth payload missing"));
|
|
68
|
+
}
|
|
69
|
+
const { accessToken, refreshToken, expiresAt } = oauth;
|
|
70
|
+
if (!isNonEmptyString(accessToken)) {
|
|
71
|
+
throw new ClaudeAuthProviderError(buildMissingOauthMessage("access token missing"));
|
|
72
|
+
}
|
|
73
|
+
if (!isNonEmptyString(refreshToken)) {
|
|
74
|
+
throw new ClaudeAuthProviderError(buildMissingOauthMessage("refresh token missing"));
|
|
75
|
+
}
|
|
76
|
+
if (!isFiniteTimestamp(expiresAt)) {
|
|
77
|
+
throw new ClaudeAuthProviderError(buildMissingOauthMessage("expiry missing"));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function resolveClaudeConfigCandidates(options) {
|
|
81
|
+
const { runtime: { env, homeDir }, } = options;
|
|
82
|
+
const candidates = [];
|
|
83
|
+
const configured = env.CLAUDE_CONFIG_DIR?.trim();
|
|
84
|
+
if (configured) {
|
|
85
|
+
candidates.push(resolvePathNative(configured));
|
|
86
|
+
}
|
|
87
|
+
const xdg = env.XDG_CONFIG_HOME?.trim();
|
|
88
|
+
if (xdg) {
|
|
89
|
+
candidates.push(resolvePathNative(xdg, "claude"));
|
|
90
|
+
}
|
|
91
|
+
if (homeDir) {
|
|
92
|
+
candidates.push(resolveChildPath(homeDir, ".config", "claude"));
|
|
93
|
+
candidates.push(resolveChildPath(homeDir, CLAUDE_CONFIG_DIRNAME));
|
|
94
|
+
}
|
|
95
|
+
return candidates;
|
|
96
|
+
}
|
|
97
|
+
function isNonEmptyString(value) {
|
|
98
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
99
|
+
}
|
|
100
|
+
function isFiniteTimestamp(value) {
|
|
101
|
+
if (typeof value === "number") {
|
|
102
|
+
return Number.isFinite(value);
|
|
103
|
+
}
|
|
104
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
105
|
+
const parsed = Number.parseInt(value, 10);
|
|
106
|
+
return Number.isFinite(parsed);
|
|
107
|
+
}
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
function buildMissingOauthMessage(detail) {
|
|
111
|
+
return `${CLAUDE_OAUTH_RELOGIN_HINT} (${detail}).`;
|
|
112
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AuthRuntimeContext } from "../types.js";
|
|
2
|
+
export declare function ensureKeychainCredential(runtime: AuthRuntimeContext): Promise<void>;
|
|
3
|
+
export declare function readKeychainCredential(runtime: AuthRuntimeContext): Promise<string>;
|
|
4
|
+
export declare function assertLoginKeychainExists(homeDir: string): Promise<void>;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { access, readdir, readFile } from "node:fs/promises";
|
|
3
|
+
import { resolve as resolvePathNative } from "node:path";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
import { isMissing, resolveChildPath } from "../utils.js";
|
|
6
|
+
import { CLAUDE_LOGIN_HINT, CLAUDE_SERVICE_NAME, MAC_LOGIN_KEYCHAIN_HINT, } from "./constants.js";
|
|
7
|
+
import { ClaudeAuthProviderError } from "./error.js";
|
|
8
|
+
const execFileAsync = promisify(execFile);
|
|
9
|
+
const LOGIN_KEYCHAIN_FILENAMES = [
|
|
10
|
+
"login.keychain-db",
|
|
11
|
+
"login.keychain",
|
|
12
|
+
];
|
|
13
|
+
const TEST_KEYCHAIN_SECRET_PATH_ENV = "VORATIQ_TEST_KEYCHAIN_SECRET_PATH";
|
|
14
|
+
export async function ensureKeychainCredential(runtime) {
|
|
15
|
+
await readKeychainCredential(runtime);
|
|
16
|
+
}
|
|
17
|
+
export async function readKeychainCredential(runtime) {
|
|
18
|
+
const testSecretPath = getTestKeychainSecretPath();
|
|
19
|
+
if (testSecretPath) {
|
|
20
|
+
return readTestSecret(testSecretPath);
|
|
21
|
+
}
|
|
22
|
+
await assertLoginKeychainExists(runtime.homeDir);
|
|
23
|
+
try {
|
|
24
|
+
const { stdout } = await execFileAsync("security", [
|
|
25
|
+
"find-generic-password",
|
|
26
|
+
"-s",
|
|
27
|
+
CLAUDE_SERVICE_NAME,
|
|
28
|
+
"-a",
|
|
29
|
+
runtime.username,
|
|
30
|
+
"-w",
|
|
31
|
+
]);
|
|
32
|
+
return stdout;
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (isMissingKeychainError(error)) {
|
|
36
|
+
throw new ClaudeAuthProviderError(MAC_LOGIN_KEYCHAIN_HINT, {
|
|
37
|
+
cause: error,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
throw new ClaudeAuthProviderError(CLAUDE_LOGIN_HINT, { cause: error });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export async function assertLoginKeychainExists(homeDir) {
|
|
44
|
+
const testSecretPath = getTestKeychainSecretPath();
|
|
45
|
+
if (testSecretPath) {
|
|
46
|
+
await ensureTestSecretAvailable(testSecretPath);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const hasKeychain = await hasLoginKeychain(homeDir);
|
|
51
|
+
if (!hasKeychain) {
|
|
52
|
+
throw new ClaudeAuthProviderError(MAC_LOGIN_KEYCHAIN_HINT);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (error instanceof ClaudeAuthProviderError) {
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
throw new ClaudeAuthProviderError(MAC_LOGIN_KEYCHAIN_HINT, {
|
|
60
|
+
cause: error,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function hasLoginKeychain(homeDir) {
|
|
65
|
+
if (!homeDir) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
const keychainsRoot = resolveChildPath(homeDir, "Library", "Keychains");
|
|
69
|
+
let entries;
|
|
70
|
+
try {
|
|
71
|
+
entries = await readdir(keychainsRoot, { withFileTypes: true });
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (isMissing(error)) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
for (const entry of entries) {
|
|
80
|
+
if (isLoginKeychainName(entry.name) &&
|
|
81
|
+
(entry.isFile() || entry.isSymbolicLink())) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
if (entry.isDirectory()) {
|
|
85
|
+
const directoryPath = resolvePathNative(keychainsRoot, entry.name);
|
|
86
|
+
const hasKeychainFile = await directoryContainsLoginKeychain(directoryPath);
|
|
87
|
+
if (hasKeychainFile) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
async function directoryContainsLoginKeychain(directory) {
|
|
95
|
+
for (const filename of LOGIN_KEYCHAIN_FILENAMES) {
|
|
96
|
+
const candidatePath = resolvePathNative(directory, filename);
|
|
97
|
+
try {
|
|
98
|
+
await access(candidatePath);
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
if (!isMissing(error)) {
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
function isLoginKeychainName(name) {
|
|
110
|
+
return LOGIN_KEYCHAIN_FILENAMES.includes(name);
|
|
111
|
+
}
|
|
112
|
+
function isMissingKeychainError(error) {
|
|
113
|
+
if (error &&
|
|
114
|
+
typeof error === "object" &&
|
|
115
|
+
"stderr" in error &&
|
|
116
|
+
typeof error.stderr === "string") {
|
|
117
|
+
const stderr = error.stderr;
|
|
118
|
+
if (/errSecNoSuchKeychain/i.test(stderr)) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
if (/SecKeychainCopyDefault:.*could not be found/i.test(stderr)) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
if (/The specified keychain could not be found/i.test(stderr)) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (error instanceof Error && error.message) {
|
|
129
|
+
if (/errSecNoSuchKeychain/i.test(error.message)) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
if (/The specified keychain could not be found/i.test(error.message)) {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
function getTestKeychainSecretPath() {
|
|
139
|
+
const override = process.env[TEST_KEYCHAIN_SECRET_PATH_ENV];
|
|
140
|
+
if (override && override.trim().length > 0) {
|
|
141
|
+
return override;
|
|
142
|
+
}
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
async function ensureTestSecretAvailable(path) {
|
|
146
|
+
try {
|
|
147
|
+
await access(path);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
throw new ClaudeAuthProviderError(MAC_LOGIN_KEYCHAIN_HINT, {
|
|
151
|
+
cause: error,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async function readTestSecret(path) {
|
|
156
|
+
await ensureTestSecretAvailable(path);
|
|
157
|
+
return readFile(path, "utf8");
|
|
158
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { CLAUDE_CONFIG_DIRNAME, CLAUDE_CREDENTIAL_FILENAME, CLAUDE_LOGIN_HINT, CLAUDE_PROVIDER_ID, } from "./claude/constants.js";
|
|
3
|
+
import { locateClaudeApiKey, locateClaudeCredentials, validateClaudeCredentialSecret, } from "./claude/credentials.js";
|
|
4
|
+
import { ClaudeAuthProviderError } from "./claude/error.js";
|
|
5
|
+
import { ensureKeychainCredential, readKeychainCredential, } from "./claude/keychain.js";
|
|
6
|
+
import { disposeHandles, registerSandboxSecrets, stageSecretFile, } from "./secret-staging.js";
|
|
7
|
+
import { teardownAuthProvider } from "./teardown.js";
|
|
8
|
+
import { assertReadableFileOrThrow, composeSandboxEnvResult, createSandboxPaths, ensureDirectories, resolveChildPath, writeFileWithPermissions, } from "./utils.js";
|
|
9
|
+
export const claudeAuthProvider = {
|
|
10
|
+
id: CLAUDE_PROVIDER_ID,
|
|
11
|
+
async verify(options) {
|
|
12
|
+
if (isMac(options.runtime.platform)) {
|
|
13
|
+
await ensureKeychainCredential(options.runtime);
|
|
14
|
+
return { status: "ok" };
|
|
15
|
+
}
|
|
16
|
+
const credentialsPath = await locateClaudeCredentials(options);
|
|
17
|
+
if (credentialsPath) {
|
|
18
|
+
return { status: "ok" };
|
|
19
|
+
}
|
|
20
|
+
const apiKey = await locateClaudeApiKey(options);
|
|
21
|
+
if (!apiKey) {
|
|
22
|
+
throw new ClaudeAuthProviderError(CLAUDE_LOGIN_HINT);
|
|
23
|
+
}
|
|
24
|
+
return { status: "ok" };
|
|
25
|
+
},
|
|
26
|
+
async stage(options) {
|
|
27
|
+
return stageClaudeCredentials(options);
|
|
28
|
+
},
|
|
29
|
+
async teardown(options) {
|
|
30
|
+
await teardownAuthProvider(options);
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
async function stageClaudeCredentials(options) {
|
|
34
|
+
const sandboxPaths = createSandboxPaths(options.agentRoot, {
|
|
35
|
+
config: [".config"],
|
|
36
|
+
cache: [".cache"],
|
|
37
|
+
data: [".local", "share"],
|
|
38
|
+
state: [".local", "state"],
|
|
39
|
+
logs: ["logs"],
|
|
40
|
+
debugLogs: ["logs", "debug"],
|
|
41
|
+
tmp: ["tmp"],
|
|
42
|
+
});
|
|
43
|
+
const claudeConfigDir = resolveChildPath(sandboxPaths.home, CLAUDE_CONFIG_DIRNAME);
|
|
44
|
+
const debugLogFile = resolveChildPath(sandboxPaths.debugLogs, "claude.log");
|
|
45
|
+
const sandboxCredentialPath = resolveChildPath(claudeConfigDir, CLAUDE_CREDENTIAL_FILENAME);
|
|
46
|
+
let stagedApiKey;
|
|
47
|
+
await ensureDirectories([...Object.values(sandboxPaths), claudeConfigDir]);
|
|
48
|
+
await writeFileWithPermissions(debugLogFile, "", { flag: "a" });
|
|
49
|
+
const secretHandles = [];
|
|
50
|
+
const stageCredential = async (payload) => {
|
|
51
|
+
validateClaudeCredentialSecret(payload);
|
|
52
|
+
const handle = await stageSecretFile(sandboxPaths.home, {
|
|
53
|
+
destinationPath: sandboxCredentialPath,
|
|
54
|
+
sourceBytes: Buffer.from(payload, "utf8"),
|
|
55
|
+
providerId: CLAUDE_PROVIDER_ID,
|
|
56
|
+
fileLabel: CLAUDE_CREDENTIAL_FILENAME,
|
|
57
|
+
});
|
|
58
|
+
secretHandles.push(handle);
|
|
59
|
+
};
|
|
60
|
+
try {
|
|
61
|
+
if (isMac(options.runtime.platform)) {
|
|
62
|
+
const secret = await readKeychainCredential(options.runtime);
|
|
63
|
+
if (!secret) {
|
|
64
|
+
throw new ClaudeAuthProviderError(CLAUDE_LOGIN_HINT);
|
|
65
|
+
}
|
|
66
|
+
await stageCredential(secret);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
const credentialsPath = await locateClaudeCredentials(options);
|
|
70
|
+
if (credentialsPath) {
|
|
71
|
+
await assertReadableFileOrThrow(credentialsPath, (cause) => new ClaudeAuthProviderError(CLAUDE_LOGIN_HINT, { cause }));
|
|
72
|
+
const credentialsContent = await readFile(credentialsPath, "utf8");
|
|
73
|
+
await stageCredential(credentialsContent);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
const apiKey = await locateClaudeApiKey(options);
|
|
77
|
+
if (!apiKey) {
|
|
78
|
+
throw new ClaudeAuthProviderError(CLAUDE_LOGIN_HINT);
|
|
79
|
+
}
|
|
80
|
+
stagedApiKey = apiKey;
|
|
81
|
+
const apiKeyConfigPath = resolveChildPath(options.runtime.homeDir, ".claude.json");
|
|
82
|
+
await assertReadableFileOrThrow(apiKeyConfigPath, (cause) => new ClaudeAuthProviderError(CLAUDE_LOGIN_HINT, { cause }));
|
|
83
|
+
const apiKeyConfigContent = await readFile(apiKeyConfigPath, "utf8");
|
|
84
|
+
const handle = await stageSecretFile(sandboxPaths.home, {
|
|
85
|
+
destinationPath: resolveChildPath(sandboxPaths.home, ".claude.json"),
|
|
86
|
+
sourceBytes: Buffer.from(apiKeyConfigContent, "utf8"),
|
|
87
|
+
providerId: CLAUDE_PROVIDER_ID,
|
|
88
|
+
fileLabel: ".claude.json",
|
|
89
|
+
});
|
|
90
|
+
secretHandles.push(handle);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
await disposeHandles(secretHandles);
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
registerSandboxSecrets(sandboxPaths.home, secretHandles);
|
|
99
|
+
const stagedEnv = buildSandboxEnvironment(sandboxPaths, claudeConfigDir, debugLogFile);
|
|
100
|
+
if (stagedApiKey) {
|
|
101
|
+
stagedEnv.ANTHROPIC_API_KEY = stagedApiKey;
|
|
102
|
+
}
|
|
103
|
+
return composeSandboxEnvResult(sandboxPaths.home, stagedEnv);
|
|
104
|
+
}
|
|
105
|
+
function buildSandboxEnvironment(paths, claudeConfigDir, debugLogFile) {
|
|
106
|
+
return {
|
|
107
|
+
CLAUDE_CONFIG_DIR: claudeConfigDir,
|
|
108
|
+
XDG_CONFIG_HOME: paths.config,
|
|
109
|
+
XDG_CACHE_HOME: paths.cache,
|
|
110
|
+
XDG_DATA_HOME: paths.data,
|
|
111
|
+
XDG_STATE_HOME: paths.state,
|
|
112
|
+
CLAUDE_CODE_DEBUG_LOGS_DIR: debugLogFile,
|
|
113
|
+
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "true",
|
|
114
|
+
DISABLE_AUTOUPDATER: "true",
|
|
115
|
+
DISABLE_ERROR_REPORTING: "true",
|
|
116
|
+
CLAUDE_CODE_ENABLE_TELEMETRY: "0",
|
|
117
|
+
TMPDIR: paths.tmp,
|
|
118
|
+
TEMP: paths.tmp,
|
|
119
|
+
TMP: paths.tmp,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function isMac(platform) {
|
|
123
|
+
return platform === "darwin";
|
|
124
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { constants as fsConstants } from "node:fs";
|
|
2
|
+
import { access, readFile } from "node:fs/promises";
|
|
3
|
+
import { buildAuthFailedMessage } from "./messages.js";
|
|
4
|
+
import { disposeHandles, registerSandboxSecrets, stageSecretFile, } from "./secret-staging.js";
|
|
5
|
+
import { teardownAuthProvider } from "./teardown.js";
|
|
6
|
+
import { assertReadableFileOrThrow, composeSandboxEnvResult, copyOptionalFileWithPermissions, createSandboxPaths, ensureDirectories, isMissing, resolveChildPath, resolveProviderHome, } from "./utils.js";
|
|
7
|
+
const { F_OK } = fsConstants;
|
|
8
|
+
const CODEX_PROVIDER_ID = "codex";
|
|
9
|
+
const CODEX_AUTH_FILENAME = "auth.json";
|
|
10
|
+
const CODEX_CONFIG_FILENAME = "config.toml";
|
|
11
|
+
const CODEX_LOGIN_HINT = buildAuthFailedMessage("Codex");
|
|
12
|
+
export const codexAuthProvider = {
|
|
13
|
+
id: CODEX_PROVIDER_ID,
|
|
14
|
+
async verify(options) {
|
|
15
|
+
const authPath = await locateCodexAuthFile(options);
|
|
16
|
+
if (!authPath) {
|
|
17
|
+
throw new CodexAuthProviderError(CODEX_LOGIN_HINT);
|
|
18
|
+
}
|
|
19
|
+
await assertReadableFileOrThrow(authPath, (cause) => new CodexAuthProviderError(CODEX_LOGIN_HINT, { cause }));
|
|
20
|
+
return { status: "ok" };
|
|
21
|
+
},
|
|
22
|
+
async stage(options) {
|
|
23
|
+
const authPath = await locateCodexAuthFile(options);
|
|
24
|
+
if (!authPath) {
|
|
25
|
+
throw new CodexAuthProviderError(CODEX_LOGIN_HINT);
|
|
26
|
+
}
|
|
27
|
+
await assertReadableFileOrThrow(authPath, (cause) => new CodexAuthProviderError(CODEX_LOGIN_HINT, { cause }));
|
|
28
|
+
const sandboxPaths = createSandboxPaths(options.agentRoot, {
|
|
29
|
+
codex: [".codex"],
|
|
30
|
+
logs: ["Library", "Logs", "Codex"],
|
|
31
|
+
support: ["Library", "Application Support", "Codex"],
|
|
32
|
+
});
|
|
33
|
+
await ensureDirectories(Object.values(sandboxPaths));
|
|
34
|
+
const secretHandles = [];
|
|
35
|
+
try {
|
|
36
|
+
const credentialPath = resolveChildPath(sandboxPaths.codex, CODEX_AUTH_FILENAME);
|
|
37
|
+
const bytes = await readFile(authPath);
|
|
38
|
+
const handle = await stageSecretFile(sandboxPaths.home, {
|
|
39
|
+
destinationPath: credentialPath,
|
|
40
|
+
sourceBytes: bytes,
|
|
41
|
+
providerId: CODEX_PROVIDER_ID,
|
|
42
|
+
fileLabel: CODEX_AUTH_FILENAME,
|
|
43
|
+
});
|
|
44
|
+
secretHandles.push(handle);
|
|
45
|
+
await copyOptionalConfig(options, sandboxPaths.codex);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
await disposeHandles(secretHandles);
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
registerSandboxSecrets(sandboxPaths.home, secretHandles);
|
|
52
|
+
const envResult = composeSandboxEnvResult(sandboxPaths.home, {
|
|
53
|
+
CODEX_HOME: sandboxPaths.codex,
|
|
54
|
+
RUST_BACKTRACE: "1",
|
|
55
|
+
});
|
|
56
|
+
return envResult;
|
|
57
|
+
},
|
|
58
|
+
async teardown(options) {
|
|
59
|
+
await teardownAuthProvider(options);
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
class CodexAuthProviderError extends Error {
|
|
63
|
+
constructor(message, options) {
|
|
64
|
+
super(message, options);
|
|
65
|
+
this.name = "CodexAuthProviderError";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function locateCodexAuthFile(options) {
|
|
69
|
+
const codexHome = resolveProviderHome(options.runtime, "CODEX_HOME", ".codex");
|
|
70
|
+
if (!codexHome) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
const authPath = resolveChildPath(codexHome, CODEX_AUTH_FILENAME);
|
|
74
|
+
try {
|
|
75
|
+
await access(authPath, F_OK);
|
|
76
|
+
return authPath;
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
if (isMissing(error)) {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
throw new CodexAuthProviderError(CODEX_LOGIN_HINT, { cause: error });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function copyOptionalConfig(options, sandboxPath) {
|
|
86
|
+
const codexHome = resolveProviderHome(options.runtime, "CODEX_HOME", ".codex");
|
|
87
|
+
if (!codexHome) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const configPath = resolveChildPath(codexHome, CODEX_CONFIG_FILENAME);
|
|
91
|
+
const destinationConfigPath = resolveChildPath(sandboxPath, CODEX_CONFIG_FILENAME);
|
|
92
|
+
await copyOptionalFileWithPermissions(configPath, destinationConfigPath, (cause) => new CodexAuthProviderError(CODEX_LOGIN_HINT, { cause }));
|
|
93
|
+
}
|