@skrr-ai/cli 0.1.109 → 0.1.110

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.
Files changed (63) hide show
  1. package/dist/base-command.d.ts +15 -0
  2. package/dist/base-command.js +64 -17
  3. package/dist/commands/agents/triggers/create.js +1 -1
  4. package/dist/commands/agents/triggers/update.js +1 -1
  5. package/dist/commands/agents/update.d.ts +11 -0
  6. package/dist/commands/agents/update.js +58 -2
  7. package/dist/commands/daemon/install.js +17 -1
  8. package/dist/commands/daemon/login.js +14 -0
  9. package/dist/commands/harnesses/prune.d.ts +26 -0
  10. package/dist/commands/harnesses/prune.js +172 -0
  11. package/dist/commands/login.js +11 -0
  12. package/dist/commands/spaces/workflows/start.js +3 -1
  13. package/dist/commands/spaces/workflows/validate.js +12 -2
  14. package/dist/commands/tasks/activity.js +11 -1
  15. package/dist/commands/tasks/list.js +6 -2
  16. package/dist/commands/tasks/rearm-recurrence.js +22 -3
  17. package/dist/commands/tasks/show.d.ts +8 -0
  18. package/dist/commands/tasks/show.js +64 -32
  19. package/dist/commands/tasks/unschedule.js +5 -1
  20. package/dist/commands/tasks/update.js +11 -1
  21. package/dist/commands/triggers/audit.js +12 -3
  22. package/dist/commands/triggers/create.js +1 -1
  23. package/dist/commands/triggers/fire-detail.d.ts +7 -0
  24. package/dist/commands/triggers/fire-detail.js +30 -12
  25. package/dist/commands/triggers/fire.js +13 -3
  26. package/dist/commands/triggers/parse-intent.js +1 -1
  27. package/dist/commands/triggers/update.js +1 -1
  28. package/dist/commands/workspaces/grants.js +1 -4
  29. package/dist/commands/workspaces/members.js +6 -6
  30. package/dist/lib/commitment-product.js +5 -2
  31. package/dist/lib/commitments.d.ts +2 -1
  32. package/dist/lib/commitments.js +40 -40
  33. package/dist/lib/daemon-machine-identity-copy.d.ts +14 -0
  34. package/dist/lib/daemon-machine-identity-copy.js +27 -0
  35. package/dist/lib/daemon-machine-identity.d.ts +27 -0
  36. package/dist/lib/daemon-machine-identity.js +61 -0
  37. package/dist/lib/daemonHandoff.d.ts +19 -1
  38. package/dist/lib/daemonHandoff.js +59 -0
  39. package/dist/lib/harnesses.d.ts +71 -0
  40. package/dist/lib/harnesses.js +70 -0
  41. package/dist/lib/list-output.d.ts +1 -1
  42. package/dist/lib/list-output.js +2 -0
  43. package/dist/lib/profile-machine-identity-guard.js +11 -1
  44. package/dist/lib/task-economics.d.ts +10 -0
  45. package/dist/lib/task-economics.js +24 -2
  46. package/dist/lib/triggers.d.ts +11 -0
  47. package/dist/lib/triggers.js +43 -1
  48. package/dist/lib/workflow-run-view.d.ts +4 -0
  49. package/dist/lib/workflow-run-view.js +5 -0
  50. package/dist/lib/workspaces.d.ts +24 -7
  51. package/dist/lib/workspaces.js +14 -2
  52. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -1
  53. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +5 -3
  54. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.d.ts +60 -0
  55. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.js +130 -6
  56. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -1
  57. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +1 -1
  58. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.d.ts +60 -0
  59. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.js +128 -6
  60. package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
  61. package/dist/node_modules/@skrr-ai/data-provider/index.js +4003 -3968
  62. package/oclif.manifest.json +99 -9
  63. package/package.json +10 -1
@@ -218,7 +218,7 @@ function readPersistedChoice(file, hardware, profile, requireProfile = false) {
218
218
  return null;
219
219
  }
220
220
  }
221
- function persistChoice(dir, file, hardware, machineUuid, reason, profile) {
221
+ function persistChoice(dir, file, hardware, machineUuid, reason, profile, evidence) {
222
222
  try {
223
223
  fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
224
224
  const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;
@@ -228,6 +228,12 @@ function persistChoice(dir, file, hardware, machineUuid, reason, profile) {
228
228
  machineUuid,
229
229
  profile,
230
230
  reason,
231
+ // WHICH file made a profile "already hold credentials". The reason alone
232
+ // says a profile shares the default's machine row; this says what put it
233
+ // there, which is the difference between "an older Skrr set it up" and
234
+ // "its first credential was written before anything chose its identity".
235
+ // Additive: a reader that predates it ignores the field.
236
+ ...(evidence && evidence.length > 0 ? { evidence: [...evidence] } : {}),
231
237
  decidedAt: new Date().toISOString(),
232
238
  };
233
239
  fs.writeFileSync(tmp, `${JSON.stringify(body)}\n`, { mode: 0o600 });
@@ -267,7 +273,7 @@ function resolveProfileMachineUuid(profile, hardware) {
267
273
  persistChoice(dir, file, hardware, chosen, 'restored_profile', profile);
268
274
  }
269
275
  if (!chosen) {
270
- const preExisting = PRE_EXISTING_PROFILE_EVIDENCE.some((name) => {
276
+ const evidence = PRE_EXISTING_PROFILE_EVIDENCE.filter((name) => {
271
277
  try {
272
278
  return fs.existsSync(path.join(dir, name));
273
279
  }
@@ -275,8 +281,9 @@ function resolveProfileMachineUuid(profile, hardware) {
275
281
  return false;
276
282
  }
277
283
  });
284
+ const preExisting = evidence.length > 0;
278
285
  chosen = preExisting ? hardware : qualifyMachineUuid(hardware, profile);
279
- persistChoice(dir, file, hardware, chosen, preExisting ? 'pre_existing_profile' : 'new_profile', profile);
286
+ persistChoice(dir, file, hardware, chosen, preExisting ? 'pre_existing_profile' : 'new_profile', profile, evidence);
280
287
  }
281
288
  preserveRecoveryChoice(profile, hardware, chosen);
282
289
  profileChoiceCache.set(cacheKey, chosen);
@@ -296,14 +303,129 @@ function resolveProfileMachineUuid(profile, hardware) {
296
303
  * profile that already held credentials; see the block above.
297
304
  */
298
305
  export function getMachineUuid() {
306
+ return getMachineUuidForProfile(activeMachineProfile);
307
+ }
308
+ /**
309
+ * The `machineUuid` a process running as `profile` sends, WITHOUT changing which
310
+ * profile this process runs as.
311
+ *
312
+ * The CLI needs the answer for the profile it is about to hand a credential to,
313
+ * and asks the daemon binary what IT will send (`accept-handoff --print-id`).
314
+ * Two programs that compute one identity can only be known to agree by
315
+ * comparing them, and a daemon that predates per-profile identities does not
316
+ * agree: it sends the hardware value whatever the profile's
317
+ * `machine-identity.json` says, so a credential minted for what it reports
318
+ * registers the profile on the default machine's row (the OSK-13845 failure, now
319
+ * reached through version skew rather than through the rule). The comparison
320
+ * needs this: the expected value for the TARGET profile, which is not
321
+ * necessarily the one this process is running as.
322
+ *
323
+ * Decides and persists the profile's identity if nothing has yet — the same
324
+ * side effect `getMachineUuid()` has, for the same reason.
325
+ */
326
+ export function getMachineUuidForProfile(profile) {
299
327
  const hardware = getHardwareMachineUuid();
300
328
  // A hosted runtime's identity is ISSUED and fenced by the control plane.
301
329
  if (hostedRuntimeIdOverride('OVERSKY_MACHINE_UUID'))
302
330
  return hardware;
303
- const profile = activeMachineProfile;
304
- if (!profile || profile === DEFAULT_PROFILE_NAME)
331
+ const name = typeof profile === 'string' ? profile.trim() : '';
332
+ if (!name || name === DEFAULT_PROFILE_NAME)
305
333
  return hardware;
306
- return resolveProfileMachineUuid(profile, hardware);
334
+ return resolveProfileMachineUuid(name, hardware);
335
+ }
336
+ function readRecordedChoice(profile) {
337
+ try {
338
+ const file = path.join(resolveConfigRoot(), 'profiles', profile, MACHINE_IDENTITY_FILENAME);
339
+ const parsed = JSON.parse(fs.readFileSync(file, 'utf-8'));
340
+ const reason = parsed.reason === 'new_profile' ||
341
+ parsed.reason === 'pre_existing_profile' ||
342
+ parsed.reason === 'restored_profile'
343
+ ? parsed.reason
344
+ : null;
345
+ return {
346
+ reason,
347
+ evidence: Array.isArray(parsed.evidence)
348
+ ? parsed.evidence.filter((e) => typeof e === 'string')
349
+ : [],
350
+ decidedAt: typeof parsed.decidedAt === 'string' ? parsed.decidedAt : null,
351
+ };
352
+ }
353
+ catch {
354
+ return { reason: null, evidence: [], decidedAt: null };
355
+ }
356
+ }
357
+ /**
358
+ * Which machine this process registers as, and WHY — the question a person has
359
+ * when two profiles turn up on one machine page and the logs say nothing.
360
+ *
361
+ * A read, not a decision: it reports the identity `getMachineUuid()` settled on
362
+ * (settling it if nothing has, exactly as any caller would) and the record that
363
+ * explains it. It never changes what a profile registers as.
364
+ */
365
+ export function describeMachineIdentity() {
366
+ const hardware = getHardwareMachineUuid();
367
+ const machineUuid = getMachineUuid();
368
+ const active = activeMachineProfile;
369
+ const profile = active && active !== DEFAULT_PROFILE_NAME ? active : null;
370
+ const base = { profile, machineUuid, hardware };
371
+ if (hostedRuntimeIdOverride('OVERSKY_MACHINE_UUID')) {
372
+ return {
373
+ ...base,
374
+ sharesDefaultMachine: false,
375
+ reason: 'hosted_runtime',
376
+ evidence: [],
377
+ decidedAt: null,
378
+ sentence: 'This runtime is hosted; its machine identity was issued by the control plane.',
379
+ };
380
+ }
381
+ if (!profile) {
382
+ return {
383
+ ...base,
384
+ sharesDefaultMachine: false,
385
+ reason: 'default_profile',
386
+ evidence: [],
387
+ decidedAt: null,
388
+ sentence: "The default profile uses this computer's own machine identity.",
389
+ };
390
+ }
391
+ const recorded = readRecordedChoice(profile);
392
+ const sharesDefaultMachine = machineUuid === hardware;
393
+ const reason = recorded.reason ?? 'unrecorded';
394
+ const decided = recorded.decidedAt ? ` (decided ${recorded.decidedAt})` : '';
395
+ const held = recorded.evidence.length > 0 ? ` (${recorded.evidence.join(', ')})` : '';
396
+ let sentence;
397
+ if (reason === 'new_profile') {
398
+ sentence =
399
+ `Profile '${profile}' has its own machine identity: it held no credentials when that ` +
400
+ `identity was first chosen${decided}.`;
401
+ }
402
+ else if (reason === 'pre_existing_profile') {
403
+ sentence =
404
+ `Profile '${profile}' shares this computer's default machine identity: it already held ` +
405
+ `credentials${held} when its identity was first chosen${decided}, and the server ties ` +
406
+ 'those credentials to that identity, so changing it would sign the profile out.';
407
+ }
408
+ else if (reason === 'restored_profile') {
409
+ sentence = sharesDefaultMachine
410
+ ? `Profile '${profile}' shares this computer's default machine identity, restored from the ` +
411
+ `copy kept outside the profile after its state was removed${decided}.`
412
+ : `Profile '${profile}' has its own machine identity, restored from the copy kept outside ` +
413
+ `the profile after its state was removed${decided}.`;
414
+ }
415
+ else {
416
+ sentence = sharesDefaultMachine
417
+ ? `Profile '${profile}' uses this computer's default machine identity; the record of why ` +
418
+ 'could not be read.'
419
+ : `Profile '${profile}' has its own machine identity; the record of why could not be read.`;
420
+ }
421
+ return {
422
+ ...base,
423
+ sharesDefaultMachine,
424
+ reason,
425
+ evidence: recorded.evidence,
426
+ decidedAt: recorded.decidedAt,
427
+ sentence,
428
+ };
307
429
  }
308
430
  /** @internal test seam — forget the cached value so the next call re-probes. */
309
431
  export function __resetMachineUuidCacheForTest() {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skrr-ai/auth-core",
3
- "version": "0.4.26",
3
+ "version": "0.4.27",
4
4
  "main": "dist/cjs/index.js",
5
5
  "types": "dist/esm/index.d.ts",
6
6
  "exports": {