@skrr-ai/cli 0.1.49 → 0.1.51
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/README.md +5 -4
- package/dist/base-command.js +75 -6
- package/dist/commands/agents/chat.d.ts +14 -0
- package/dist/commands/agents/chat.js +37 -1
- package/dist/commands/agents/create.js +14 -7
- package/dist/commands/agents/show.d.ts +9 -0
- package/dist/commands/agents/show.js +53 -0
- package/dist/commands/agents/update.d.ts +9 -0
- package/dist/commands/agents/update.js +38 -5
- package/dist/commands/balance/show.d.ts +34 -0
- package/dist/commands/balance/show.js +92 -2
- package/dist/commands/code/index.d.ts +1 -0
- package/dist/commands/code/index.js +49 -5
- package/dist/commands/code/run.js +5 -1
- package/dist/commands/commitments/cycles.d.ts +19 -0
- package/dist/commands/commitments/cycles.js +46 -0
- package/dist/commands/commitments/doctor.d.ts +1 -0
- package/dist/commands/commitments/doctor.js +19 -4
- package/dist/commands/commitments/effective-policy.js +40 -1
- package/dist/commands/commitments/explain.d.ts +17 -0
- package/dist/commands/commitments/explain.js +40 -0
- package/dist/commands/commitments/next-tick.js +3 -1
- package/dist/commands/commitments/preflight.js +10 -0
- package/dist/commands/commitments/show.js +11 -1
- package/dist/commands/daemon/config.d.ts +15 -0
- package/dist/commands/daemon/config.js +38 -0
- package/dist/commands/daemon/index.js +1 -0
- package/dist/commands/daemon/status.js +15 -1
- package/dist/commands/goals/create.d.ts +1 -0
- package/dist/commands/goals/create.js +22 -0
- package/dist/commands/harnesses/models.d.ts +54 -0
- package/dist/commands/harnesses/models.js +100 -7
- package/dist/commands/harnesses/show.d.ts +11 -0
- package/dist/commands/harnesses/show.js +35 -0
- package/dist/commands/harnesses/update.d.ts +28 -1
- package/dist/commands/harnesses/update.js +73 -10
- package/dist/commands/logout.js +12 -1
- package/dist/commands/machines/dedicated/index.js +1 -1
- package/dist/commands/machines/dedicated/sign-in.js +4 -1
- package/dist/commands/machines/dedicated/terminal/kill.d.ts +21 -0
- package/dist/commands/machines/dedicated/terminal/kill.js +55 -0
- package/dist/commands/machines/dedicated/terminal/ls.d.ts +22 -0
- package/dist/commands/machines/dedicated/terminal/ls.js +70 -0
- package/dist/commands/machines/dedicated/terminal/rename.d.ts +23 -0
- package/dist/commands/machines/dedicated/terminal/rename.js +64 -0
- package/dist/commands/machines/dedicated/terminal.d.ts +9 -0
- package/dist/commands/machines/dedicated/terminal.js +27 -2
- package/dist/commands/machines/hosted/connect.js +2 -2
- package/dist/commands/machines/hosted/destroy.js +1 -1
- package/dist/commands/machines/hosted/exec.js +1 -1
- package/dist/commands/machines/hosted/list.js +1 -1
- package/dist/commands/machines/hosted/pause.js +1 -1
- package/dist/commands/machines/hosted/pull.js +1 -1
- package/dist/commands/machines/hosted/resume.js +1 -1
- package/dist/commands/machines/hosted/start.js +2 -2
- package/dist/commands/machines/hosted/status.js +2 -1
- package/dist/commands/outbox/list.d.ts +12 -1
- package/dist/commands/outbox/list.js +31 -2
- package/dist/commands/revoke-daemon.js +9 -0
- package/dist/commands/spaces/create.d.ts +1 -0
- package/dist/commands/spaces/create.js +17 -0
- package/dist/commands/spaces/show.js +5 -0
- package/dist/commands/spaces/update.d.ts +1 -0
- package/dist/commands/spaces/update.js +16 -0
- package/dist/commands/tasks/create.d.ts +1 -0
- package/dist/commands/tasks/create.js +6 -0
- package/dist/commands/tasks/list.js +1 -0
- package/dist/commands/tasks/show.js +45 -0
- package/dist/commands/tasks/update.d.ts +1 -0
- package/dist/commands/tasks/update.js +22 -0
- package/dist/commands/tasks/upsert.d.ts +1 -0
- package/dist/commands/tasks/upsert.js +16 -0
- package/dist/lib/agent-config.d.ts +2 -0
- package/dist/lib/agent-config.js +3 -1
- package/dist/lib/agentic-stream.d.ts +68 -1
- package/dist/lib/agentic-stream.js +294 -7
- package/dist/lib/api-fetch.js +19 -0
- package/dist/lib/auth-core-init.d.ts +2 -10
- package/dist/lib/auth-core-init.js +20 -67
- package/dist/lib/auth-failure.d.ts +33 -0
- package/dist/lib/auth-failure.js +65 -0
- package/dist/lib/auth-storage.d.ts +14 -0
- package/dist/lib/auth-storage.js +14 -0
- package/dist/lib/commitments.d.ts +37 -2
- package/dist/lib/commitments.js +148 -0
- package/dist/lib/daemonBroker.d.ts +134 -31
- package/dist/lib/daemonBroker.js +376 -31
- package/dist/lib/dedicated-lease-command.d.ts +14 -0
- package/dist/lib/dedicated-lease-command.js +30 -1
- package/dist/lib/dedicated-machines.js +8 -25
- package/dist/lib/dedicated-service-command.d.ts +11 -3
- package/dist/lib/dedicated-service-command.js +20 -3
- package/dist/lib/dedicated-service.d.ts +46 -0
- package/dist/lib/dedicated-service.js +85 -7
- package/dist/lib/dedicated-terminal.d.ts +21 -0
- package/dist/lib/dedicated-terminal.js +104 -9
- package/dist/lib/delegated-cli.js +4 -1
- package/dist/lib/exec-runtime-binary.d.ts +3 -1
- package/dist/lib/exec-runtime-binary.js +4 -2
- package/dist/lib/first-party-harness-broker.d.ts +10 -0
- package/dist/lib/first-party-harness-broker.js +13 -1
- package/dist/lib/first-party-harness-doctor.js +41 -1
- package/dist/lib/first-party-harness-managed.d.ts +4 -3
- package/dist/lib/first-party-harness-project-trust.d.ts +125 -0
- package/dist/lib/first-party-harness-project-trust.js +364 -0
- package/dist/lib/first-party-harness.d.ts +9 -2
- package/dist/lib/first-party-harness.js +6 -5
- package/dist/lib/harnesses.d.ts +10 -0
- package/dist/lib/hosted-machines.d.ts +10 -1
- package/dist/lib/hosted-machines.js +36 -2
- package/dist/lib/live-runtime-binary.d.ts +40 -0
- package/dist/lib/live-runtime-binary.js +193 -0
- package/dist/lib/login.d.ts +23 -0
- package/dist/lib/login.js +60 -10
- package/dist/lib/machine-spend-cap.d.ts +23 -0
- package/dist/lib/machine-spend-cap.js +68 -0
- package/dist/lib/message-intent.js +3 -1
- package/dist/lib/node-adapter.js +15 -3
- package/dist/lib/tasks.d.ts +20 -0
- package/dist/lib/tasks.js +54 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/cliHandoffWire.d.ts +90 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/cliHandoffWire.js +113 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialEnvelopeBridge.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialEnvelopeBridge.js +26 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialSession.d.ts +47 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialSession.js +69 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonToolApproval.d.ts +133 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonToolApproval.js +189 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.js +41 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +3 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +25 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/loopbackHttp.d.ts +32 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/loopbackHttp.js +268 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineId.d.ts +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineId.js +11 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.d.ts +36 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.js +156 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/messages.d.ts +8 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/messages.js +9 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refresh.d.ts +8 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refresh.js +16 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refreshClassification.d.ts +6 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refreshClassification.js +32 -9
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/sessionPermissionAuthority.d.ts +81 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/sessionPermissionAuthority.js +87 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.d.ts +22 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.js +61 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/types.d.ts +6 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/cliHandoffWire.d.ts +90 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/cliHandoffWire.js +105 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialEnvelopeBridge.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialEnvelopeBridge.js +25 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialSession.d.ts +47 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialSession.js +66 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonToolApproval.d.ts +133 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonToolApproval.js +182 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.js +41 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +3 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +10 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/loopbackHttp.d.ts +32 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/loopbackHttp.js +257 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineId.d.ts +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineId.js +11 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.d.ts +36 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.js +147 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/messages.d.ts +8 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/messages.js +9 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refresh.d.ts +8 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refresh.js +16 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refreshClassification.d.ts +6 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refreshClassification.js +31 -9
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/sessionPermissionAuthority.d.ts +81 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/sessionPermissionAuthority.js +80 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.d.ts +22 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.js +58 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/types.d.ts +6 -1
- package/dist/node_modules/@skrr-ai/auth-core/package.json +61 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +3418 -3344
- package/oclif.manifest.json +24813 -24242
- package/package.json +4 -1
|
@@ -33,6 +33,33 @@ const PERMANENT_CODE_SET = new Set([
|
|
|
33
33
|
'REFRESH_EXPIRED',
|
|
34
34
|
'SESSION_REVOKED',
|
|
35
35
|
]);
|
|
36
|
+
/**
|
|
37
|
+
* Server refusal codes that are permanent but are not themselves reason names.
|
|
38
|
+
*
|
|
39
|
+
* `DEVICE_PROOF_THUMBPRINT_MISMATCH` (`daemonRefreshTokens.verifyDeviceProofPinForRow`)
|
|
40
|
+
* means the proof was signed by a key other than the one enrolled on the daemon's
|
|
41
|
+
* row. Every retry is signed by the same key, so it can never succeed — but
|
|
42
|
+
* because it was not in the set above it fell through to the unknown-401 path,
|
|
43
|
+
* where a daemon retrying on a five-minute cadence never exhausted its budget:
|
|
44
|
+
* one laptop logged 741 "transient, retrying" refusals over four days, and the
|
|
45
|
+
* reason it eventually surfaced was `UNKNOWN_401` (OSK-12056).
|
|
46
|
+
*/
|
|
47
|
+
const PERMANENT_CODE_ALIASES = {
|
|
48
|
+
REFRESH_MISSING: 'REFRESH_INVALID',
|
|
49
|
+
DEVICE_PROOF_THUMBPRINT_MISMATCH: 'DEVICE_KEY_MISMATCH',
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* The permanent reason a 401 refresh refusal's `code` names, or `null` when the
|
|
53
|
+
* code is missing or unrecognised (an unknown-shape 401). The ONE mapping both
|
|
54
|
+
* this classifier and the daemon's `refresh.ts` read.
|
|
55
|
+
*/
|
|
56
|
+
export function permanentReasonForRefreshCode(code) {
|
|
57
|
+
if (!code)
|
|
58
|
+
return null;
|
|
59
|
+
if (PERMANENT_CODE_SET.has(code))
|
|
60
|
+
return code;
|
|
61
|
+
return PERMANENT_CODE_ALIASES[code] ?? null;
|
|
62
|
+
}
|
|
36
63
|
/**
|
|
37
64
|
* Classify an HTTP response from /api/auth/refresh (or /api/daemons/token/refresh)
|
|
38
65
|
* into a discriminated union of success or failure.
|
|
@@ -65,17 +92,12 @@ export function classifyRefreshResponse(status, body) {
|
|
|
65
92
|
}
|
|
66
93
|
// 401 — auth failure; check for known permanent code
|
|
67
94
|
if (status === 401) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
failure: new PermanentAuthFailure('REFRESH_INVALID', body.message ?? 'Refresh token missing'),
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
const code = body?.code;
|
|
75
|
-
if (code && PERMANENT_CODE_SET.has(code)) {
|
|
95
|
+
const reason = permanentReasonForRefreshCode(body?.code);
|
|
96
|
+
if (reason) {
|
|
97
|
+
const fallback = body?.code === 'REFRESH_MISSING' ? 'Refresh token missing' : reason;
|
|
76
98
|
return {
|
|
77
99
|
kind: 'failure',
|
|
78
|
-
failure: new PermanentAuthFailure(
|
|
100
|
+
failure: new PermanentAuthFailure(reason, body?.message ?? fallback),
|
|
79
101
|
};
|
|
80
102
|
}
|
|
81
103
|
// Unknown-shape 401 (no code, or a code we don't recognise). This is NOT a
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session permission authority — the ONE rule that decides whether a session's
|
|
3
|
+
* execution contract governs the run's permissions, shared by the server and
|
|
4
|
+
* the daemon (OSK-11975 introduced it; it was implemented twice — the server
|
|
5
|
+
* read `kind !== 'commitment'`, the daemon read the `permissionSource` marker —
|
|
6
|
+
* which is exactly how a new contract kind or a new source value would drift
|
|
7
|
+
* them apart).
|
|
8
|
+
*
|
|
9
|
+
* The wire model:
|
|
10
|
+
*
|
|
11
|
+
* - The contract is closed (`hasOnlyKeys` on the daemon), so "whose
|
|
12
|
+
* permissions govern" can never ride INSIDE it. It is a top-level session
|
|
13
|
+
* field: `permissionSource`.
|
|
14
|
+
* - `'agent'` means the Agent's own configured permission mode, tool policy,
|
|
15
|
+
* Grants, session env, MCP servers and machine consent govern the run,
|
|
16
|
+
* exactly as for an unattended Task of the same Agent. Today only a
|
|
17
|
+
* `commitment` contract may carry it.
|
|
18
|
+
* - A `commitment` contract WITHOUT the marker (an older server mid-deploy)
|
|
19
|
+
* still governs permissions — the marker is the version signal, so its
|
|
20
|
+
* absence must keep the legacy fence, not silently lift it.
|
|
21
|
+
* - `task_delivery` contracts always govern, marker or not.
|
|
22
|
+
*
|
|
23
|
+
* Server vs daemon asymmetry, on purpose: the server STAMPS the marker
|
|
24
|
+
* (`permissionSourceForContract`), so on its own side the predicate reduces to
|
|
25
|
+
* "a commitment never governs" — `contractGovernsPermissions(c,
|
|
26
|
+
* permissionSourceForContract(c))` is exactly `kind !== 'commitment'`. The
|
|
27
|
+
* daemon reads the marker it received, because it cannot distinguish "new
|
|
28
|
+
* server, agent permissions" from "old server, contract fence" any other way.
|
|
29
|
+
* Both call the same function; only the input differs.
|
|
30
|
+
*/
|
|
31
|
+
/** The wire vocabulary for `permissionSource`. Top-level session field. */
|
|
32
|
+
export declare const SESSION_PERMISSION_SOURCES: readonly ["agent"];
|
|
33
|
+
export type SessionPermissionSource = (typeof SESSION_PERMISSION_SOURCES)[number];
|
|
34
|
+
/**
|
|
35
|
+
* The daemon capability that proves a build honours `permissionSource`. The
|
|
36
|
+
* server announces it in preflight and refuses to dispatch a Commitment Run to
|
|
37
|
+
* a daemon without it (`COMMITMENT_AGENT_PERMISSIONS_RUNTIME_UNSUPPORTED`), so
|
|
38
|
+
* the marker never reaches a daemon that would ignore it.
|
|
39
|
+
*/
|
|
40
|
+
export declare const COMMITMENT_AGENT_PERMISSIONS_CAPABILITY = "commitment_execution_contract_v2_agent_permissions";
|
|
41
|
+
/**
|
|
42
|
+
* The minimal contract shape this rule reads. The predicate only ever needs
|
|
43
|
+
* `kind` — keeping the input structural means this module never imports the
|
|
44
|
+
* full `CommitmentExecutionContract` type, which lives daemon-side
|
|
45
|
+
* (`daemon/src/commitment-execution-contract.ts`) and server-side in the
|
|
46
|
+
* commitment services.
|
|
47
|
+
*/
|
|
48
|
+
export type PermissionContractKind = {
|
|
49
|
+
kind?: unknown;
|
|
50
|
+
} | null | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Untrusted wire input: anything but an exact vocabulary literal reads as
|
|
53
|
+
* absent. Never widen by coercion — an unrecognized future value must degrade
|
|
54
|
+
* to "contract governs", the conservative answer.
|
|
55
|
+
*/
|
|
56
|
+
export declare function normalizeSessionPermissionSource(value: unknown): SessionPermissionSource | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* What the server stamps on the wire for this contract. A `commitment`
|
|
59
|
+
* contract no longer carries permissions (OSK-11975); every other contract
|
|
60
|
+
* kind keeps its own authority and stamps nothing.
|
|
61
|
+
*/
|
|
62
|
+
export declare function permissionSourceForContract(contract: PermissionContractKind): SessionPermissionSource | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Whether the contract is the run's PERMISSION authority — the single place
|
|
65
|
+
* this rule lives.
|
|
66
|
+
*
|
|
67
|
+
* True for a non-commitment contract regardless of marker, and for a
|
|
68
|
+
* commitment whose server did not declare agent permissions. False for no
|
|
69
|
+
* contract at all, and for a commitment carrying `permissionSource: 'agent'`,
|
|
70
|
+
* which then follows the Agent's own permissions exactly as a Task does while
|
|
71
|
+
* the contract keeps its non-permission roles (normalized shape, ephemeral
|
|
72
|
+
* worktree, result validation, `GIT_OPTIONAL_LOCKS`, provider restriction).
|
|
73
|
+
*/
|
|
74
|
+
export declare function contractGovernsPermissions(contract: PermissionContractKind, permissionSource: unknown): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* The contract when it governs permissions, else `undefined` — for the sites
|
|
77
|
+
* that used `executionContract` as "is this run permission-fenced".
|
|
78
|
+
*/
|
|
79
|
+
export declare function permissionGoverningContract<T extends {
|
|
80
|
+
kind?: unknown;
|
|
81
|
+
}>(contract: T | null | undefined, permissionSource: unknown): T | undefined;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session permission authority — the ONE rule that decides whether a session's
|
|
3
|
+
* execution contract governs the run's permissions, shared by the server and
|
|
4
|
+
* the daemon (OSK-11975 introduced it; it was implemented twice — the server
|
|
5
|
+
* read `kind !== 'commitment'`, the daemon read the `permissionSource` marker —
|
|
6
|
+
* which is exactly how a new contract kind or a new source value would drift
|
|
7
|
+
* them apart).
|
|
8
|
+
*
|
|
9
|
+
* The wire model:
|
|
10
|
+
*
|
|
11
|
+
* - The contract is closed (`hasOnlyKeys` on the daemon), so "whose
|
|
12
|
+
* permissions govern" can never ride INSIDE it. It is a top-level session
|
|
13
|
+
* field: `permissionSource`.
|
|
14
|
+
* - `'agent'` means the Agent's own configured permission mode, tool policy,
|
|
15
|
+
* Grants, session env, MCP servers and machine consent govern the run,
|
|
16
|
+
* exactly as for an unattended Task of the same Agent. Today only a
|
|
17
|
+
* `commitment` contract may carry it.
|
|
18
|
+
* - A `commitment` contract WITHOUT the marker (an older server mid-deploy)
|
|
19
|
+
* still governs permissions — the marker is the version signal, so its
|
|
20
|
+
* absence must keep the legacy fence, not silently lift it.
|
|
21
|
+
* - `task_delivery` contracts always govern, marker or not.
|
|
22
|
+
*
|
|
23
|
+
* Server vs daemon asymmetry, on purpose: the server STAMPS the marker
|
|
24
|
+
* (`permissionSourceForContract`), so on its own side the predicate reduces to
|
|
25
|
+
* "a commitment never governs" — `contractGovernsPermissions(c,
|
|
26
|
+
* permissionSourceForContract(c))` is exactly `kind !== 'commitment'`. The
|
|
27
|
+
* daemon reads the marker it received, because it cannot distinguish "new
|
|
28
|
+
* server, agent permissions" from "old server, contract fence" any other way.
|
|
29
|
+
* Both call the same function; only the input differs.
|
|
30
|
+
*/
|
|
31
|
+
/** The wire vocabulary for `permissionSource`. Top-level session field. */
|
|
32
|
+
export const SESSION_PERMISSION_SOURCES = ['agent'];
|
|
33
|
+
/**
|
|
34
|
+
* The daemon capability that proves a build honours `permissionSource`. The
|
|
35
|
+
* server announces it in preflight and refuses to dispatch a Commitment Run to
|
|
36
|
+
* a daemon without it (`COMMITMENT_AGENT_PERMISSIONS_RUNTIME_UNSUPPORTED`), so
|
|
37
|
+
* the marker never reaches a daemon that would ignore it.
|
|
38
|
+
*/
|
|
39
|
+
export const COMMITMENT_AGENT_PERMISSIONS_CAPABILITY = 'commitment_execution_contract_v2_agent_permissions';
|
|
40
|
+
/**
|
|
41
|
+
* Untrusted wire input: anything but an exact vocabulary literal reads as
|
|
42
|
+
* absent. Never widen by coercion — an unrecognized future value must degrade
|
|
43
|
+
* to "contract governs", the conservative answer.
|
|
44
|
+
*/
|
|
45
|
+
export function normalizeSessionPermissionSource(value) {
|
|
46
|
+
return SESSION_PERMISSION_SOURCES.includes(value)
|
|
47
|
+
? value
|
|
48
|
+
: undefined;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* What the server stamps on the wire for this contract. A `commitment`
|
|
52
|
+
* contract no longer carries permissions (OSK-11975); every other contract
|
|
53
|
+
* kind keeps its own authority and stamps nothing.
|
|
54
|
+
*/
|
|
55
|
+
export function permissionSourceForContract(contract) {
|
|
56
|
+
return contract?.kind === 'commitment' ? 'agent' : undefined;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Whether the contract is the run's PERMISSION authority — the single place
|
|
60
|
+
* this rule lives.
|
|
61
|
+
*
|
|
62
|
+
* True for a non-commitment contract regardless of marker, and for a
|
|
63
|
+
* commitment whose server did not declare agent permissions. False for no
|
|
64
|
+
* contract at all, and for a commitment carrying `permissionSource: 'agent'`,
|
|
65
|
+
* which then follows the Agent's own permissions exactly as a Task does while
|
|
66
|
+
* the contract keeps its non-permission roles (normalized shape, ephemeral
|
|
67
|
+
* worktree, result validation, `GIT_OPTIONAL_LOCKS`, provider restriction).
|
|
68
|
+
*/
|
|
69
|
+
export function contractGovernsPermissions(contract, permissionSource) {
|
|
70
|
+
if (!contract)
|
|
71
|
+
return false;
|
|
72
|
+
return !(contract.kind === 'commitment' && normalizeSessionPermissionSource(permissionSource) === 'agent');
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The contract when it governs permissions, else `undefined` — for the sites
|
|
76
|
+
* that used `executionContract` as "is this run permission-fenced".
|
|
77
|
+
*/
|
|
78
|
+
export function permissionGoverningContract(contract, permissionSource) {
|
|
79
|
+
return contract && contractGovernsPermissions(contract, permissionSource) ? contract : undefined;
|
|
80
|
+
}
|
|
@@ -84,3 +84,25 @@ export declare const SENSITIVE_ENV_PREFIX_EXCEPTIONS: ReadonlySet<string>;
|
|
|
84
84
|
* etc.) so legitimate tools keep working.
|
|
85
85
|
*/
|
|
86
86
|
export declare function sanitizeSpawnEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
87
|
+
/**
|
|
88
|
+
* OSK-12134 — loopback names a spawned child must reach directly, never through
|
|
89
|
+
* a proxy. A harness talks to this machine constantly: the daemon's local
|
|
90
|
+
* bridges (browser, delegated CLI, message intents), the inference broker, and
|
|
91
|
+
* the engine's own loopback services (skrr Code's `session/new` reaches a local
|
|
92
|
+
* directory service and failed with "service failure" behind a shell proxy).
|
|
93
|
+
*/
|
|
94
|
+
export declare const LOOPBACK_NO_PROXY_HOSTS: readonly string[];
|
|
95
|
+
/** True when `env` names a proxy some client in the child might honour. */
|
|
96
|
+
export declare function envHasProxy(env: Readonly<Record<string, string | undefined>>): boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Return `env` with the loopback hosts appended to BOTH `NO_PROXY` and
|
|
99
|
+
* `no_proxy`, when (and only when) it names a proxy. Tools disagree on which
|
|
100
|
+
* spelling they read and whether they fall back to the other, so an unset
|
|
101
|
+
* spelling is seeded from the other one before the hosts are appended —
|
|
102
|
+
* seeding only the hosts would silently drop every existing exemption for a
|
|
103
|
+
* tool that prefers the unset spelling. Existing entries keep their order.
|
|
104
|
+
*
|
|
105
|
+
* Exported for a parent that layers a proxy onto the child's env AFTER
|
|
106
|
+
* {@link sanitizeSpawnEnv}: call it again on the final map.
|
|
107
|
+
*/
|
|
108
|
+
export declare function withLoopbackNoProxy<T extends Record<string, string | undefined>>(env: T): T;
|
|
@@ -183,5 +183,62 @@ export function sanitizeSpawnEnv(env) {
|
|
|
183
183
|
continue;
|
|
184
184
|
out[key] = value;
|
|
185
185
|
}
|
|
186
|
-
return out;
|
|
186
|
+
return withLoopbackNoProxy(out);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* OSK-12134 — loopback names a spawned child must reach directly, never through
|
|
190
|
+
* a proxy. A harness talks to this machine constantly: the daemon's local
|
|
191
|
+
* bridges (browser, delegated CLI, message intents), the inference broker, and
|
|
192
|
+
* the engine's own loopback services (skrr Code's `session/new` reaches a local
|
|
193
|
+
* directory service and failed with "service failure" behind a shell proxy).
|
|
194
|
+
*/
|
|
195
|
+
export const LOOPBACK_NO_PROXY_HOSTS = ['127.0.0.1', 'localhost', '::1'];
|
|
196
|
+
const PROXY_ENV_VARS = [
|
|
197
|
+
'HTTP_PROXY',
|
|
198
|
+
'http_proxy',
|
|
199
|
+
'HTTPS_PROXY',
|
|
200
|
+
'https_proxy',
|
|
201
|
+
'ALL_PROXY',
|
|
202
|
+
'all_proxy',
|
|
203
|
+
];
|
|
204
|
+
/** True when `env` names a proxy some client in the child might honour. */
|
|
205
|
+
export function envHasProxy(env) {
|
|
206
|
+
return PROXY_ENV_VARS.some((name) => typeof env[name] === 'string' && env[name].trim() !== '');
|
|
207
|
+
}
|
|
208
|
+
function appendNoProxyHosts(list, hosts) {
|
|
209
|
+
const entries = list
|
|
210
|
+
.split(',')
|
|
211
|
+
.map((entry) => entry.trim().toLowerCase())
|
|
212
|
+
.filter(Boolean);
|
|
213
|
+
// `*` already exempts everything, and some clients honour it only as the
|
|
214
|
+
// entire value, so appending to it would break them.
|
|
215
|
+
if (entries.includes('*'))
|
|
216
|
+
return list;
|
|
217
|
+
const missing = hosts.filter((host) => !entries.includes(host));
|
|
218
|
+
if (missing.length === 0)
|
|
219
|
+
return list;
|
|
220
|
+
const kept = list.replace(/[\s,]+$/, '');
|
|
221
|
+
return kept ? `${kept},${missing.join(',')}` : missing.join(',');
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Return `env` with the loopback hosts appended to BOTH `NO_PROXY` and
|
|
225
|
+
* `no_proxy`, when (and only when) it names a proxy. Tools disagree on which
|
|
226
|
+
* spelling they read and whether they fall back to the other, so an unset
|
|
227
|
+
* spelling is seeded from the other one before the hosts are appended —
|
|
228
|
+
* seeding only the hosts would silently drop every existing exemption for a
|
|
229
|
+
* tool that prefers the unset spelling. Existing entries keep their order.
|
|
230
|
+
*
|
|
231
|
+
* Exported for a parent that layers a proxy onto the child's env AFTER
|
|
232
|
+
* {@link sanitizeSpawnEnv}: call it again on the final map.
|
|
233
|
+
*/
|
|
234
|
+
export function withLoopbackNoProxy(env) {
|
|
235
|
+
if (!envHasProxy(env))
|
|
236
|
+
return env;
|
|
237
|
+
const upper = env.NO_PROXY?.trim() ? env.NO_PROXY : undefined;
|
|
238
|
+
const lower = env.no_proxy?.trim() ? env.no_proxy : undefined;
|
|
239
|
+
return {
|
|
240
|
+
...env,
|
|
241
|
+
NO_PROXY: appendNoProxyHosts(upper ?? lower ?? '', LOOPBACK_NO_PROXY_HOSTS),
|
|
242
|
+
no_proxy: appendNoProxyHosts(lower ?? upper ?? '', LOOPBACK_NO_PROXY_HOSTS),
|
|
243
|
+
};
|
|
187
244
|
}
|
|
@@ -62,6 +62,11 @@ export interface TokenPair {
|
|
|
62
62
|
* - TOKEN_* — access-token specific (server pushes 4402 close;
|
|
63
63
|
* daemon classifies as TOKEN_INVALID/TOKEN_EXPIRED).
|
|
64
64
|
* - SESSION_REVOKED — admin/forensic revoke; whole family burned.
|
|
65
|
+
* - DEVICE_KEY_MISMATCH — the refresh carried a device proof signed by a key
|
|
66
|
+
* other than the one enrolled on this daemon's row
|
|
67
|
+
* (server code `DEVICE_PROOF_THUMBPRINT_MISMATCH`).
|
|
68
|
+
* The daemon signs every retry with the same key, so
|
|
69
|
+
* retrying can never succeed.
|
|
65
70
|
* - UNKNOWN_401 — server returned 401 with a code we don't
|
|
66
71
|
* recognize. Treated as permanent (better to prompt
|
|
67
72
|
* re-auth than to loop forever) but tagged
|
|
@@ -74,7 +79,7 @@ export interface TokenPair {
|
|
|
74
79
|
* Without this, the client `describeAuthFailure` exhaustiveness check
|
|
75
80
|
* was silently broken for the non-REFRESH branches.
|
|
76
81
|
*/
|
|
77
|
-
export type PermanentAuthReason = 'REFRESH_INVALID' | 'REFRESH_REUSED' | 'REFRESH_EXPIRED' | 'SESSION_REVOKED' | 'TOKEN_INVALID' | 'TOKEN_EXPIRED' | 'UNKNOWN_401';
|
|
82
|
+
export type PermanentAuthReason = 'REFRESH_INVALID' | 'REFRESH_REUSED' | 'REFRESH_EXPIRED' | 'SESSION_REVOKED' | 'DEVICE_KEY_MISMATCH' | 'TOKEN_INVALID' | 'TOKEN_EXPIRED' | 'UNKNOWN_401';
|
|
78
83
|
export declare class PermanentAuthFailure extends Error {
|
|
79
84
|
readonly code: PermanentAuthReason;
|
|
80
85
|
constructor(code: PermanentAuthReason, message: string);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skrr-ai/auth-core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"main": "dist/cjs/index.js",
|
|
5
5
|
"types": "dist/esm/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -43,6 +43,66 @@
|
|
|
43
43
|
"types": "./dist/cjs/harnessSkillLayout.d.ts",
|
|
44
44
|
"default": "./dist/cjs/harnessSkillLayout.js"
|
|
45
45
|
}
|
|
46
|
+
},
|
|
47
|
+
"./daemon-tool-approval": {
|
|
48
|
+
"import": {
|
|
49
|
+
"types": "./dist/esm/daemonToolApproval.d.ts",
|
|
50
|
+
"default": "./dist/esm/daemonToolApproval.js"
|
|
51
|
+
},
|
|
52
|
+
"require": {
|
|
53
|
+
"types": "./dist/cjs/daemonToolApproval.d.ts",
|
|
54
|
+
"default": "./dist/cjs/daemonToolApproval.js"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"./session-permission-authority": {
|
|
58
|
+
"import": {
|
|
59
|
+
"types": "./dist/esm/sessionPermissionAuthority.d.ts",
|
|
60
|
+
"default": "./dist/esm/sessionPermissionAuthority.js"
|
|
61
|
+
},
|
|
62
|
+
"require": {
|
|
63
|
+
"types": "./dist/cjs/sessionPermissionAuthority.d.ts",
|
|
64
|
+
"default": "./dist/cjs/sessionPermissionAuthority.js"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"./credential-session": {
|
|
68
|
+
"import": {
|
|
69
|
+
"types": "./dist/esm/credentialSession.d.ts",
|
|
70
|
+
"default": "./dist/esm/credentialSession.js"
|
|
71
|
+
},
|
|
72
|
+
"require": {
|
|
73
|
+
"types": "./dist/cjs/credentialSession.d.ts",
|
|
74
|
+
"default": "./dist/cjs/credentialSession.js"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"./cli-handoff-wire": {
|
|
78
|
+
"import": {
|
|
79
|
+
"types": "./dist/esm/cliHandoffWire.d.ts",
|
|
80
|
+
"default": "./dist/esm/cliHandoffWire.js"
|
|
81
|
+
},
|
|
82
|
+
"require": {
|
|
83
|
+
"types": "./dist/cjs/cliHandoffWire.d.ts",
|
|
84
|
+
"default": "./dist/cjs/cliHandoffWire.js"
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"./loopback-http": {
|
|
88
|
+
"import": {
|
|
89
|
+
"types": "./dist/esm/loopbackHttp.d.ts",
|
|
90
|
+
"default": "./dist/esm/loopbackHttp.js"
|
|
91
|
+
},
|
|
92
|
+
"require": {
|
|
93
|
+
"types": "./dist/cjs/loopbackHttp.d.ts",
|
|
94
|
+
"default": "./dist/cjs/loopbackHttp.js"
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"./machine-uuid": {
|
|
98
|
+
"import": {
|
|
99
|
+
"types": "./dist/esm/machineUuid.d.ts",
|
|
100
|
+
"default": "./dist/esm/machineUuid.js"
|
|
101
|
+
},
|
|
102
|
+
"require": {
|
|
103
|
+
"types": "./dist/cjs/machineUuid.d.ts",
|
|
104
|
+
"default": "./dist/cjs/machineUuid.js"
|
|
105
|
+
}
|
|
46
106
|
}
|
|
47
107
|
},
|
|
48
108
|
"dependencies": {
|