@skrr-ai/cli 0.1.62 → 0.1.64

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.
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@oclif/core");
4
4
  const daemon_binding_1 = require("../../lib/daemon-binding");
5
5
  const exec_runtime_binary_1 = require("../../lib/exec-runtime-binary");
6
+ const live_runtime_binary_1 = require("../../lib/live-runtime-binary");
6
7
  /**
7
8
  * `skrr daemon login` — authenticate the local runtime.
8
9
  *
@@ -37,11 +38,28 @@ class DaemonLogin extends core_1.Command {
37
38
  // (OSK-296).
38
39
  const argv = this.argv;
39
40
  try {
41
+ const boundArgv = (0, daemon_binding_1.bindToCliSession)(argv);
42
+ // A re-login must prove the key the running service uses. A development
43
+ // skrrd earlier on PATH can have a different auth configuration and
44
+ // silently leave the service's server pin unchanged (OSK-12758).
45
+ const pathBinary = (0, exec_runtime_binary_1.findRuntimeBinary)();
46
+ const decision = pathBinary
47
+ ? (0, live_runtime_binary_1.decideStatusBinary)(pathBinary, (0, live_runtime_binary_1.profileFromArgs)(boundArgv), (0, live_runtime_binary_1.defaultLiveRuntimeDeps)())
48
+ : null;
49
+ if (decision?.kind === 'mismatch') {
50
+ this.error(`The live daemon runs ${decision.live}, but this command found ${decision.binary} on PATH. ` +
51
+ 'Run login with the live daemon program so it proves the same device key.');
52
+ }
53
+ if (decision?.kind === 'forward-live') {
54
+ this.warn(`Signing in with the live daemon binary ${decision.binary}.`);
55
+ }
40
56
  // `--cwd` is deliberately NOT defaulted here. `skrrd login` resolves it
41
57
  // from the installed service definition, which is the only authoritative
42
58
  // answer; guessing it from the CLI's cwd is exactly the mistake that made
43
59
  // the old default wrong.
44
- const code = await (0, exec_runtime_binary_1.execRuntimeBinary)(['login', ...(0, daemon_binding_1.bindToCliSession)(argv)]);
60
+ const code = await (0, exec_runtime_binary_1.execRuntimeBinary)(['login', ...boundArgv], {
61
+ binary: decision?.binary,
62
+ });
45
63
  this.exit(code);
46
64
  }
47
65
  catch (err) {
@@ -0,0 +1,10 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ /** The buyer's installed copies, including stopped copies and their source releases. */
3
+ export default class StoreInstalls extends BaseCommand {
4
+ static description: string;
5
+ static examples: string[];
6
+ static flags: {
7
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
+ };
9
+ run(): Promise<void>;
10
+ }
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const data_provider_1 = require("@skrr-ai/data-provider");
5
+ const base_command_1 = require("../../base-command");
6
+ const format_1 = require("../../lib/format");
7
+ /** The buyer's installed copies, including stopped copies and their source releases. */
8
+ class StoreInstalls extends base_command_1.BaseCommand {
9
+ static description = 'List your Store installs and the releases they came from';
10
+ static examples = [
11
+ '<%= config.bin %> store installs',
12
+ '<%= config.bin %> store installs --json',
13
+ ];
14
+ static flags = {
15
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
16
+ };
17
+ async run() {
18
+ this.requireAuth();
19
+ const { flags } = await this.parse(StoreInstalls);
20
+ let response;
21
+ try {
22
+ response = await data_provider_1.dataService.getStoreInstalls();
23
+ }
24
+ catch (error) {
25
+ this.handleApiError(error);
26
+ return;
27
+ }
28
+ const installs = response?.installs ?? [];
29
+ if (flags.json) {
30
+ this.log(JSON.stringify({ object: 'list', data: installs }, null, 2));
31
+ return;
32
+ }
33
+ if (installs.length === 0) {
34
+ this.log('No Store installs found.');
35
+ return;
36
+ }
37
+ (0, format_1.renderTable)(installs.map((install) => ({
38
+ agent: install.agentId,
39
+ copy: install.installedAgentId ?? '-',
40
+ release: install.installedReleaseId ?? '-',
41
+ version: install.installedVersionLabel ?? '-',
42
+ state: install.copyMissing ? 'copy missing' : install.stopReason ? 'stopped' : 'installed',
43
+ reason: install.stopReason ?? '-',
44
+ })), [
45
+ { key: 'agent', header: 'LISTING' },
46
+ { key: 'copy', header: 'YOUR COPY' },
47
+ { key: 'release', header: 'RELEASE' },
48
+ { key: 'version', header: 'VERSION' },
49
+ { key: 'state', header: 'STATE' },
50
+ { key: 'reason', header: 'REASON', maxWidth: 40 },
51
+ ], (line) => this.log(line));
52
+ }
53
+ }
54
+ exports.default = StoreInstalls;
@@ -214,8 +214,8 @@ function notInstalledMessage() {
214
214
  */
215
215
  function execRuntimeBinary(args, opts = {}) {
216
216
  return new Promise((resolve, reject) => {
217
- // `binary` lets `status` render from the LIVE daemon's program rather than
218
- // the first one on PATH (OSK-12102); every other verb forwards to PATH.
217
+ // `binary` lets status and login use the LIVE daemon's program rather than
218
+ // the first one on PATH (OSK-12102, OSK-12758).
219
219
  const bin = opts.binary ?? findRuntimeBinary();
220
220
  if (!bin) {
221
221
  reject(new Error('runtime-binary-not-installed'));
@@ -37,4 +37,10 @@ export declare function decideStatusBinary(pathBinary: string, profile: string,
37
37
  /** One stderr line naming the binary that rendered status, when it is not obvious. */
38
38
  export declare function describeStatusBinary(decision: StatusBinaryDecision): string | null;
39
39
  export declare function scriptFromArgs(exec: string, args: string): string | null;
40
+ /**
41
+ * The daemon keeps its singleton holder while auth is latched, but removes the
42
+ * broker bootstrap because it cannot serve hand-offs. Status and login still
43
+ * need to address that live process during recovery (OSK-12807).
44
+ */
45
+ export declare function livePidFromLockInfo(profile: string, homeDir?: string): number | null;
40
46
  export declare function defaultLiveRuntimeDeps(): LiveRuntimeDeps;
@@ -7,10 +7,12 @@ exports.profileFromArgs = profileFromArgs;
7
7
  exports.decideStatusBinary = decideStatusBinary;
8
8
  exports.describeStatusBinary = describeStatusBinary;
9
9
  exports.scriptFromArgs = scriptFromArgs;
10
+ exports.livePidFromLockInfo = livePidFromLockInfo;
10
11
  exports.defaultLiveRuntimeDeps = defaultLiveRuntimeDeps;
11
12
  /**
12
13
  * Which runtime binary is the LIVE daemon running, and is it the one
13
- * `skrr daemon status` is about to forward to? (OSK-12102)
14
+ * `skrr daemon status` or `skrr daemon login` is about to forward to?
15
+ * (OSK-12102, OSK-12758)
14
16
  *
15
17
  * `execRuntimeBinary` forwards to the first `skrrd` on PATH. That is right for
16
18
  * lifecycle verbs, where PATH order is the person's choice of install. It is
@@ -28,6 +30,7 @@ exports.defaultLiveRuntimeDeps = defaultLiveRuntimeDeps;
28
30
  */
29
31
  const node_child_process_1 = require("node:child_process");
30
32
  const node_fs_1 = require("node:fs");
33
+ const node_os_1 = __importDefault(require("node:os"));
31
34
  const node_path_1 = __importDefault(require("node:path"));
32
35
  const daemonBroker_1 = require("./daemonBroker");
33
36
  const exec_runtime_binary_1 = require("./exec-runtime-binary");
@@ -162,6 +165,35 @@ function scriptFromArgs(exec, args) {
162
165
  }
163
166
  return null;
164
167
  }
168
+ /**
169
+ * The daemon keeps its singleton holder while auth is latched, but removes the
170
+ * broker bootstrap because it cannot serve hand-offs. Status and login still
171
+ * need to address that live process during recovery (OSK-12807).
172
+ */
173
+ function livePidFromLockInfo(profile, homeDir = node_os_1.default.homedir()) {
174
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(profile) || profile === '..')
175
+ return null;
176
+ try {
177
+ const lockInfoPath = node_path_1.default.join(homeDir, '.skrr', 'profiles', profile, 'daemon.lock.info.json');
178
+ const parsed = JSON.parse((0, node_fs_1.readFileSync)(lockInfoPath, 'utf8'));
179
+ const pid = parsed?.pid;
180
+ if (typeof pid !== 'number' || !Number.isSafeInteger(pid) || pid <= 0)
181
+ return null;
182
+ try {
183
+ process.kill(pid, 0);
184
+ }
185
+ catch (error) {
186
+ // EPERM still means a process holds the PID; all other probe failures
187
+ // leave this untrusted, potentially stale sidecar out of the decision.
188
+ if (error.code !== 'EPERM')
189
+ return null;
190
+ }
191
+ return pid;
192
+ }
193
+ catch {
194
+ return null;
195
+ }
196
+ }
165
197
  function defaultLiveRuntimeDeps() {
166
198
  return {
167
199
  livePid(profile) {
@@ -170,7 +202,7 @@ function defaultLiveRuntimeDeps() {
170
202
  if (typeof bootstrap?.pid === 'number' && bootstrap.pid > 0)
171
203
  return bootstrap.pid;
172
204
  }
173
- return null;
205
+ return livePidFromLockInfo(profile);
174
206
  },
175
207
  programOf(pid) {
176
208
  if (process.platform === 'darwin')
@@ -239,11 +239,16 @@ function createNodeAdapter(opts = {}) {
239
239
  const cred = currentCredential();
240
240
  if (cred.kind === 'ci')
241
241
  return false;
242
- // Bare-mode signal is on the resolved credential when populated by
243
- // BaseCommand. We don't have direct access here; instead we look at
244
- // the override's source — `bareMode` produces tokens sourced from
245
- // `flag` or `env-token`, both of which we already filter above. The
246
- // remaining bareMode case (no token at all) wouldn't reach this
242
+ // An operator-supplied `--token` is that operator's explicit
243
+ // authority: when the server refuses it, the honest answer is the
244
+ // 401 — not a silent retry under the daemon's principal (OSK-12801).
245
+ // `isEnvAuthOverride` above covers OVERSKY_TOKEN; the flag slot was
246
+ // missed because `kind` stays 'standard' for arbitrary flag strings.
247
+ // Broker-minted overrides carry 'env-token' too but are the daemon's
248
+ // own principal — re-recovering them preserves today's renewal path.
249
+ if (_credOverride?.source === 'flag')
250
+ return false;
251
+ // The remaining bareMode case (no token at all) wouldn't reach this
247
252
  // function — the adapter only retries on 401, which presupposes a
248
253
  // request was made with SOME bearer.
249
254
  let outcome;
@@ -48514,7 +48514,7 @@ exports.ACCEPTED_AGENT_TRIGGER_FIRE_OUTCOMES = ["succeeded", "in_progress", "awa
48514
48514
  var r2 = null === (t2 = e2.resolution) || void 0 === t2 ? void 0 : t2.closure;
48515
48515
  return r2 ? (null !== (o2 = null === (n2 = r2.overrode) || void 0 === n2 ? void 0 : n2.length) && void 0 !== o2 ? o2 : 0) > 0 ? "overridden" : false === r2.closable ? "open_items" : r2.degraded ? "unrecorded" : "clean" : "unrecorded";
48516
48516
  }, exports.deriveTaskCompletion = function(e2) {
48517
- var t2, n2 = (function(e3) {
48517
+ var t2, n2, o2 = (function(e3) {
48518
48518
  for (var t3 = false !== e3.evidenceRead, n3 = (e3.deliverables || []).filter(function(e4) {
48519
48519
  return gb(e4);
48520
48520
  }), o3 = null, r3 = 0, a3 = n3; r3 < a3.length; r3++) {
@@ -48526,23 +48526,23 @@ exports.ACCEPTED_AGENT_TRIGGER_FIRE_OUTCOMES = ["succeeded", "in_progress", "awa
48526
48526
  if (!(function(e3) {
48527
48527
  return e3.statusType ? "completed" === e3.statusType : "done" === e3.status;
48528
48528
  })(e2)) {
48529
- var o2 = Sb(e2);
48530
- return { state: "not_done", label: hb.not_done, sentence: "".concat(hb.not_done, ", because ").concat(Tb(o2.text)), reason: o2, alsoOutstanding: [], evidence: n2 };
48529
+ var r2 = Sb(e2);
48530
+ return { state: "not_done", label: hb.not_done, sentence: "".concat(hb.not_done, ", because ").concat(Tb(r2.text)), reason: r2, alsoOutstanding: [], evidence: o2 };
48531
48531
  }
48532
- var r2 = [], a2 = e2.closure;
48533
- n2.read || r2.push("The record of what was produced could not be read just now."), (null === (t2 = null == a2 ? void 0 : a2.overrode) || void 0 === t2 ? void 0 : t2.length) && r2.push("Someone closed it past a gate its owner had declared.");
48534
- for (var i2 = 0, s2 = Gy(a2); i2 < s2.length; i2++) {
48535
- var c2 = s2[i2];
48536
- r2.push(c2);
48532
+ var a2 = [], i2 = e2.closure;
48533
+ o2.read || a2.push("The record of what was produced could not be read just now."), (null === (t2 = null == i2 ? void 0 : i2.overrode) || void 0 === t2 ? void 0 : t2.length) && a2.push("Someone closed it past a gate its owner had declared.");
48534
+ for (var s2 = 0, c2 = Gy(i2); s2 < c2.length; s2++) {
48535
+ var l2 = c2[s2];
48536
+ a2.push(l2);
48537
48537
  }
48538
- if (a2 || r2.push("It was closed before the platform recorded what it was closed over."), n2.read && (0 === n2.arrived ? r2.push("Nothing it produced was recorded, so there is nothing here to look at.") : n2.aboveSelfReport || r2.push("The only thing standing behind what it produced is ".concat(lb(n2.highestLevel), "."))), 0 === r2.length) {
48539
- var l2 = "".concat((function(e3) {
48538
+ if (i2 || a2.push("It was closed before the platform recorded what it was closed over."), o2.read && (0 === o2.arrived ? a2.push((null === (n2 = e2.deliverables) || void 0 === n2 ? void 0 : n2.some(Boolean)) ? "A deliverable is recorded, but its availability has not been confirmed." : "No deliverable is recorded for this task.") : o2.aboveSelfReport || a2.push("The only thing standing behind what it produced is ".concat(lb(o2.highestLevel), "."))), 0 === a2.length) {
48539
+ var u2 = "".concat((function(e3) {
48540
48540
  return e3 ? e3[0].toUpperCase() + e3.slice(1) : e3;
48541
- })(lb(n2.highestLevel)), " stands behind what it produced.");
48542
- return { state: "done_and_checked", label: hb.done_and_checked, sentence: "".concat(hb.done_and_checked, " \u2014 ").concat(Tb(l2)), reason: { text: l2, phrased: true, code: null }, alsoOutstanding: [], evidence: n2 };
48541
+ })(lb(o2.highestLevel)), " stands behind what it produced.");
48542
+ return { state: "done_and_checked", label: hb.done_and_checked, sentence: "".concat(hb.done_and_checked, " \u2014 ").concat(Tb(u2)), reason: { text: u2, phrased: true, code: null }, alsoOutstanding: [], evidence: o2 };
48543
48543
  }
48544
- var u2 = r2[0], d2 = r2.slice(1);
48545
- return { state: "done_needs_your_eyes", label: hb.done_needs_your_eyes, sentence: "".concat(hb.done_needs_your_eyes, " \u2014 ").concat(Tb(u2)), reason: { text: u2, phrased: true, code: null }, alsoOutstanding: d2, evidence: n2 };
48544
+ var d2 = a2[0], p2 = a2.slice(1);
48545
+ return { state: "done_needs_your_eyes", label: hb.done_needs_your_eyes, sentence: "".concat(hb.done_needs_your_eyes, " \u2014 ").concat(Tb(d2)), reason: { text: d2, phrased: true, code: null }, alsoOutstanding: p2, evidence: o2 };
48546
48546
  }, exports.deriveWorkEdges = function(e2) {
48547
48547
  for (var t2, n2, o2 = /* @__PURE__ */ new Map(), r2 = 0, a2 = e2; r2 < a2.length; r2++) {
48548
48548
  var i2 = a2[r2];