@skrr-ai/cli 0.1.39 → 0.1.41

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 (134) hide show
  1. package/README.md +1 -1
  2. package/dist/base-command.d.ts +9 -0
  3. package/dist/base-command.js +26 -3
  4. package/dist/commands/agent-shares/list-for.js +4 -11
  5. package/dist/commands/agent-shares/received.js +4 -11
  6. package/dist/commands/agent-shares/sent.js +4 -11
  7. package/dist/commands/agent-shares/with.js +3 -10
  8. package/dist/commands/agents/activity.js +1 -1
  9. package/dist/commands/agents/api-actions/add.js +6 -0
  10. package/dist/commands/agents/chat.js +6 -1
  11. package/dist/commands/agents/create.d.ts +7 -0
  12. package/dist/commands/agents/create.js +19 -2
  13. package/dist/commands/agents/manager/ensure.d.ts +18 -0
  14. package/dist/commands/agents/manager/ensure.js +56 -0
  15. package/dist/commands/agents/show.js +4 -0
  16. package/dist/commands/agents/tools/auth.d.ts +6 -0
  17. package/dist/commands/agents/tools/auth.js +27 -1
  18. package/dist/commands/agents/tools/index.js +11 -1
  19. package/dist/commands/agents/triggers/policy.d.ts +1 -0
  20. package/dist/commands/agents/triggers/policy.js +32 -0
  21. package/dist/commands/agents/update.js +10 -4
  22. package/dist/commands/code/install.d.ts +4 -2
  23. package/dist/commands/code/install.js +12 -10
  24. package/dist/commands/convos/list.js +1 -3
  25. package/dist/commands/convos/show.js +4 -11
  26. package/dist/commands/daemon/index.js +3 -3
  27. package/dist/commands/daemon/install.js +4 -4
  28. package/dist/commands/daemon/login.js +1 -1
  29. package/dist/commands/daemon/logs.d.ts +3 -1
  30. package/dist/commands/daemon/logs.js +16 -1
  31. package/dist/commands/daemon/start.js +3 -3
  32. package/dist/commands/daemon/status.d.ts +9 -0
  33. package/dist/commands/daemon/status.js +22 -0
  34. package/dist/commands/dm/messages.js +1 -11
  35. package/dist/commands/followups/cancel.js +1 -1
  36. package/dist/commands/followups/observability.js +6 -2
  37. package/dist/commands/followups/remind.js +5 -2
  38. package/dist/commands/followups/reschedule.js +2 -1
  39. package/dist/commands/followups/resolve.js +1 -1
  40. package/dist/commands/followups/show.js +20 -0
  41. package/dist/commands/followups/watch.d.ts +1 -0
  42. package/dist/commands/followups/watch.js +9 -3
  43. package/dist/commands/harnesses/forget.js +20 -3
  44. package/dist/commands/harnesses/install.js +18 -6
  45. package/dist/commands/harnesses/installers.d.ts +1 -1
  46. package/dist/commands/harnesses/installers.js +36 -12
  47. package/dist/commands/harnesses/list.d.ts +74 -2
  48. package/dist/commands/harnesses/list.js +231 -15
  49. package/dist/commands/harnesses/ping.d.ts +2 -0
  50. package/dist/commands/harnesses/ping.js +21 -0
  51. package/dist/commands/harnesses/show.d.ts +22 -0
  52. package/dist/commands/harnesses/show.js +116 -17
  53. package/dist/commands/harnesses/update.d.ts +8 -0
  54. package/dist/commands/harnesses/update.js +25 -1
  55. package/dist/commands/harnesses/usage.d.ts +2 -0
  56. package/dist/commands/harnesses/usage.js +7 -2
  57. package/dist/commands/instructions/status.js +13 -0
  58. package/dist/commands/instructions/update-target.d.ts +1 -0
  59. package/dist/commands/instructions/update-target.js +11 -3
  60. package/dist/commands/login.js +5 -5
  61. package/dist/commands/machines/list.js +8 -9
  62. package/dist/commands/machines/show.js +46 -17
  63. package/dist/commands/messages/show.js +3 -10
  64. package/dist/commands/shares/get.js +2 -9
  65. package/dist/commands/shares/list.js +1 -9
  66. package/dist/commands/shortcuts/show.js +4 -11
  67. package/dist/commands/skills/local.js +6 -0
  68. package/dist/commands/spaces/actions/run.js +3 -4
  69. package/dist/commands/spaces/briefs/get.js +2 -9
  70. package/dist/commands/spaces/briefs/list.js +1 -9
  71. package/dist/commands/spaces/conversations.js +1 -9
  72. package/dist/commands/spaces/heartbeats/list.js +1 -9
  73. package/dist/commands/spaces/heartbeats/status.js +2 -9
  74. package/dist/commands/tasks/activity.js +1 -10
  75. package/dist/commands/tasks/approvals/list.js +1 -9
  76. package/dist/commands/tasks/attachments/list.js +1 -9
  77. package/dist/commands/tasks/comments/list.js +1 -9
  78. package/dist/commands/tasks/dri-status.js +2 -9
  79. package/dist/commands/tasks/events/append.js +9 -7
  80. package/dist/commands/tasks/execution-timeline.js +1 -9
  81. package/dist/commands/tasks/lifecycle/detach.js +26 -5
  82. package/dist/commands/tasks/monitor.js +1 -9
  83. package/dist/commands/tasks/result/submit.js +9 -0
  84. package/dist/commands/tasks/runs.js +1 -9
  85. package/dist/commands/tasks/show.js +5 -12
  86. package/dist/commands/token/list.d.ts +8 -0
  87. package/dist/commands/token/list.js +51 -6
  88. package/dist/help.js +8 -12
  89. package/dist/lib/agent-home-workspace.d.ts +19 -0
  90. package/dist/lib/agent-home-workspace.js +39 -0
  91. package/dist/lib/agent-resolver.js +2 -2
  92. package/dist/lib/agentic-stream.d.ts +22 -1
  93. package/dist/lib/agentic-stream.js +48 -7
  94. package/dist/lib/cli-installers.d.ts +84 -2
  95. package/dist/lib/cli-installers.js +146 -13
  96. package/dist/lib/command-miss.d.ts +22 -0
  97. package/dist/lib/command-miss.js +78 -0
  98. package/dist/lib/daemon-setup.js +2 -2
  99. package/dist/lib/daemon-target.d.ts +14 -0
  100. package/dist/lib/daemon-target.js +32 -0
  101. package/dist/lib/daemonBroker.js +1 -1
  102. package/dist/lib/daemonHandoff.js +1 -1
  103. package/dist/lib/dedicated-lease-command.js +4 -1
  104. package/dist/lib/dedicated-machines.d.ts +8 -1
  105. package/dist/lib/dedicated-machines.js +22 -6
  106. package/dist/lib/dedicated-wait.js +13 -0
  107. package/dist/lib/exec-runtime-binary.js +2 -2
  108. package/dist/lib/followups.d.ts +18 -0
  109. package/dist/lib/followups.js +14 -1
  110. package/dist/lib/format.d.ts +11 -0
  111. package/dist/lib/format.js +21 -0
  112. package/dist/lib/harness-labels.d.ts +39 -0
  113. package/dist/lib/harness-labels.js +60 -0
  114. package/dist/lib/harnesses.d.ts +6 -0
  115. package/dist/lib/instruction-input.d.ts +13 -0
  116. package/dist/lib/instruction-input.js +20 -1
  117. package/dist/lib/label-ref.d.ts +8 -1
  118. package/dist/lib/label-ref.js +12 -2
  119. package/dist/lib/local-skills.d.ts +17 -1
  120. package/dist/lib/local-skills.js +20 -2
  121. package/dist/lib/login.js +5 -5
  122. package/dist/lib/machines.d.ts +6 -0
  123. package/dist/lib/machines.js +68 -2
  124. package/dist/lib/option-hint.d.ts +15 -0
  125. package/dist/lib/option-hint.js +75 -0
  126. package/dist/lib/runtime-tool-support.d.ts +34 -0
  127. package/dist/lib/runtime-tool-support.js +77 -0
  128. package/dist/lib/share-rows.d.ts +17 -0
  129. package/dist/lib/share-rows.js +35 -0
  130. package/dist/lib/workspaces.d.ts +3 -0
  131. package/dist/lib/workspaces.js +38 -0
  132. package/dist/node_modules/@skrr-ai/data-provider/index.js +5029 -5007
  133. package/oclif.manifest.json +34255 -34142
  134. package/package.json +10 -5
@@ -4,6 +4,7 @@ const core_1 = require("@oclif/core");
4
4
  const data_provider_1 = require("@skrr-ai/data-provider");
5
5
  const base_command_1 = require("../../../base-command");
6
6
  const space_output_1 = require("../../../lib/space-output");
7
+ const format_1 = require("../../../lib/format");
7
8
  class SpacesHeartbeatsStatus extends base_command_1.BaseCommand {
8
9
  static description = 'Get the live status of a heartbeat for an agent in a space';
9
10
  static examples = [
@@ -45,16 +46,8 @@ class SpacesHeartbeatsStatus extends base_command_1.BaseCommand {
45
46
  // `running`/`nextRun`/`jobKey` which always rendered "no" / "-".
46
47
  const s = result;
47
48
  this.log(`Running: ${s.isRunning === true ? 'yes' : 'no'}`);
48
- this.log(`Next Run: ${s.nextRunAt ? formatTime(s.nextRunAt) : '-'}`);
49
+ this.log(`Next Run: ${s.nextRunAt ? (0, format_1.localTime)(s.nextRunAt) : '-'}`);
49
50
  this.log(`BullMQ Job Key: ${s.bullmqJobKey ?? '-'}`);
50
51
  }
51
52
  }
52
53
  exports.default = SpacesHeartbeatsStatus;
53
- function formatTime(value) {
54
- try {
55
- return new Date(String(value)).toISOString().slice(0, 19).replace('T', ' ');
56
- }
57
- catch {
58
- return String(value);
59
- }
60
- }
@@ -19,7 +19,7 @@ function activityRow(entry) {
19
19
  : `system:${actor.service}`
20
20
  : (entry.userId ?? entry.actorId);
21
21
  return {
22
- time: formatTime(entry.occurredAt ?? entry.timestamp ?? entry.createdAt),
22
+ time: (0, format_1.localTime)(entry.occurredAt ?? entry.timestamp ?? entry.createdAt),
23
23
  event: (0, format_1.formatCell)(entry.action ?? entry.event ?? entry.type),
24
24
  actor: (0, format_1.formatCell)(actorText),
25
25
  details: (0, format_1.formatCell)(entry.data ?? entry.details ?? entry.metadata),
@@ -71,15 +71,6 @@ function runFailuresFromActivity(entries) {
71
71
  }
72
72
  return out;
73
73
  }
74
- /** Same contract as `tasks monitor`'s timestamp column — never throws, never prints "undefined". */
75
- function formatTime(value) {
76
- if (!value)
77
- return '-';
78
- const date = new Date(String(value));
79
- if (Number.isNaN(date.getTime()))
80
- return String(value);
81
- return date.toISOString().slice(0, 19).replace('T', ' ');
82
- }
83
74
  class TasksActivity extends base_command_1.BaseCommand {
84
75
  static description = 'Show the immutable, multi-actor Activity ledger for a Task';
85
76
  static examples = [
@@ -5,14 +5,6 @@ const core_1 = require("@oclif/core");
5
5
  const data_provider_1 = require("@skrr-ai/data-provider");
6
6
  const base_command_1 = require("../../../base-command");
7
7
  const format_1 = require("../../../lib/format");
8
- function formatTime(value) {
9
- try {
10
- return new Date(String(value)).toISOString().slice(0, 19).replace('T', ' ');
11
- }
12
- catch {
13
- return String(value);
14
- }
15
- }
16
8
  /**
17
9
  * One approval document → one table row.
18
10
  *
@@ -27,7 +19,7 @@ function approvalRow(a) {
27
19
  type: (0, format_1.formatCell)(a.type),
28
20
  status: (0, format_1.formatCell)(a.status),
29
21
  approver: (0, format_1.formatCell)(a.approverAgentId ?? a.approverUserId ?? a.approver),
30
- created: a.createdAt ? formatTime(a.createdAt) : '-',
22
+ created: a.createdAt ? (0, format_1.localTime)(a.createdAt) : '-',
31
23
  };
32
24
  }
33
25
  class TasksApprovalsList extends base_command_1.BaseCommand {
@@ -5,14 +5,6 @@ const core_1 = require("@oclif/core");
5
5
  const data_provider_1 = require("@skrr-ai/data-provider");
6
6
  const base_command_1 = require("../../../base-command");
7
7
  const format_1 = require("../../../lib/format");
8
- function formatTime(value) {
9
- try {
10
- return new Date(String(value)).toISOString().slice(0, 19).replace('T', ' ');
11
- }
12
- catch {
13
- return String(value);
14
- }
15
- }
16
8
  function humanBytes(bytes) {
17
9
  const n = Number(bytes);
18
10
  if (!Number.isFinite(n))
@@ -41,7 +33,7 @@ function attachmentRow(a) {
41
33
  filename: (0, format_1.formatCell)(a.originalName ?? a.filename ?? a.name),
42
34
  size: humanBytes(a.size ?? a.fileSize),
43
35
  mime: (0, format_1.formatCell)(a.mimeType ?? a.contentType),
44
- uploaded: a.createdAt ? formatTime(a.createdAt) : '-',
36
+ uploaded: a.createdAt ? (0, format_1.localTime)(a.createdAt) : '-',
45
37
  };
46
38
  }
47
39
  class TasksAttachmentsList extends base_command_1.BaseCommand {
@@ -5,14 +5,6 @@ const data_provider_1 = require("@skrr-ai/data-provider");
5
5
  const base_command_1 = require("../../../base-command");
6
6
  const format_1 = require("../../../lib/format");
7
7
  const task_resolver_1 = require("../../../lib/task-resolver");
8
- function formatTime(value) {
9
- try {
10
- return new Date(String(value)).toISOString().slice(0, 19).replace('T', ' ');
11
- }
12
- catch {
13
- return String(value);
14
- }
15
- }
16
8
  class TasksCommentsList extends base_command_1.BaseCommand {
17
9
  static description = 'List comments on a task';
18
10
  static examples = [
@@ -76,7 +68,7 @@ class TasksCommentsList extends base_command_1.BaseCommand {
76
68
  return;
77
69
  }
78
70
  const rows = items.map((c) => ({
79
- time: formatTime(c.createdAt),
71
+ time: (0, format_1.localTime)(c.createdAt),
80
72
  author: String(c.authorAgentId ?? c.authorUserId ?? c.author ?? '-'),
81
73
  body: (0, format_1.truncate)(String(c.body ?? c.content ?? '-'), 60),
82
74
  id: String(c.id ?? c._id ?? '-'),
@@ -3,14 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@oclif/core");
4
4
  const data_provider_1 = require("@skrr-ai/data-provider");
5
5
  const base_command_1 = require("../../base-command");
6
- function formatTime(value) {
7
- try {
8
- return new Date(String(value)).toISOString().slice(0, 19).replace('T', ' ');
9
- }
10
- catch {
11
- return String(value);
12
- }
13
- }
6
+ const format_1 = require("../../lib/format");
14
7
  class TasksDriStatus extends base_command_1.BaseCommand {
15
8
  static description = 'Show DRI agent status for a task';
16
9
  static examples = [
@@ -40,7 +33,7 @@ class TasksDriStatus extends base_command_1.BaseCommand {
40
33
  const s = result;
41
34
  this.log(`Status: ${s.status ?? '-'}`);
42
35
  this.log(`Mode: ${s.mode ?? '-'}`);
43
- this.log(`Started At: ${s.startedAt ? formatTime(s.startedAt) : '-'}`);
36
+ this.log(`Started At: ${s.startedAt ? (0, format_1.localTime)(s.startedAt) : '-'}`);
44
37
  this.log(`Total: ${s.totalSubtasks ?? s.total ?? '-'}`);
45
38
  this.log(`Done: ${s.doneCount ?? s.done ?? '-'}`);
46
39
  this.log(`In Progress: ${s.inProgressCount ?? s.inProgress ?? '-'}`);
@@ -18,15 +18,17 @@ class TasksEventsAppend extends base_command_1.BaseCommand {
18
18
  static summary = 'DEPRECATED compatibility spelling for `tasks updates add` — append a legacy task event';
19
19
  // The FULL mapping, not a sample of it. The previous description named
20
20
  // `handoff`/`checkpoint` and `started|lifecycle` and stopped — so a caller
21
- // passing `--kind evidence` had no way to learn, before writing, that it
22
- // becomes a `verification` Update. Those are different claims: `evidence`
23
- // says a flow was exercised, `verification` says a claim was CHECKED, and the
24
- // typed-Update vocabulary exists precisely so the two cannot be confused.
21
+ // passing `--kind evidence` had no way to learn, before writing, what it
22
+ // became. It used to become a `verification` with an invented `inconclusive`
23
+ // result; `evidence` says a flow was exercised, `verification` says a claim was
24
+ // CHECKED, so it now becomes `progress` and keeps the evidence as a reference
25
+ // (OSK-9312).
25
26
  // Mirrors `LEGACY_KIND_TO_UPDATE_TYPE` in `api/server/services/TaskWorkEvent.js`.
26
27
  static description = 'DEPRECATED compatibility adapter for the historical Event vocabulary. Every kind is ' +
27
28
  'stored as a canonical Update of a DIFFERENT name, so read this before relying on one: ' +
28
- '`evidence` and `verification` both become `verification`; `checkpoint`, `changed`, ' +
29
- '`completed` and `handoff` all become `progress`; `input_requested` and `failed` become ' +
29
+ '`verification` becomes a passed `verification`; `evidence`, `checkpoint`, `changed`, ' +
30
+ "`completed` and `handoff` all become `progress` (evidence text is kept as the Update's reference, " +
31
+ 'with no invented result); `input_requested` and `failed` become ' +
30
32
  '`blocker`; `decision` stays `decision`. `--kind started|lifecycle` writes only to the ' +
31
33
  'Activity ledger and will NOT appear in `tasks updates list`. Use `tasks updates add` ' +
32
34
  'instead, which writes the type you name.';
@@ -129,7 +131,7 @@ class TasksEventsAppend extends base_command_1.BaseCommand {
129
131
  * where it happens to be true. `finding` and `progress` exist only on the
130
132
  * canonical command; `evidence`, `checkpoint` and the rest only here.
131
133
  */
132
- this.log(`\`tasks events append --kind ${written.canonicalType}\` maps onto ` +
134
+ this.log(`\`tasks events append --kind ${flags.kind}\` maps onto ` +
133
135
  `\`${this.config.bin} tasks updates add --type ${written.canonicalType}\`, which is the ` +
134
136
  'canonical command. Their vocabularies differ otherwise — `--type ' +
135
137
  'progress|finding` exist only there — and `tasks updates list` reads them back.');
@@ -4,14 +4,6 @@ const core_1 = require("@oclif/core");
4
4
  const data_provider_1 = require("@skrr-ai/data-provider");
5
5
  const base_command_1 = require("../../base-command");
6
6
  const format_1 = require("../../lib/format");
7
- function formatTime(value) {
8
- try {
9
- return new Date(String(value)).toISOString().slice(0, 19).replace('T', ' ');
10
- }
11
- catch {
12
- return String(value);
13
- }
14
- }
15
7
  class TasksExecutionTimeline extends base_command_1.BaseCommand {
16
8
  static description = 'Show execution timeline for a task';
17
9
  static examples = [
@@ -49,7 +41,7 @@ class TasksExecutionTimeline extends base_command_1.BaseCommand {
49
41
  return;
50
42
  }
51
43
  const rows = items.map((entry) => ({
52
- timestamp: formatTime(entry.timestamp ?? entry.createdAt),
44
+ timestamp: (0, format_1.localTime)(entry.timestamp ?? entry.createdAt),
53
45
  event: String(entry.event ?? entry.type ?? '-'),
54
46
  duration: entry.durationMs != null ? `${entry.durationMs}ms` : '-',
55
47
  tokens: String(entry.tokens ?? entry.totalTokens ?? '-'),
@@ -43,11 +43,26 @@ class TasksLifecycleDetach extends base_command_1.BaseCommand {
43
43
  return this.log('No lifecycle is attached to this Task — nothing to detach.');
44
44
  this.log(`Would detach ${lifecycle.packId ? `pack ${lifecycle.packId}` : `definition ${lifecycle.definitionId}`}` +
45
45
  ` at generation ${lifecycle.generation}, stage ${lifecycle.currentStageKey ?? '—'}.`);
46
- this.log(' The run is cancelled and kept as history; nothing already recorded is removed.');
47
- this.log(' The generation is bumped, so no in-flight writer from the old run can land.');
46
+ if (lifecycle.runId) {
47
+ this.log(' The run is cancelled and kept as history; nothing already recorded is removed.');
48
+ this.log(' The generation is bumped, so no in-flight writer from the old run can land.');
49
+ }
50
+ else {
51
+ this.log(' It has not started, so there is no run to cancel.');
52
+ }
48
53
  this.log(' Re-attaching afterwards starts a NEW generation — it does not resume this one.');
49
54
  return;
50
55
  }
56
+ // The server clears runId on detach, so whether there WAS a run to cancel
57
+ // is only knowable before the write. Best-effort: a failed read must not
58
+ // block the detach, it only costs the sentence its precision.
59
+ let hadRun;
60
+ try {
61
+ hadRun = Boolean((await data_provider_1.dataService.getTaskLifecycle(taskId)).lifecycle?.runId);
62
+ }
63
+ catch {
64
+ hadRun = undefined;
65
+ }
51
66
  let response;
52
67
  try {
53
68
  response = await data_provider_1.dataService.detachTaskLifecycle({
@@ -62,9 +77,15 @@ class TasksLifecycleDetach extends base_command_1.BaseCommand {
62
77
  return this.log(JSON.stringify(response, null, 2));
63
78
  const lifecycle = response.lifecycle;
64
79
  // Name what changed. "Detached lifecycle from the Task." left the reader to
65
- // diff the state afterwards to learn what had happened.
66
- this.log(`Detached${lifecycle?.packId ? ` pack ${lifecycle.packId}` : ''} — the run is cancelled and` +
67
- ` kept as history, and the binding is now generation ${lifecycle?.generation ?? '?'}` +
80
+ // diff the state afterwards to learn what had happened — and saying a run
81
+ // was cancelled when none had started is the same problem the other way.
82
+ const runSentence = hadRun === false
83
+ ? 'it had not started, so there was no run to cancel'
84
+ : hadRun
85
+ ? 'the run is cancelled and kept as history'
86
+ : 'any run is cancelled and kept as history';
87
+ this.log(`Detached${lifecycle?.packId ? ` pack ${lifecycle.packId}` : ''} — ${runSentence},` +
88
+ ` and the binding is now generation ${lifecycle?.generation ?? '?'}` +
68
89
  ` (${lifecycle?.status ?? 'detached'}).`);
69
90
  this.log('Re-attach with: skrr tasks lifecycle attach <task-id> --pack <pack>');
70
91
  }
@@ -205,7 +205,7 @@ async function fetchRecentEvents(tasks, limit) {
205
205
  ref: String(task.identifier ?? task.taskNumber ?? '-'),
206
206
  taskId: (0, tasks_1.taskId)(task),
207
207
  event: String(record.event ?? record.type ?? '-'),
208
- time: formatTime(record.timestamp ?? record.createdAt),
208
+ time: (0, format_1.localTime)(record.timestamp ?? record.createdAt),
209
209
  run: String(record.runId ?? '-'),
210
210
  };
211
211
  });
@@ -216,11 +216,3 @@ async function fetchRecentEvents(tasks, limit) {
216
216
  }));
217
217
  return responses.flat();
218
218
  }
219
- function formatTime(value) {
220
- if (!value)
221
- return '-';
222
- const date = new Date(String(value));
223
- if (Number.isNaN(date.getTime()))
224
- return String(value);
225
- return date.toISOString().slice(0, 19).replace('T', ' ');
226
- }
@@ -122,6 +122,15 @@ class TasksResultSubmit extends base_command_1.BaseCommand {
122
122
  : await data_provider_1.dataService.submitTaskResult({ taskId: task.id, data });
123
123
  }
124
124
  catch (error) {
125
+ // A closed Task refuses a Result. Name the two ways forward here, where
126
+ // the commands are known: the API's own message stays surface-neutral
127
+ // (OSK-10031).
128
+ const refusal = (0, base_command_1.apiRefusal)(error);
129
+ if (refusal.code === 'TASK_REOPEN_REQUIRED') {
130
+ this.error(`${refusal.message ?? 'This Task is closed.'}\n` +
131
+ `→ Reopen it and submit again: ${this.config.bin} tasks move ${task.id} --status in_progress\n` +
132
+ `→ Or record the Result and close it in one step: ${this.config.bin} tasks complete ${task.id} --summary "…"`, { exit: 1, code: 'TASK_REOPEN_REQUIRED' });
133
+ }
125
134
  this.handleApiError(error);
126
135
  }
127
136
  const url = (0, web_url_1.taskUrlFrom)(this.cliConfig.baseURL, { id: task.id });
@@ -10,14 +10,6 @@ const data_provider_1 = require("@skrr-ai/data-provider");
10
10
  const base_command_1 = require("../../base-command");
11
11
  const format_1 = require("../../lib/format");
12
12
  const activity_1 = require("./activity");
13
- function formatTime(value) {
14
- try {
15
- return new Date(String(value)).toISOString().slice(0, 19).replace('T', ' ');
16
- }
17
- catch {
18
- return String(value);
19
- }
20
- }
21
13
  /**
22
14
  * OSK-4836 — say WHERE a run executed. A named daemon wins over the environment
23
15
  * label; an environment with no daemon is the cloud worker (or a runtime whose
@@ -163,7 +155,7 @@ class TasksRuns extends base_command_1.BaseCommand {
163
155
  runId: String(run.runId ?? run.id ?? run._id ?? '-'),
164
156
  status: String(run.status ?? '-'),
165
157
  executor: formatRunExecutor(run),
166
- started: run.startedAt ? formatTime(run.startedAt) : '-',
158
+ started: run.startedAt ? (0, format_1.localTime)(run.startedAt) : '-',
167
159
  duration: run.durationMs != null ? `${run.durationMs}ms` : '-',
168
160
  tokens: String(run.totalTokens ?? run.tokens ?? '-'),
169
161
  }));
@@ -11,6 +11,7 @@ const task_closure_1 = require("../../lib/task-closure");
11
11
  const task_resolver_1 = require("../../lib/task-resolver");
12
12
  const web_url_1 = require("../../lib/web-url");
13
13
  const html_text_1 = require("../../lib/html-text");
14
+ const format_1 = require("../../lib/format");
14
15
  /**
15
16
  * Where to look next — as COMMANDS, not as facts about the task.
16
17
  *
@@ -67,7 +68,7 @@ function taskPointerLines(t, ref, bin = 'skrr') {
67
68
  */
68
69
  function taskFailureLines(t, bin = 'skrr') {
69
70
  const error = typeof t.executionError === 'string' ? t.executionError.trim() : '';
70
- const failedAt = t.lastFailedAt ? formatTime(t.lastFailedAt) : null;
71
+ const failedAt = t.lastFailedAt ? (0, format_1.localTime)(t.lastFailedAt) : null;
71
72
  const isFailed = t.status === 'failed';
72
73
  if (!error && !failedAt && !isFailed)
73
74
  return [];
@@ -335,7 +336,7 @@ class TasksShow extends base_command_1.BaseCommand {
335
336
  this.log(`Previews: ${delivery.previewLinks.length}`);
336
337
  }
337
338
  if (delivery.prStateUpdatedAt)
338
- this.log(`PR updated: ${formatTime(delivery.prStateUpdatedAt)}`);
339
+ this.log(`PR updated: ${(0, format_1.localTime)(delivery.prStateUpdatedAt)}`);
339
340
  }
340
341
  // Prefer server-enriched names; fall back to bare ids under --no-enrich.
341
342
  const enrichedSkills = Array.isArray(t._pinnedSkills)
@@ -369,9 +370,9 @@ class TasksShow extends base_command_1.BaseCommand {
369
370
  .join(', ')} (attached; injected on every run)`);
370
371
  }
371
372
  if (t.createdAt)
372
- this.log(`Created: ${formatTime(t.createdAt)}`);
373
+ this.log(`Created: ${(0, format_1.localTime)(t.createdAt)}`);
373
374
  if (t.updatedAt)
374
- this.log(`Updated: ${formatTime(t.updatedAt)}`);
375
+ this.log(`Updated: ${(0, format_1.localTime)(t.updatedAt)}`);
375
376
  /**
376
377
  * Say which Task model this row belongs to, on the one surface everybody
377
378
  * reads first.
@@ -434,11 +435,3 @@ class TasksShow extends base_command_1.BaseCommand {
434
435
  }
435
436
  }
436
437
  exports.default = TasksShow;
437
- function formatTime(value) {
438
- try {
439
- return new Date(String(value)).toISOString().slice(0, 19).replace('T', ' ');
440
- }
441
- catch {
442
- return String(value);
443
- }
444
- }
@@ -11,11 +11,19 @@ import { BaseCommand } from '../../base-command';
11
11
  *
12
12
  * `GET /api/auth/sessions/refresh` has served exactly this list all along; it
13
13
  * was simply not reachable from the CLI.
14
+ *
15
+ * The server returns at most `--limit` rows and says whether it left any out.
16
+ * It used to stop at 100 without saying so, and the session somebody went
17
+ * looking for — an old daemon's, still holding the login a purge refusal named
18
+ * — was exactly the one past the cut (OSK-9980). So a partial list says it is
19
+ * partial, and `--kind daemon` is the short way to the row that matters.
14
20
  */
15
21
  export default class TokenList extends BaseCommand {
16
22
  static description: string;
17
23
  static examples: string[];
18
24
  static flags: {
25
+ kind: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
26
+ limit: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
19
27
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
20
28
  };
21
29
  run(): Promise<void>;
@@ -4,6 +4,7 @@ const core_1 = require("@oclif/core");
4
4
  const base_command_1 = require("../../base-command");
5
5
  const api_fetch_1 = require("../../lib/api-fetch");
6
6
  const format_1 = require("../../lib/format");
7
+ const SESSION_KINDS = ['web', 'daemon', 'cli', 'ci'];
7
8
  /**
8
9
  * `skrr token list`
9
10
  *
@@ -16,20 +17,44 @@ const format_1 = require("../../lib/format");
16
17
  *
17
18
  * `GET /api/auth/sessions/refresh` has served exactly this list all along; it
18
19
  * was simply not reachable from the CLI.
20
+ *
21
+ * The server returns at most `--limit` rows and says whether it left any out.
22
+ * It used to stop at 100 without saying so, and the session somebody went
23
+ * looking for — an old daemon's, still holding the login a purge refusal named
24
+ * — was exactly the one past the cut (OSK-9980). So a partial list says it is
25
+ * partial, and `--kind daemon` is the short way to the row that matters.
19
26
  */
20
27
  class TokenList extends base_command_1.BaseCommand {
21
28
  static description = 'List the active sessions a minted token belongs to — the other half of `token mint`';
22
29
  static examples = [
23
30
  '<%= config.bin %> token list',
24
- '<%= config.bin %> token list --json',
31
+ '<%= config.bin %> token list --kind daemon',
32
+ '<%= config.bin %> token list --kind cli --limit 500 --json',
25
33
  ];
26
- static flags = { json: core_1.Flags.boolean({ description: 'Output JSON' }) };
34
+ static flags = {
35
+ kind: core_1.Flags.string({
36
+ description: 'Only sessions of this kind',
37
+ options: [...SESSION_KINDS],
38
+ }),
39
+ limit: core_1.Flags.integer({
40
+ description: 'Most sessions to list (server maximum 500)',
41
+ min: 1,
42
+ max: 500,
43
+ }),
44
+ json: core_1.Flags.boolean({ description: 'Output JSON' }),
45
+ };
27
46
  async run() {
28
47
  this.requireAuth();
29
48
  const { flags } = await this.parse(TokenList);
49
+ const query = new URLSearchParams();
50
+ if (flags.kind)
51
+ query.set('kind', flags.kind);
52
+ if (flags.limit)
53
+ query.set('limit', String(flags.limit));
54
+ const suffix = query.toString() ? `?${query.toString()}` : '';
30
55
  let data = null;
31
56
  try {
32
- data = await (0, api_fetch_1.apiFetch)('/api/auth/sessions/refresh', {
57
+ data = await (0, api_fetch_1.apiFetch)(`/api/auth/sessions/refresh${suffix}`, {
33
58
  method: 'GET',
34
59
  credential: this.resolvedCredential,
35
60
  });
@@ -37,9 +62,17 @@ class TokenList extends base_command_1.BaseCommand {
37
62
  catch (err) {
38
63
  this.handleApiError(err);
39
64
  }
40
- const sessions = data?.sessions || [];
41
- if (flags.json)
42
- return this.log(JSON.stringify({ sessions, count: sessions.length }, null, 2));
65
+ // Filtered here as well: a server from before `kind` existed ignores the
66
+ // parameter and returns every kind, and `--kind daemon` must never list a
67
+ // web session as if it were one.
68
+ const sessions = (data?.sessions || []).filter((session) => !flags.kind || session.kind === flags.kind);
69
+ // A server from before `hasMore` stopped at 100 and said nothing about it,
70
+ // and ignores `--limit` too — so it gets its own, weaker statement.
71
+ const olderServer = data?.hasMore === undefined;
72
+ const hasMore = olderServer ? (data?.sessions?.length ?? 0) >= 100 : data?.hasMore === true;
73
+ if (flags.json) {
74
+ return this.log(JSON.stringify({ sessions, count: sessions.length, hasMore }, null, 2));
75
+ }
43
76
  if (!sessions.length)
44
77
  return this.log('No active sessions.');
45
78
  (0, format_1.renderTable)(sessions.map((session) => ({
@@ -48,6 +81,8 @@ class TokenList extends base_command_1.BaseCommand {
48
81
  // The operator's own name for the credential wins over a derived
49
82
  // device string — it is what they would search by.
50
83
  device: session.label || session.device || '-',
84
+ // What `instructions`, `machines` and a purge refusal call it.
85
+ daemon: session.daemonId || '-',
51
86
  ip: session.ip || '-',
52
87
  lastActive: session.lastActiveAt || session.createdAt || '-',
53
88
  // The session you are typing in. Revoking it signs THIS machine out,
@@ -57,11 +92,21 @@ class TokenList extends base_command_1.BaseCommand {
57
92
  { key: 'id', header: 'ID' },
58
93
  { key: 'kind', header: 'KIND' },
59
94
  { key: 'device', header: 'DEVICE', maxWidth: 34 },
95
+ { key: 'daemon', header: 'DAEMON', maxWidth: 40 },
60
96
  { key: 'ip', header: 'IP' },
61
97
  { key: 'lastActive', header: 'LAST ACTIVE' },
62
98
  { key: 'current', header: 'CURRENT' },
63
99
  ], (line) => this.log(line));
64
100
  this.log('');
101
+ if (hasMore && olderServer) {
102
+ this.log('This server lists at most 100 sessions and does not say whether it left any out, so older ones may be missing.');
103
+ }
104
+ else if (hasMore) {
105
+ const remedy = flags.kind
106
+ ? 'Raise --limit (up to 500) to see them.'
107
+ : 'Narrow the list with --kind, or raise --limit (up to 500).';
108
+ this.log(`Showing the ${sessions.length} most recently active sessions; older ones were left out. ${remedy}`);
109
+ }
65
110
  this.log('Retire one with: skrr token revoke <id>');
66
111
  }
67
112
  }
package/dist/help.js CHANGED
@@ -46,26 +46,22 @@ class SkrrHelp extends core_1.Help {
46
46
  */
47
47
  async showRootHelp() {
48
48
  this.log('GETTING STARTED');
49
- this.log(' skrr login Sign in. Offers to set this machine up if it has no runtime.');
50
- this.log(' skrr daemon install Install the runtime by hand (fetches the signed release).');
49
+ this.log(' skrr login Sign in. Offers to install the background service if this computer has none.');
50
+ this.log(' skrr daemon install Install the background service by hand (fetches the signed release).');
51
51
  this.log('');
52
52
  return super.showRootHelp();
53
53
  }
54
54
  async showHelp(argv) {
55
- // Mirror oclif's own id resolution: the topic separator is a space here, so
56
- // the id is the leading non-flag tokens joined with `:`.
57
- const tokens = [];
58
- for (const token of argv) {
59
- if (token.startsWith('-'))
60
- break;
61
- tokens.push(token);
62
- }
63
- const id = tokens.join(':');
55
+ // Resolve the id exactly as running the same words would — a word after a
56
+ // command that takes arguments is an argument, not part of the name
57
+ // (OSK-10099: `harnesses install devin --help` was refused).
58
+ const lookup = (0, command_miss_1.lookupFromConfig)(this.config);
59
+ const id = (0, command_miss_1.helpSubjectId)(argv, lookup);
64
60
  // A bare topic (`skrr daemon`) has no command but DOES have help to show,
65
61
  // so it must fall through — only an id that is neither a command nor a
66
62
  // topic is a miss.
67
63
  if (id && !this.config.findCommand(id) && !this.config.findTopic(id)) {
68
- throw new Error((0, command_miss_1.describeCommandMiss)((0, command_miss_1.lookupFromConfig)(this.config), id));
64
+ throw new Error((0, command_miss_1.describeCommandMiss)(lookup, id));
69
65
  }
70
66
  return super.showHelp(argv);
71
67
  }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The workspace an `agents chat` turn runs in when the caller named none.
3
+ *
4
+ * A turn with no workspace context reaches the server without `X-Workspace-Id`.
5
+ * The server lets it through after checking membership in the agent's own
6
+ * workspace, but the agent runtime then has no workspace, so the shared
7
+ * workspace memory tier refuses with "no workspace context" (OSK-9937). By
8
+ * owner decision the CLI now uses the agent's home workspace in that case: the
9
+ * same thing the web app sends, and the only workspace the server would accept
10
+ * for that agent anyway.
11
+ *
12
+ * Never applied when anything already chose: `--workspace`, an exported
13
+ * `OVERSKY_WORKSPACE_ID`, or `skrr workspaces use` (all arrive as that env var),
14
+ * and never inside an autonomous Agent process, whose workspace belongs to its
15
+ * daemon session.
16
+ */
17
+ export declare function applyAgentHomeWorkspaceDefault(agentId: string, lookup: (agentId: string) => Promise<{
18
+ workspaceId?: string | null;
19
+ } | null | undefined>, env?: NodeJS.ProcessEnv): Promise<string | null>;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.applyAgentHomeWorkspaceDefault = applyAgentHomeWorkspaceDefault;
4
+ /**
5
+ * The workspace an `agents chat` turn runs in when the caller named none.
6
+ *
7
+ * A turn with no workspace context reaches the server without `X-Workspace-Id`.
8
+ * The server lets it through after checking membership in the agent's own
9
+ * workspace, but the agent runtime then has no workspace, so the shared
10
+ * workspace memory tier refuses with "no workspace context" (OSK-9937). By
11
+ * owner decision the CLI now uses the agent's home workspace in that case: the
12
+ * same thing the web app sends, and the only workspace the server would accept
13
+ * for that agent anyway.
14
+ *
15
+ * Never applied when anything already chose: `--workspace`, an exported
16
+ * `OVERSKY_WORKSPACE_ID`, or `skrr workspaces use` (all arrive as that env var),
17
+ * and never inside an autonomous Agent process, whose workspace belongs to its
18
+ * daemon session.
19
+ */
20
+ async function applyAgentHomeWorkspaceDefault(agentId, lookup, env = process.env) {
21
+ if (env.OVERSKY_AUTONOMOUS_SESSION === '1')
22
+ return null;
23
+ if (env.OVERSKY_WORKSPACE_ID?.trim())
24
+ return null;
25
+ let agent;
26
+ try {
27
+ agent = await lookup(agentId);
28
+ }
29
+ catch {
30
+ // Unreadable agent: keep the headerless request. The server still decides
31
+ // access, and the chat call itself reports a missing or forbidden agent.
32
+ return null;
33
+ }
34
+ const workspaceId = typeof agent?.workspaceId === 'string' ? agent.workspaceId.trim() : '';
35
+ if (!workspaceId)
36
+ return null;
37
+ env.OVERSKY_WORKSPACE_ID = workspaceId;
38
+ return workspaceId;
39
+ }
@@ -38,7 +38,7 @@ async function resolveAgentIdentity(explicitAgentId) {
38
38
  if (explicitAgentId && explicitAgentId !== runtime.agent.id) {
39
39
  throw new AgentResolutionError({
40
40
  code: 'AGENT_CONTEXT_CONFLICT',
41
- message: 'This local runtime is bound to OVERSKY_SESSION_AGENT_ID. Do not override it with another agent ID.',
41
+ message: 'This session is bound to the agent in OVERSKY_SESSION_AGENT_ID. Do not override it with another agent ID.',
42
42
  suggestion: 'Use the bound session agent, or start a new daemon session for a different agent.',
43
43
  details: {
44
44
  explicitAgentId,
@@ -129,7 +129,7 @@ function resolveSessionAgentIdentity(explicitAgentId, env = process.env) {
129
129
  if (explicitAgentId && explicitAgentId !== runtime.agent.id) {
130
130
  throw new AgentResolutionError({
131
131
  code: 'AGENT_CONTEXT_CONFLICT',
132
- message: 'This local runtime is bound to OVERSKY_SESSION_AGENT_ID. Do not override it with another agent ID.',
132
+ message: 'This session is bound to the agent in OVERSKY_SESSION_AGENT_ID. Do not override it with another agent ID.',
133
133
  suggestion: 'Use the bound session agent, or start a new daemon session for a different agent.',
134
134
  details: {
135
135
  explicitAgentId,