Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
667 changes: 338 additions & 329 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/ai/advisor.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* @file Spawn advisor — composes tier + route + billing + profile into ONE
* call so callers stop hand-wiring the AI stack layer by layer. Given a
* @file Spawn advisor — composes tier + route + billing + profile into ONE call
* so callers stop hand-wiring the AI stack layer by layer. Given a
* `TaskClass` and a probed `RouteContext` (plus an optional
* `BillingContext`), `adviseSpawn` resolves the capability tier
* (`taskClassToTier`), orders the usable cross-engine candidates
Expand All @@ -10,8 +10,8 @@
* I/O, no spawn: the caller still probes availability/billing once
* (`billing-context.mts`) and hands the resulting `RouteContext` /
* `BillingContext` in, then calls `spawnAiAgent` / `spawnTierWithFallback`
* with the advice. Modeled on the "advisor" pattern from Copilot-style
* CLIs: one seam a skill consults instead of importing four modules and
* with the advice. Modeled on the "advisor" pattern from Copilot-style CLIs:
* one entry point a skill consults instead of importing four modules and
* reimplementing the same composition at every call site.
*/

Expand Down
2 changes: 1 addition & 1 deletion src/ai/builtin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export type LanguageModelAvailability =
| 'unavailable'

/**
* Stable factory seam shared by Chrome and the native Node implementations.
* Stable factory boundary shared by Chrome and the native Node implementations.
* The session is intentionally opaque while the Prompt API surface is still
* changing across browser versions.
*/
Expand Down
12 changes: 6 additions & 6 deletions src/ai/credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* hook-point: the forthcoming biometric credential daemon slots in as a
* layer between the env check and the keychain read inside `resolve()`'s
* implementation — call sites here do not change when it lands. This module
* is the stable seam.
* is the stable injection point.
*/

import { resolve } from '../secrets/find'
Expand All @@ -43,11 +43,11 @@ export type KeyedCredentialProvider =

/**
* The keyless on-device provider: a `local` engine (the `builtin.mts`
* LanguageModel seam / an injected local runner) that needs NO credential — it
* runs on the machine, so it is "always present with no token". It is a
* `CredentialProvider` so routing can name it uniformly, but it is deliberately
* NOT in `PROVIDER_CREDENTIALS` because there is nothing to resolve. Use
* `isKeylessProvider` to branch before a token lookup.
* LanguageModel injection point / an injected local runner) that needs NO
* credential — it runs on the machine, so it is "always present with no token".
* It is a `CredentialProvider` so routing can name it uniformly, but it is
* deliberately NOT in `PROVIDER_CREDENTIALS` because there is nothing to
* resolve. Use `isKeylessProvider` to branch before a token lookup.
*/
export const KEYLESS_PROVIDER = 'local' as const

Expand Down
22 changes: 11 additions & 11 deletions src/ai/exec.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
/**
* @file Exec-backend seam: WHERE a shell command runs, a separate axis from
* WHICH model produced it (`ai/backends`). The lib owns the INTERFACE plus
* the cheap built-in `real` runner (the host shell via lib `spawn`); a
* SANDBOXED runner is INJECTED by the caller, never imported here. That keeps
* the small-dist lib free of a heavy sandbox dependency — Socket's sandbox
* of choice (`just-bash`, ~40MB incl. WASM) is owned by the wheelhouse hook /
* CI tooling and passed in, so a lib consumer that never sandboxes pays
* nothing. Layering: ExecRunner.run() — the injectable primitive (real |
* sandboxed) composed into ExecContext — { runners: { real, sandboxed? },
* resolve(trust) } used by runShell(script, { context, trust }) — the
* ergonomic entry point Pick a runner by TRUST LEVEL, never by model.
* @file Exec-backend injection point: WHERE a shell command runs, a separate
* axis from WHICH model produced it (`ai/backends`). The lib owns the
* INTERFACE plus the cheap built-in `real` runner (the host shell via lib
* `spawn`); a SANDBOXED runner is INJECTED by the caller, never imported
* here. That keeps the small-dist lib free of a heavy sandbox dependency —
* Socket's sandbox of choice (`just-bash`, ~40MB incl. WASM) is owned by the
* wheelhouse hook / CI tooling and passed in, so a lib consumer that never
* sandboxes pays nothing. Layering: ExecRunner.run() — the injectable
* primitive (real | sandboxed) composed into ExecContext — { runners: { real,
* sandboxed? }, resolve(trust) } used by runShell(script, { context, trust })
* — the ergonomic entry point Pick a runner by TRUST LEVEL, never by model.
* `untrusted` resolves to the sandboxed runner — which a caller that hasn't
* injected one cannot run, so `resolve` throws a clear "provide a sandboxed
* runner" error rather than silently falling back to the host shell. Both
Expand Down
2 changes: 1 addition & 1 deletion src/ai/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* code fences, synonymous keys, an object that ends one `}` short, or prose
* wrapped around the payload. The router already parses JSON out of model
* output (`cost.mts` reads usage objects), so these tolerant, pure repair
* primitives live here as the shared seam: strip a fence, normalize
* primitives live here as the shared boundary: strip a fence, normalize
* typographic punctuation, canonicalize keys, extract the first balanced
* object, or close an under-terminated one. Every function is pure and
* allocation-light, and each runs only on a REPAIR path after a strict parse
Expand Down
21 changes: 11 additions & 10 deletions src/ai/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ import type { AiTier } from './tier'
* A non-CLI, on-device engine. Distinct from `AiAgentName` (the agent CLIs that
* drive `spawn.mts`'s per-agent switch and the `which` probe) so a keyless
* local target is nameable WITHOUT widening the CLI unions. `builtin` is the
* `builtin.mts` LanguageModel seam (`getLanguageModel()`); the heavy provider
* impl is injected at the spawn layer (`spawn-local.mts`), never imported
* here.
* `builtin.mts` LanguageModel injection point (`getLanguageModel()`); the heavy
* provider impl is injected at the spawn layer (`spawn-local.mts`), never
* imported here.
*/
export type LocalEngineName = 'builtin'

Expand All @@ -52,10 +52,10 @@ export interface CliTierCandidate {

/**
* A keyless on-device target: a `local` engine driven through the `builtin.mts`
* LanguageModel seam or an injected local provider (see `spawn-local.mts`). It
* carries `kind: 'local'`, `provider: 'local'` (keyless — no credential gates
* it), and a non-CLI `engine`. Reserved for grunt-tier TAIL rungs; never a
* chain head.
* LanguageModel injection point or an injected local provider (see
* `spawn-local.mts`). It carries `kind: 'local'`, `provider: 'local'` (keyless
* — no credential gates it), and a non-CLI `engine`. Reserved for grunt-tier
* TAIL rungs; never a chain head.
*/
export interface LocalTierCandidate {
readonly effort: AiEffort | undefined
Expand Down Expand Up @@ -98,9 +98,10 @@ export interface RouteContext {
readonly keyed: ReadonlySet<CredentialProvider>
/**
* Whether the keyless local engine is usable, probed once by the caller via
* the `builtin.mts` availability seam (`getLanguageModel().availability()` —
* see `isLocalEngineAvailable` in `spawn-local.mts`). Undefined/false means a
* `local` candidate is skipped, so callers that never probe are unaffected.
* the `builtin.mts` availability injection point
* (`getLanguageModel().availability()` — see `isLocalEngineAvailable` in
* `spawn-local.mts`). Undefined/false means a `local` candidate is skipped,
* so callers that never probe are unaffected.
*/
readonly localAvailable?: boolean | undefined
}
Expand Down
10 changes: 5 additions & 5 deletions src/ai/spawn-local.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* @file Keyless on-device execution seam for a `local` TierCandidate, the
* @file Keyless on-device execution path for a `local` TierCandidate, the
* non-CLI complement to `spawn.mts`. Where `spawnAiAgent` shells out to an
* installed agent CLI, this drives an on-device LanguageModel and normalizes
* the reply into the SAME `AgentSpawnResult` shape, so a caller (or
Expand All @@ -10,7 +10,7 @@
* provider — a real on-device model such as odai — is INJECTED by the caller
* and never imported here. That keeps the small-dist lib free of any model
* dependency: a consumer that never routes local pays nothing, and the local
* engine is discovered lazily through the seam.
* engine is discovered lazily through the injection point.
*/

import { errorMessage } from '../errors/message'
Expand Down Expand Up @@ -140,9 +140,9 @@ export function isLocalModelSession(
* Tier-orchestration entry: run a `local` candidate for
* `spawnTierWithFallback`. Maps the shared spawn options plus the candidate's
* model onto a `LocalSpawnOptions`, defaults the provider to the built-in
* LanguageModel seam, and normalizes prototype-polluted input. Kept here (not
* inline in spawn.mts) so the null-proto normalization and provider default
* live beside the local seam they belong to.
* LanguageModel injection point, and normalizes prototype-polluted input. Kept
* here (not inline in spawn.mts) so the null-proto normalization and provider
* default live beside the local path they belong to.
*/
export async function runLocalTierSpawn(
options: Pick<SpawnAiAgentOptions, 'cwd' | 'prompt' | 'timeoutMs'>,
Expand Down
2 changes: 1 addition & 1 deletion src/ai/spawn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ export async function spawnTierWithFallback(
let last: { candidate: TierCandidate; result: AgentSpawnResult } | undefined
for (let i = 0, { length } = candidates; i < length; i += 1) {
const candidate = candidates[i]!
// A `local` candidate drives the keyless on-device seam (returning the same
// A `local` candidate drives the keyless on-device path (returning the same
// AgentSpawnResult) so the fall-over logic below stays uniform across kinds.
const result =
candidate.kind === 'local'
Expand Down
8 changes: 4 additions & 4 deletions src/exe/smol/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
* an in-C++ `findUp`). Returns `undefined` on stock Node, non-Node runtimes,
* and on socket-btm binaries that haven't shipped the binding yet; callers
* fall back to the JS implementation. Result is cached. The binding does not
* exist yet, since the plan is unbuilt. This accessor is the seam so that
* when it lands, only this file changes and `paths/walk`, `fs/access`, and
* `fs/find` light up natively. Today `getSmolPath()` is always `undefined`
* and the JS paths run.
* exist yet, since the plan is unbuilt. This accessor is the injection point
* so that when it lands, only this file changes and `paths/walk`,
* `fs/access`, and `fs/find` light up natively. Today `getSmolPath()` is
* always `undefined` and the JS paths run.
*/

import { isNodeBuiltin, requireBuiltin } from '../../node/module'
Expand Down
12 changes: 6 additions & 6 deletions src/fs/allowed-dirs-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ export function invalidatePathCache(): void {
* module-init turn, so the circular import is fully wired before the call.
* Guarded + self-rescheduling: in the require cycle (`allowed-dirs-cache →
* shared → paths/socket → … → rewire`) the `registerCacheInvalidation` live
* binding can still be in its temporal dead zone when the first microtask
* fires under some import orders, throwing `registerCacheInvalidation is not
* defined`. Vitest loads many modules concurrently, so those orders do come
* up. Check that the binding is callable; if not, re-defer to the next
* microtask. The registration is a test-seam best-effort that lets path-rewire
* flush this cache, so a bounded retry that lands on a later turn is correct. A
* binding can still be in its temporal dead zone when the first microtask fires
* under some import orders, throwing `registerCacheInvalidation is not
* defined`. Vitest loads many modules concurrently, so those orders do come up.
* Check that the binding is callable; if not, re-defer to the next microtask.
* The registration is a test-injection best-effort that lets path-rewire flush
* this cache, so a bounded retry that lands on a later turn is correct. A
* never-resolving binding, as in production where rewire is unused, simply
* stops retrying without throwing.
*
Expand Down
4 changes: 2 additions & 2 deletions src/github/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { safeDeleteSync } from '../fs/safe'

/**
* How long a `gh` invocation may run before it is killed. A CLI call that has
* not answered in this long is wedged rather than slow: `gh` does its own
* not answered in this long is unresponsive rather than slow: `gh` does its own
* network retries well inside it.
*/
export const GH_DEFAULT_TIMEOUT_MS = 30_000
Expand Down Expand Up @@ -83,7 +83,7 @@ export interface GhResult {
/**
* Options for {@link runGh}. `body` is JSON text written to a temp file whose
* path replaces {@link GH_BODY_PLACEHOLDER}. `spawnGh` is the injectable launch
* seam, so a test drives the runner without a `gh` binary present.
* injection point, so a test drives the runner without a `gh` binary present.
*/
export interface RunGhOptions {
readonly body?: string | undefined
Expand Down
13 changes: 7 additions & 6 deletions src/node/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
* capture when `getNodeFs` is unused. Was a lazy first-call loader; the
* eager-but-guarded form keeps the browser-safe behavior while gaining the
* load-time snapshot. Two surfaces: `getNodeFs()` returns the module object
* with LATE method lookup (spy-able — the test seam); the `fs<Method>` consts
* (`fsExistsSync`, `fsReadFileSync`, …) are method references FROZEN at
* load, tamper-proof against a method swap but not spy-able, for Socket's
* hot fs calls. Both stay browser-safe behind IS_NODE + `/*@__PURE__*\/`.
* with LATE method lookup (spy-able — the test injection point); the
* `fs<Method>` consts (`fsExistsSync`, `fsReadFileSync`, …) are method
* references FROZEN at load, tamper-proof against a method swap but not
* spy-able, for Socket's hot fs calls. Both stay browser-safe behind IS_NODE
* \+ `/*@__PURE__*\/`.
*/

import type * as NodeFs from 'node:fs'
Expand All @@ -32,7 +33,7 @@ const nodeFs = IS_NODE ? /*@__PURE__*/ require('fs') : undefined
// `getNodeFs()` returns the captured MODULE object; methods are looked up LATE
// off it (`getNodeFs().existsSync(...)`). That is deliberate: the object
// snapshot defends against `require.cache['fs']` redirection, while late method
// lookup keeps the test seam intact — a `vi.spyOn(getNodeFs(), 'existsSync')`
// lookup keeps the test injection point intact — a `vi.spyOn(getNodeFs(), 'existsSync')`
// (or a direct property swap, as binary-cache.test does) is still observed.
// For a HOT path that wants tamper-proof methods too (a method swap on the
// captured object can't redirect a frozen ref), use the `fs<Method>` consts
Expand All @@ -48,7 +49,7 @@ export function getNodeFs(): typeof NodeFs {
// binding needed — verified), so a plain member read freezes the reference:
// unlike `getNodeFs().existsSync`, a later `nodeFs.existsSync = evil` cannot
// redirect these — the method-level twin of the object snapshot. Frozen refs
// are NOT spy-able — use `getNodeFs()` for the test-seam path; reach for these
// are NOT spy-able — use `getNodeFs()` for the test injection path; reach for these
// only on a hot path that wants tamper-resistance. Exported as direct consts
// (the `primordials/intl` shape) so there's no helper/getter to sort and no
// `/*@__PURE__*/`-on-a-call concern; an unused const tree-shakes on its own.
Expand Down
2 changes: 1 addition & 1 deletion src/node/os.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function getNodeOs(): typeof NodeOs {
// ── Frozen hot-method snapshots ──────────────────────────────────────
// Socket's hottest os methods, captured by reference at load off the
// IS_NODE-gated module, which is undefined in a browser. Frozen refs aren't
// spy-able — use `getNodeOs()` for the test-seam path. See node/fs.ts for the
// spy-able — use `getNodeOs()` for the test injection path. See node/fs.ts for the
// full two-surface rationale.
export const osArch = nodeOs?.arch
export const osHomedir = nodeOs?.homedir
Expand Down
2 changes: 1 addition & 1 deletion src/node/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function getNodePath(): typeof NodePath {
// IS_NODE-gated module, which is undefined in a browser. path methods are
// standalone (no `this`), so a member read freezes the reference; a later
// `nodePath.join = evil` can't redirect these. Frozen refs aren't spy-able —
// use `getNodePath()` for the test-seam path. Direct-const exports (the
// use `getNodePath()` for the test injection path. Direct-const exports (the
// primordials/intl shape) keep it sort-clean + tree-shakable.
export const pathBasename = nodePath?.basename
export const pathDirname = nodePath?.dirname
Expand Down
6 changes: 3 additions & 3 deletions src/primordials/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
* is CALLED at access time off that captured object — so `vi.spyOn(process,
* 'cwd')`, which mutates the same captured object, still intercepts. Binding
* the method reference instead (`process.cwd.bind(process)`) would freeze it
* and break that test seam, so we deliberately keep the late call. Consumers
* read cwd / platform / env / argv through these instead of touching
* `process` directly; enforced Socket-wide by
* and break that test injection point, so we deliberately keep the late call.
* Consumers read cwd / platform / env / argv through these instead of
* touching `process` directly; enforced Socket-wide by
* `socket/prefer-process-primordial`. This is the `process` leaf of the
* node-module primordials: where `node/fs` / `node/path` lazy-load a `node:`
* module behind a function, this captures the always-present `process` global
Expand Down
Loading
Loading