@theokit/sdk 5.12.1 → 5.14.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/CHANGELOG.md +74 -0
- package/dist/{agent-Cn0sphpA.d.cts → agent-DExqjqYy.d.cts} +18 -3
- package/dist/{agent-CVzDy_Oj.d.ts → agent-Dfw3VsIX.d.ts} +18 -3
- package/dist/{agent-IG7BP6GN.js → agent-T34LCGQM.js} +11 -11
- package/dist/{agent-IG7BP6GN.js.map → agent-T34LCGQM.js.map} +1 -1
- package/dist/{agent-BVKIUP7F.cjs → agent-TL4K7BTG.cjs} +12 -12
- package/dist/{agent-BVKIUP7F.cjs.map → agent-TL4K7BTG.cjs.map} +1 -1
- package/dist/auth/index.cjs +17 -16
- package/dist/auth/index.cjs.map +1 -1
- package/dist/auth/index.js +5 -4
- package/dist/auth/index.js.map +1 -1
- package/dist/{chunk-NHOEXFZT.js → chunk-2HXTNVLM.js} +5 -2
- package/dist/chunk-2HXTNVLM.js.map +1 -0
- package/dist/{chunk-Q6WT5535.cjs → chunk-2WY2OFSC.cjs} +259 -79
- package/dist/chunk-2WY2OFSC.cjs.map +1 -0
- package/dist/{chunk-HN4IKB6X.cjs → chunk-2XWAYCFM.cjs} +15 -13
- package/dist/chunk-2XWAYCFM.cjs.map +1 -0
- package/dist/{chunk-3FSBE4PS.js → chunk-3GTN4HOO.js} +10 -6
- package/dist/chunk-3GTN4HOO.js.map +1 -0
- package/dist/{chunk-VVGFZQZC.js → chunk-3LMVJTNJ.js} +9 -5
- package/dist/chunk-3LMVJTNJ.js.map +1 -0
- package/dist/{chunk-4GUFNDZR.js → chunk-3ONIVO2I.js} +3 -3
- package/dist/{chunk-4GUFNDZR.js.map → chunk-3ONIVO2I.js.map} +1 -1
- package/dist/{chunk-7WARNHWW.cjs → chunk-3UMPP553.cjs} +5 -2
- package/dist/chunk-3UMPP553.cjs.map +1 -0
- package/dist/{chunk-NWWTYBD3.cjs → chunk-4KBI37F3.cjs} +5 -5
- package/dist/{chunk-NWWTYBD3.cjs.map → chunk-4KBI37F3.cjs.map} +1 -1
- package/dist/{chunk-S46WJTDL.cjs → chunk-4TEGFMSP.cjs} +6 -6
- package/dist/{chunk-S46WJTDL.cjs.map → chunk-4TEGFMSP.cjs.map} +1 -1
- package/dist/{chunk-QISSETTG.cjs → chunk-5645PMVU.cjs} +6 -4
- package/dist/chunk-5645PMVU.cjs.map +1 -0
- package/dist/{chunk-ZLFFDPXC.js → chunk-73IITAF7.js} +36 -14
- package/dist/chunk-73IITAF7.js.map +1 -0
- package/dist/{chunk-5A4UFBHW.cjs → chunk-A77UMVMD.cjs} +15 -11
- package/dist/chunk-A77UMVMD.cjs.map +1 -0
- package/dist/{chunk-IO4RI5ZJ.cjs → chunk-BZK5QL3N.cjs} +4 -4
- package/dist/{chunk-IO4RI5ZJ.cjs.map → chunk-BZK5QL3N.cjs.map} +1 -1
- package/dist/{chunk-5HSMH2ZZ.js → chunk-CJN5CEI3.js} +4 -4
- package/dist/{chunk-5HSMH2ZZ.js.map → chunk-CJN5CEI3.js.map} +1 -1
- package/dist/{chunk-XRPMZ7TO.js → chunk-CYWOJA6B.js} +6 -4
- package/dist/chunk-CYWOJA6B.js.map +1 -0
- package/dist/{chunk-AQW54OWQ.js → chunk-DFBWYETS.js} +5 -3
- package/dist/chunk-DFBWYETS.js.map +1 -0
- package/dist/{chunk-EPANMGH7.cjs → chunk-FLDHYF5C.cjs} +11 -2
- package/dist/chunk-FLDHYF5C.cjs.map +1 -0
- package/dist/{chunk-BJ7BPLQK.js → chunk-GARVAUCU.js} +209 -29
- package/dist/chunk-GARVAUCU.js.map +1 -0
- package/dist/{chunk-YOVZMN4P.cjs → chunk-LXG6VL6R.cjs} +3 -3
- package/dist/{chunk-YOVZMN4P.cjs.map → chunk-LXG6VL6R.cjs.map} +1 -1
- package/dist/{chunk-NJBJ3CUG.js → chunk-NAVUTK6X.js} +3 -3
- package/dist/{chunk-NJBJ3CUG.js.map → chunk-NAVUTK6X.js.map} +1 -1
- package/dist/{chunk-2SFLLOMN.js → chunk-NVQSBRG6.js} +3 -3
- package/dist/{chunk-2SFLLOMN.js.map → chunk-NVQSBRG6.js.map} +1 -1
- package/dist/{chunk-FEAWEBWN.cjs → chunk-PDOXYXWX.cjs} +6 -4
- package/dist/chunk-PDOXYXWX.cjs.map +1 -0
- package/dist/{chunk-MS3TQSXU.js → chunk-QD6B6W6I.js} +6 -4
- package/dist/chunk-QD6B6W6I.js.map +1 -0
- package/dist/{chunk-NBNRQN6T.js → chunk-QGDPMM3C.js} +11 -2
- package/dist/chunk-QGDPMM3C.js.map +1 -0
- package/dist/{chunk-ZWLFHSON.cjs → chunk-R35ZJAYT.cjs} +38 -15
- package/dist/chunk-R35ZJAYT.cjs.map +1 -0
- package/dist/{chunk-4YD2WI57.cjs → chunk-R427EOZE.cjs} +19 -15
- package/dist/chunk-R427EOZE.cjs.map +1 -0
- package/dist/chunk-R5UQL2R5.cjs +18 -0
- package/dist/{chunk-LO6LIUZ6.cjs.map → chunk-R5UQL2R5.cjs.map} +1 -1
- package/dist/{chunk-TLVI2OQK.cjs → chunk-SETHRLQS.cjs} +18 -2
- package/dist/chunk-SETHRLQS.cjs.map +1 -0
- package/dist/{chunk-LSWHDOCL.cjs → chunk-SNVYOX46.cjs} +88 -72
- package/dist/chunk-SNVYOX46.cjs.map +1 -0
- package/dist/{chunk-BO3PV3OP.js → chunk-TDED5XES.js} +18 -3
- package/dist/chunk-TDED5XES.js.map +1 -0
- package/dist/{chunk-NKQVLWDF.js → chunk-ULEK4OM4.js} +3 -3
- package/dist/{chunk-NKQVLWDF.js.map → chunk-ULEK4OM4.js.map} +1 -1
- package/dist/{chunk-XJ4C4NFX.js → chunk-ZOL3L4EH.js} +63 -49
- package/dist/chunk-ZOL3L4EH.js.map +1 -0
- package/dist/{compact-session-NM56BREJ.cjs → compact-session-D2MQDB6G.cjs} +15 -15
- package/dist/{compact-session-NM56BREJ.cjs.map → compact-session-D2MQDB6G.cjs.map} +1 -1
- package/dist/{compact-session-3U2JYTVG.js → compact-session-N2PPHQO6.js} +6 -6
- package/dist/{compact-session-3U2JYTVG.js.map → compact-session-N2PPHQO6.js.map} +1 -1
- package/dist/{cron-CHn-F0fC.d.ts → cron-BubDpFJG.d.ts} +2 -2
- package/dist/{cron-BWDYetbq.d.cts → cron-CK2v0VWA.d.cts} +2 -2
- package/dist/cron.cjs +11 -11
- package/dist/cron.d.cts +3 -3
- package/dist/cron.d.ts +3 -3
- package/dist/cron.js +10 -10
- package/dist/eval.cjs +15 -15
- package/dist/eval.js +10 -10
- package/dist/{executor-HKHT4CWS.cjs → executor-5QL5AXIZ.cjs} +18 -15
- package/dist/executor-5QL5AXIZ.cjs.map +1 -0
- package/dist/{executor-3D2UDJHW.js → executor-THUXNAFR.js} +6 -3
- package/dist/executor-THUXNAFR.js.map +1 -0
- package/dist/generate-object-A5F576IT.cjs +20 -0
- package/dist/{generate-object-XBWD2PU7.cjs.map → generate-object-A5F576IT.cjs.map} +1 -1
- package/dist/{generate-object-S7MNVF2V.js → generate-object-TBDOBBYW.js} +4 -4
- package/dist/{generate-object-S7MNVF2V.js.map → generate-object-TBDOBBYW.js.map} +1 -1
- package/dist/generate-object.d.ts +14 -1
- package/dist/index.cjs +81 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -7
- package/dist/index.d.ts +36 -7
- package/dist/index.js +44 -28
- package/dist/index.js.map +1 -1
- package/dist/{inject-session-JVTZNQF6.cjs → inject-session-3ICZIJ2N.cjs} +4 -4
- package/dist/{inject-session-JVTZNQF6.cjs.map → inject-session-3ICZIJ2N.cjs.map} +1 -1
- package/dist/{inject-session-THABTKJY.js → inject-session-J26SHHIO.js} +3 -3
- package/dist/{inject-session-THABTKJY.js.map → inject-session-J26SHHIO.js.map} +1 -1
- package/dist/internal/agent-loop/prune-tool-results.d.ts +37 -0
- package/dist/internal/auth/credential-store.d.ts +1 -1
- package/dist/internal/auth/types.d.ts +4 -0
- package/dist/internal/providers/discovery.d.ts +2 -2
- package/dist/internal/providers/trust-gate.d.ts +35 -0
- package/dist/internal/runtime/plugin-loader/manifest-entry-import.d.ts +17 -0
- package/dist/internal/runtime/plugin-loader/workspace-plugin-trust.d.ts +16 -0
- package/dist/internal/runtime/skills/binary-on-path.d.ts +1 -0
- package/dist/internal/runtime/skills/discover-skills.d.ts +2 -0
- package/dist/internal/structured-output-helpers.d.ts +5 -2
- package/dist/mcp-auth.cjs +2 -2
- package/dist/mcp-auth.js +1 -1
- package/dist/models.cjs +11 -11
- package/dist/models.js +4 -4
- package/dist/providers.cjs +6 -6
- package/dist/providers.js +4 -4
- package/dist/sandbox/bwrap.d.cts +10 -8
- package/dist/sandbox/bwrap.d.ts +10 -8
- package/dist/sandbox/deny-read.d.cts +24 -0
- package/dist/sandbox/deny-read.d.ts +24 -0
- package/dist/sandbox/index.cjs +114 -35
- package/dist/sandbox/index.cjs.map +1 -1
- package/dist/sandbox/index.d.cts +2 -1
- package/dist/sandbox/index.d.ts +2 -1
- package/dist/sandbox/index.js +96 -21
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/linux-sandbox.d.cts +16 -1
- package/dist/sandbox/linux-sandbox.d.ts +16 -1
- package/dist/sandbox/local-sandbox.d.cts +3 -1
- package/dist/sandbox/local-sandbox.d.ts +3 -1
- package/dist/sandbox/seccomp-delivery.d.cts +3 -0
- package/dist/sandbox/seccomp-delivery.d.ts +3 -0
- package/dist/sandbox/shell-escape.d.cts +14 -2
- package/dist/sandbox/shell-escape.d.ts +14 -2
- package/dist/sandbox/types.d.cts +45 -0
- package/dist/sandbox/types.d.ts +45 -0
- package/dist/{sdk-agent-4-dXI2GS.d.cts → sdk-agent-DwzHcuxy.d.cts} +28 -3
- package/dist/{sdk-agent-CTOJlWA_.d.ts → sdk-agent-a3fW1xUK.d.ts} +28 -3
- package/dist/skills.cjs +4 -4
- package/dist/skills.js +1 -1
- package/dist/stream-object-AS4YYM4B.cjs +20 -0
- package/dist/{stream-object-TEEK3CAX.cjs.map → stream-object-AS4YYM4B.cjs.map} +1 -1
- package/dist/stream-object-EKM4WGTI.js +7 -0
- package/dist/{stream-object-R6SMYV4R.js.map → stream-object-EKM4WGTI.js.map} +1 -1
- package/dist/stream-object.d.ts +14 -1
- package/dist/subagents-loader.d.cts +2 -2
- package/dist/subagents-loader.d.ts +2 -2
- package/dist/types/agent.d.ts +14 -1
- package/dist/types/run.d.ts +27 -2
- package/dist/workflow-as-tool.d.ts +39 -5
- package/dist/workflow-errors.d.ts +16 -0
- package/dist/workflow.cjs +31 -23
- package/dist/workflow.d.cts +55 -5
- package/dist/workflow.d.ts +55 -5
- package/dist/workflow.js +2 -2
- package/docs/adr/mutation-testing-scope.md +56 -0
- package/docs/error-codes.md +23 -18
- package/docs/harness-capability-map.md +78 -4
- package/package.json +1 -1
- package/dist/chunk-3FSBE4PS.js.map +0 -1
- package/dist/chunk-4YD2WI57.cjs.map +0 -1
- package/dist/chunk-5A4UFBHW.cjs.map +0 -1
- package/dist/chunk-7WARNHWW.cjs.map +0 -1
- package/dist/chunk-AQW54OWQ.js.map +0 -1
- package/dist/chunk-BJ7BPLQK.js.map +0 -1
- package/dist/chunk-BO3PV3OP.js.map +0 -1
- package/dist/chunk-EPANMGH7.cjs.map +0 -1
- package/dist/chunk-FEAWEBWN.cjs.map +0 -1
- package/dist/chunk-HN4IKB6X.cjs.map +0 -1
- package/dist/chunk-LO6LIUZ6.cjs +0 -18
- package/dist/chunk-LSWHDOCL.cjs.map +0 -1
- package/dist/chunk-MS3TQSXU.js.map +0 -1
- package/dist/chunk-NBNRQN6T.js.map +0 -1
- package/dist/chunk-NHOEXFZT.js.map +0 -1
- package/dist/chunk-Q6WT5535.cjs.map +0 -1
- package/dist/chunk-QISSETTG.cjs.map +0 -1
- package/dist/chunk-TLVI2OQK.cjs.map +0 -1
- package/dist/chunk-VVGFZQZC.js.map +0 -1
- package/dist/chunk-XJ4C4NFX.js.map +0 -1
- package/dist/chunk-XRPMZ7TO.js.map +0 -1
- package/dist/chunk-ZLFFDPXC.js.map +0 -1
- package/dist/chunk-ZWLFHSON.cjs.map +0 -1
- package/dist/executor-3D2UDJHW.js.map +0 -1
- package/dist/executor-HKHT4CWS.cjs.map +0 -1
- package/dist/generate-object-XBWD2PU7.cjs +0 -20
- package/dist/stream-object-R6SMYV4R.js +0 -7
- package/dist/stream-object-TEEK3CAX.cjs +0 -20
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,79 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.14.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#859](https://github.com/usetheokit/theokit-sdk/pull/859) [`3f2e8fb`](https://github.com/usetheokit/theokit-sdk/commit/3f2e8fbdd14a06dc2bf65a0a97265b339d388843) Thanks [@usetheodev](https://github.com/usetheodev)! - An application can ship skills in its own package and gate them on a binary. `skills.bundledDirs`
|
|
8
|
+
lists extra skill roots read after the project roots and plugin bundles, so a workspace skill of the
|
|
9
|
+
same name always wins. A skill declaring `requires-bins: git, rg` in its frontmatter is not offered
|
|
10
|
+
to the model while one of those executables is absent from PATH; `skills.get(name)` still resolves
|
|
11
|
+
it. `SkillReadTool.create` also accepts a function returning the skills, evaluated on every call, so
|
|
12
|
+
a skill discovered after the agent was created is readable by the model.
|
|
13
|
+
|
|
14
|
+
- [#859](https://github.com/usetheokit/theokit-sdk/pull/859) [`8469d37`](https://github.com/usetheokit/theokit-sdk/commit/8469d37b56e3c4551f90b8707c55d4ed79c5621b) Thanks [@usetheodev](https://github.com/usetheodev)! - The OAuth ID token is now kept from the token response to the credential file ([#821](https://github.com/usetheokit/theokit-sdk/issues/821)). `exchangeCode`,
|
|
15
|
+
`refreshOAuthTokens`, `pollDeviceToken` and `openaiDeviceLogin` return it as `OAuthTokens.idToken` when
|
|
16
|
+
the provider sends a non-empty `id_token`, `persistOAuthTokens` writes it as `id_token`, and
|
|
17
|
+
`readStoredOAuth` reads it back on `StoredOAuthCredential.id_token`. `ensureFreshCredential` keeps the
|
|
18
|
+
stored ID token when a refresh response has none and stores the new one when it has one. It used to be
|
|
19
|
+
read only to derive the account id and then dropped, so a consumer that drives the Codex CLI, which reads
|
|
20
|
+
the plan and account from the ID token's claims, had to run its own login. A provider that sends no ID
|
|
21
|
+
token gets exactly the file it got before. A file that holds an `id_token` is refused by the read schema
|
|
22
|
+
of earlier SDK versions, so a store shared with an older reader should stay on one version.
|
|
23
|
+
|
|
24
|
+
- [#859](https://github.com/usetheokit/theokit-sdk/pull/859) [`f43cea5`](https://github.com/usetheokit/theokit-sdk/commit/f43cea503a2af8a2ca3ed842dbd0bb6d5732f7e9) Thanks [@usetheodev](https://github.com/usetheodev)! - A run can now stop resending old tool results to the model. Every tool result used to be resent on
|
|
25
|
+
every later LLM call of a run, so a run whose tools print a lot grew its request by that output on
|
|
26
|
+
every round. The new per-send option `pruneToolResults: { olderThanRounds: n }` replaces the
|
|
27
|
+
content of each tool result older than `n` tool rounds with a short stub in the request the agent
|
|
28
|
+
loop sends. The stub keeps the result's `toolUseId` and `isError`. The transcript the run keeps,
|
|
29
|
+
persists and resumes from stays whole, so the stub applies only to the request. The option is off by default, and
|
|
30
|
+
without it the request is unchanged. `olderThanRounds` must be an integer of at least 1. Any other
|
|
31
|
+
value fails the send with `ConfigurationError` code `invalid_prune_tool_results` before any provider
|
|
32
|
+
call. The option type is exported as `PruneToolResultsOptions`.
|
|
33
|
+
Pruning trades request size against prefix-cache reuse: each new round stubs one more previously
|
|
34
|
+
sent result, so on providers that cache message prefixes the cached prefix ends earlier. That cost
|
|
35
|
+
was not measured.
|
|
36
|
+
|
|
37
|
+
## 5.13.0
|
|
38
|
+
|
|
39
|
+
### Minor Changes
|
|
40
|
+
|
|
41
|
+
- [#783](https://github.com/usetheokit/theokit-sdk/pull/783) [`a390f10`](https://github.com/usetheokit/theokit-sdk/commit/a390f101a28e7207fdff9b50891b1defcb89bcde) Thanks [@usetheodev](https://github.com/usetheodev)! - The manifest plugin entry of a trusted workspace plugin folder is now imported. A folder under `<cwd>/.theokit/plugins/<folder>/` whose `PLUGIN.md` names an `entry` used to be listed by `agent.plugins.list()` and never imported, so the tools its `register` adds never reached a run. With `local.settingSources` including `"plugins"`, `Agent.create` now imports that entry and registers its default export, which must be a `kind: "general"` plugin, alongside `AgentOptions.plugins`.
|
|
42
|
+
|
|
43
|
+
Trust is by the folder's absolute realpath, in a trust record of its own: `~/.theokit/plugins/trusted-workspace-plugins.json`, a JSON array of folder realpaths, read on every `Agent.create`. The provider trust list (`trusted-providers.json`, `THEOKIT_TRUSTED_PROVIDERS`) does not authorize a workspace folder, so a repository you cloned cannot get its code run by naming a folder after a provider you trust. A relative entry is discarded with a warning, and a record that is not a valid JSON array trusts nothing. An untrusted folder is listed, never imported, and diagnosed once per process with the realpath to add. Plugins found under a foreign root (`compatSources`, such as `.claude/plugins`) are never imported, and neither `agent.reload()` nor a manifest without an `entry` imports anything. A changed entry needs a process restart, since Node caches the module.
|
|
44
|
+
|
|
45
|
+
The provider trust gate is now read on every `Agent.create` too: a provider plugin trusted between two creates is imported by the second, and each provider is still imported at most once per process. The untrusted-provider warning no longer says to restart.
|
|
46
|
+
|
|
47
|
+
A trusted entry that cannot be used fails `Agent.create` with a `ConfigurationError` naming the plugin: `plugin_entry_import_failed` when the module throws on import (the thrown error is the `cause`), and `plugin_entry_shape` when its default export is not a general plugin with a `name` and a `register` function.
|
|
48
|
+
|
|
49
|
+
- [#801](https://github.com/usetheokit/theokit-sdk/pull/801) [`bcac0e7`](https://github.com/usetheokit/theokit-sdk/commit/bcac0e702d99bb7e2a491c5c96e5f14b051cef2c) Thanks [@usetheodev](https://github.com/usetheodev)! - Add `denyReadPaths` to the `@theokit/sdk/sandbox` backends (`LinuxSandbox`, `createSandboxBackend`, `interactiveWrapCommand`, `wrapCommandForSandbox` and `buildBwrapArgv`) so a `workspace-write` or `read-only` shell cannot read named absolute paths. A directory is masked with `--tmpfs` and reads as empty, a file with `--ro-bind /dev/null` and reads as permission denied; the mask is placed after the writable binds, so it also hides a path inside the workspace or `/tmp`. A masked file still appears in the listing of its directory. A list that cannot be honoured throws instead of running unconfined: `TypeError` for a relative or missing path, a path that contains the workspace, `/tmp` or `/`, or any list under `danger-full-access`, and `SandboxNotAvailableError` when bubblewrap is absent. Without the option nothing changes.
|
|
50
|
+
|
|
51
|
+
- [#805](https://github.com/usetheokit/theokit-sdk/pull/805) [`742f101`](https://github.com/usetheokit/theokit-sdk/commit/742f101d28034188070b0da822cdee414fdefbde) Thanks [@usetheodev](https://github.com/usetheodev)! - A custom `SandboxBackend` can now release what it holds with `dispose()` (a no-op by default, safe to call twice) and state its egress with an optional `networkPolicy` of type `SandboxNetworkPolicy`; `LocalSandbox` declares `unrestricted` and `LinuxSandbox` declares `none` when the network is unshared (`usetheokit/theokit#1130`). `@theokit/sdk/sandbox` also exports `shellEscapePosix`, so a command line built outside a backend subclass can quote its arguments (`usetheokit/theokit#1131`).
|
|
52
|
+
|
|
53
|
+
- [#793](https://github.com/usetheokit/theokit-sdk/pull/793) [`2e5c1e4`](https://github.com/usetheokit/theokit-sdk/commit/2e5c1e4e8c04509606e4c3b96191a96751b1b73b) Thanks [@usetheodev](https://github.com/usetheodev)! - `Agent.generateObject` and `Agent.streamObject` accept `withheldBuiltinTools` and `memory`, forwarded to the transient agent each call creates. Pass `withheldBuiltinTools: ["shell"]` and `memory: { enabled: false }` for a JSON-only step that must hold no shell and write no transcript; the `output` tool stays available. With `structuringModel`, the reasoning-phase agent receives the same options. Without them nothing changes: the transient agent holds `shell` and writes a transcript as before.
|
|
54
|
+
|
|
55
|
+
- [#791](https://github.com/usetheokit/theokit-sdk/pull/791) [`3fba608`](https://github.com/usetheokit/theokit-sdk/commit/3fba60809c872395bc26525ad8bdad6655caefc0) Thanks [@usetheodev](https://github.com/usetheodev)! - A model can now continue a suspended workflow run. `workflowAsTool` used to raise `WorkflowToolError`
|
|
56
|
+
for a run that suspended and never handed the model the run id, and no tool called `Workflow.resume`.
|
|
57
|
+
Its spec gains an opt-in `reportSuspended`: a suspended run then returns
|
|
58
|
+
`{"status":"suspended","runId":"…","stepId":"…"}`, ids only, never the suspended payload. The new
|
|
59
|
+
`workflowResumeTool(workflow, { name, description, reportSuspended? })`, exported from
|
|
60
|
+
`@theokit/sdk/workflow`, resumes that run by id with an optional payload validated against the suspend
|
|
61
|
+
step's schema, and returns the run's output. The run id stays the same across resumes, so a second
|
|
62
|
+
suspension is told apart by its `stepId`. Without the opt-in a suspended run still raises. The tool
|
|
63
|
+
resumes any run id it is given: who may approve a run is the host's decision. The default snapshot
|
|
64
|
+
store is in memory and process-local.
|
|
65
|
+
|
|
66
|
+
`Workflow.resume`, and so the resume tool, now refuses a run id whose snapshot was written by a
|
|
67
|
+
workflow of another name with the typed `WorkflowResumeWorkflowMismatchError` and leaves the snapshot
|
|
68
|
+
for the workflow that suspended it. Before, a workflow sharing the suspended step id ran its own tail on
|
|
69
|
+
the other workflow's input. A report's `stepId` is `null` for a run that carries no step result.
|
|
70
|
+
|
|
71
|
+
### Patch Changes
|
|
72
|
+
|
|
73
|
+
- [#781](https://github.com/usetheokit/theokit-sdk/pull/781) [`c300464`](https://github.com/usetheokit/theokit-sdk/commit/c3004649223dcddb5582746977a622f0aef03d09) Thanks [@usetheodev](https://github.com/usetheodev)! - A local run cancelled while its MCP servers start up no longer starts the MCP servers after the one whose handshake was in progress. Until now every remaining server was still initialized, and each stdio server spawned its child process, after the cancel. The handshake already in progress still finishes, and the run still closes every MCP client it owns.
|
|
74
|
+
|
|
75
|
+
- [#785](https://github.com/usetheokit/theokit-sdk/pull/785) [`4a9ab1c`](https://github.com/usetheokit/theokit-sdk/commit/4a9ab1c608fdb2903837054ed59ad3976e2e2906) Thanks [@usetheodev](https://github.com/usetheodev)! - The seccomp temp-dir cleanup of `seccompPathForArch` and `restrictedSeccompPath` no longer cuts off a host's shutdown handler registered with `process.once`: it runs first, removes its directory, and leaves the ending to the host. The directory is now gone before the host's handler starts; a process with no handler of its own still ends by the signal. One order is not covered: a host that itself prepends a `once` handler (`process.prependOnceListener`) after the first sandboxed command runs before the cleanup and is not counted, so the signal is raised again while its shutdown runs.
|
|
76
|
+
|
|
3
77
|
## 5.12.1
|
|
4
78
|
|
|
5
79
|
### Patch Changes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { W as MemoryFact, T as MemoryAdapter, V as MemoryContext,
|
|
1
|
+
import { W as MemoryFact, T as MemoryAdapter, V as MemoryContext, aV as SystemPromptSkillRef, M as McpServerConfig, C as ContextSettings, P as ProviderRoutingSettings, a as PluginsSettings, c as Processor, S as SDKAgent } from './sdk-agent-DwzHcuxy.cjs';
|
|
2
2
|
import { M as ModelSelection, C as CustomTool, P as PermissionMode } from './agent-prims-CZyxfCmS.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -224,6 +224,8 @@ interface Skill$1 {
|
|
|
224
224
|
source: string;
|
|
225
225
|
category?: string;
|
|
226
226
|
dependencies?: string[];
|
|
227
|
+
/** `requires-bins` — executables that must be on PATH for the model to be offered this skill. */
|
|
228
|
+
requiresBins?: string[];
|
|
227
229
|
/** `disable-model-invocation: true` — the model is never told this skill exists. */
|
|
228
230
|
disableModelInvocation?: boolean;
|
|
229
231
|
/** `user-invocable: false` — carried for a host that has a picker; this SDK has no such surface. */
|
|
@@ -1377,6 +1379,12 @@ interface SkillsSettings {
|
|
|
1377
1379
|
* default `<cwd>/.theokit/skills`. Absent ⇒ the default root.
|
|
1378
1380
|
*/
|
|
1379
1381
|
skillsDir?: string;
|
|
1382
|
+
/**
|
|
1383
|
+
* B-546 — directories (each containing `<name>/SKILL.md`) an application ships inside its own
|
|
1384
|
+
* package. They are read AFTER the project roots and plugin bundles, so a workspace skill of the
|
|
1385
|
+
* same name always wins, and they are kept even when `skillsDir` replaces the default roots.
|
|
1386
|
+
*/
|
|
1387
|
+
bundledDirs?: string[];
|
|
1380
1388
|
/**
|
|
1381
1389
|
* M22 — code-defined skills (from `createSkill`) merged with the discovered ones. An inline skill
|
|
1382
1390
|
* overrides a discovered file skill of the same name.
|
|
@@ -1614,7 +1622,14 @@ interface AgentOptions {
|
|
|
1614
1622
|
*
|
|
1615
1623
|
* - **Named-enable settings** — `{ enabled: ["name", ...] }`. Selects which
|
|
1616
1624
|
* file-discovered plugin providers (under `.theokit/plugins/`) are active.
|
|
1617
|
-
* Plugin sources must also be active via `local.settingSources`.
|
|
1625
|
+
* Plugin sources must also be active via `local.settingSources`. A folder
|
|
1626
|
+
* under `<cwd>/.theokit/plugins/` whose `PLUGIN.md` names an `entry` has
|
|
1627
|
+
* that entry imported and its default export (a `kind: "general"` plugin)
|
|
1628
|
+
* registered, but only when the folder's absolute realpath is listed in
|
|
1629
|
+
* `~/.theokit/plugins/trusted-workspace-plugins.json` (a JSON array, read on
|
|
1630
|
+
* each `Agent.create`). The provider trust list never authorizes a workspace
|
|
1631
|
+
* folder. An untrusted folder is listed and never imported; foreign roots
|
|
1632
|
+
* are never imported.
|
|
1618
1633
|
* - **Code `Plugin` objects** — an array of `Plugin` instances, e.g.
|
|
1619
1634
|
* `plugins: [Handoff.asPlugin({ ... })]`. These are registered directly by
|
|
1620
1635
|
* the runtime (`extractCodePlugins`); no `settingSources` entry is needed.
|
|
@@ -2055,4 +2070,4 @@ interface ListResult<T> {
|
|
|
2055
2070
|
nextCursor?: string;
|
|
2056
2071
|
}
|
|
2057
2072
|
|
|
2058
|
-
export { type RecordSessionSummaryArgs as $, type AgentOptions as A, type
|
|
2073
|
+
export { type RecordSessionSummaryArgs as $, type AgentOptions as A, type BuiltinToolName as B, type CloudOptions as C, type CreateSkillSpec as D, type HookApprovalRequest as E, type HookName as F, type GetAgentOptions as G, type HookApprovalGate as H, type InlineSkill as I, type LlmCallContext as J, type MemoryProviderAgentRef as K, type LocalOptions as L, type MemorySettings as M, type MemoryProviderFactory as N, type MemoryProviderHandle as O, type Plugin as P, type MemoryProviderInitOptions as Q, type PluginContext as R, type SystemPromptResolver as S, type PluginHookDisposer as T, type PostAssistantReplyContext as U, type PostToolCallContext as V, type PreToolCallContext as W, type PreUserSendContext as X, type PreUserSendResult as Y, type ProviderTransform as Z, type ProviderTransformContext as _, type AgentDefinition as a, type SessionLifecycleContext as a0, type SessionRecord as a1, type SessionStore as a2, type SettingSource as a3, Skill as a4, type SkillsResolver as a5, type SkillsResolverContext as a6, type SystemPromptContext as a7, type SystemPromptMemoryFact as a8, type TelemetrySettings as a9, type ToolCallSummary as aa, type ToolContext as ab, type ToolResultTransformContext as ac, type TransformContext as ad, type SkillsSettings as b, type ListAgentsOptions as c, type ListResult as d, type SDKAgentInfo as e, type ListRunsOptions as f, type GetRunOptions as g, type AgentOperationOptions as h, type AgentDescription as i, type ProviderProfile as j, type Skill$1 as k, type BudgetTracker as l, type MemoryProvider as m, type PreToolCallDecision as n, type ActiveMemoryPassArgs as o, type ActiveMemoryPassResult as p, type AgentSubagentDescription as q, type AgentToolDescription as r, type BudgetCheck as s, type BudgetTotal as t, type BudgetUsageEvent as u, type CloudEnv as v, type CloudRepo as w, type CompatSource as x, type CompatSourceAdapter as y, type CompatSurface as z };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { W as MemoryFact, T as MemoryAdapter, V as MemoryContext,
|
|
1
|
+
import { W as MemoryFact, T as MemoryAdapter, V as MemoryContext, aV as SystemPromptSkillRef, M as McpServerConfig, C as ContextSettings, P as ProviderRoutingSettings, a as PluginsSettings, c as Processor, S as SDKAgent } from './sdk-agent-a3fW1xUK.js';
|
|
2
2
|
import { M as ModelSelection, C as CustomTool, P as PermissionMode } from './agent-prims-CZyxfCmS.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -224,6 +224,8 @@ interface Skill$1 {
|
|
|
224
224
|
source: string;
|
|
225
225
|
category?: string;
|
|
226
226
|
dependencies?: string[];
|
|
227
|
+
/** `requires-bins` — executables that must be on PATH for the model to be offered this skill. */
|
|
228
|
+
requiresBins?: string[];
|
|
227
229
|
/** `disable-model-invocation: true` — the model is never told this skill exists. */
|
|
228
230
|
disableModelInvocation?: boolean;
|
|
229
231
|
/** `user-invocable: false` — carried for a host that has a picker; this SDK has no such surface. */
|
|
@@ -1377,6 +1379,12 @@ interface SkillsSettings {
|
|
|
1377
1379
|
* default `<cwd>/.theokit/skills`. Absent ⇒ the default root.
|
|
1378
1380
|
*/
|
|
1379
1381
|
skillsDir?: string;
|
|
1382
|
+
/**
|
|
1383
|
+
* B-546 — directories (each containing `<name>/SKILL.md`) an application ships inside its own
|
|
1384
|
+
* package. They are read AFTER the project roots and plugin bundles, so a workspace skill of the
|
|
1385
|
+
* same name always wins, and they are kept even when `skillsDir` replaces the default roots.
|
|
1386
|
+
*/
|
|
1387
|
+
bundledDirs?: string[];
|
|
1380
1388
|
/**
|
|
1381
1389
|
* M22 — code-defined skills (from `createSkill`) merged with the discovered ones. An inline skill
|
|
1382
1390
|
* overrides a discovered file skill of the same name.
|
|
@@ -1614,7 +1622,14 @@ interface AgentOptions {
|
|
|
1614
1622
|
*
|
|
1615
1623
|
* - **Named-enable settings** — `{ enabled: ["name", ...] }`. Selects which
|
|
1616
1624
|
* file-discovered plugin providers (under `.theokit/plugins/`) are active.
|
|
1617
|
-
* Plugin sources must also be active via `local.settingSources`.
|
|
1625
|
+
* Plugin sources must also be active via `local.settingSources`. A folder
|
|
1626
|
+
* under `<cwd>/.theokit/plugins/` whose `PLUGIN.md` names an `entry` has
|
|
1627
|
+
* that entry imported and its default export (a `kind: "general"` plugin)
|
|
1628
|
+
* registered, but only when the folder's absolute realpath is listed in
|
|
1629
|
+
* `~/.theokit/plugins/trusted-workspace-plugins.json` (a JSON array, read on
|
|
1630
|
+
* each `Agent.create`). The provider trust list never authorizes a workspace
|
|
1631
|
+
* folder. An untrusted folder is listed and never imported; foreign roots
|
|
1632
|
+
* are never imported.
|
|
1618
1633
|
* - **Code `Plugin` objects** — an array of `Plugin` instances, e.g.
|
|
1619
1634
|
* `plugins: [Handoff.asPlugin({ ... })]`. These are registered directly by
|
|
1620
1635
|
* the runtime (`extractCodePlugins`); no `settingSources` entry is needed.
|
|
@@ -2055,4 +2070,4 @@ interface ListResult<T> {
|
|
|
2055
2070
|
nextCursor?: string;
|
|
2056
2071
|
}
|
|
2057
2072
|
|
|
2058
|
-
export { type RecordSessionSummaryArgs as $, type AgentOptions as A, type
|
|
2073
|
+
export { type RecordSessionSummaryArgs as $, type AgentOptions as A, type BuiltinToolName as B, type CloudOptions as C, type CreateSkillSpec as D, type HookApprovalRequest as E, type HookName as F, type GetAgentOptions as G, type HookApprovalGate as H, type InlineSkill as I, type LlmCallContext as J, type MemoryProviderAgentRef as K, type LocalOptions as L, type MemorySettings as M, type MemoryProviderFactory as N, type MemoryProviderHandle as O, type Plugin as P, type MemoryProviderInitOptions as Q, type PluginContext as R, type SystemPromptResolver as S, type PluginHookDisposer as T, type PostAssistantReplyContext as U, type PostToolCallContext as V, type PreToolCallContext as W, type PreUserSendContext as X, type PreUserSendResult as Y, type ProviderTransform as Z, type ProviderTransformContext as _, type AgentDefinition as a, type SessionLifecycleContext as a0, type SessionRecord as a1, type SessionStore as a2, type SettingSource as a3, Skill as a4, type SkillsResolver as a5, type SkillsResolverContext as a6, type SystemPromptContext as a7, type SystemPromptMemoryFact as a8, type TelemetrySettings as a9, type ToolCallSummary as aa, type ToolContext as ab, type ToolResultTransformContext as ac, type TransformContext as ad, type SkillsSettings as b, type ListAgentsOptions as c, type ListResult as d, type SDKAgentInfo as e, type ListRunsOptions as f, type GetRunOptions as g, type AgentOperationOptions as h, type AgentDescription as i, type ProviderProfile as j, type Skill$1 as k, type BudgetTracker as l, type MemoryProvider as m, type PreToolCallDecision as n, type ActiveMemoryPassArgs as o, type ActiveMemoryPassResult as p, type AgentSubagentDescription as q, type AgentToolDescription as r, type BudgetCheck as s, type BudgetTotal as t, type BudgetUsageEvent as u, type CloudEnv as v, type CloudRepo as w, type CompatSource as x, type CompatSourceAdapter as y, type CompatSurface as z };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { Agent } from './chunk-
|
|
1
|
+
export { Agent } from './chunk-GARVAUCU.js';
|
|
2
2
|
import './chunk-HWMGR3HA.js';
|
|
3
|
-
import './chunk-
|
|
3
|
+
import './chunk-3ONIVO2I.js';
|
|
4
4
|
import './chunk-K2BQQ445.js';
|
|
5
5
|
import './chunk-2C24NSNV.js';
|
|
6
6
|
import './chunk-HJ2LV464.js';
|
|
@@ -10,7 +10,7 @@ import './chunk-H73MEMQB.js';
|
|
|
10
10
|
import './chunk-QK2ERTO3.js';
|
|
11
11
|
import './chunk-DF77RBF4.js';
|
|
12
12
|
import './chunk-AB4OPJLD.js';
|
|
13
|
-
import './chunk-
|
|
13
|
+
import './chunk-ZOL3L4EH.js';
|
|
14
14
|
import './chunk-5AR6O7GW.js';
|
|
15
15
|
import './chunk-2XC6KDJM.js';
|
|
16
16
|
import './chunk-ZJAYFSVI.js';
|
|
@@ -27,7 +27,7 @@ import './chunk-FJWQP6EE.js';
|
|
|
27
27
|
import './chunk-NAF4L3T6.js';
|
|
28
28
|
import './chunk-VZGE7NAI.js';
|
|
29
29
|
import './chunk-6X6ID4MO.js';
|
|
30
|
-
import './chunk-
|
|
30
|
+
import './chunk-2HXTNVLM.js';
|
|
31
31
|
import './chunk-4QCJAJAG.js';
|
|
32
32
|
import './chunk-SAGRF4IB.js';
|
|
33
33
|
import './chunk-PKRPV3R7.js';
|
|
@@ -47,16 +47,16 @@ import './chunk-RN3XDZGS.js';
|
|
|
47
47
|
import './chunk-YMVTUV5K.js';
|
|
48
48
|
import './chunk-Q7UG242V.js';
|
|
49
49
|
import './chunk-SZQFCHU6.js';
|
|
50
|
-
import './chunk-
|
|
50
|
+
import './chunk-NVQSBRG6.js';
|
|
51
51
|
import './chunk-R7WIIPUR.js';
|
|
52
|
-
import './chunk-
|
|
53
|
-
import './chunk-
|
|
52
|
+
import './chunk-ULEK4OM4.js';
|
|
53
|
+
import './chunk-CJN5CEI3.js';
|
|
54
54
|
import './chunk-AGACYRJ2.js';
|
|
55
|
-
import './chunk-
|
|
56
|
-
import './chunk-
|
|
55
|
+
import './chunk-3GTN4HOO.js';
|
|
56
|
+
import './chunk-QD6B6W6I.js';
|
|
57
57
|
import './chunk-5IUDICRK.js';
|
|
58
58
|
import './chunk-Q7GYMXVC.js';
|
|
59
59
|
import './chunk-TNFOU6SB.js';
|
|
60
60
|
import './chunk-3OY6H3I7.js';
|
|
61
|
-
//# sourceMappingURL=agent-
|
|
62
|
-
//# sourceMappingURL=agent-
|
|
61
|
+
//# sourceMappingURL=agent-T34LCGQM.js.map
|
|
62
|
+
//# sourceMappingURL=agent-T34LCGQM.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"agent-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"agent-T34LCGQM.js"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk2WY2OFSC_cjs = require('./chunk-2WY2OFSC.cjs');
|
|
4
4
|
require('./chunk-L7JPXZ2C.cjs');
|
|
5
|
-
require('./chunk-
|
|
5
|
+
require('./chunk-LXG6VL6R.cjs');
|
|
6
6
|
require('./chunk-BUUUWQMB.cjs');
|
|
7
7
|
require('./chunk-CWQPQTUZ.cjs');
|
|
8
8
|
require('./chunk-7YUPSBDV.cjs');
|
|
@@ -12,7 +12,7 @@ require('./chunk-GHX4P3V2.cjs');
|
|
|
12
12
|
require('./chunk-RS7YQR4X.cjs');
|
|
13
13
|
require('./chunk-SDZ4XDWS.cjs');
|
|
14
14
|
require('./chunk-6OCJWGVD.cjs');
|
|
15
|
-
require('./chunk-
|
|
15
|
+
require('./chunk-SNVYOX46.cjs');
|
|
16
16
|
require('./chunk-SXH37C7X.cjs');
|
|
17
17
|
require('./chunk-YJNYDJ2T.cjs');
|
|
18
18
|
require('./chunk-NP362THY.cjs');
|
|
@@ -29,7 +29,7 @@ require('./chunk-YSTXFWQE.cjs');
|
|
|
29
29
|
require('./chunk-FRITRLZQ.cjs');
|
|
30
30
|
require('./chunk-H7HD6RXO.cjs');
|
|
31
31
|
require('./chunk-NINIJCHU.cjs');
|
|
32
|
-
require('./chunk-
|
|
32
|
+
require('./chunk-3UMPP553.cjs');
|
|
33
33
|
require('./chunk-SWALPLFQ.cjs');
|
|
34
34
|
require('./chunk-IJ7M6GOG.cjs');
|
|
35
35
|
require('./chunk-3KIUY67P.cjs');
|
|
@@ -49,13 +49,13 @@ require('./chunk-WDVG5R2Q.cjs');
|
|
|
49
49
|
require('./chunk-YQ3XC6C2.cjs');
|
|
50
50
|
require('./chunk-6XQLTQB6.cjs');
|
|
51
51
|
require('./chunk-KX5QXLBS.cjs');
|
|
52
|
-
require('./chunk-
|
|
52
|
+
require('./chunk-4KBI37F3.cjs');
|
|
53
53
|
require('./chunk-3EE6LVWT.cjs');
|
|
54
|
-
require('./chunk-
|
|
55
|
-
require('./chunk-
|
|
54
|
+
require('./chunk-R5UQL2R5.cjs');
|
|
55
|
+
require('./chunk-4TEGFMSP.cjs');
|
|
56
56
|
require('./chunk-NVXXWAU7.cjs');
|
|
57
|
-
require('./chunk-
|
|
58
|
-
require('./chunk-
|
|
57
|
+
require('./chunk-A77UMVMD.cjs');
|
|
58
|
+
require('./chunk-5645PMVU.cjs');
|
|
59
59
|
require('./chunk-IOFMRS6T.cjs');
|
|
60
60
|
require('./chunk-EHD25JBZ.cjs');
|
|
61
61
|
require('./chunk-CEGU5AVD.cjs');
|
|
@@ -65,7 +65,7 @@ require('./chunk-RNXXYF22.cjs');
|
|
|
65
65
|
|
|
66
66
|
Object.defineProperty(exports, "Agent", {
|
|
67
67
|
enumerable: true,
|
|
68
|
-
get: function () { return
|
|
68
|
+
get: function () { return chunk2WY2OFSC_cjs.Agent; }
|
|
69
69
|
});
|
|
70
|
-
//# sourceMappingURL=agent-
|
|
71
|
-
//# sourceMappingURL=agent-
|
|
70
|
+
//# sourceMappingURL=agent-TL4K7BTG.cjs.map
|
|
71
|
+
//# sourceMappingURL=agent-TL4K7BTG.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"agent-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"agent-TL4K7BTG.cjs"}
|
package/dist/auth/index.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkFRITRLZQ_cjs = require('../chunk-FRITRLZQ.cjs');
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var chunkA77UMVMD_cjs = require('../chunk-A77UMVMD.cjs');
|
|
5
|
+
var chunk5645PMVU_cjs = require('../chunk-5645PMVU.cjs');
|
|
6
6
|
var chunkIOFMRS6T_cjs = require('../chunk-IOFMRS6T.cjs');
|
|
7
7
|
require('../chunk-EHD25JBZ.cjs');
|
|
8
8
|
require('../chunk-CEGU5AVD.cjs');
|
|
@@ -104,7 +104,8 @@ async function pollDeviceToken(config, grant, deps) {
|
|
|
104
104
|
// token as the refresh handle.
|
|
105
105
|
refresh: data.refresh_token ?? data.access_token,
|
|
106
106
|
expires: deps.now() + expiresIn * 1e3,
|
|
107
|
-
...accountId !== void 0 ? { accountId } : {}
|
|
107
|
+
...accountId !== void 0 ? { accountId } : {},
|
|
108
|
+
...typeof data.id_token === "string" && data.id_token.length > 0 ? { idToken: data.id_token } : {}
|
|
108
109
|
};
|
|
109
110
|
}
|
|
110
111
|
if (data.error === "authorization_pending") {
|
|
@@ -202,7 +203,7 @@ async function openaiDeviceLogin(config, deps, hooks) {
|
|
|
202
203
|
"device poll returned no authorization_code"
|
|
203
204
|
);
|
|
204
205
|
}
|
|
205
|
-
const tokens = await
|
|
206
|
+
const tokens = await chunkA77UMVMD_cjs.exchangeCode(
|
|
206
207
|
config,
|
|
207
208
|
{ code: data.authorization_code, verifier: data.code_verifier },
|
|
208
209
|
deps
|
|
@@ -250,51 +251,51 @@ Object.defineProperty(exports, "providerFromApiKeyPrefix", {
|
|
|
250
251
|
});
|
|
251
252
|
Object.defineProperty(exports, "ensureFreshCredential", {
|
|
252
253
|
enumerable: true,
|
|
253
|
-
get: function () { return
|
|
254
|
+
get: function () { return chunkA77UMVMD_cjs.ensureFreshCredential; }
|
|
254
255
|
});
|
|
255
256
|
Object.defineProperty(exports, "exchangeCode", {
|
|
256
257
|
enumerable: true,
|
|
257
|
-
get: function () { return
|
|
258
|
+
get: function () { return chunkA77UMVMD_cjs.exchangeCode; }
|
|
258
259
|
});
|
|
259
260
|
Object.defineProperty(exports, "persistOAuthTokens", {
|
|
260
261
|
enumerable: true,
|
|
261
|
-
get: function () { return
|
|
262
|
+
get: function () { return chunkA77UMVMD_cjs.persistOAuthTokens; }
|
|
262
263
|
});
|
|
263
264
|
Object.defineProperty(exports, "refreshOAuthTokens", {
|
|
264
265
|
enumerable: true,
|
|
265
|
-
get: function () { return
|
|
266
|
+
get: function () { return chunkA77UMVMD_cjs.refreshOAuthTokens; }
|
|
266
267
|
});
|
|
267
268
|
Object.defineProperty(exports, "resolveCredential", {
|
|
268
269
|
enumerable: true,
|
|
269
|
-
get: function () { return
|
|
270
|
+
get: function () { return chunkA77UMVMD_cjs.resolveCredential; }
|
|
270
271
|
});
|
|
271
272
|
Object.defineProperty(exports, "CredentialError", {
|
|
272
273
|
enumerable: true,
|
|
273
|
-
get: function () { return
|
|
274
|
+
get: function () { return chunk5645PMVU_cjs.CredentialError; }
|
|
274
275
|
});
|
|
275
276
|
Object.defineProperty(exports, "assertSecureModes", {
|
|
276
277
|
enumerable: true,
|
|
277
|
-
get: function () { return
|
|
278
|
+
get: function () { return chunk5645PMVU_cjs.assertSecureModes; }
|
|
278
279
|
});
|
|
279
280
|
Object.defineProperty(exports, "authFilePath", {
|
|
280
281
|
enumerable: true,
|
|
281
|
-
get: function () { return
|
|
282
|
+
get: function () { return chunk5645PMVU_cjs.authFilePath; }
|
|
282
283
|
});
|
|
283
284
|
Object.defineProperty(exports, "credentialHome", {
|
|
284
285
|
enumerable: true,
|
|
285
|
-
get: function () { return
|
|
286
|
+
get: function () { return chunk5645PMVU_cjs.credentialHome; }
|
|
286
287
|
});
|
|
287
288
|
Object.defineProperty(exports, "readAuthFile", {
|
|
288
289
|
enumerable: true,
|
|
289
|
-
get: function () { return
|
|
290
|
+
get: function () { return chunk5645PMVU_cjs.readAuthFile; }
|
|
290
291
|
});
|
|
291
292
|
Object.defineProperty(exports, "readStoredOAuth", {
|
|
292
293
|
enumerable: true,
|
|
293
|
-
get: function () { return
|
|
294
|
+
get: function () { return chunk5645PMVU_cjs.readStoredOAuth; }
|
|
294
295
|
});
|
|
295
296
|
Object.defineProperty(exports, "writeCredential", {
|
|
296
297
|
enumerable: true,
|
|
297
|
-
get: function () { return
|
|
298
|
+
get: function () { return chunk5645PMVU_cjs.writeCredential; }
|
|
298
299
|
});
|
|
299
300
|
exports.deviceLogin = deviceLogin;
|
|
300
301
|
exports.extractAccountId = extractAccountId;
|
package/dist/auth/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/internal/auth/oauth-device.ts"],"names":["AuthCallbackError","exchangeCode"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * M42 — the SDK OAuth device-authorization flows (RFC 8628 + OpenAI two-step headless). Split out of\n * oauth-engine.ts to respect the 500-line file budget; a sibling of the core engine. Promoted DOWN from\n * agent-builder's hardened `agents/lib/oauth-device.ts` (M37).\n *\n * Implements two device flows against their published specs: the RFC 8628 device-grant poll loop\n * (device_code → authorization_pending / slow_down) and OpenAI's two-step headless flow, including the\n * JWT-claim / account-id extraction used to attribute an account.\n * Design choices: network I/O + clock + sleep are INJECTED (deterministic tests), failures raise the SDK's\n * typed `AuthCallbackError`, and a device-code expiry DEADLINE guards each poll loop.\n *\n * @internal\n */\nimport { AuthCallbackError } from \"../../server/auth/errors.js\";\nimport { exchangeCode } from \"./oauth-engine.js\";\nimport type {\n DeviceCodeGrant,\n DeviceDeps,\n DeviceOAuthConfig,\n OAuthTokens,\n OpenAIDeviceConfig,\n} from \"./types.js\";\n\n// ─── OAuth 2.0 Device Authorization Grant (RFC 8628) — terminal-first / headless login ───\n\n/** Buffer added to every poll interval to avoid hitting the server a hair early. */\nconst POLLING_SAFETY_MARGIN_MS = 3000;\n\n/**\n * Parse a JSON body, or fail with this module's typed error instead of a raw `SyntaxError`.\n *\n * Every failure in this file is supposed to reach the caller as an `AuthCallbackError` carrying a code\n * the CLI can branch on. `res.json()` breaks that contract: a device endpoint that answers with HTML —\n * a captive portal, a corporate proxy's sign-in page, a load balancer's error page — makes it reject\n * with a `SyntaxError` that no `catch` here handles, so it escapes untyped past a caller prepared only\n * for `AuthCallbackError`.\n *\n * The body is quoted, truncated, because \"not JSON\" and \"not JSON, and it looks like a proxy login\n * page\" are different diagnoses for whoever is holding the terminal — and routing them to the provider\n * when the fault is their network is the expensive kind of wrong.\n */\nasync function parseJsonOrFail(res: Response, code: string, what: string): Promise<unknown> {\n const text = await res.text().catch(() => \"\");\n try {\n return JSON.parse(text);\n } catch {\n throw new AuthCallbackError(code, `${what} returned a non-JSON body: ${text.slice(0, 120)}`);\n }\n}\n\n/** Step 1 — request a device code. POSTs `{client_id, scope}` to the device endpoint. */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: RFC 8628 device-code request — cohesive network response parser ported verbatim (ADR D3).\nexport async function requestDeviceCode(\n config: DeviceOAuthConfig,\n deps: Pick<DeviceDeps, \"fetch\">,\n): Promise<DeviceCodeGrant> {\n let res: Response;\n try {\n res = await deps.fetch(config.deviceCodeEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\", accept: \"application/json\" },\n body: new URLSearchParams({\n client_id: config.clientId,\n scope: config.scopes.join(\" \"),\n }).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `device request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `device endpoint returned HTTP ${res.status}`,\n );\n }\n const data = (await parseJsonOrFail(\n res,\n \"oauth_device_authorization_failed\",\n \"device endpoint\",\n )) as {\n device_code?: unknown;\n user_code?: unknown;\n verification_uri?: unknown;\n verification_uri_complete?: unknown;\n interval?: unknown;\n expires_in?: unknown;\n };\n if (typeof data.device_code !== \"string\" || typeof data.user_code !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n \"device response missing device_code/user_code\",\n );\n }\n const verification =\n typeof data.verification_uri === \"string\"\n ? data.verification_uri\n : typeof data.verification_uri_complete === \"string\"\n ? data.verification_uri_complete\n : \"\";\n return {\n deviceCode: data.device_code,\n userCode: data.user_code,\n verificationUri: verification,\n interval: typeof data.interval === \"number\" && data.interval > 0 ? data.interval : 5,\n expiresIn: typeof data.expires_in === \"number\" && data.expires_in > 0 ? data.expires_in : 900,\n };\n}\n\n/**\n * Step 2 — poll the token endpoint until the user approves (or the code expires). Handles RFC 8628\n * `authorization_pending` (keep waiting) and `slow_down` (back off), with an expiry deadline so it cannot\n * spin forever.\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: RFC 8628 poll state machine (authorization_pending / slow_down / success / expiry) — a cohesive loop ported verbatim (ADR D3); fragmenting it would obscure the protocol.\nexport async function pollDeviceToken(\n config: DeviceOAuthConfig,\n grant: DeviceCodeGrant,\n deps: DeviceDeps,\n): Promise<OAuthTokens> {\n const deadline = deps.now() + grant.expiresIn * 1000;\n let intervalMs = grant.interval * 1000;\n\n while (deps.now() < deadline) {\n let res: Response;\n try {\n res = await deps.fetch(config.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n accept: \"application/json\",\n },\n body: new URLSearchParams({\n client_id: config.clientId,\n device_code: grant.deviceCode,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device token poll failed: ${(err as Error).message}`,\n );\n }\n // RFC 8628 §3.5: `authorization_pending` / `slow_down` arrive as a 400 with an `error` body — so the\n // body MUST be read before deciding failure. Parse first; only a non-OAuth-shaped body on a non-2xx fails.\n const data = (await res.json().catch(() => ({}))) as {\n access_token?: string;\n refresh_token?: string;\n expires_in?: number;\n id_token?: string;\n error?: string;\n interval?: number;\n };\n if (!res.ok && typeof data.error !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device token endpoint returned HTTP ${res.status}`,\n );\n }\n\n if (typeof data.access_token === \"string\" && data.access_token.length > 0) {\n const expiresIn = typeof data.expires_in === \"number\" ? data.expires_in : 0;\n const accountId = extractAccountId({\n access_token: data.access_token,\n id_token: data.id_token,\n });\n return {\n access: data.access_token,\n // Some device-grant providers (e.g. GitHub) issue no separate refresh token — reuse the access\n // token as the refresh handle.\n refresh: data.refresh_token ?? data.access_token,\n expires: deps.now() + expiresIn * 1000,\n ...(accountId !== undefined ? { accountId } : {}),\n };\n }\n\n if (data.error === \"authorization_pending\") {\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n continue;\n }\n if (data.error === \"slow_down\") {\n // RFC 8628 §3.5: add 5s to the interval, or honor a server-provided one.\n intervalMs =\n (typeof data.interval === \"number\" && data.interval > 0\n ? data.interval\n : grant.interval + 5) * 1000;\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n continue;\n }\n if (typeof data.error === \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device authorization rejected: ${data.error}`,\n );\n }\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n }\n throw new AuthCallbackError(\n \"oauth_device_code_expired\",\n \"the device code expired before it was approved\",\n );\n}\n\n/**\n * The full device login: request a code, hand the user the verification URL + user code via `onPrompt`\n * (never printed here — the caller renders it, keeping this module output-free), then poll to completion.\n */\nexport async function deviceLogin(\n config: DeviceOAuthConfig,\n deps: DeviceDeps,\n hooks: {\n onPrompt: (p: { userCode: string; verificationUri: string; expiresIn: number }) => void;\n },\n): Promise<OAuthTokens> {\n const grant = await requestDeviceCode(config, deps);\n hooks.onPrompt({\n userCode: grant.userCode,\n verificationUri: grant.verificationUri,\n expiresIn: grant.expiresIn,\n });\n return pollDeviceToken(config, grant, deps);\n}\n\n// ─── OpenAI / ChatGPT \"headless\" device flow (two-step) ───\n\n/** Step 1 (OpenAI) — request the user code. */\nexport async function requestOpenAIUsercode(\n config: OpenAIDeviceConfig,\n deps: Pick<DeviceDeps, \"fetch\">,\n): Promise<{ deviceAuthId: string; userCode: string; interval: number }> {\n let res: Response;\n try {\n res = await deps.fetch(config.deviceUsercodeEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({ client_id: config.clientId }),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `usercode request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `usercode endpoint returned HTTP ${res.status}`,\n );\n }\n const data = (await parseJsonOrFail(\n res,\n \"oauth_device_authorization_failed\",\n \"usercode endpoint\",\n )) as {\n device_auth_id?: unknown;\n user_code?: unknown;\n interval?: unknown;\n };\n if (typeof data.device_auth_id !== \"string\" || typeof data.user_code !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n \"usercode response missing device_auth_id/user_code\",\n );\n }\n const interval = Math.max(\n typeof data.interval === \"string\" ? parseInt(data.interval, 10) || 5 : 5,\n 1,\n );\n return { deviceAuthId: data.device_auth_id, userCode: data.user_code, interval };\n}\n\n/**\n * Step 2+3 (OpenAI) — poll for the authorization code (200 = ready; 403/404 = pending; else fail), then\n * exchange it for tokens at the standard `/oauth/token` endpoint (reuses `exchangeCode`).\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: OpenAI two-step headless poll loop (200 ready / 403,404 pending / else fail) — cohesive network state machine ported verbatim (ADR D3).\nexport async function openaiDeviceLogin(\n config: OpenAIDeviceConfig,\n deps: DeviceDeps,\n hooks: { onPrompt: (p: { userCode: string; verificationUri: string }) => void },\n): Promise<OAuthTokens> {\n const { deviceAuthId, userCode, interval } = await requestOpenAIUsercode(config, deps);\n hooks.onPrompt({ userCode, verificationUri: config.verificationUri });\n\n const intervalMs = interval * 1000;\n // Bound the loop so it cannot spin forever if the provider never resolves (upstream loops unbounded).\n const deadline = deps.now() + 15 * 60 * 1000;\n while (deps.now() < deadline) {\n let res: Response;\n try {\n res = await deps.fetch(config.devicePollEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({ device_auth_id: deviceAuthId, user_code: userCode }),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device poll failed: ${(err as Error).message}`,\n );\n }\n if (res.ok) {\n const data = (await parseJsonOrFail(res, \"oauth_token_exchange_failed\", \"device poll\")) as {\n authorization_code?: unknown;\n code_verifier?: unknown;\n };\n if (typeof data.authorization_code !== \"string\" || typeof data.code_verifier !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n \"device poll returned no authorization_code\",\n );\n }\n const tokens = await exchangeCode(\n config,\n { code: data.authorization_code, verifier: data.code_verifier },\n deps,\n );\n // M43 D4 fix #2 — the two-step exchange returns a JWT access token but `parseTokenResponse` only reads a\n // top-level `account_id`. JWT-extract the `chatgpt_account_id` (as the generic device poll already does)\n // so the login persists a non-empty account_id for the Codex `ChatGPT-Account-Id` header.\n return {\n ...tokens,\n accountId: tokens.accountId ?? extractAccountId({ access_token: tokens.access }),\n };\n }\n // 403/404 = still pending (user has not approved yet); anything else is a hard failure.\n if (res.status !== 403 && res.status !== 404) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device poll returned HTTP ${res.status}`,\n );\n }\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n }\n throw new AuthCallbackError(\n \"oauth_device_code_expired\",\n \"the device authorization expired before approval\",\n );\n}\n\n/** JWT id/access-token claims we read to attribute an account. */\ninterface IdTokenClaims {\n chatgpt_account_id?: string;\n organizations?: Array<{ id: string }>;\n \"https://api.openai.com/auth\"?: { chatgpt_account_id?: string };\n}\n\n/** Decode a JWT's claim set (no signature verification — used only to read a self-reported account id). */\nexport function parseJwtClaims(token: string): IdTokenClaims | undefined {\n const parts = token.split(\".\");\n if (parts.length !== 3) return undefined;\n try {\n return JSON.parse(Buffer.from(parts[1] as string, \"base64url\").toString()) as IdTokenClaims;\n } catch {\n return undefined;\n }\n}\n\n/** Best-effort account id from an id/access token's claims (OpenAI/ChatGPT shape). */\nexport function extractAccountId(tokens: {\n id_token?: string;\n access_token?: string;\n}): string | undefined {\n for (const token of [tokens.id_token, tokens.access_token]) {\n if (token === undefined) continue;\n const claims = parseJwtClaims(token);\n const id =\n claims?.chatgpt_account_id ??\n claims?.[\"https://api.openai.com/auth\"]?.chatgpt_account_id ??\n claims?.organizations?.[0]?.id;\n if (id !== undefined) return id;\n }\n return undefined;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/internal/auth/oauth-device.ts"],"names":["AuthCallbackError","exchangeCode"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * M42 — the SDK OAuth device-authorization flows (RFC 8628 + OpenAI two-step headless). Split out of\n * oauth-engine.ts to respect the 500-line file budget; a sibling of the core engine. Promoted DOWN from\n * agent-builder's hardened `agents/lib/oauth-device.ts` (M37).\n *\n * Implements two device flows against their published specs: the RFC 8628 device-grant poll loop\n * (device_code → authorization_pending / slow_down) and OpenAI's two-step headless flow, including the\n * JWT-claim / account-id extraction used to attribute an account.\n * Design choices: network I/O + clock + sleep are INJECTED (deterministic tests), failures raise the SDK's\n * typed `AuthCallbackError`, and a device-code expiry DEADLINE guards each poll loop.\n *\n * @internal\n */\nimport { AuthCallbackError } from \"../../server/auth/errors.js\";\nimport { exchangeCode } from \"./oauth-engine.js\";\nimport type {\n DeviceCodeGrant,\n DeviceDeps,\n DeviceOAuthConfig,\n OAuthTokens,\n OpenAIDeviceConfig,\n} from \"./types.js\";\n\n// ─── OAuth 2.0 Device Authorization Grant (RFC 8628) — terminal-first / headless login ───\n\n/** Buffer added to every poll interval to avoid hitting the server a hair early. */\nconst POLLING_SAFETY_MARGIN_MS = 3000;\n\n/**\n * Parse a JSON body, or fail with this module's typed error instead of a raw `SyntaxError`.\n *\n * Every failure in this file is supposed to reach the caller as an `AuthCallbackError` carrying a code\n * the CLI can branch on. `res.json()` breaks that contract: a device endpoint that answers with HTML —\n * a captive portal, a corporate proxy's sign-in page, a load balancer's error page — makes it reject\n * with a `SyntaxError` that no `catch` here handles, so it escapes untyped past a caller prepared only\n * for `AuthCallbackError`.\n *\n * The body is quoted, truncated, because \"not JSON\" and \"not JSON, and it looks like a proxy login\n * page\" are different diagnoses for whoever is holding the terminal — and routing them to the provider\n * when the fault is their network is the expensive kind of wrong.\n */\nasync function parseJsonOrFail(res: Response, code: string, what: string): Promise<unknown> {\n const text = await res.text().catch(() => \"\");\n try {\n return JSON.parse(text);\n } catch {\n throw new AuthCallbackError(code, `${what} returned a non-JSON body: ${text.slice(0, 120)}`);\n }\n}\n\n/** Step 1 — request a device code. POSTs `{client_id, scope}` to the device endpoint. */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: RFC 8628 device-code request — cohesive network response parser ported verbatim (ADR D3).\nexport async function requestDeviceCode(\n config: DeviceOAuthConfig,\n deps: Pick<DeviceDeps, \"fetch\">,\n): Promise<DeviceCodeGrant> {\n let res: Response;\n try {\n res = await deps.fetch(config.deviceCodeEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\", accept: \"application/json\" },\n body: new URLSearchParams({\n client_id: config.clientId,\n scope: config.scopes.join(\" \"),\n }).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `device request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `device endpoint returned HTTP ${res.status}`,\n );\n }\n const data = (await parseJsonOrFail(\n res,\n \"oauth_device_authorization_failed\",\n \"device endpoint\",\n )) as {\n device_code?: unknown;\n user_code?: unknown;\n verification_uri?: unknown;\n verification_uri_complete?: unknown;\n interval?: unknown;\n expires_in?: unknown;\n };\n if (typeof data.device_code !== \"string\" || typeof data.user_code !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n \"device response missing device_code/user_code\",\n );\n }\n const verification =\n typeof data.verification_uri === \"string\"\n ? data.verification_uri\n : typeof data.verification_uri_complete === \"string\"\n ? data.verification_uri_complete\n : \"\";\n return {\n deviceCode: data.device_code,\n userCode: data.user_code,\n verificationUri: verification,\n interval: typeof data.interval === \"number\" && data.interval > 0 ? data.interval : 5,\n expiresIn: typeof data.expires_in === \"number\" && data.expires_in > 0 ? data.expires_in : 900,\n };\n}\n\n/**\n * Step 2 — poll the token endpoint until the user approves (or the code expires). Handles RFC 8628\n * `authorization_pending` (keep waiting) and `slow_down` (back off), with an expiry deadline so it cannot\n * spin forever.\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: RFC 8628 poll state machine (authorization_pending / slow_down / success / expiry) — a cohesive loop ported verbatim (ADR D3); fragmenting it would obscure the protocol.\nexport async function pollDeviceToken(\n config: DeviceOAuthConfig,\n grant: DeviceCodeGrant,\n deps: DeviceDeps,\n): Promise<OAuthTokens> {\n const deadline = deps.now() + grant.expiresIn * 1000;\n let intervalMs = grant.interval * 1000;\n\n while (deps.now() < deadline) {\n let res: Response;\n try {\n res = await deps.fetch(config.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n accept: \"application/json\",\n },\n body: new URLSearchParams({\n client_id: config.clientId,\n device_code: grant.deviceCode,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device token poll failed: ${(err as Error).message}`,\n );\n }\n // RFC 8628 §3.5: `authorization_pending` / `slow_down` arrive as a 400 with an `error` body — so the\n // body MUST be read before deciding failure. Parse first; only a non-OAuth-shaped body on a non-2xx fails.\n const data = (await res.json().catch(() => ({}))) as {\n access_token?: string;\n refresh_token?: string;\n expires_in?: number;\n id_token?: string;\n error?: string;\n interval?: number;\n };\n if (!res.ok && typeof data.error !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device token endpoint returned HTTP ${res.status}`,\n );\n }\n\n if (typeof data.access_token === \"string\" && data.access_token.length > 0) {\n const expiresIn = typeof data.expires_in === \"number\" ? data.expires_in : 0;\n const accountId = extractAccountId({\n access_token: data.access_token,\n id_token: data.id_token,\n });\n return {\n access: data.access_token,\n // Some device-grant providers (e.g. GitHub) issue no separate refresh token — reuse the access\n // token as the refresh handle.\n refresh: data.refresh_token ?? data.access_token,\n expires: deps.now() + expiresIn * 1000,\n ...(accountId !== undefined ? { accountId } : {}),\n ...(typeof data.id_token === \"string\" && data.id_token.length > 0\n ? { idToken: data.id_token }\n : {}),\n };\n }\n\n if (data.error === \"authorization_pending\") {\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n continue;\n }\n if (data.error === \"slow_down\") {\n // RFC 8628 §3.5: add 5s to the interval, or honor a server-provided one.\n intervalMs =\n (typeof data.interval === \"number\" && data.interval > 0\n ? data.interval\n : grant.interval + 5) * 1000;\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n continue;\n }\n if (typeof data.error === \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device authorization rejected: ${data.error}`,\n );\n }\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n }\n throw new AuthCallbackError(\n \"oauth_device_code_expired\",\n \"the device code expired before it was approved\",\n );\n}\n\n/**\n * The full device login: request a code, hand the user the verification URL + user code via `onPrompt`\n * (never printed here — the caller renders it, keeping this module output-free), then poll to completion.\n */\nexport async function deviceLogin(\n config: DeviceOAuthConfig,\n deps: DeviceDeps,\n hooks: {\n onPrompt: (p: { userCode: string; verificationUri: string; expiresIn: number }) => void;\n },\n): Promise<OAuthTokens> {\n const grant = await requestDeviceCode(config, deps);\n hooks.onPrompt({\n userCode: grant.userCode,\n verificationUri: grant.verificationUri,\n expiresIn: grant.expiresIn,\n });\n return pollDeviceToken(config, grant, deps);\n}\n\n// ─── OpenAI / ChatGPT \"headless\" device flow (two-step) ───\n\n/** Step 1 (OpenAI) — request the user code. */\nexport async function requestOpenAIUsercode(\n config: OpenAIDeviceConfig,\n deps: Pick<DeviceDeps, \"fetch\">,\n): Promise<{ deviceAuthId: string; userCode: string; interval: number }> {\n let res: Response;\n try {\n res = await deps.fetch(config.deviceUsercodeEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({ client_id: config.clientId }),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `usercode request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `usercode endpoint returned HTTP ${res.status}`,\n );\n }\n const data = (await parseJsonOrFail(\n res,\n \"oauth_device_authorization_failed\",\n \"usercode endpoint\",\n )) as {\n device_auth_id?: unknown;\n user_code?: unknown;\n interval?: unknown;\n };\n if (typeof data.device_auth_id !== \"string\" || typeof data.user_code !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n \"usercode response missing device_auth_id/user_code\",\n );\n }\n const interval = Math.max(\n typeof data.interval === \"string\" ? parseInt(data.interval, 10) || 5 : 5,\n 1,\n );\n return { deviceAuthId: data.device_auth_id, userCode: data.user_code, interval };\n}\n\n/**\n * Step 2+3 (OpenAI) — poll for the authorization code (200 = ready; 403/404 = pending; else fail), then\n * exchange it for tokens at the standard `/oauth/token` endpoint (reuses `exchangeCode`).\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: OpenAI two-step headless poll loop (200 ready / 403,404 pending / else fail) — cohesive network state machine ported verbatim (ADR D3).\nexport async function openaiDeviceLogin(\n config: OpenAIDeviceConfig,\n deps: DeviceDeps,\n hooks: { onPrompt: (p: { userCode: string; verificationUri: string }) => void },\n): Promise<OAuthTokens> {\n const { deviceAuthId, userCode, interval } = await requestOpenAIUsercode(config, deps);\n hooks.onPrompt({ userCode, verificationUri: config.verificationUri });\n\n const intervalMs = interval * 1000;\n // Bound the loop so it cannot spin forever if the provider never resolves (upstream loops unbounded).\n const deadline = deps.now() + 15 * 60 * 1000;\n while (deps.now() < deadline) {\n let res: Response;\n try {\n res = await deps.fetch(config.devicePollEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({ device_auth_id: deviceAuthId, user_code: userCode }),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device poll failed: ${(err as Error).message}`,\n );\n }\n if (res.ok) {\n const data = (await parseJsonOrFail(res, \"oauth_token_exchange_failed\", \"device poll\")) as {\n authorization_code?: unknown;\n code_verifier?: unknown;\n };\n if (typeof data.authorization_code !== \"string\" || typeof data.code_verifier !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n \"device poll returned no authorization_code\",\n );\n }\n const tokens = await exchangeCode(\n config,\n { code: data.authorization_code, verifier: data.code_verifier },\n deps,\n );\n // M43 D4 fix #2 — the two-step exchange returns a JWT access token but `parseTokenResponse` only reads a\n // top-level `account_id`. JWT-extract the `chatgpt_account_id` (as the generic device poll already does)\n // so the login persists a non-empty account_id for the Codex `ChatGPT-Account-Id` header.\n return {\n ...tokens,\n accountId: tokens.accountId ?? extractAccountId({ access_token: tokens.access }),\n };\n }\n // 403/404 = still pending (user has not approved yet); anything else is a hard failure.\n if (res.status !== 403 && res.status !== 404) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device poll returned HTTP ${res.status}`,\n );\n }\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n }\n throw new AuthCallbackError(\n \"oauth_device_code_expired\",\n \"the device authorization expired before approval\",\n );\n}\n\n/** JWT id/access-token claims we read to attribute an account. */\ninterface IdTokenClaims {\n chatgpt_account_id?: string;\n organizations?: Array<{ id: string }>;\n \"https://api.openai.com/auth\"?: { chatgpt_account_id?: string };\n}\n\n/** Decode a JWT's claim set (no signature verification — used only to read a self-reported account id). */\nexport function parseJwtClaims(token: string): IdTokenClaims | undefined {\n const parts = token.split(\".\");\n if (parts.length !== 3) return undefined;\n try {\n return JSON.parse(Buffer.from(parts[1] as string, \"base64url\").toString()) as IdTokenClaims;\n } catch {\n return undefined;\n }\n}\n\n/** Best-effort account id from an id/access token's claims (OpenAI/ChatGPT shape). */\nexport function extractAccountId(tokens: {\n id_token?: string;\n access_token?: string;\n}): string | undefined {\n for (const token of [tokens.id_token, tokens.access_token]) {\n if (token === undefined) continue;\n const claims = parseJwtClaims(token);\n const id =\n claims?.chatgpt_account_id ??\n claims?.[\"https://api.openai.com/auth\"]?.chatgpt_account_id ??\n claims?.organizations?.[0]?.id;\n if (id !== undefined) return id;\n }\n return undefined;\n}\n"]}
|
package/dist/auth/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { providerFromApiKeyPrefix } from '../chunk-NAF4L3T6.js';
|
|
2
|
-
import { exchangeCode } from '../chunk-
|
|
3
|
-
export { ensureFreshCredential, exchangeCode, persistOAuthTokens, refreshOAuthTokens, resolveCredential } from '../chunk-
|
|
4
|
-
export { CredentialError, assertSecureModes, authFilePath, credentialHome, readAuthFile, readStoredOAuth, writeCredential } from '../chunk-
|
|
2
|
+
import { exchangeCode } from '../chunk-3GTN4HOO.js';
|
|
3
|
+
export { ensureFreshCredential, exchangeCode, persistOAuthTokens, refreshOAuthTokens, resolveCredential } from '../chunk-3GTN4HOO.js';
|
|
4
|
+
export { CredentialError, assertSecureModes, authFilePath, credentialHome, readAuthFile, readStoredOAuth, writeCredential } from '../chunk-QD6B6W6I.js';
|
|
5
5
|
import { AuthCallbackError } from '../chunk-5IUDICRK.js';
|
|
6
6
|
import '../chunk-Q7GYMXVC.js';
|
|
7
7
|
import '../chunk-TNFOU6SB.js';
|
|
@@ -103,7 +103,8 @@ async function pollDeviceToken(config, grant, deps) {
|
|
|
103
103
|
// token as the refresh handle.
|
|
104
104
|
refresh: data.refresh_token ?? data.access_token,
|
|
105
105
|
expires: deps.now() + expiresIn * 1e3,
|
|
106
|
-
...accountId !== void 0 ? { accountId } : {}
|
|
106
|
+
...accountId !== void 0 ? { accountId } : {},
|
|
107
|
+
...typeof data.id_token === "string" && data.id_token.length > 0 ? { idToken: data.id_token } : {}
|
|
107
108
|
};
|
|
108
109
|
}
|
|
109
110
|
if (data.error === "authorization_pending") {
|