@skrr-ai/cli 0.1.32 → 0.1.34
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/bin/run.js +2 -2
- package/dist/base-command.js +5 -0
- package/dist/commands/agents/list.d.ts +2 -1
- package/dist/commands/agents/list.js +2 -1
- package/dist/commands/agents/show.js +2 -1
- package/dist/commands/balance/statement.js +8 -4
- package/dist/commands/browser/install.js +6 -2
- package/dist/commands/browser/uninstall.js +6 -2
- package/dist/commands/code/acp.js +2 -1
- package/dist/commands/code/doctor.d.ts +1 -1
- package/dist/commands/code/doctor.js +6 -5
- package/dist/commands/code/handover.d.ts +2 -2
- package/dist/commands/code/handover.js +2 -2
- package/dist/commands/code/index.d.ts +2 -2
- package/dist/commands/code/index.js +18 -17
- package/dist/commands/code/install.d.ts +3 -3
- package/dist/commands/code/install.js +18 -11
- package/dist/commands/code/migrate.js +3 -2
- package/dist/commands/code/oversky-agent.d.ts +5 -4
- package/dist/commands/code/oversky-agent.js +24 -22
- package/dist/commands/code/run.js +2 -1
- package/dist/commands/harnesses/list.d.ts +9 -1
- package/dist/commands/harnesses/list.js +28 -7
- package/dist/commands/harnesses/show.js +7 -2
- package/dist/commands/instructions/install.js +16 -6
- package/dist/commands/learning/delete.d.ts +9 -0
- package/dist/commands/learning/delete.js +40 -0
- package/dist/commands/learning/export.d.ts +9 -0
- package/dist/commands/learning/export.js +56 -0
- package/dist/commands/learning/reset.d.ts +9 -0
- package/dist/commands/learning/reset.js +36 -0
- package/dist/commands/learning/set.d.ts +10 -0
- package/dist/commands/learning/set.js +52 -0
- package/dist/commands/learning/status.d.ts +8 -0
- package/dist/commands/learning/status.js +35 -0
- package/dist/commands/logout.js +10 -5
- package/dist/commands/machines/dedicated/attach.js +2 -1
- package/dist/commands/tasks/runs.js +3 -1
- package/dist/commands/workspaces/use.js +2 -1
- package/dist/lib/adaptive-learning.d.ts +37 -0
- package/dist/lib/adaptive-learning.js +39 -0
- package/dist/lib/auth-core-init.d.ts +23 -0
- package/dist/lib/auth-core-init.js +61 -0
- package/dist/lib/code-handover.d.ts +1 -1
- package/dist/lib/code-handover.js +3 -2
- package/dist/lib/config.d.ts +30 -4
- package/dist/lib/config.js +2 -1
- package/dist/lib/daemon-installer.d.ts +1 -1
- package/dist/lib/daemon-target.js +2 -2
- package/dist/lib/dedicated-machines.d.ts +2 -2
- package/dist/lib/dedicated-machines.js +11 -4
- package/dist/lib/exec-runtime-binary.d.ts +2 -2
- package/dist/lib/exec-runtime-binary.js +2 -2
- package/dist/lib/{sky-code-agent.d.ts → first-party-harness-agent.d.ts} +20 -19
- package/dist/lib/{sky-code-agent.js → first-party-harness-agent.js} +85 -47
- package/dist/lib/{sky-code-broker.d.ts → first-party-harness-broker.d.ts} +6 -6
- package/dist/lib/{sky-code-broker.js → first-party-harness-broker.js} +23 -23
- package/dist/lib/{sky-code-doctor.d.ts → first-party-harness-doctor.d.ts} +12 -2
- package/dist/lib/{sky-code-doctor.js → first-party-harness-doctor.js} +181 -94
- package/dist/lib/{sky-code-managed.d.ts → first-party-harness-managed.d.ts} +55 -30
- package/dist/lib/{sky-code-managed.js → first-party-harness-managed.js} +92 -35
- package/dist/lib/{sky-code.d.ts → first-party-harness.d.ts} +107 -36
- package/dist/lib/{sky-code.js → first-party-harness.js} +172 -73
- package/dist/lib/harness-provider-input.d.ts +35 -0
- package/dist/lib/harness-provider-input.js +57 -0
- package/dist/lib/harness-tiers.d.ts +8 -2
- package/dist/lib/harness-tiers.js +11 -6
- package/dist/lib/task-instruction-offer.js +10 -4
- package/dist/lib/worklogs.js +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/configRoot.d.ts +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/configRoot.js +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.d.ts +248 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.js +361 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.d.ts +147 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.js +180 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessHome.d.ts +111 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessHome.js +314 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.d.ts +11 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.js +14 -7
- 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 +51 -14
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releaseManifest.js +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.d.ts +4 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.js +4 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/configRoot.d.ts +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/configRoot.js +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.d.ts +248 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.js +332 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.d.ts +147 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.js +170 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessHome.d.ts +111 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessHome.js +303 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.d.ts +11 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.js +14 -7
- 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 +12 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releaseManifest.js +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.d.ts +4 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.js +4 -4
- package/dist/node_modules/@skrr-ai/auth-core/package.json +11 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +4816 -4782
- package/dist/node_modules/@skrr-ai/inference-broker/dist/cjs/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/inference-broker/dist/cjs/index.js +1 -1
- package/dist/node_modules/@skrr-ai/inference-broker/dist/cjs/managed-inference-broker.js +1 -1
- package/dist/node_modules/@skrr-ai/inference-broker/dist/esm/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/inference-broker/dist/esm/index.js +1 -1
- package/dist/node_modules/@skrr-ai/inference-broker/dist/esm/managed-inference-broker.js +1 -1
- package/dist/node_modules/@skrr-ai/inference-broker/package.json +1 -1
- package/oclif.manifest.json +34286 -33962
- package/package.json +5 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/skyCodeChannels.d.ts +0 -96
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/skyCodeChannels.js +0 -115
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/skyCodeChannels.d.ts +0 -96
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/skyCodeChannels.js +0 -107
|
@@ -1,27 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* WL-2.2 — locate and forward to the local
|
|
3
|
+
* WL-2.2 — locate and forward to the local first-party harness engine.
|
|
4
4
|
*
|
|
5
5
|
* The same `gh → git` shape `exec-runtime-binary.ts` uses, for the same reason: the
|
|
6
|
-
*
|
|
6
|
+
* skrr CLI is a REST client, the engine is a separately-built, separately-
|
|
7
7
|
* released binary with its own lifetime and failure model. Unifying them at
|
|
8
8
|
* the command surface (`skrr code`) gives users one thing to type without
|
|
9
9
|
* coupling the two release cycles.
|
|
10
10
|
*
|
|
11
11
|
* The naming constraint from the plan (§3) is load-bearing and easy to get
|
|
12
12
|
* wrong: skrr already publishes `oversky` (daemon) and `skrr` (control
|
|
13
|
-
* plane). This must NOT become a third top-level executable.
|
|
14
|
-
*
|
|
13
|
+
* plane). This must NOT become a third top-level executable. The engine's file
|
|
14
|
+
* name (`firstPartyHarnessBinaryName()`) is internal; `skrr code` is the only
|
|
15
|
+
* public entry point.
|
|
16
|
+
*
|
|
17
|
+
* ── No product name in this file ──────────────────────────────────────────
|
|
18
|
+
*
|
|
19
|
+
* Every product-named value — the binary's file name, the engine home, the env
|
|
20
|
+
* var names, the display name — is read from the identity module in
|
|
21
|
+
* `@skrr-ai/auth-core` (`docs/architecture/skrr-code-identifier-rename-2026-09-13.md`).
|
|
22
|
+
* The engine's file name has more than one spelling while a rename is in
|
|
23
|
+
* flight, so resolution tries every spelling, canonical first, in each location.
|
|
15
24
|
*/
|
|
16
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
27
|
};
|
|
19
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.ENGINE_START_REFUSED_EXIT_CODE = exports.EngineStartRefusedError = exports.DEDICATED_RUNTIME_ENGINE_MESSAGE = exports.DEDICATED_WORKLOAD_UID_ENV = exports.
|
|
29
|
+
exports.ENGINE_START_REFUSED_EXIT_CODE = exports.EngineStartRefusedError = exports.DEDICATED_RUNTIME_ENGINE_MESSAGE = exports.DEDICATED_WORKLOAD_UID_ENV = exports.ENGINE_NOT_INSTALLED = void 0;
|
|
21
30
|
exports.engineHome = engineHome;
|
|
22
|
-
exports.
|
|
31
|
+
exports.engineInstructionHome = engineInstructionHome;
|
|
23
32
|
exports.managedEnginePath = managedEnginePath;
|
|
24
|
-
exports.
|
|
33
|
+
exports.legacyManagedEnginePaths = legacyManagedEnginePaths;
|
|
34
|
+
exports.legacyManagedEngineBinDirs = legacyManagedEngineBinDirs;
|
|
25
35
|
exports.resolveEngine = resolveEngine;
|
|
26
36
|
exports.buildEngineArgs = buildEngineArgs;
|
|
27
37
|
exports.isDedicatedRuntimeWorkload = isDedicatedRuntimeWorkload;
|
|
@@ -30,6 +40,7 @@ exports.inheritedProviderCredentials = inheritedProviderCredentials;
|
|
|
30
40
|
exports.hasProviderCredential = hasProviderCredential;
|
|
31
41
|
exports.strippedProviderCredentialNames = strippedProviderCredentialNames;
|
|
32
42
|
exports.engineSpawnEnv = engineSpawnEnv;
|
|
43
|
+
exports.engineOwnedEnv = engineOwnedEnv;
|
|
33
44
|
exports.execEngine = execEngine;
|
|
34
45
|
const node_child_process_1 = require("node:child_process");
|
|
35
46
|
const node_fs_1 = require("node:fs");
|
|
@@ -42,25 +53,42 @@ const config_1 = require("./config");
|
|
|
42
53
|
// read it to decide whether a run was managed; that decision now arrives as a
|
|
43
54
|
// declared `credentialMode`, and re-introducing the import here would be the first
|
|
44
55
|
// step back toward inferring a security-relevant fact from a string.
|
|
45
|
-
/** Env override, mirroring the daemon's `OVERSKY_SKY_CODE_PATH`. */
|
|
46
|
-
exports.ENGINE_PATH_ENV = 'OVERSKY_SKY_CODE_PATH';
|
|
47
56
|
/**
|
|
48
|
-
* The
|
|
57
|
+
* The error `execEngine` throws when no engine resolves. A value the commands
|
|
58
|
+
* compare against, so it is exported rather than retyped at each catch site.
|
|
59
|
+
*/
|
|
60
|
+
exports.ENGINE_NOT_INSTALLED = 'engine-not-installed';
|
|
61
|
+
/**
|
|
62
|
+
* The engine's user-state root: the engine home under skrr's `~/.skrr/`.
|
|
49
63
|
*
|
|
50
64
|
* Honours `OVERSKY_CONFIG_DIR`, the same root override the daemon reads
|
|
51
65
|
* (`daemon/src/bun-entry.ts`). Without it the CLI would keep looking under
|
|
52
66
|
* `$HOME` for a user who relocated their skrr root, and would resolve a
|
|
53
67
|
* different engine than the daemon — the exact divergence the managed-first
|
|
54
68
|
* ordering below exists to prevent.
|
|
69
|
+
*
|
|
70
|
+
* The directory NAME follows the engine's own namespace, not the provider slug
|
|
71
|
+
* (`firstPartyHarnessHomeDirname`, contract §5): the engine reads its config and
|
|
72
|
+
* the managed `AGENTS.md` from here, so a home named after anything else would be
|
|
73
|
+
* a directory the engine never reads.
|
|
55
74
|
*/
|
|
56
75
|
function engineHome(env = process.env) {
|
|
57
|
-
//
|
|
58
|
-
// twice is what let this function and `getConfigPath()` disagree
|
|
59
|
-
|
|
76
|
+
// The shared resolver and not a second reading of the environment: deriving
|
|
77
|
+
// the root twice is what let this function and `getConfigPath()` disagree
|
|
78
|
+
// (OSK-300).
|
|
79
|
+
return (0, auth_core_1.firstPartyHarnessHomeDir)(env);
|
|
60
80
|
}
|
|
61
|
-
/**
|
|
62
|
-
|
|
63
|
-
|
|
81
|
+
/**
|
|
82
|
+
* The user-level instruction root the engine owns.
|
|
83
|
+
*
|
|
84
|
+
* Read under the neutral variable first and its older name second
|
|
85
|
+
* (`readFirstPartyHarnessEnv`). The older name is also the one the ENGINE reads,
|
|
86
|
+
* which is why {@link engineOwnedEnv} hands the resolved value to the engine under
|
|
87
|
+
* that name — otherwise the doctor would honour the neutral variable and the
|
|
88
|
+
* engine would not.
|
|
89
|
+
*/
|
|
90
|
+
function engineInstructionHome(env = process.env) {
|
|
91
|
+
const configured = (0, auth_core_1.readFirstPartyHarnessEnv)(env, 'home').value;
|
|
64
92
|
// Falls through to `engineHome()` rather than re-deriving `~/.skrr` — the two
|
|
65
93
|
// describe the same root, and re-deriving it is what made them disagree under
|
|
66
94
|
// `OVERSKY_CONFIG_DIR` (OSK-300).
|
|
@@ -73,14 +101,16 @@ function skyCodeInstructionHome(env = process.env) {
|
|
|
73
101
|
return node_path_1.default.resolve(configured);
|
|
74
102
|
}
|
|
75
103
|
/**
|
|
76
|
-
* The managed install location
|
|
77
|
-
*
|
|
104
|
+
* The managed install location for one spelling of the binary (canonical by
|
|
105
|
+
* default) — where the daemon, the Desktop app, and
|
|
106
|
+
* `scripts/first-party-harness/build.mjs --install` all put the engine.
|
|
78
107
|
*/
|
|
79
|
-
function managedEnginePath(
|
|
80
|
-
return
|
|
108
|
+
function managedEnginePath(env = process.env, provider = auth_core_1.FIRST_PARTY_HARNESS.provider) {
|
|
109
|
+
return (0, auth_core_1.firstPartyHarnessInstalledBinaryPath)(env, provider, process.platform);
|
|
81
110
|
}
|
|
82
111
|
/**
|
|
83
|
-
* The same managed location under the PREVIOUS config root
|
|
112
|
+
* The same managed location under the PREVIOUS config root, for every spelling of
|
|
113
|
+
* the binary and every engine home name, canonical first.
|
|
84
114
|
*
|
|
85
115
|
* The root moved `~/.oversky` → `~/.skrr` in the skrr rename, and an engine
|
|
86
116
|
* installed before that is still on disk under the old one. `daemon/src/
|
|
@@ -88,14 +118,22 @@ function managedEnginePath(exeName, env = process.env) {
|
|
|
88
118
|
* the same machine the daemon found the engine and `skrr code` reported that no
|
|
89
119
|
* engine was installed — the same product, the same 106 MB binary, two answers.
|
|
90
120
|
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
121
|
+
* The engine-home move (`migrateFirstPartyHarnessHome`) only ever works under the
|
|
122
|
+
* CURRENT root, so nothing renames a binary here — which is why this list carries
|
|
123
|
+
* every spelling rather than only the canonical one.
|
|
124
|
+
*
|
|
125
|
+
* Empty when an explicit `OVERSKY_CONFIG_DIR` is set, matching the daemon: that
|
|
126
|
+
* override names one root deliberately, and reaching past it to a hard-coded home
|
|
127
|
+
* would defeat the pinning {@link engineHome} relies on.
|
|
94
128
|
*/
|
|
95
|
-
function
|
|
129
|
+
function legacyManagedEnginePaths(env = process.env) {
|
|
130
|
+
return legacyManagedEngineBinDirs(env).flatMap((dir) => (0, auth_core_1.firstPartyHarnessBinaryNames)(process.platform).map((name) => node_path_1.default.join(dir, name)));
|
|
131
|
+
}
|
|
132
|
+
/** The `bin` directories {@link legacyManagedEnginePaths} looks in. */
|
|
133
|
+
function legacyManagedEngineBinDirs(env = process.env) {
|
|
96
134
|
if ((0, auth_core_1.isConfigRootOverridden)(env))
|
|
97
|
-
return
|
|
98
|
-
return node_path_1.default.join((0,
|
|
135
|
+
return [];
|
|
136
|
+
return [(0, auth_core_1.firstPartyHarnessHomeDirname)(), ...auth_core_1.FIRST_PARTY_HARNESS_ENGINE.legacyAppNames].map((home) => node_path_1.default.join((0, config_1.priorConfigDir)(), home, 'bin'));
|
|
99
137
|
}
|
|
100
138
|
/**
|
|
101
139
|
* Unmanaged well-known locations, checked after PATH.
|
|
@@ -110,6 +148,15 @@ function fallbackPaths(exeName) {
|
|
|
110
148
|
node_path_1.default.join((0, node_os_1.homedir)(), '.local', 'bin', exeName),
|
|
111
149
|
];
|
|
112
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* The file names a PATH directory may hold the engine under, canonical first.
|
|
153
|
+
* Windows also accepts a `.cmd` shim, as a package manager may install one.
|
|
154
|
+
*/
|
|
155
|
+
function pathExecutableNames(platform) {
|
|
156
|
+
return (0, auth_core_1.firstPartyHarnessSpellings)().flatMap((spelling) => platform === 'win32'
|
|
157
|
+
? [(0, auth_core_1.firstPartyHarnessBinaryName)(spelling, platform), `${spelling}.cmd`]
|
|
158
|
+
: [(0, auth_core_1.firstPartyHarnessBinaryName)(spelling, platform)]);
|
|
159
|
+
}
|
|
113
160
|
function isExecutable(p) {
|
|
114
161
|
try {
|
|
115
162
|
(0, node_fs_1.accessSync)(p, node_fs_1.constants.X_OK);
|
|
@@ -126,19 +173,23 @@ function isExecutable(p) {
|
|
|
126
173
|
* binary am I actually running" is the first question when a managed session
|
|
127
174
|
* and an interactive session behave differently.
|
|
128
175
|
*
|
|
129
|
-
*
|
|
176
|
+
* The env override is checked first and is absolute-only. A relative override
|
|
130
177
|
* would resolve against the caller's cwd, which for an agent-invoked command is
|
|
131
|
-
* attacker-influenced: a repo containing
|
|
178
|
+
* attacker-influenced: a repo containing a file named like the engine could
|
|
179
|
+
* hijack it. It is read under its neutral name first and its older name second.
|
|
132
180
|
*
|
|
133
|
-
* **Order: env → managed → PATH → well-known (WL-6.2).**
|
|
181
|
+
* **Order: env → managed → PATH → well-known (WL-6.2).** Within each location
|
|
182
|
+
* every spelling of the binary is tried, canonical first — the daemon's order —
|
|
183
|
+
* so an engine installed under an older name still resolves, and the canonical
|
|
184
|
+
* one wins wherever both exist.
|
|
134
185
|
*
|
|
135
186
|
* The managed location beating `PATH` is the load-bearing part, and it is a
|
|
136
187
|
* deliberate reversal of the obvious ordering.
|
|
137
188
|
*
|
|
138
189
|
* WL-6.2's acceptance criterion is that "Desktop-bundled and standalone
|
|
139
190
|
* installations resolve the same version deterministically". With `PATH` first
|
|
140
|
-
* they do not: a Desktop app that ships a pinned, signed engine into
|
|
141
|
-
*
|
|
191
|
+
* they do not: a Desktop app that ships a pinned, signed engine into the managed
|
|
192
|
+
* `bin` directory silently loses to whatever engine binary happens to sit
|
|
142
193
|
* earlier on the user's `PATH` — a months-old dev build, a Homebrew copy of a
|
|
143
194
|
* different version, a shim from an uninstalled package manager. The user sees
|
|
144
195
|
* one product and gets two engines depending on their shell, and the daemon
|
|
@@ -151,33 +202,40 @@ function isExecutable(p) {
|
|
|
151
202
|
*
|
|
152
203
|
* `skrr code doctor` prints the winning `source`, so a surprising resolution is
|
|
153
204
|
* one command away from being explained rather than being a mystery.
|
|
205
|
+
*
|
|
206
|
+
* Pure: it reads the filesystem and moves nothing. The engine-home move runs in
|
|
207
|
+
* {@link execEngine}, before it resolves, so the doctor stays safe to run anywhere.
|
|
154
208
|
*/
|
|
155
209
|
function resolveEngine(env = process.env) {
|
|
156
|
-
const
|
|
157
|
-
const override = env
|
|
158
|
-
if (override && override.
|
|
159
|
-
const
|
|
210
|
+
const platform = process.platform;
|
|
211
|
+
const override = (0, auth_core_1.readFirstPartyHarnessEnv)(env, 'path');
|
|
212
|
+
if (override.value && override.name) {
|
|
213
|
+
const origin = { envName: override.name, legacyEnv: override.legacy };
|
|
214
|
+
const candidate = override.value;
|
|
160
215
|
if (!node_path_1.default.isAbsolute(candidate))
|
|
161
|
-
return { path: null, source: 'unresolved' };
|
|
216
|
+
return { path: null, source: 'unresolved', ...origin };
|
|
162
217
|
return isExecutable(candidate)
|
|
163
|
-
? { path: candidate, source: 'env' }
|
|
164
|
-
: { path: null, source: 'unresolved' };
|
|
218
|
+
? { path: candidate, source: 'env', ...origin }
|
|
219
|
+
: { path: null, source: 'unresolved', ...origin };
|
|
220
|
+
}
|
|
221
|
+
for (const spelling of (0, auth_core_1.firstPartyHarnessSpellings)()) {
|
|
222
|
+
const managed = managedEnginePath(env, spelling);
|
|
223
|
+
if (isExecutable(managed))
|
|
224
|
+
return { path: managed, source: 'managed' };
|
|
165
225
|
}
|
|
166
|
-
const managed = managedEnginePath(exeName, env);
|
|
167
|
-
if (isExecutable(managed))
|
|
168
|
-
return { path: managed, source: 'managed' };
|
|
169
226
|
// The pre-rename managed location, SECOND. After the current one, so a fresh
|
|
170
227
|
// install always wins; before PATH, for the same WL-6.2 reason the current one
|
|
171
228
|
// beats PATH — a binary skrr installed outranks whatever happens to sit on the
|
|
172
229
|
// user's PATH, and which config root it was installed under does not change
|
|
173
230
|
// that. Reported as its own `source` so `skrr code doctor` can say where it
|
|
174
231
|
// came from rather than quietly resolving something surprising.
|
|
175
|
-
const legacy
|
|
176
|
-
|
|
177
|
-
|
|
232
|
+
for (const legacy of legacyManagedEnginePaths(env)) {
|
|
233
|
+
if (isExecutable(legacy))
|
|
234
|
+
return { path: legacy, source: 'legacy-managed' };
|
|
235
|
+
}
|
|
178
236
|
const PATH = env.PATH ?? '';
|
|
179
|
-
const sep =
|
|
180
|
-
const exeNames =
|
|
237
|
+
const sep = platform === 'win32' ? ';' : ':';
|
|
238
|
+
const exeNames = pathExecutableNames(platform);
|
|
181
239
|
for (const dir of PATH.split(sep)) {
|
|
182
240
|
if (!dir)
|
|
183
241
|
continue;
|
|
@@ -187,9 +245,11 @@ function resolveEngine(env = process.env) {
|
|
|
187
245
|
return { path: candidate, source: 'path' };
|
|
188
246
|
}
|
|
189
247
|
}
|
|
190
|
-
for (const
|
|
191
|
-
|
|
192
|
-
|
|
248
|
+
for (const exeName of (0, auth_core_1.firstPartyHarnessBinaryNames)(platform)) {
|
|
249
|
+
for (const candidate of fallbackPaths(exeName)) {
|
|
250
|
+
if (isExecutable(candidate))
|
|
251
|
+
return { path: candidate, source: 'fallback' };
|
|
252
|
+
}
|
|
193
253
|
}
|
|
194
254
|
return { path: null, source: 'unresolved' };
|
|
195
255
|
}
|
|
@@ -239,20 +299,20 @@ exports.DEDICATED_RUNTIME_ENGINE_MESSAGE = 'On a Dedicated Runtime, coding engin
|
|
|
239
299
|
* Message shown when no engine is installed.
|
|
240
300
|
*
|
|
241
301
|
* Points at the DAEMON's managed installer rather than at a package manager.
|
|
242
|
-
* The earlier version of this text offered
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
302
|
+
* The earlier version of this text offered a Homebrew formula for the engine and
|
|
303
|
+
* a `curl .../install.sh | bash` on the update feed; neither exists — the tap
|
|
304
|
+
* carries only the `oversky` formula and the feed serves no install script — so
|
|
305
|
+
* a user following it hit a 404 and a 403 and reasonably concluded the engine
|
|
306
|
+
* was not real.
|
|
247
307
|
*
|
|
248
308
|
* The managed path is also the only one that establishes provenance: it
|
|
249
309
|
* verifies the signed manifest and writes the sidecar the daemon reads before
|
|
250
310
|
* it will hand the engine a platform credential. A hand-placed binary works, and
|
|
251
311
|
* since the owner decision of 2026-08-11 it runs at the SAME tier as a managed
|
|
252
|
-
* one — the daemon's floor for
|
|
253
|
-
* (OSK-3894; this said "stays at Tier 2"). The managed path is still
|
|
254
|
-
* recommendation, but the reason is now "you can prove which bytes ran"
|
|
255
|
-
* than "otherwise you get a weaker credential".
|
|
312
|
+
* one — the daemon's floor for the first-party harness is Tier 1 regardless of
|
|
313
|
+
* provenance (OSK-3894; this said "stays at Tier 2"). The managed path is still
|
|
314
|
+
* the recommendation, but the reason is now "you can prove which bytes ran"
|
|
315
|
+
* rather than "otherwise you get a weaker credential".
|
|
256
316
|
*
|
|
257
317
|
* Keep this in step with what actually ships. An install instruction that does
|
|
258
318
|
* not work is worse than none: it moves the failure from "I could not find how
|
|
@@ -262,9 +322,10 @@ exports.DEDICATED_RUNTIME_ENGINE_MESSAGE = 'On a Dedicated Runtime, coding engin
|
|
|
262
322
|
* below fails there (see {@link DEDICATED_RUNTIME_ENGINE_MESSAGE}).
|
|
263
323
|
*/
|
|
264
324
|
function notInstalledMessage(env = process.env) {
|
|
325
|
+
const { command, displayName } = auth_core_1.FIRST_PARTY_HARNESS;
|
|
265
326
|
if (isDedicatedRuntimeWorkload(env)) {
|
|
266
327
|
return [
|
|
267
|
-
|
|
328
|
+
`The ${displayName} engine (\`${(0, auth_core_1.firstPartyHarnessBinaryName)()}\`) is not on this machine.`,
|
|
268
329
|
'',
|
|
269
330
|
exports.DEDICATED_RUNTIME_ENGINE_MESSAGE,
|
|
270
331
|
'This machine was built from an image without it; it arrives when the',
|
|
@@ -272,18 +333,18 @@ function notInstalledMessage(env = process.env) {
|
|
|
272
333
|
].join('\n');
|
|
273
334
|
}
|
|
274
335
|
return [
|
|
275
|
-
|
|
336
|
+
`The ${displayName} engine (\`${(0, auth_core_1.firstPartyHarnessBinaryName)()}\`) is not installed on this machine.`,
|
|
276
337
|
'',
|
|
277
338
|
'Install it through the daemon, which verifies the signed release:',
|
|
278
|
-
|
|
279
|
-
|
|
339
|
+
` • \`${command} install\` — from here, no browser needed`,
|
|
340
|
+
` • Or in the web app: the runtime menu beside the chat input → ${displayName} → Install`,
|
|
280
341
|
' • Either way a daemon must be running here: `skrr daemon status`',
|
|
281
342
|
'',
|
|
282
|
-
`Or point the CLI at an existing build: export ${
|
|
343
|
+
`Or point the CLI at an existing build: export ${auth_core_1.FIRST_PARTY_HARNESS_ENV.path.name}=/absolute/path/to/${(0, auth_core_1.firstPartyHarnessBinaryName)()}`,
|
|
283
344
|
' (an unsigned build runs, and since 2026-08-11 at the same trust tier as a',
|
|
284
|
-
|
|
345
|
+
` signed one — see \`${command} doctor\` under trust-tier)`,
|
|
285
346
|
'',
|
|
286
|
-
|
|
347
|
+
`Run \`${command} doctor\` for a full diagnosis. Its \`release-channel\` line`,
|
|
287
348
|
'names the channel this machine follows and the exact manifest URL to check',
|
|
288
349
|
'for a published release.',
|
|
289
350
|
].join('\n');
|
|
@@ -344,7 +405,7 @@ const BYOK_CREDENTIAL_NAMES = new Set(['HUGGINGFACE_HUB_TOKEN']);
|
|
|
344
405
|
* shared config, a file the engine can read anyway. Stripping them therefore
|
|
345
406
|
* protected nothing and cost an entire provider.
|
|
346
407
|
*
|
|
347
|
-
* Dogfooded as OSK-262, where `
|
|
408
|
+
* Dogfooded as OSK-262, where the bare engine's `run "say hi"` answered on a Bedrock
|
|
348
409
|
* model and the identical run through `skrr code` died in the engine's generic
|
|
349
410
|
* error handler — because `AWS_PROFILE` did not survive the sanitizer.
|
|
350
411
|
* `env -u AWS_PROFILE` on the bare engine reproduced the failure exactly.
|
|
@@ -389,7 +450,7 @@ const ENGINE_NEVER_INHERITS_PREFIXES = ['OVERSKY_', 'AWS_'];
|
|
|
389
450
|
*
|
|
390
451
|
* Exported because two callers need ONE answer to "does this machine have a
|
|
391
452
|
* provider key at all": this module, to decide what the engine inherits, and the
|
|
392
|
-
* BYOK fallback line in `
|
|
453
|
+
* BYOK fallback line in `first-party-harness-broker.ts`, which used to promise "continuing
|
|
393
454
|
* with your own provider credentials" on a machine that had none (invariant I4 —
|
|
394
455
|
* managed, BYOK and offline must never be confused). Two definitions of that
|
|
395
456
|
* question is how the promise and the reality drift apart.
|
|
@@ -495,10 +556,14 @@ function strippedProviderCredentialNames(env = process.env) {
|
|
|
495
556
|
*
|
|
496
557
|
* One sharp edge to know about before adding a subcommand: the shared sanitizer
|
|
497
558
|
* strips anything ending in `_PASSWORD`, which includes the engine's own
|
|
498
|
-
*
|
|
499
|
-
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
559
|
+
* server-password variable (`FIRST_PARTY_HARNESS_ENGINE.env.serverPassword`, Basic
|
|
560
|
+
* auth for the engine's `serve` / `web`). No `skrr code` subcommand reaches those
|
|
561
|
+
* today — they are run against the engine binary directly — so nothing regresses;
|
|
562
|
+
* a future `skrr code serve` would have to pass that credential deliberately,
|
|
563
|
+
* under that name, rather than rely on inheritance.
|
|
564
|
+
*
|
|
565
|
+
* The layering, in full: sanitized parent → the user's own model credential (BYOK
|
|
566
|
+
* only) → {@link engineOwnedEnv} → `extraEnv`.
|
|
502
567
|
*/
|
|
503
568
|
function engineSpawnEnv(env, extraEnv,
|
|
504
569
|
// Required, not defaulted: the safe value differs per call and a parameter that
|
|
@@ -507,6 +572,7 @@ mode) {
|
|
|
507
572
|
const spawnEnv = {
|
|
508
573
|
...(0, auth_core_1.sanitizeSpawnEnv)(env),
|
|
509
574
|
...(mode === 'managed' ? {} : inheritedProviderCredentials(env)),
|
|
575
|
+
...engineOwnedEnv(env),
|
|
510
576
|
...extraEnv,
|
|
511
577
|
};
|
|
512
578
|
if (mode !== 'managed')
|
|
@@ -519,7 +585,40 @@ mode) {
|
|
|
519
585
|
// otherwise have received rather than replacing it.
|
|
520
586
|
return { ...spawnEnv, ...(0, inference_broker_1.inferenceBrokerNoProxyEnv)(spawnEnv) };
|
|
521
587
|
}
|
|
588
|
+
/**
|
|
589
|
+
* Settings the platform reads under NEUTRAL names, handed to the engine under the
|
|
590
|
+
* engine's OWN names.
|
|
591
|
+
*
|
|
592
|
+
* The engine is a fork with its own variable namespace
|
|
593
|
+
* (`FIRST_PARTY_HARNESS_ENGINE.env`), and it reads none of the platform's neutral
|
|
594
|
+
* names. So an operator who sets the neutral home override would see
|
|
595
|
+
* `skrr code doctor` honour it while the engine it launches ignored it — two
|
|
596
|
+
* answers to "where do my instructions live" from one command.
|
|
597
|
+
*
|
|
598
|
+
* Only when the value came from a name the engine does NOT read: a value set under
|
|
599
|
+
* the engine's own name is inherited already, and rewriting it would only replace
|
|
600
|
+
* the user's spelling of a path with ours. The resolved path is passed rather than
|
|
601
|
+
* the raw value, so the engine and the doctor agree on `~` expansion too.
|
|
602
|
+
*
|
|
603
|
+
* Not a credential and never one: it cannot reintroduce anything the sanitizer
|
|
604
|
+
* strips, and `extraEnv` still layers over it.
|
|
605
|
+
*/
|
|
606
|
+
function engineOwnedEnv(env) {
|
|
607
|
+
const out = {};
|
|
608
|
+
const home = (0, auth_core_1.readFirstPartyHarnessEnv)(env, 'home');
|
|
609
|
+
if (home.value && home.name !== auth_core_1.FIRST_PARTY_HARNESS_ENGINE.env.home) {
|
|
610
|
+
out[auth_core_1.FIRST_PARTY_HARNESS_ENGINE.env.home] = engineInstructionHome(env);
|
|
611
|
+
}
|
|
612
|
+
return out;
|
|
613
|
+
}
|
|
522
614
|
async function execEngine(args, env = process.env, options = {}) {
|
|
615
|
+
// Move an engine installed under an older binary name onto the canonical one,
|
|
616
|
+
// BEFORE resolving. Idempotent, lossless, and it never throws: a move that
|
|
617
|
+
// cannot be made leaves every file where it was, and `resolveEngine` still tries
|
|
618
|
+
// every spelling — so the worst case is today's path, never a missing engine.
|
|
619
|
+
// Here and not in `resolveEngine`, which the doctor also calls and which must
|
|
620
|
+
// not move anything.
|
|
621
|
+
(0, auth_core_1.migrateFirstPartyHarnessHome)({ env });
|
|
523
622
|
// Resolve the binary FIRST, before `prepare` runs.
|
|
524
623
|
//
|
|
525
624
|
// Order matters: a caller learns "not installed" from here, and starting a
|
|
@@ -527,7 +626,7 @@ async function execEngine(args, env = process.env, options = {}) {
|
|
|
527
626
|
// engine that never runs.
|
|
528
627
|
const { path: bin } = resolveEngine(env);
|
|
529
628
|
if (!bin)
|
|
530
|
-
throw new Error(
|
|
629
|
+
throw new Error(exports.ENGINE_NOT_INSTALLED);
|
|
531
630
|
// Assumed until the spawn tells us otherwise, so a teardown that runs after a
|
|
532
631
|
// spawn ERROR does not claim the run was interrupted.
|
|
533
632
|
const outcome = { interrupted: false };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Harness-valued INPUT, normalised at the edge.
|
|
3
|
+
*
|
|
4
|
+
* The first-party harness has more than one accepted spelling while a rename is
|
|
5
|
+
* in flight (`FIRST_PARTY_HARNESS.aliases`). Every flag, setting and filter that
|
|
6
|
+
* takes a harness name must accept all of them — a script written against either
|
|
7
|
+
* spelling keeps working — and must hand the rest of the CLI ONE value, so no
|
|
8
|
+
* comparison downstream has to know there were two
|
|
9
|
+
* (`docs/architecture/skrr-code-identifier-rename-2026-09-13.md` §2).
|
|
10
|
+
*
|
|
11
|
+
* Two destinations, two spellings, and the difference is the point:
|
|
12
|
+
*
|
|
13
|
+
* - to the SERVER (HTTP bodies, query params) and to the terminal: CANONICAL,
|
|
14
|
+
* which is what the platform stores and returns;
|
|
15
|
+
* - to the local DAEMON binary: the WIRE spelling, which every daemon version
|
|
16
|
+
* already installed on a user's machine understands. A daemon that predates
|
|
17
|
+
* the rename cannot be taught a new spelling by the CLI that talks to it.
|
|
18
|
+
*
|
|
19
|
+
* Every other harness name passes through unchanged — this normalises one
|
|
20
|
+
* harness's spellings, it is not a general lower-caser, and silently rewriting a
|
|
21
|
+
* name this module knows nothing about would be a behaviour change nobody asked for.
|
|
22
|
+
*/
|
|
23
|
+
/** The canonical provider for any spelling of the first-party harness; anything else trimmed. */
|
|
24
|
+
export declare function canonicalHarnessInput(value: string): string;
|
|
25
|
+
/** Canonicalise a repeatable flag, keeping the first occurrence of each value. */
|
|
26
|
+
export declare function canonicalHarnessInputs(values: readonly string[]): string[];
|
|
27
|
+
/** The spelling to hand the LOCAL daemon binary for a harness-valued argument. */
|
|
28
|
+
export declare function daemonHarnessArgument(value: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* The `options` list for an oclif flag that enumerates harness names: the given
|
|
31
|
+
* names with every spelling of the first-party harness in place of its canonical
|
|
32
|
+
* one, so oclif's own validation accepts an alias instead of rejecting it before
|
|
33
|
+
* the command ever runs.
|
|
34
|
+
*/
|
|
35
|
+
export declare function harnessFlagOptions(names: readonly string[]): string[];
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Harness-valued INPUT, normalised at the edge.
|
|
4
|
+
*
|
|
5
|
+
* The first-party harness has more than one accepted spelling while a rename is
|
|
6
|
+
* in flight (`FIRST_PARTY_HARNESS.aliases`). Every flag, setting and filter that
|
|
7
|
+
* takes a harness name must accept all of them — a script written against either
|
|
8
|
+
* spelling keeps working — and must hand the rest of the CLI ONE value, so no
|
|
9
|
+
* comparison downstream has to know there were two
|
|
10
|
+
* (`docs/architecture/skrr-code-identifier-rename-2026-09-13.md` §2).
|
|
11
|
+
*
|
|
12
|
+
* Two destinations, two spellings, and the difference is the point:
|
|
13
|
+
*
|
|
14
|
+
* - to the SERVER (HTTP bodies, query params) and to the terminal: CANONICAL,
|
|
15
|
+
* which is what the platform stores and returns;
|
|
16
|
+
* - to the local DAEMON binary: the WIRE spelling, which every daemon version
|
|
17
|
+
* already installed on a user's machine understands. A daemon that predates
|
|
18
|
+
* the rename cannot be taught a new spelling by the CLI that talks to it.
|
|
19
|
+
*
|
|
20
|
+
* Every other harness name passes through unchanged — this normalises one
|
|
21
|
+
* harness's spellings, it is not a general lower-caser, and silently rewriting a
|
|
22
|
+
* name this module knows nothing about would be a behaviour change nobody asked for.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.canonicalHarnessInput = canonicalHarnessInput;
|
|
26
|
+
exports.canonicalHarnessInputs = canonicalHarnessInputs;
|
|
27
|
+
exports.daemonHarnessArgument = daemonHarnessArgument;
|
|
28
|
+
exports.harnessFlagOptions = harnessFlagOptions;
|
|
29
|
+
const auth_core_1 = require("@skrr-ai/auth-core");
|
|
30
|
+
/** The canonical provider for any spelling of the first-party harness; anything else trimmed. */
|
|
31
|
+
function canonicalHarnessInput(value) {
|
|
32
|
+
const trimmed = value.trim();
|
|
33
|
+
return String((0, auth_core_1.canonicalHarnessProvider)(trimmed));
|
|
34
|
+
}
|
|
35
|
+
/** Canonicalise a repeatable flag, keeping the first occurrence of each value. */
|
|
36
|
+
function canonicalHarnessInputs(values) {
|
|
37
|
+
const out = [];
|
|
38
|
+
for (const value of values) {
|
|
39
|
+
const canonical = canonicalHarnessInput(value);
|
|
40
|
+
if (canonical && !out.includes(canonical))
|
|
41
|
+
out.push(canonical);
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
/** The spelling to hand the LOCAL daemon binary for a harness-valued argument. */
|
|
46
|
+
function daemonHarnessArgument(value) {
|
|
47
|
+
return (0, auth_core_1.wireHarnessProvider)(canonicalHarnessInput(value));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The `options` list for an oclif flag that enumerates harness names: the given
|
|
51
|
+
* names with every spelling of the first-party harness in place of its canonical
|
|
52
|
+
* one, so oclif's own validation accepts an alias instead of rejecting it before
|
|
53
|
+
* the command ever runs.
|
|
54
|
+
*/
|
|
55
|
+
function harnessFlagOptions(names) {
|
|
56
|
+
return canonicalHarnessInputs(names).flatMap((name) => (0, auth_core_1.isFirstPartyHarnessProvider)(name) ? [...(0, auth_core_1.firstPartyHarnessSpellings)()] : [name]);
|
|
57
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* ── What this file used to be, and why it changed twice ────────────────────
|
|
5
5
|
*
|
|
6
|
-
* `skrr code doctor` reported "
|
|
6
|
+
* `skrr code doctor` reported "<the first-party harness> is Tier 2 … its tool calls are adjudicated
|
|
7
7
|
* per call by the daemon" while the daemon had recorded Tier 1 since the owner
|
|
8
8
|
* decision of 2026-08-11. The audience that runs `doctor` runs it BECAUSE
|
|
9
9
|
* permissions are confusing them, so that line was wrong to exactly the people it
|
|
@@ -44,7 +44,13 @@ export { HARNESS_TIERS, getHarnessTier };
|
|
|
44
44
|
*/
|
|
45
45
|
export declare const HARNESS_TIER_TABLE = "packages/auth-core/src/harnessTrust.ts";
|
|
46
46
|
export declare const HARNESS_TIER_AUTHORITY = "daemon/src/harness-trust.ts";
|
|
47
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* The tier the shared table records for a harness, or `null` for an unknown name.
|
|
49
|
+
*
|
|
50
|
+
* Canonicalised first, so no spelling of the first-party harness can reach the
|
|
51
|
+
* lookup as an unknown name — the shared table also carries every spelling, and
|
|
52
|
+
* this keeps the answer right even for one written in a different case.
|
|
53
|
+
*/
|
|
48
54
|
export declare function mirroredTier(harness: string): HarnessTrustTier | null;
|
|
49
55
|
export interface TierDescription {
|
|
50
56
|
/** What is true, in one line. */
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* ── What this file used to be, and why it changed twice ────────────────────
|
|
6
6
|
*
|
|
7
|
-
* `skrr code doctor` reported "
|
|
7
|
+
* `skrr code doctor` reported "<the first-party harness> is Tier 2 … its tool calls are adjudicated
|
|
8
8
|
* per call by the daemon" while the daemon had recorded Tier 1 since the owner
|
|
9
9
|
* decision of 2026-08-11. The audience that runs `doctor` runs it BECAUSE
|
|
10
10
|
* permissions are confusing them, so that line was wrong to exactly the people it
|
|
@@ -49,11 +49,16 @@ Object.defineProperty(exports, "getHarnessTier", { enumerable: true, get: functi
|
|
|
49
49
|
*/
|
|
50
50
|
exports.HARNESS_TIER_TABLE = 'packages/auth-core/src/harnessTrust.ts';
|
|
51
51
|
exports.HARNESS_TIER_AUTHORITY = 'daemon/src/harness-trust.ts';
|
|
52
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* The tier the shared table records for a harness, or `null` for an unknown name.
|
|
54
|
+
*
|
|
55
|
+
* Canonicalised first, so no spelling of the first-party harness can reach the
|
|
56
|
+
* lookup as an unknown name — the shared table also carries every spelling, and
|
|
57
|
+
* this keeps the answer right even for one written in a different case.
|
|
58
|
+
*/
|
|
53
59
|
function mirroredTier(harness) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
: null;
|
|
60
|
+
const key = String((0, auth_core_1.canonicalHarnessProvider)(harness));
|
|
61
|
+
return Object.prototype.hasOwnProperty.call(auth_core_1.HARNESS_TIERS, key) ? (0, auth_core_1.getHarnessTier)(key) : null;
|
|
57
62
|
}
|
|
58
63
|
/**
|
|
59
64
|
* Render the user-facing meaning of a tier.
|
|
@@ -79,7 +84,7 @@ function describeTier(harness, tier) {
|
|
|
79
84
|
detail: `${harness} is Tier 1: an operator-configured \`auto\` permission mode STANDS ` +
|
|
80
85
|
'(it is not downgraded to per-call adjudication), and direct platform-key ' +
|
|
81
86
|
'delivery is permitted. A tier still never approves an individual tool call.',
|
|
82
|
-
remedy:
|
|
87
|
+
remedy: `skrr does not yet sign ${auth_core_1.FIRST_PARTY_HARNESS.displayName} releases, so in practice an UNSIGNED build can ` +
|
|
83
88
|
'receive the platform master key. The provenance machinery still runs and still ' +
|
|
84
89
|
'verifies binaries — signing stops being what earns the key and becomes what lets ' +
|
|
85
90
|
`you prove which bytes held it. Reverting to the strict posture is one line in ${exports.HARNESS_TIER_TABLE}.`,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.maybeOfferTaskManagementInstructions = maybeOfferTaskManagementInstructions;
|
|
4
|
+
const auth_core_1 = require("@skrr-ai/auth-core");
|
|
4
5
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
6
|
const config_1 = require("./config");
|
|
6
7
|
const daemon_target_1 = require("./daemon-target");
|
|
@@ -31,8 +32,11 @@ function detectedProviders(daemon) {
|
|
|
31
32
|
providers.push('claude');
|
|
32
33
|
if (capabilities.includes('codex_session'))
|
|
33
34
|
providers.push('codex');
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
// A daemon advertises the first-party harness under whichever spelling its
|
|
36
|
+
// version speaks; any of them means the harness is there, and the offer names
|
|
37
|
+
// it canonically, which is what the server stores.
|
|
38
|
+
if (capabilities.some(auth_core_1.isFirstPartyHarnessCapability))
|
|
39
|
+
providers.push(auth_core_1.FIRST_PARTY_HARNESS_PROVIDER);
|
|
36
40
|
return providers;
|
|
37
41
|
}
|
|
38
42
|
function providerLabel(provider) {
|
|
@@ -40,14 +44,16 @@ function providerLabel(provider) {
|
|
|
40
44
|
return 'Claude Code';
|
|
41
45
|
if (provider === 'codex')
|
|
42
46
|
return 'Codex';
|
|
43
|
-
return
|
|
47
|
+
return auth_core_1.FIRST_PARTY_HARNESS.displayName;
|
|
44
48
|
}
|
|
45
49
|
function providerPath(provider) {
|
|
46
50
|
if (provider === 'claude')
|
|
47
51
|
return '~/.claude/CLAUDE.md';
|
|
48
52
|
if (provider === 'codex')
|
|
49
53
|
return '~/.codex/AGENTS.md';
|
|
50
|
-
|
|
54
|
+
// The engine home follows the ENGINE's namespace, not the provider slug — the
|
|
55
|
+
// engine reads its managed `AGENTS.md` from there (contract §5).
|
|
56
|
+
return `~/.skrr/${(0, auth_core_1.firstPartyHarnessHomeDirname)()}/AGENTS.md`;
|
|
51
57
|
}
|
|
52
58
|
function shouldSkipOffer() {
|
|
53
59
|
return Boolean(!process.stdin.isTTY ||
|
package/dist/lib/worklogs.js
CHANGED
|
@@ -14,8 +14,8 @@ exports.renderWorklogEntry = renderWorklogEntry;
|
|
|
14
14
|
* ── Why this file exists ──────────────────────────────────────────────────
|
|
15
15
|
*
|
|
16
16
|
* Worklog writing was an MCP capability, and MCP tools execute in the CLOUD.
|
|
17
|
-
* An agent pinned to a LOCAL daemon runtime — Claude Code, Codex,
|
|
18
|
-
* alike — could read a worklog and could not write one, because the route
|
|
17
|
+
* An agent pinned to a LOCAL daemon runtime — Claude Code, Codex, the
|
|
18
|
+
* first-party harness alike — could read a worklog and could not write one, because the route
|
|
19
19
|
* exposed three endpoints and all three were reads (OSK-3495).
|
|
20
20
|
*
|
|
21
21
|
* That is the same gap the CLI already closes for every sibling domain: tasks,
|