@theokit/sdk 5.13.0 → 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 +34 -0
- package/dist/{agent-iW5kPpfT.d.cts → agent-DExqjqYy.d.cts} +9 -1
- package/dist/{agent-DSMuwADp.d.ts → agent-Dfw3VsIX.d.ts} +9 -1
- package/dist/{agent-5DSDDH7K.js → agent-T34LCGQM.js} +11 -11
- package/dist/{agent-5DSDDH7K.js.map → agent-T34LCGQM.js.map} +1 -1
- package/dist/{agent-WOMRT3KX.cjs → agent-TL4K7BTG.cjs} +12 -12
- package/dist/{agent-WOMRT3KX.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-KL7ZUMK3.cjs → chunk-2WY2OFSC.cjs} +146 -77
- package/dist/chunk-2WY2OFSC.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-XOYNB3YN.js → chunk-3ONIVO2I.js} +3 -3
- package/dist/{chunk-XOYNB3YN.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-5A4UFBHW.cjs → chunk-A77UMVMD.cjs} +15 -11
- package/dist/chunk-A77UMVMD.cjs.map +1 -0
- package/dist/{chunk-47EACDOC.cjs → chunk-BZK5QL3N.cjs} +4 -4
- package/dist/{chunk-47EACDOC.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-JX4LB6XO.js → chunk-GARVAUCU.js} +93 -24
- package/dist/chunk-GARVAUCU.js.map +1 -0
- package/dist/{chunk-DVP3YMDA.cjs → chunk-LXG6VL6R.cjs} +3 -3
- package/dist/{chunk-DVP3YMDA.cjs.map → chunk-LXG6VL6R.cjs.map} +1 -1
- package/dist/{chunk-ZTP6ZACR.js → chunk-NAVUTK6X.js} +3 -3
- package/dist/{chunk-ZTP6ZACR.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-MS3TQSXU.js → chunk-QD6B6W6I.js} +6 -4
- package/dist/chunk-QD6B6W6I.js.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-4UYHP6NF.cjs → chunk-SNVYOX46.cjs} +28 -28
- package/dist/{chunk-4UYHP6NF.cjs.map → chunk-SNVYOX46.cjs.map} +1 -1
- 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-2PRGRYEQ.js → chunk-ZOL3L4EH.js} +4 -4
- package/dist/{chunk-2PRGRYEQ.js.map → chunk-ZOL3L4EH.js.map} +1 -1
- package/dist/{compact-session-B7P6EU3Z.cjs → compact-session-D2MQDB6G.cjs} +15 -15
- package/dist/{compact-session-B7P6EU3Z.cjs.map → compact-session-D2MQDB6G.cjs.map} +1 -1
- package/dist/{compact-session-5HMX6KYT.js → compact-session-N2PPHQO6.js} +6 -6
- package/dist/{compact-session-5HMX6KYT.js.map → compact-session-N2PPHQO6.js.map} +1 -1
- package/dist/{cron-DdKzwJqK.d.ts → cron-BubDpFJG.d.ts} +2 -2
- package/dist/{cron-BvxrLW5J.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 +10 -10
- package/dist/eval.js +9 -9
- package/dist/index.cjs +69 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -6
- package/dist/index.d.ts +9 -6
- package/dist/index.js +38 -22
- package/dist/index.js.map +1 -1
- package/dist/{inject-session-WOH7TPDX.cjs → inject-session-3ICZIJ2N.cjs} +4 -4
- package/dist/{inject-session-WOH7TPDX.cjs.map → inject-session-3ICZIJ2N.cjs.map} +1 -1
- package/dist/{inject-session-75L3NCNL.js → inject-session-J26SHHIO.js} +3 -3
- package/dist/{inject-session-75L3NCNL.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/runtime/skills/binary-on-path.d.ts +1 -0
- package/dist/internal/runtime/skills/discover-skills.d.ts +2 -0
- 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/{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/subagents-loader.d.cts +2 -2
- package/dist/subagents-loader.d.ts +2 -2
- package/dist/types/agent.d.ts +6 -0
- package/dist/types/run.d.ts +27 -2
- package/dist/workflow.d.cts +1 -1
- package/dist/workflow.d.ts +1 -1
- package/docs/adr/mutation-testing-scope.md +56 -0
- package/docs/error-codes.md +8 -6
- package/docs/harness-capability-map.md +29 -1
- package/package.json +1 -1
- package/dist/chunk-3FSBE4PS.js.map +0 -1
- package/dist/chunk-5A4UFBHW.cjs.map +0 -1
- package/dist/chunk-7WARNHWW.cjs.map +0 -1
- package/dist/chunk-JX4LB6XO.js.map +0 -1
- package/dist/chunk-KL7ZUMK3.cjs.map +0 -1
- package/dist/chunk-LO6LIUZ6.cjs +0 -18
- package/dist/chunk-MS3TQSXU.js.map +0 -1
- package/dist/chunk-NHOEXFZT.js.map +0 -1
- package/dist/chunk-QISSETTG.cjs.map +0 -1
package/dist/chunk-LO6LIUZ6.cjs
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var chunkS46WJTDL_cjs = require('./chunk-S46WJTDL.cjs');
|
|
4
|
-
|
|
5
|
-
// src/providers.ts
|
|
6
|
-
function listProviders2() {
|
|
7
|
-
chunkS46WJTDL_cjs.registerBuiltins();
|
|
8
|
-
return chunkS46WJTDL_cjs.listProviders();
|
|
9
|
-
}
|
|
10
|
-
function getProviderProfile2(name) {
|
|
11
|
-
chunkS46WJTDL_cjs.registerBuiltins();
|
|
12
|
-
return chunkS46WJTDL_cjs.getProviderProfile(name);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
exports.getProviderProfile = getProviderProfile2;
|
|
16
|
-
exports.listProviders = listProviders2;
|
|
17
|
-
//# sourceMappingURL=chunk-LO6LIUZ6.cjs.map
|
|
18
|
-
//# sourceMappingURL=chunk-LO6LIUZ6.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/auth/credential-store.ts"],"names":[],"mappings":"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","file":"chunk-MS3TQSXU.js","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport {\n chmodSync,\n closeSync,\n fsyncSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { z } from \"zod\";\n\nimport { AuthenticationError } from \"../../errors.js\";\n\n/**\n * M42 — the SDK credential store. Promoted DOWN from agent-builder's hardened `agents/lib/credentials.ts`\n * (M37), generalized from a closed `openrouter|anthropic|openai` union to an open `provider: string` and\n * driven by a caller-supplied {@link CredentialStoreConfig} (no hardcoded `.agent-builder`/`auth.json` /\n * `AGENT_BUILDER_HOME`). The security-critical file mechanics are ported VERBATIM (ADR D3 of the M42 plan):\n * atomic O_EXCL + rename + fsync write, 0700/0600 mode gates, `env` is always a PARAMETER (never an ambient\n * `process.env` read).\n *\n * The env-precedence + key-prefix-inference + declared-provider rungs of the agent-builder resolver are\n * APP POLICY and deliberately stay UP in the consumer; this module owns only the on-disk store + the\n * `api|oauth` discriminated union. See {@link resolveCredential} (SDK) for the store-read + refresh path.\n *\n * Re-exported from `@theokit/sdk/auth`, and therefore PUBLIC, under semver.\n *\n * NOTE — no internal-visibility tag in this block. `tsconfig.base.json` sets `stripInternal: true`,\n * and TypeScript scans EVERY leading comment range of the declaration that follows, including the\n * import right below this one. The tag that used to sit here deleted that import from the emitted\n * `.d.ts`, leaving the types it binds unresolvable for any consumer running type-aware lint\n * (usetheodev/theokit-sdk#283 records the same trap on a declaration).\n */\nimport type { CredentialStoreConfig, StoredCredential, StoredOAuthCredential } from \"./types.js\";\n\n/** The store directory, honoring an optional `homeEnvVar` override. */\nexport function credentialHome(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const override = config.homeEnvVar !== undefined ? env[config.homeEnvVar]?.trim() : undefined;\n return override !== undefined && override.length > 0\n ? override\n : join(config.home, config.dirName);\n}\n\n/** The credential file path inside the (possibly overridden) store directory. */\nexport function authFilePath(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n return join(credentialHome(config, env), config.fileName);\n}\n\n/**\n * A credential problem the caller can act on. Never carries the key value.\n *\n * M78 — this used to extend bare `Error`, which quietly disabled classification for the entire auth\n * path: `isTransientError` is `err instanceof TheokitAgentError && err.isRetryable === true`\n * (`errors.ts:443`), so a credential failure could never be judged transient OR permanent. The\n * predicate was not \"forgotten\" downstream — it was unusable there by construction.\n *\n * Extending `AuthenticationError` is ADDITIVE: the class still exists, still reports\n * `name: \"CredentialError\"`, and every existing `instanceof CredentialError` stays true. It only\n * gains ancestors. `AuthenticationError` pins `isRetryable: false`, so gaining the ability to be\n * classified does NOT turn a revoked credential into a retry loop.\n *\n * The single reference does the same thing with one root type: Codex routes every domain failure\n * through `CodexErr` with `is_retryable()` as a method (`protocol/src/error.rs:176`), rather than\n * parallel classes extending the language's `Error`.\n */\nexport class CredentialError extends AuthenticationError {\n // Field, not an assignment in the constructor: `AuthenticationError.name` is `override readonly`\n // (`errors.ts:174`), so `this.name = …` does not compile. Caught by `tsc`, not by vitest — the\n // suite was green with the broken assignment because the transpiler strips the type.\n override readonly name: string = \"CredentialError\";\n}\n\n/**\n * The on-disk store — a discriminated union on `type`. A legacy file with NO\n * `type` (or `type: 'api'`) is the API-key variant — read unchanged, no migration. The `oauth` variant\n * carries the token pair + expiry.\n */\nconst apiFileSchema = z\n .object({\n type: z.literal(\"api\").optional(),\n provider: z.string().min(1).optional(),\n api_key: z.string(),\n })\n .strict();\n\nconst oauthFileSchema = z\n .object({\n type: z.literal(\"oauth\"),\n provider: z.string().min(1),\n access: z.string().min(1),\n refresh: z.string().min(1),\n expires: z.number(),\n account_id: z.string().optional(),\n })\n .strict();\n\n// oauth first (it requires `type: 'oauth'`); a legacy `{provider?, api_key}` falls through to api.\nconst fileSchema = z.union([oauthFileSchema, apiFileSchema]);\n\n/**\n * The 0700-dir / 0600-file mode gates (ported verbatim). The DIRECTORY matters as much as the file:\n * `mkdirSync(mode)` applies only at creation, so a pre-existing store dir keeps whatever mode it had, and a\n * writable dir lets an attacker replace the credential file with a symlink to their own 0600 file — the\n * agent then runs on THEIR account.\n */\nexport function assertSecureModes(dirPath: string, path: string): void {\n // Windows has no POSIX mode bits. `statSync().mode` there is SYNTHETIC — 0666 for any writable\n // entry, whatever the ACLs actually say — so `mode & 0o022` was non-zero for every valid store and\n // this gate refused all of them, which made the credential path unreadable on that platform\n // rather than protected. A check that cannot observe the real permission system must not report a\n // verdict about it; ACL enforcement is a separate mechanism and not one this function can fake.\n if (process.platform === \"win32\") return;\n\n const dirMode = statSync(dirPath).mode & 0o777;\n if ((dirMode & 0o022) !== 0) {\n throw new CredentialError(\n `${dirPath} is writable by other users (mode ${dirMode.toString(8)}), so the credential file ` +\n `inside it can be replaced. Fix it with: chmod 700 ${dirPath}`,\n );\n }\n const mode = statSync(path).mode & 0o777;\n if ((mode & 0o077) !== 0) {\n throw new CredentialError(\n `${path} is readable by other users (mode ${mode.toString(8)}). ` +\n `A credential file must not be. Fix it with: chmod 600 ${path}`,\n );\n }\n}\n\n/**\n * A `z.union` reports a generic \"Invalid input\" at the root, hiding WHAT is wrong. Pick the sub-schema the\n * file was CLEARLY aiming at (by its `type` discriminant) and surface that schema's specific issue.\n */\nfunction describeUnionError(parsed: unknown, err: unknown, path: string): CredentialError {\n const looksOAuth =\n typeof parsed === \"object\" &&\n parsed !== null &&\n (parsed as { type?: unknown }).type === \"oauth\";\n const specific = looksOAuth ? oauthFileSchema.safeParse(parsed) : apiFileSchema.safeParse(parsed);\n let issue: z.ZodIssue | undefined;\n if (!specific.success) {\n issue = specific.error.issues[0];\n } else if (err instanceof z.ZodError) {\n issue = err.issues[0];\n }\n return new CredentialError(\n `${path}: ${issue?.message ?? String(err)} [${issue?.path.join(\".\") || \"root\"}]`,\n );\n}\n\n/** Parse the raw file into the store union, surfacing the SPECIFIC sub-schema issue (not a generic union error). */\nfunction parseStoredFile(raw: string, path: string): StoredCredential {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n // The parser's message embeds a snippet of the INPUT — up to the raw key when a user pastes the bare\n // key instead of JSON. The position is not actionable anyway, so the expected shape is more useful.\n throw new CredentialError(\n `${path} is not valid JSON. Expected: {\"provider\": \"<name>\", \"api_key\": \"...\"}`,\n );\n }\n try {\n return fileSchema.parse(parsed);\n } catch (err) {\n throw describeUnionError(parsed, err, path);\n }\n}\n\n/**\n * Read the credential file. Absent ⇒ `undefined` (the normal case). Present-but-wrong is a typed error\n * naming the file: a malformed credential store must not surface as a raw parse crash. Enforces the\n * 0700 dir / 0600 file mode gates (ported verbatim — a writable dir lets an attacker swap the file for a\n * symlink to their own account).\n */\nexport function readAuthFile(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredCredential | undefined {\n const path = authFilePath(config, env);\n\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw new CredentialError(`cannot read ${path}: ${(err as Error).message}`);\n }\n\n assertSecureModes(credentialHome(config, env), path);\n return parseStoredFile(raw, path);\n}\n\n/**\n * Read the stored OAuth credential (with its refresh token), or `undefined` when the store is absent or\n * holds an api credential. The oauth engine needs the refresh token, which the resolved bearer does not\n * carry. Enforces the same 0600/0700 gates as every other read.\n */\nexport function readStoredOAuth(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredOAuthCredential | undefined {\n const stored = readAuthFile(config, env);\n return stored !== undefined && stored.type === \"oauth\" ? stored : undefined;\n}\n\n/** Narrows a writable credential to the oauth variant. */\nfunction isOAuthWrite(\n c: { provider: string; apiKey: string } | StoredOAuthCredential,\n): c is StoredOAuthCredential {\n return \"type\" in c && c.type === \"oauth\";\n}\n\n/** Build the on-disk JSON payload for the credential variant, validating non-empty tokens. */\nfunction buildStorePayload(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n): Record<string, unknown> {\n if (isOAuthWrite(cred)) {\n if (cred.access.length === 0 || cred.refresh.length === 0) {\n throw new CredentialError(\n \"refusing to write an oauth credential with an empty access/refresh token\",\n );\n }\n return {\n type: \"oauth\",\n provider: cred.provider,\n access: cred.access,\n refresh: cred.refresh,\n expires: cred.expires,\n ...(cred.account_id !== undefined ? { account_id: cred.account_id } : {}),\n };\n }\n if (typeof cred.apiKey !== \"string\" || cred.apiKey.length === 0) {\n throw new CredentialError(\"refusing to write an empty API key\");\n }\n return { provider: cred.provider, api_key: cred.apiKey };\n}\n\n/**\n * Persist a credential atomically at mode `0600`. Ported VERBATIM (ADR D3): write to a random-named temp\n * file in the same directory with `wx` (O_EXCL), fsync, close, chmod, then `rename` (atomic on POSIX) —\n * so a crash mid-write leaves whatever was there untouched, and a pre-planted symlink cannot capture the\n * key. The api variant persists the unchanged `{provider, api_key}` (back-compat, no `type` key); the\n * oauth variant persists `{type:'oauth', provider, access, refresh, expires, account_id?}`.\n */\nexport function writeCredential(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const payload = buildStorePayload(cred);\n\n const dir = credentialHome(config, env);\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n chmodSync(dir, 0o700); // unconditional: mkdirSync's mode applies only at creation\n\n const path = authFilePath(config, env);\n // RANDOM name + `wx` (O_EXCL): a predictable temp name with a plain write follows a pre-planted SYMLINK,\n // landing the key in an attacker's file while reporting success. O_EXCL refuses any pre-existing file or\n // link; the random suffix also removes the pid collision two containers sharing a bind-mounted home make.\n const tmp = `${path}.tmp-${randomBytes(8).toString(\"hex\")}`;\n try {\n const fd = openSync(tmp, \"wx\", 0o600);\n try {\n writeFileSync(fd, `${JSON.stringify(payload, null, 2)}\\n`);\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n chmodSync(tmp, 0o600); // explicit: the mode argument is subject to umask\n renameSync(tmp, path);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n // the temp file may not exist; its absence is not a failure of the write\n }\n throw new CredentialError(`cannot write ${path}: ${(err as Error).message}`);\n }\n return path;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/runtime/skills/skill-frontmatter.ts","../src/internal/runtime/skills/discover-skills.ts","../src/internal/runtime/system-prompt/escape.ts","../src/internal/runtime/skills/skills-block.ts"],"names":[],"mappings":"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","file":"chunk-NHOEXFZT.js","sourcesContent":["import { ConfigurationError } from \"../../../errors.js\";\nimport { type FrontmatterValue, parseSimpleYaml } from \"../context/yaml-frontmatter.js\";\n\ntype StringFields = Record<string, string | undefined>;\n\n/** Narrow a FrontmatterValue to string; non-strings + undefined → undefined. */\nfunction asString(v: FrontmatterValue | undefined): string | undefined {\n return typeof v === \"string\" ? v : undefined;\n}\n\n/** Coerce parser output to legacy string-only shape (skill schema is all-string). */\nfunction toStringFields(raw: Record<string, FrontmatterValue | undefined>): StringFields {\n const out: StringFields = {};\n for (const [k, v] of Object.entries(raw)) out[k] = asString(v);\n return out;\n}\n\n/**\n * Strict skill frontmatter schema (ADR D10).\n *\n * Required: `name`, `description`.\n * Optional: `category`, `dependencies` (comma-separated string in the\n * simple-YAML dialect — parsed to `string[]`).\n *\n * Unknown fields are ignored (forward-compat). Malformed YAML or missing\n * required fields surface as `ConfigurationError` with one of the typed\n * codes below.\n *\n * @internal\n */\nexport interface SkillFrontmatter {\n name: string;\n description: string;\n category?: string;\n dependencies?: string[];\n /**\n * `disable-model-invocation: true` — the model is not told this skill exists.\n *\n * The SDK owns this boundary: a skill reaches the model through exactly one place,\n * `buildSystemPromptContext`, so the declaration is enforceable here. It is a DISCLOSURE rule,\n * not an execution rule — `skills.get(name)` still resolves it, because a caller naming a skill\n * has already made the decision the field exists to keep away from the model.\n */\n disableModelInvocation?: boolean;\n /**\n * `user-invocable: false` — carried, deliberately not enforced here.\n *\n * This SDK has no user-facing invocation surface for skills; there is no slash command. Reading\n * `agent.skills.list()` as \"the user\" would be a guess — a host may call it to build a picker or\n * to introspect, and the two want opposite answers. So the declaration travels to the host that\n * does know, instead of being discarded (the defect) or enforced against an invented boundary.\n */\n userInvocable?: boolean;\n}\n\n/**\n * Parse a SKILL.md file body into validated frontmatter.\n *\n * @throws ConfigurationError(code: \"missing_frontmatter\") — no `---` block at file head.\n * @throws ConfigurationError(code: \"schema_invalid\") — YAML malformed OR required field missing.\n *\n * @internal\n */\nexport function parseSkillFrontmatter(raw: string, fallbackName: string): SkillFrontmatter {\n const parsed = extractAndParseFrontmatter(raw, fallbackName);\n const fields = toStringFields(parsed);\n const name = resolveName(fields, fallbackName);\n ensureRequiredFields(fields, name);\n return buildFrontmatter(fields, parsed, name);\n}\n\n/**\n * SE20 — return a SKILL.md's BODY (everything after the frontmatter block), trimmed.\n * When there is no frontmatter block, the whole file is the body. Reuses the same\n * frontmatter regex as {@link parseSkillFrontmatter} (DRY).\n */\nexport function stripSkillFrontmatter(raw: string): string {\n const match = /^---\\s*\\n[\\s\\S]*?\\n---\\s*\\n/.exec(raw);\n return (match === null ? raw : raw.slice(match[0].length)).trim();\n}\n\nfunction extractAndParseFrontmatter(\n raw: string,\n fallbackName: string,\n): Record<string, FrontmatterValue | undefined> {\n const match = /^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n/.exec(raw);\n if (match === null) {\n throw new ConfigurationError(`Skill ${fallbackName} is missing frontmatter`, {\n code: \"missing_frontmatter\",\n });\n }\n const frontmatter = match[1] ?? \"\";\n // EC-5: guard against syntactically invalid frontmatter so the loader\n // surfaces schema_invalid rather than crashing.\n try {\n return parseSimpleYaml(frontmatter);\n } catch (cause) {\n const detail = cause instanceof Error ? cause.message : String(cause);\n throw new ConfigurationError(\n `Skill ${fallbackName} has malformed YAML frontmatter: ${detail}`,\n { code: \"schema_invalid\", cause },\n );\n }\n}\n\nfunction resolveName(fields: StringFields, fallbackName: string): string {\n if (hasContent(fields.name)) return fields.name;\n if (hasContent(fallbackName)) return fallbackName;\n throw new ConfigurationError(\"Skill at unknown path is missing required field: name\", {\n code: \"schema_invalid\",\n });\n}\n\nfunction ensureRequiredFields(fields: StringFields, name: string): void {\n if (!hasContent(fields.description)) {\n throw new ConfigurationError(`Skill ${name} is missing required field: description`, {\n code: \"schema_invalid\",\n });\n }\n}\n\nfunction buildFrontmatter(\n fields: StringFields,\n parsed: Record<string, FrontmatterValue | undefined>,\n name: string,\n): SkillFrontmatter {\n const description = fields.description;\n if (description === undefined) {\n // ensureRequiredFields already threw; this is unreachable but satisfies TS\n throw new ConfigurationError(`Skill ${name} missing description`, { code: \"schema_invalid\" });\n }\n const result: SkillFrontmatter = { name, description };\n if (hasContent(fields.category)) result.category = fields.category;\n const deps = parseDependencies(fields.dependencies);\n if (deps !== undefined) result.dependencies = deps;\n const disable = readAuthorizationFlag(parsed, \"disable-model-invocation\", name);\n if (disable !== undefined) result.disableModelInvocation = disable;\n const invocable = readAuthorizationFlag(parsed, \"user-invocable\", name);\n if (invocable !== undefined) result.userInvocable = invocable;\n return result;\n}\n\n/**\n * Read one boolean authorization flag, refusing a value this parser cannot represent.\n *\n * Unknown frontmatter keys are ignored here for forward compatibility, and that is right for\n * metadata. It is wrong for these two: the simple-YAML dialect coerces only the literals `true`\n * and `false`, so `disable-model-invocation: yes` — a valid YAML boolean — arrives as the STRING\n * `\"yes\"`, compares unequal to `true`, and the skill is disclosed to the model. The author wrote a\n * restriction and got the default.\n *\n * A restriction that fails open is worse than one that is absent, because the author stops looking.\n * So the value is refused and named, and the run stops on the line that caused it.\n */\nfunction readAuthorizationFlag(\n parsed: Record<string, FrontmatterValue | undefined>,\n key: string,\n name: string,\n): boolean | undefined {\n const value = parsed[key];\n if (value === undefined) return undefined;\n if (typeof value === \"boolean\") return value;\n throw new ConfigurationError(\n `Skill ${name}: \"${key}\" must be true or false (got ${JSON.stringify(value)}) — ` +\n `this dialect reads only the literals \\`true\\` and \\`false\\`, and a value it cannot read ` +\n `would leave the skill disclosed`,\n { code: \"schema_invalid\" },\n );\n}\n\nfunction parseDependencies(raw: string | undefined): string[] | undefined {\n if (!hasContent(raw)) return undefined;\n const deps = (raw as string)\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n return deps.length > 0 ? deps : undefined;\n}\n\nfunction hasContent(value: string | undefined): value is string {\n return value !== undefined && value.trim().length > 0;\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { ConfigurationError } from \"../../../errors.js\";\nimport { assertNoSymlinkEscape, safePathJoin } from \"../../security/path-guard.js\";\nimport { readWorkspaceDir } from \"../config/workspace-dir.js\";\nimport { parseSkillFrontmatter, stripSkillFrontmatter } from \"./skill-frontmatter.js\";\n\n/**\n * A discovered skill's metadata. The skill BODY is never included — only the\n * strict frontmatter fields plus the resolved `source` path.\n *\n * Public via `@theokit/sdk/skills`.\n *\n * @public\n */\nexport interface Skill {\n name: string;\n description: string;\n /** Absolute path to the discovered `SKILL.md`. */\n source: string;\n category?: string;\n dependencies?: string[];\n /** `disable-model-invocation: true` — the model is never told this skill exists. */\n disableModelInvocation?: boolean;\n /** `user-invocable: false` — carried for a host that has a picker; this SDK has no such surface. */\n userInvocable?: boolean;\n}\n\n/**\n * Information passed to `onInvalidSkill` when a `SKILL.md` is present but its\n * frontmatter is malformed (missing required field or invalid YAML).\n *\n * @public\n */\nexport interface InvalidSkillInfo {\n /** The skill directory name (used as the fallback skill name). */\n name: string;\n /** Absolute path to the offending `SKILL.md`. */\n source: string;\n /** Typed reason: `missing_frontmatter` or `schema_invalid`. */\n code: string;\n message: string;\n}\n\n/**\n * Options for {@link discoverSkills}.\n *\n * @public\n */\nexport interface DiscoverSkillsOptions {\n /**\n * Called once per directory that contains a `SKILL.md` with malformed\n * frontmatter. The skill is excluded from the result; discovery continues\n * (strict-frontmatter ADR / EC-5). A directory WITHOUT a `SKILL.md` is NOT a\n * malformed skill and does not trigger this callback.\n *\n * Default: no-op (a library primitive must not write to the consumer's\n * stderr by default).\n */\n onInvalidSkill?: (info: InvalidSkillInfo) => void;\n}\n\n/**\n * Discover `SKILL.md` skills under an arbitrary directory.\n *\n * For each immediate subdirectory `<dir>/<name>/` containing a `SKILL.md`, the\n * file's strict YAML frontmatter is parsed (`name`/`description` required;\n * `category`/`dependencies` optional). Malformed skills are skipped (optionally\n * reported via {@link DiscoverSkillsOptions.onInvalidSkill}); a subdirectory\n * whose realpath escapes `dir` (via symlink) is skipped (symlink-escape guard,\n * reusing `@theokit/sdk/path-safety`).\n *\n * NEVER throws: a missing, unreadable, or non-directory `dir` yields `[]`.\n *\n * Discovery order follows the filesystem `readdir` order (OS-dependent). Sort\n * the result before {@link buildSkillsBlock} if a stable block order matters.\n *\n * Public via `@theokit/sdk/skills`.\n *\n * @public\n */\nexport async function discoverSkills(\n dir: string,\n options?: DiscoverSkillsOptions,\n): Promise<Skill[]> {\n let entries: Awaited<ReturnType<typeof readWorkspaceDir>>;\n try {\n entries = await readWorkspaceDir(dir, \"skills_read_error\", \"skills directory\");\n } catch {\n // never-throw contract: unreadable / not-a-directory → no skills (EC-1)\n return [];\n }\n\n const skills: Skill[] = [];\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n let skillDir: string;\n try {\n skillDir = safePathJoin(dir, entry.name);\n assertNoSymlinkEscape(skillDir, dir);\n } catch {\n continue;\n }\n const skillPath = join(skillDir, \"SKILL.md\");\n let raw: string;\n try {\n raw = await readFile(skillPath, \"utf8\");\n } catch {\n // no SKILL.md in this subdir → not a skill, not an error (EC-2)\n continue;\n }\n const skill = tryParseSkill(raw, entry.name, skillPath, options);\n if (skill !== undefined) skills.push(skill);\n }\n return skills;\n}\n\nfunction tryParseSkill(\n raw: string,\n fallbackName: string,\n source: string,\n options: DiscoverSkillsOptions | undefined,\n): Skill | undefined {\n try {\n const frontmatter = parseSkillFrontmatter(raw, fallbackName);\n const skill: Skill = {\n name: frontmatter.name,\n description: frontmatter.description,\n source,\n };\n if (frontmatter.category !== undefined) skill.category = frontmatter.category;\n if (frontmatter.dependencies !== undefined) skill.dependencies = frontmatter.dependencies;\n // The authorization flags travel with the record. Dropping them here would reproduce the defect\n // one layer down: the parser would read the declaration and the discovery result would not\n // carry it, which is indistinguishable from never having parsed it.\n if (frontmatter.disableModelInvocation !== undefined) {\n skill.disableModelInvocation = frontmatter.disableModelInvocation;\n }\n if (frontmatter.userInvocable !== undefined) skill.userInvocable = frontmatter.userInvocable;\n return skill;\n } catch (cause) {\n if (cause instanceof ConfigurationError) {\n options?.onInvalidSkill?.({\n name: fallbackName,\n source,\n code: cause.code ?? \"unknown\",\n message: cause.message,\n });\n return undefined;\n }\n throw cause;\n }\n}\n\n/**\n * Read the BODY of a discovered skill — everything after its frontmatter.\n *\n * A thin selector over {@link discoverSkills} rather than a second reader, which is the same\n * relationship `loadSubagentDefinition` has to `discoverSubagents` in the sibling domain: one\n * parser is the point.\n *\n * ## Why this exists rather than a field on `Skill`\n *\n * `Skill` documents that *\"the skill BODY is never included\"*. That is a written contract with no\n * written reason, and widening it on a guess about the reason is not a trade worth making — a\n * catalog you can put in a prompt without carrying every body is the likely intent, and this keeps\n * that shape intact for whoever relied on it.\n *\n * The body was never expensive to obtain: `discoverSkills` already reads each file in full and\n * discards everything but the frontmatter. What was missing was a door that hands it over.\n *\n * ## What it is for\n *\n * Turning a discovered skill into an inline one — `SkillsSettings.inline` requires `instructions`,\n * and without this the only route was to open `source` and split the frontmatter by hand. That is a\n * second implementation of this module's own convention, and it would fail SILENTLY if the format\n * moved: the frontmatter would land inside the instructions and nothing would say so.\n *\n * Reported by the `theocode` session, which needed exactly that to give an operator's\n * `~/.theokit/skills/` to an agent through the SDK's own parser.\n *\n * @param skill - a record returned by {@link discoverSkills}; its `source` is read.\n * @returns the trimmed body. A file that is all frontmatter yields an empty string.\n * @throws if `source` is unreadable — unlike discovery, which skips what it cannot read, a caller\n * naming ONE skill has asked about that skill and an empty string would answer a question it did\n * not ask.\n * @public\n */\nexport async function loadSkillInstructions(skill: Skill): Promise<string> {\n return stripSkillFrontmatter(await readFile(skill.source, \"utf8\"));\n}\n","/**\n * Block-body XML escape (ADR D9 — prompt-injection defence).\n *\n * Order matters: `&` MUST be escaped first so subsequent `<`/`>` replacements\n * do not double-encode the `&` characters they introduce.\n *\n * @internal\n */\nexport const escapeBlockBody = (s: string): string =>\n s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\n","import { escapeBlockBody } from \"../system-prompt/escape.js\";\n\n/**\n * Render the `<skills>` system-prompt block from a skill list.\n *\n * Input is the structural subset `{ name, description }` — the skill BODY is\n * NOT in the type, so it cannot leak into the prompt. Both fields are passed\n * through `escapeBlockBody` to neutralise prompt-injection vectors hidden in\n * user-controlled SKILL.md frontmatter (injection-escape ADR).\n *\n * Returns `undefined` for an empty list so the caller can omit the block.\n *\n * Public via `@theokit/sdk/skills`.\n *\n * @public\n */\nexport function buildSkillsBlock(\n skills: ReadonlyArray<{ name: string; description: string }>,\n): string | undefined {\n if (skills.length === 0) return undefined;\n const lines = skills.map(\n (skill) => ` - ${escapeBlockBody(skill.name)}: ${escapeBlockBody(skill.description)}`,\n );\n return `<skills>\\n${lines.join(\"\\n\")}\\n</skills>`;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/auth/credential-store.ts"],"names":["join","AuthenticationError","z","statSync","readFileSync","mkdirSync","chmodSync","randomBytes","openSync","writeFileSync","fsyncSync","closeSync","renameSync","unlinkSync"],"mappings":"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","file":"chunk-QISSETTG.cjs","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport {\n chmodSync,\n closeSync,\n fsyncSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { z } from \"zod\";\n\nimport { AuthenticationError } from \"../../errors.js\";\n\n/**\n * M42 — the SDK credential store. Promoted DOWN from agent-builder's hardened `agents/lib/credentials.ts`\n * (M37), generalized from a closed `openrouter|anthropic|openai` union to an open `provider: string` and\n * driven by a caller-supplied {@link CredentialStoreConfig} (no hardcoded `.agent-builder`/`auth.json` /\n * `AGENT_BUILDER_HOME`). The security-critical file mechanics are ported VERBATIM (ADR D3 of the M42 plan):\n * atomic O_EXCL + rename + fsync write, 0700/0600 mode gates, `env` is always a PARAMETER (never an ambient\n * `process.env` read).\n *\n * The env-precedence + key-prefix-inference + declared-provider rungs of the agent-builder resolver are\n * APP POLICY and deliberately stay UP in the consumer; this module owns only the on-disk store + the\n * `api|oauth` discriminated union. See {@link resolveCredential} (SDK) for the store-read + refresh path.\n *\n * Re-exported from `@theokit/sdk/auth`, and therefore PUBLIC, under semver.\n *\n * NOTE — no internal-visibility tag in this block. `tsconfig.base.json` sets `stripInternal: true`,\n * and TypeScript scans EVERY leading comment range of the declaration that follows, including the\n * import right below this one. The tag that used to sit here deleted that import from the emitted\n * `.d.ts`, leaving the types it binds unresolvable for any consumer running type-aware lint\n * (usetheodev/theokit-sdk#283 records the same trap on a declaration).\n */\nimport type { CredentialStoreConfig, StoredCredential, StoredOAuthCredential } from \"./types.js\";\n\n/** The store directory, honoring an optional `homeEnvVar` override. */\nexport function credentialHome(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const override = config.homeEnvVar !== undefined ? env[config.homeEnvVar]?.trim() : undefined;\n return override !== undefined && override.length > 0\n ? override\n : join(config.home, config.dirName);\n}\n\n/** The credential file path inside the (possibly overridden) store directory. */\nexport function authFilePath(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n return join(credentialHome(config, env), config.fileName);\n}\n\n/**\n * A credential problem the caller can act on. Never carries the key value.\n *\n * M78 — this used to extend bare `Error`, which quietly disabled classification for the entire auth\n * path: `isTransientError` is `err instanceof TheokitAgentError && err.isRetryable === true`\n * (`errors.ts:443`), so a credential failure could never be judged transient OR permanent. The\n * predicate was not \"forgotten\" downstream — it was unusable there by construction.\n *\n * Extending `AuthenticationError` is ADDITIVE: the class still exists, still reports\n * `name: \"CredentialError\"`, and every existing `instanceof CredentialError` stays true. It only\n * gains ancestors. `AuthenticationError` pins `isRetryable: false`, so gaining the ability to be\n * classified does NOT turn a revoked credential into a retry loop.\n *\n * The single reference does the same thing with one root type: Codex routes every domain failure\n * through `CodexErr` with `is_retryable()` as a method (`protocol/src/error.rs:176`), rather than\n * parallel classes extending the language's `Error`.\n */\nexport class CredentialError extends AuthenticationError {\n // Field, not an assignment in the constructor: `AuthenticationError.name` is `override readonly`\n // (`errors.ts:174`), so `this.name = …` does not compile. Caught by `tsc`, not by vitest — the\n // suite was green with the broken assignment because the transpiler strips the type.\n override readonly name: string = \"CredentialError\";\n}\n\n/**\n * The on-disk store — a discriminated union on `type`. A legacy file with NO\n * `type` (or `type: 'api'`) is the API-key variant — read unchanged, no migration. The `oauth` variant\n * carries the token pair + expiry.\n */\nconst apiFileSchema = z\n .object({\n type: z.literal(\"api\").optional(),\n provider: z.string().min(1).optional(),\n api_key: z.string(),\n })\n .strict();\n\nconst oauthFileSchema = z\n .object({\n type: z.literal(\"oauth\"),\n provider: z.string().min(1),\n access: z.string().min(1),\n refresh: z.string().min(1),\n expires: z.number(),\n account_id: z.string().optional(),\n })\n .strict();\n\n// oauth first (it requires `type: 'oauth'`); a legacy `{provider?, api_key}` falls through to api.\nconst fileSchema = z.union([oauthFileSchema, apiFileSchema]);\n\n/**\n * The 0700-dir / 0600-file mode gates (ported verbatim). The DIRECTORY matters as much as the file:\n * `mkdirSync(mode)` applies only at creation, so a pre-existing store dir keeps whatever mode it had, and a\n * writable dir lets an attacker replace the credential file with a symlink to their own 0600 file — the\n * agent then runs on THEIR account.\n */\nexport function assertSecureModes(dirPath: string, path: string): void {\n // Windows has no POSIX mode bits. `statSync().mode` there is SYNTHETIC — 0666 for any writable\n // entry, whatever the ACLs actually say — so `mode & 0o022` was non-zero for every valid store and\n // this gate refused all of them, which made the credential path unreadable on that platform\n // rather than protected. A check that cannot observe the real permission system must not report a\n // verdict about it; ACL enforcement is a separate mechanism and not one this function can fake.\n if (process.platform === \"win32\") return;\n\n const dirMode = statSync(dirPath).mode & 0o777;\n if ((dirMode & 0o022) !== 0) {\n throw new CredentialError(\n `${dirPath} is writable by other users (mode ${dirMode.toString(8)}), so the credential file ` +\n `inside it can be replaced. Fix it with: chmod 700 ${dirPath}`,\n );\n }\n const mode = statSync(path).mode & 0o777;\n if ((mode & 0o077) !== 0) {\n throw new CredentialError(\n `${path} is readable by other users (mode ${mode.toString(8)}). ` +\n `A credential file must not be. Fix it with: chmod 600 ${path}`,\n );\n }\n}\n\n/**\n * A `z.union` reports a generic \"Invalid input\" at the root, hiding WHAT is wrong. Pick the sub-schema the\n * file was CLEARLY aiming at (by its `type` discriminant) and surface that schema's specific issue.\n */\nfunction describeUnionError(parsed: unknown, err: unknown, path: string): CredentialError {\n const looksOAuth =\n typeof parsed === \"object\" &&\n parsed !== null &&\n (parsed as { type?: unknown }).type === \"oauth\";\n const specific = looksOAuth ? oauthFileSchema.safeParse(parsed) : apiFileSchema.safeParse(parsed);\n let issue: z.ZodIssue | undefined;\n if (!specific.success) {\n issue = specific.error.issues[0];\n } else if (err instanceof z.ZodError) {\n issue = err.issues[0];\n }\n return new CredentialError(\n `${path}: ${issue?.message ?? String(err)} [${issue?.path.join(\".\") || \"root\"}]`,\n );\n}\n\n/** Parse the raw file into the store union, surfacing the SPECIFIC sub-schema issue (not a generic union error). */\nfunction parseStoredFile(raw: string, path: string): StoredCredential {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n // The parser's message embeds a snippet of the INPUT — up to the raw key when a user pastes the bare\n // key instead of JSON. The position is not actionable anyway, so the expected shape is more useful.\n throw new CredentialError(\n `${path} is not valid JSON. Expected: {\"provider\": \"<name>\", \"api_key\": \"...\"}`,\n );\n }\n try {\n return fileSchema.parse(parsed);\n } catch (err) {\n throw describeUnionError(parsed, err, path);\n }\n}\n\n/**\n * Read the credential file. Absent ⇒ `undefined` (the normal case). Present-but-wrong is a typed error\n * naming the file: a malformed credential store must not surface as a raw parse crash. Enforces the\n * 0700 dir / 0600 file mode gates (ported verbatim — a writable dir lets an attacker swap the file for a\n * symlink to their own account).\n */\nexport function readAuthFile(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredCredential | undefined {\n const path = authFilePath(config, env);\n\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw new CredentialError(`cannot read ${path}: ${(err as Error).message}`);\n }\n\n assertSecureModes(credentialHome(config, env), path);\n return parseStoredFile(raw, path);\n}\n\n/**\n * Read the stored OAuth credential (with its refresh token), or `undefined` when the store is absent or\n * holds an api credential. The oauth engine needs the refresh token, which the resolved bearer does not\n * carry. Enforces the same 0600/0700 gates as every other read.\n */\nexport function readStoredOAuth(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredOAuthCredential | undefined {\n const stored = readAuthFile(config, env);\n return stored !== undefined && stored.type === \"oauth\" ? stored : undefined;\n}\n\n/** Narrows a writable credential to the oauth variant. */\nfunction isOAuthWrite(\n c: { provider: string; apiKey: string } | StoredOAuthCredential,\n): c is StoredOAuthCredential {\n return \"type\" in c && c.type === \"oauth\";\n}\n\n/** Build the on-disk JSON payload for the credential variant, validating non-empty tokens. */\nfunction buildStorePayload(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n): Record<string, unknown> {\n if (isOAuthWrite(cred)) {\n if (cred.access.length === 0 || cred.refresh.length === 0) {\n throw new CredentialError(\n \"refusing to write an oauth credential with an empty access/refresh token\",\n );\n }\n return {\n type: \"oauth\",\n provider: cred.provider,\n access: cred.access,\n refresh: cred.refresh,\n expires: cred.expires,\n ...(cred.account_id !== undefined ? { account_id: cred.account_id } : {}),\n };\n }\n if (typeof cred.apiKey !== \"string\" || cred.apiKey.length === 0) {\n throw new CredentialError(\"refusing to write an empty API key\");\n }\n return { provider: cred.provider, api_key: cred.apiKey };\n}\n\n/**\n * Persist a credential atomically at mode `0600`. Ported VERBATIM (ADR D3): write to a random-named temp\n * file in the same directory with `wx` (O_EXCL), fsync, close, chmod, then `rename` (atomic on POSIX) —\n * so a crash mid-write leaves whatever was there untouched, and a pre-planted symlink cannot capture the\n * key. The api variant persists the unchanged `{provider, api_key}` (back-compat, no `type` key); the\n * oauth variant persists `{type:'oauth', provider, access, refresh, expires, account_id?}`.\n */\nexport function writeCredential(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const payload = buildStorePayload(cred);\n\n const dir = credentialHome(config, env);\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n chmodSync(dir, 0o700); // unconditional: mkdirSync's mode applies only at creation\n\n const path = authFilePath(config, env);\n // RANDOM name + `wx` (O_EXCL): a predictable temp name with a plain write follows a pre-planted SYMLINK,\n // landing the key in an attacker's file while reporting success. O_EXCL refuses any pre-existing file or\n // link; the random suffix also removes the pid collision two containers sharing a bind-mounted home make.\n const tmp = `${path}.tmp-${randomBytes(8).toString(\"hex\")}`;\n try {\n const fd = openSync(tmp, \"wx\", 0o600);\n try {\n writeFileSync(fd, `${JSON.stringify(payload, null, 2)}\\n`);\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n chmodSync(tmp, 0o600); // explicit: the mode argument is subject to umask\n renameSync(tmp, path);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n // the temp file may not exist; its absence is not a failure of the write\n }\n throw new CredentialError(`cannot write ${path}: ${(err as Error).message}`);\n }\n return path;\n}\n"]}
|