@skrr-ai/cli 0.1.37 → 0.1.38

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 (174) hide show
  1. package/bin/dev-fallback.js +167 -4
  2. package/dist/base-command.js +46 -2
  3. package/dist/commands/agents/actions/create.js +18 -7
  4. package/dist/commands/agents/actions/delete.d.ts +1 -0
  5. package/dist/commands/agents/actions/delete.js +7 -0
  6. package/dist/commands/agents/actions/update.js +5 -3
  7. package/dist/commands/agents/api-actions/add.js +5 -2
  8. package/dist/commands/agents/api-actions/index.d.ts +11 -0
  9. package/dist/commands/agents/api-actions/index.js +27 -1
  10. package/dist/commands/agents/avatar/default/index.d.ts +11 -0
  11. package/dist/commands/agents/avatar/default/index.js +17 -0
  12. package/dist/commands/agents/avatar/default/set.d.ts +2 -1
  13. package/dist/commands/agents/avatar/default/set.js +32 -7
  14. package/dist/commands/agents/avatar/upload.js +7 -1
  15. package/dist/commands/agents/categories/delete.js +8 -0
  16. package/dist/commands/agents/categories/index.d.ts +21 -5
  17. package/dist/commands/agents/categories/index.js +68 -15
  18. package/dist/commands/agents/chat.d.ts +21 -0
  19. package/dist/commands/agents/chat.js +94 -7
  20. package/dist/commands/agents/create.js +11 -4
  21. package/dist/commands/agents/list.d.ts +15 -0
  22. package/dist/commands/agents/list.js +31 -1
  23. package/dist/commands/agents/scene-background/upload.d.ts +30 -0
  24. package/dist/commands/agents/scene-background/upload.js +97 -0
  25. package/dist/commands/agents/show.js +13 -0
  26. package/dist/commands/agents/tools/calls.d.ts +23 -5
  27. package/dist/commands/agents/tools/calls.js +81 -18
  28. package/dist/commands/agents/update.js +15 -5
  29. package/dist/commands/code/{oversky-agent.d.ts → skrr-agent.d.ts} +3 -3
  30. package/dist/commands/code/{oversky-agent.js → skrr-agent.js} +11 -8
  31. package/dist/commands/convos/messages.d.ts +13 -0
  32. package/dist/commands/convos/messages.js +40 -16
  33. package/dist/commands/daemon/index.js +8 -1
  34. package/dist/commands/daemon/logs.d.ts +26 -0
  35. package/dist/commands/daemon/logs.js +56 -0
  36. package/dist/commands/daemon/uninstall.js +1 -1
  37. package/dist/commands/followups/act.js +3 -2
  38. package/dist/commands/followups/cancel.d.ts +6 -3
  39. package/dist/commands/followups/cancel.js +16 -6
  40. package/dist/commands/followups/observability.d.ts +23 -0
  41. package/dist/commands/followups/observability.js +114 -0
  42. package/dist/commands/followups/reschedule.js +1 -1
  43. package/dist/commands/followups/resolve.js +3 -3
  44. package/dist/commands/followups/show.js +2 -1
  45. package/dist/commands/followups/watch.js +9 -5
  46. package/dist/commands/harnesses/forget.js +28 -0
  47. package/dist/commands/harnesses/install.d.ts +41 -0
  48. package/dist/commands/harnesses/install.js +165 -0
  49. package/dist/commands/harnesses/installers.d.ts +45 -0
  50. package/dist/commands/harnesses/installers.js +155 -0
  51. package/dist/commands/harnesses/list.d.ts +82 -1
  52. package/dist/commands/harnesses/list.js +104 -12
  53. package/dist/commands/harnesses/models.js +10 -1
  54. package/dist/commands/harnesses/show.d.ts +15 -0
  55. package/dist/commands/harnesses/show.js +44 -3
  56. package/dist/commands/harnesses/update.js +1 -1
  57. package/dist/commands/harnesses/usage.d.ts +25 -0
  58. package/dist/commands/harnesses/usage.js +24 -2
  59. package/dist/commands/instructions/status.js +13 -1
  60. package/dist/commands/machines/dedicated/catalog.js +4 -15
  61. package/dist/commands/machines/dedicated/create.d.ts +8 -0
  62. package/dist/commands/machines/dedicated/create.js +58 -1
  63. package/dist/commands/machines/dedicated/destroy.js +18 -4
  64. package/dist/commands/machines/dedicated/list.js +9 -6
  65. package/dist/commands/machines/hosted/list.js +12 -0
  66. package/dist/commands/machines/list.js +11 -0
  67. package/dist/commands/machines/show.d.ts +1 -0
  68. package/dist/commands/machines/show.js +40 -11
  69. package/dist/commands/profiles/list.d.ts +23 -0
  70. package/dist/commands/profiles/list.js +96 -0
  71. package/dist/commands/search/skills.d.ts +11 -1
  72. package/dist/commands/search/skills.js +26 -8
  73. package/dist/commands/skills/details.d.ts +2 -0
  74. package/dist/commands/skills/details.js +24 -1
  75. package/dist/commands/skills/import-as-actions.d.ts +32 -0
  76. package/dist/commands/skills/import-as-actions.js +175 -0
  77. package/dist/commands/skills/install.d.ts +2 -0
  78. package/dist/commands/skills/install.js +24 -1
  79. package/dist/commands/skills/invocable.js +6 -2
  80. package/dist/commands/skills/local.d.ts +40 -0
  81. package/dist/commands/skills/local.js +160 -0
  82. package/dist/commands/skills/search.d.ts +11 -1
  83. package/dist/commands/skills/search.js +29 -8
  84. package/dist/commands/spaces/actions/add.js +23 -5
  85. package/dist/commands/spaces/actions/available.js +3 -0
  86. package/dist/commands/spaces/actions/list.d.ts +5 -0
  87. package/dist/commands/spaces/actions/list.js +49 -3
  88. package/dist/commands/spaces/actions/run.d.ts +28 -0
  89. package/dist/commands/spaces/actions/run.js +146 -0
  90. package/dist/commands/spaces/actions/update.js +27 -5
  91. package/dist/commands/spaces/label-summaries.d.ts +27 -0
  92. package/dist/commands/spaces/label-summaries.js +64 -0
  93. package/dist/commands/spaces/task-rollups.d.ts +5 -0
  94. package/dist/commands/spaces/task-rollups.js +15 -4
  95. package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +63 -3
  96. package/dist/commands/tasks/actions/attach.js +32 -7
  97. package/dist/commands/tasks/complete.js +13 -0
  98. package/dist/commands/tasks/create.js +1 -1
  99. package/dist/commands/tasks/events/append.js +29 -6
  100. package/dist/commands/tasks/expectations/assess.d.ts +1 -0
  101. package/dist/commands/tasks/expectations/assess.js +43 -5
  102. package/dist/commands/tasks/expectations.js +77 -16
  103. package/dist/commands/tasks/follow-up.js +2 -2
  104. package/dist/commands/tasks/lifecycle/definitions.js +21 -2
  105. package/dist/commands/tasks/lifecycle/detach.d.ts +7 -0
  106. package/dist/commands/tasks/lifecycle/detach.js +43 -3
  107. package/dist/commands/tasks/lifecycle/migrate.d.ts +2 -0
  108. package/dist/commands/tasks/lifecycle/migrate.js +42 -3
  109. package/dist/commands/tasks/lifecycle/reopen.d.ts +2 -0
  110. package/dist/commands/tasks/lifecycle/reopen.js +40 -3
  111. package/dist/commands/tasks/lifecycle/transition.js +33 -2
  112. package/dist/commands/tasks/list.js +16 -9
  113. package/dist/commands/tasks/move.js +11 -13
  114. package/dist/commands/tasks/review-queue.d.ts +15 -0
  115. package/dist/commands/tasks/review-queue.js +180 -31
  116. package/dist/commands/tasks/show.d.ts +11 -0
  117. package/dist/commands/tasks/show.js +105 -12
  118. package/dist/commands/tasks/trust.js +7 -2
  119. package/dist/commands/tasks/update.js +46 -10
  120. package/dist/commands/tasks/updates/add.js +1 -1
  121. package/dist/commands/token/list.d.ts +22 -0
  122. package/dist/commands/token/list.js +68 -0
  123. package/dist/commands/token/revoke.d.ts +23 -0
  124. package/dist/commands/token/revoke.js +53 -0
  125. package/dist/lib/agent-actions.d.ts +57 -2
  126. package/dist/lib/agent-actions.js +113 -21
  127. package/dist/lib/agent-pin-mute.d.ts +10 -5
  128. package/dist/lib/agent-pin-mute.js +17 -4
  129. package/dist/lib/agent-visual-refs.d.ts +27 -0
  130. package/dist/lib/agent-visual-refs.js +127 -2
  131. package/dist/lib/agentic-stream.d.ts +6 -0
  132. package/dist/lib/agentic-stream.js +34 -3
  133. package/dist/lib/assignee-resolver.d.ts +1 -1
  134. package/dist/lib/assignee-resolver.js +8 -0
  135. package/dist/lib/bulk-task-targets.d.ts +12 -0
  136. package/dist/lib/bulk-task-targets.js +34 -1
  137. package/dist/lib/cli-installers.d.ts +130 -0
  138. package/dist/lib/cli-installers.js +145 -0
  139. package/dist/lib/command-miss.js +55 -7
  140. package/dist/lib/dedicated-lease-command.d.ts +13 -0
  141. package/dist/lib/dedicated-lease-command.js +22 -1
  142. package/dist/lib/dedicated-machines.d.ts +95 -1
  143. package/dist/lib/dedicated-machines.js +236 -2
  144. package/dist/lib/failed-lookup.d.ts +3 -0
  145. package/dist/lib/failed-lookup.js +40 -0
  146. package/dist/lib/first-party-harness-agent.js +9 -2
  147. package/dist/lib/first-party-harness-doctor.d.ts +15 -0
  148. package/dist/lib/first-party-harness-doctor.js +126 -27
  149. package/dist/lib/followups.d.ts +14 -6
  150. package/dist/lib/followups.js +31 -6
  151. package/dist/lib/harnesses.d.ts +8 -0
  152. package/dist/lib/instruction-input.d.ts +19 -1
  153. package/dist/lib/instruction-input.js +52 -1
  154. package/dist/lib/label-scope.d.ts +15 -0
  155. package/dist/lib/label-scope.js +25 -5
  156. package/dist/lib/local-skills.d.ts +98 -0
  157. package/dist/lib/local-skills.js +195 -0
  158. package/dist/lib/machines.d.ts +10 -10
  159. package/dist/lib/machines.js +23 -1
  160. package/dist/lib/search-query.d.ts +19 -0
  161. package/dist/lib/search-query.js +35 -0
  162. package/dist/lib/space-custom-actions.d.ts +72 -0
  163. package/dist/lib/space-custom-actions.js +117 -0
  164. package/dist/lib/space-resolver.d.ts +1 -21
  165. package/dist/lib/space-resolver.js +19 -10
  166. package/dist/lib/task-closure.d.ts +3 -2
  167. package/dist/lib/task-closure.js +18 -20
  168. package/dist/lib/task-lifecycle-output.js +117 -9
  169. package/dist/lib/task-ref-resolver.d.ts +1 -17
  170. package/dist/lib/task-ref-resolver.js +18 -8
  171. package/dist/lib/tasks.js +9 -3
  172. package/dist/node_modules/@skrr-ai/data-provider/index.js +5076 -4947
  173. package/oclif.manifest.json +26635 -25649
  174. package/package.json +9 -3
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveSearchQuery = resolveSearchQuery;
4
+ /**
5
+ * The search term, from a positional or `--query`, resolved the same way by
6
+ * both spellings of the same search.
7
+ *
8
+ * `skills search` and `search skills` run the identical store search. Neither
9
+ * accepted the obvious invocation — `skrr skills search git` — so the single
10
+ * most natural way to call a search command failed on both, and `--query` was
11
+ * `required` on both, which is what made it fail rather than prompt.
12
+ *
13
+ * Shared rather than copied because the two spellings staying in step is the
14
+ * whole point: the reason a reader could not tell them apart was that they had
15
+ * drifted (different one-liners, short flags on one of them), and a second copy
16
+ * of this is how that starts again.
17
+ */
18
+ function resolveSearchQuery(cmd, positional, flag, command) {
19
+ const fromPositional = positional?.trim();
20
+ const fromFlag = flag?.trim();
21
+ // Both given and DIFFERENT is a real ambiguity — refuse rather than pick.
22
+ // Both given and identical is a script that passes belt and braces; that is
23
+ // not an error and silently accepting it costs nobody anything.
24
+ if (fromPositional && fromFlag && fromPositional !== fromFlag) {
25
+ cmd.error(`Two different search terms: "${fromPositional}" and --query "${fromFlag}". Pass one.`, { exit: 2 });
26
+ }
27
+ const query = fromPositional || fromFlag;
28
+ if (!query) {
29
+ // `--query` used to be `required`, so oclif refused with its own generic
30
+ // sentence. Naming the shape people actually type is the point of the
31
+ // change, so the error names it too.
32
+ cmd.error(`What should I search for? Try \`skrr ${command} <term>\`.`, { exit: 2 });
33
+ }
34
+ return query;
35
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Shared shape for `skrr spaces actions add|update`.
3
+ *
4
+ * Both commands describe the same stored object, and they had drifted from the
5
+ * server that validates it (`spaceCustomActionSchema` in api/server/routes/spaces.js).
6
+ */
7
+ import type { SpaceCustomAction, SpaceMemberActionsResponse } from '@skrr-ai/data-provider';
8
+ /**
9
+ * The server's limit on `icon`, which is `z.string().max(4)`.
10
+ *
11
+ * The flag used to be documented as "Lucide icon name". It is not one: the web
12
+ * settings page renders `action.icon` as literal text, and almost no Lucide name
13
+ * fits in four characters, so following the help produced a 400 with a raw Zod
14
+ * message and no hint that an emoji was wanted (OSK-9631).
15
+ *
16
+ * Zod's `max` counts UTF-16 code units, not visible characters, so the check
17
+ * below uses `String.prototype.length` to agree with it exactly. Counting
18
+ * graphemes instead would accept a family emoji the server then refuses.
19
+ */
20
+ export declare const SPACE_CUSTOM_ACTION_ICON_MAX = 4;
21
+ export declare const spaceCustomActionIconFlag: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
22
+ export declare const spaceCustomActionLabelFlag: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
23
+ /** Refuse an icon the server would refuse, with a message that says what fits. */
24
+ export declare function spaceCustomActionIconProblem(icon: unknown): string | null;
25
+ type SpaceWithActions = {
26
+ id: string;
27
+ title?: string;
28
+ leadAgentId?: string | null;
29
+ customActions?: SpaceCustomAction[] | null;
30
+ };
31
+ /**
32
+ * Why a space's OWN actions cannot run, or null when they can.
33
+ *
34
+ * A space custom action runs as a task assigned to the Space Leader, so on a
35
+ * space with no Leader every one of them is dead on arrival. That fact used to
36
+ * live only in a tooltip on a disabled web button: `spaces actions add` reported
37
+ * success, `spaces actions list` listed the action happily, and nothing on the
38
+ * CLI said it could never run (OSK-9641).
39
+ */
40
+ export declare function spaceActionsNotRunnableReason(space: Pick<SpaceWithActions, 'id' | 'leadAgentId'>, bin: string): string | null;
41
+ /**
42
+ * Find a space custom action by the id `spaces actions list` prints, or by the
43
+ * `space-custom:<id>` form the projected quick-action surfaces use.
44
+ */
45
+ export declare function findSpaceCustomAction(space: SpaceWithActions, ref: string): {
46
+ customAction: SpaceCustomAction;
47
+ index: number;
48
+ } | {
49
+ problem: string;
50
+ };
51
+ export type SpaceQuickActionRow = {
52
+ source: 'space' | 'agent';
53
+ title: string;
54
+ owner: string;
55
+ type: string;
56
+ ref: string;
57
+ run: string;
58
+ };
59
+ /**
60
+ * Everything a space's action panel offers, in the order the web shows it: the
61
+ * space's own actions first, then the actions of member agents the caller can
62
+ * view, filtered by scope with the same predicate the web and server use.
63
+ *
64
+ * `spaces actions list` showed only the first half and `spaces actions
65
+ * available` a wider second half (every member agent, including ones the caller
66
+ * cannot run), so "what can I run here?" had no answer on the CLI (OSK-9641).
67
+ * Every row's `run` is a command `spaces actions run` accepts.
68
+ */
69
+ export declare function spaceQuickActionRows(space: SpaceWithActions & {
70
+ labelIds?: string[] | null;
71
+ }, members: SpaceMemberActionsResponse['agents'], bin: string): SpaceQuickActionRow[];
72
+ export {};
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ /**
3
+ * Shared shape for `skrr spaces actions add|update`.
4
+ *
5
+ * Both commands describe the same stored object, and they had drifted from the
6
+ * server that validates it (`spaceCustomActionSchema` in api/server/routes/spaces.js).
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.spaceCustomActionLabelFlag = exports.spaceCustomActionIconFlag = exports.SPACE_CUSTOM_ACTION_ICON_MAX = void 0;
10
+ exports.spaceCustomActionIconProblem = spaceCustomActionIconProblem;
11
+ exports.spaceActionsNotRunnableReason = spaceActionsNotRunnableReason;
12
+ exports.findSpaceCustomAction = findSpaceCustomAction;
13
+ exports.spaceQuickActionRows = spaceQuickActionRows;
14
+ const core_1 = require("@oclif/core");
15
+ const data_provider_1 = require("@skrr-ai/data-provider");
16
+ /**
17
+ * The server's limit on `icon`, which is `z.string().max(4)`.
18
+ *
19
+ * The flag used to be documented as "Lucide icon name". It is not one: the web
20
+ * settings page renders `action.icon` as literal text, and almost no Lucide name
21
+ * fits in four characters, so following the help produced a 400 with a raw Zod
22
+ * message and no hint that an emoji was wanted (OSK-9631).
23
+ *
24
+ * Zod's `max` counts UTF-16 code units, not visible characters, so the check
25
+ * below uses `String.prototype.length` to agree with it exactly. Counting
26
+ * graphemes instead would accept a family emoji the server then refuses.
27
+ */
28
+ exports.SPACE_CUSTOM_ACTION_ICON_MAX = 4;
29
+ exports.spaceCustomActionIconFlag = core_1.Flags.string({
30
+ description: `Emoji shown on the button, e.g. ✨ (at most ${exports.SPACE_CUSTOM_ACTION_ICON_MAX} UTF-16 units). Not an icon name.`,
31
+ });
32
+ exports.spaceCustomActionLabelFlag = core_1.Flags.string({
33
+ description: 'Button text shown in the space. Not a Label entity — to offer an agent action in every space carrying a Label, use `agents actions create --label`.',
34
+ });
35
+ /** Refuse an icon the server would refuse, with a message that says what fits. */
36
+ function spaceCustomActionIconProblem(icon) {
37
+ if (icon === undefined || icon === null)
38
+ return null;
39
+ if (typeof icon !== 'string')
40
+ return '--icon must be text.';
41
+ if (icon.length > exports.SPACE_CUSTOM_ACTION_ICON_MAX) {
42
+ return (`--icon "${icon}" is too long: it is shown as text on the button and must be an emoji ` +
43
+ `(at most ${exports.SPACE_CUSTOM_ACTION_ICON_MAX} UTF-16 units), e.g. --icon ✨. ` +
44
+ 'Icon names such as "Sparkles" are not accepted here.');
45
+ }
46
+ return null;
47
+ }
48
+ /**
49
+ * Why a space's OWN actions cannot run, or null when they can.
50
+ *
51
+ * A space custom action runs as a task assigned to the Space Leader, so on a
52
+ * space with no Leader every one of them is dead on arrival. That fact used to
53
+ * live only in a tooltip on a disabled web button: `spaces actions add` reported
54
+ * success, `spaces actions list` listed the action happily, and nothing on the
55
+ * CLI said it could never run (OSK-9641).
56
+ */
57
+ function spaceActionsNotRunnableReason(space, bin) {
58
+ if (space.leadAgentId)
59
+ return null;
60
+ return (`This space has no Space Leader, so its own actions cannot run: each runs as a task ` +
61
+ `assigned to the Leader. Set one with \`${bin} spaces update ${space.id} --lead-agent <agent-id>\`.`);
62
+ }
63
+ /**
64
+ * Find a space custom action by the id `spaces actions list` prints, or by the
65
+ * `space-custom:<id>` form the projected quick-action surfaces use.
66
+ */
67
+ function findSpaceCustomAction(space, ref) {
68
+ const actions = space.customActions ?? [];
69
+ const id = (0, data_provider_1.spaceCustomActionSourceId)(ref) ?? ref;
70
+ const index = actions.findIndex((action) => action.id === id);
71
+ if (index >= 0)
72
+ return { customAction: actions[index], index };
73
+ if (actions.length === 0) {
74
+ return { problem: `Space ${space.id} has no custom actions.` };
75
+ }
76
+ return {
77
+ problem: `No custom action ${ref} in space ${space.id}. It has: ` +
78
+ actions.map((action) => `${action.id} (${action.label})`).join(', ') +
79
+ '.',
80
+ };
81
+ }
82
+ /**
83
+ * Everything a space's action panel offers, in the order the web shows it: the
84
+ * space's own actions first, then the actions of member agents the caller can
85
+ * view, filtered by scope with the same predicate the web and server use.
86
+ *
87
+ * `spaces actions list` showed only the first half and `spaces actions
88
+ * available` a wider second half (every member agent, including ones the caller
89
+ * cannot run), so "what can I run here?" had no answer on the CLI (OSK-9641).
90
+ * Every row's `run` is a command `spaces actions run` accepts.
91
+ */
92
+ function spaceQuickActionRows(space, members, bin) {
93
+ const subject = { spaceId: space.id, labelIds: space.labelIds ?? [] };
94
+ const leaderMissing = !space.leadAgentId;
95
+ return [
96
+ ...(space.customActions ?? []).map((action) => ({
97
+ source: 'space',
98
+ title: action.label,
99
+ owner: 'Space Leader',
100
+ type: 'prompt',
101
+ ref: action.id,
102
+ run: leaderMissing
103
+ ? '(needs a Space Leader)'
104
+ : `${bin} spaces actions run ${space.id} ${action.id}`,
105
+ })),
106
+ ...members.flatMap(({ agent }) => (agent.agentActions ?? [])
107
+ .filter((action) => (0, data_provider_1.isAgentActionAvailableInSpace)(action, subject))
108
+ .map((action) => ({
109
+ source: 'agent',
110
+ title: action.title,
111
+ owner: agent.name ?? agent.id,
112
+ type: (0, data_provider_1.isBuiltinAgentAction)(action) ? `builtin:${action.builtinType}` : 'prompt',
113
+ ref: `${agent.id}:${action.id}`,
114
+ run: `${bin} spaces actions run ${space.id} ${agent.id}:${action.id}`,
115
+ }))),
116
+ ];
117
+ }
@@ -1,23 +1,3 @@
1
- /**
2
- * Space reference resolution — turn what a person typed into exactly one
3
- * space id, or an actionable failure.
4
- *
5
- * Every `--space` flag in the CLI (35 commands at last count) took a raw UUID
6
- * and nothing else. Passing a name did not error — it filtered on a UUID that
7
- * matches no space and returned an empty result:
8
- *
9
- * skrr tasks list --space "Always on" → "No tasks."
10
- *
11
- * A person retries. An agent concludes the space is empty and proceeds on a
12
- * false premise, which is the failure mode this module exists to remove. The
13
- * contract is deliberately narrow: a value that already looks like an id is
14
- * forwarded untouched (no request, no behavior change for existing scripts);
15
- * anything else must resolve to exactly one space or the command fails.
16
- *
17
- * Modeled on `assignee-resolver.ts`, which already does this for people and
18
- * agents — `--assignee-user frank` has worked for a while. Spaces were the
19
- * outlier, not the exception.
20
- */
21
1
  export type SpaceRef = {
22
2
  /** The space UUID — what every `--space` flag ultimately wants. */
23
3
  id: string;
@@ -36,7 +16,7 @@ export type SpaceResolutionFailure = {
36
16
  * hides. Distinct from NOT_FOUND because the fix is different:
37
17
  * pass --include-archived (or the id), not a different name.
38
18
  */
39
- code: 'NOT_FOUND' | 'AMBIGUOUS' | 'ARCHIVED';
19
+ code: 'NOT_FOUND' | 'AMBIGUOUS' | 'ARCHIVED' | 'NOT_A_REFERENCE';
40
20
  query: string;
41
21
  candidates: SpaceRef[];
42
22
  };
@@ -1,4 +1,15 @@
1
1
  "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SPACE_CLI_ERROR_CODE = void 0;
4
+ exports.looksLikeSpaceId = looksLikeSpaceId;
5
+ exports.looksLikeCanonicalSpaceId = looksLikeCanonicalSpaceId;
6
+ exports.normalizeSpaceRef = normalizeSpaceRef;
7
+ exports.spaceRefFrom = spaceRefFrom;
8
+ exports.resolveSpaceRef = resolveSpaceRef;
9
+ exports.describeSpace = describeSpace;
10
+ exports.describeSpaceCandidates = describeSpaceCandidates;
11
+ exports.formatSpaceResolutionFailure = formatSpaceResolutionFailure;
12
+ const failed_lookup_1 = require("./failed-lookup");
2
13
  /**
3
14
  * Space reference resolution — turn what a person typed into exactly one
4
15
  * space id, or an actionable failure.
@@ -19,16 +30,6 @@
19
30
  * agents — `--assignee-user frank` has worked for a while. Spaces were the
20
31
  * outlier, not the exception.
21
32
  */
22
- Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.SPACE_CLI_ERROR_CODE = void 0;
24
- exports.looksLikeSpaceId = looksLikeSpaceId;
25
- exports.looksLikeCanonicalSpaceId = looksLikeCanonicalSpaceId;
26
- exports.normalizeSpaceRef = normalizeSpaceRef;
27
- exports.spaceRefFrom = spaceRefFrom;
28
- exports.resolveSpaceRef = resolveSpaceRef;
29
- exports.describeSpace = describeSpace;
30
- exports.describeSpaceCandidates = describeSpaceCandidates;
31
- exports.formatSpaceResolutionFailure = formatSpaceResolutionFailure;
32
33
  const UUID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
33
34
  const OBJECT_ID_RE = /^[0-9a-fA-F]{24}$/;
34
35
  /**
@@ -106,6 +107,11 @@ function resolveSpaceRef(query, spaces) {
106
107
  if (!q) {
107
108
  return { ok: false, code: 'NOT_FOUND', query: raw, candidates: spaces };
108
109
  }
110
+ // A failed lookup's output is refused before the name tiers can match it.
111
+ // See `failed-lookup.ts`.
112
+ if ((0, failed_lookup_1.isFailedLookupValue)(raw)) {
113
+ return { ok: false, code: 'NOT_A_REFERENCE', query: raw, candidates: [] };
114
+ }
109
115
  // An exact id or ref wins over everything, archived or not: both are
110
116
  // explicit and unambiguous, so there is nothing to protect the caller from.
111
117
  // Names are matched against live spaces only — see the ARCHIVED branch.
@@ -159,6 +165,8 @@ function describeSpaceCandidates(candidates, limit = 10) {
159
165
  /** One human-readable block per failure, suitable for a CLI error body. */
160
166
  function formatSpaceResolutionFailure(failure, bin = 'skrr') {
161
167
  switch (failure.code) {
168
+ case 'NOT_A_REFERENCE':
169
+ return (0, failed_lookup_1.describeFailedLookupValue)(failure.query, 'Space');
162
170
  case 'AMBIGUOUS':
163
171
  return (`"${failure.query}" matches ${failure.candidates.length} spaces:\n` +
164
172
  `${describeSpaceCandidates(failure.candidates)}\n` +
@@ -178,4 +186,5 @@ exports.SPACE_CLI_ERROR_CODE = {
178
186
  AMBIGUOUS: 'SPACE_AMBIGUOUS',
179
187
  ARCHIVED: 'SPACE_ARCHIVED',
180
188
  NOT_FOUND: 'SPACE_NOT_FOUND',
189
+ NOT_A_REFERENCE: 'SPACE_NOT_A_REFERENCE',
181
190
  };
@@ -28,5 +28,6 @@ export type ClosureLike = TaskClosureEvaluation | {
28
28
  * the whole point is to be able to act without a second lookup.
29
29
  */
30
30
  export declare function closureReport(closure: ClosureLike): string[];
31
- /** `met (agent)` vs `met (you)` — whose judgement settled it, never hidden. */
32
- export declare function describeAssessor(kind: string | null | undefined): string;
31
+ /** `met (agent)` vs `met (person)` — shared with the web through data-provider. */
32
+ export { describeAssessorKind as describeAssessor } from '@skrr-ai/data-provider';
33
+ export { describeClosure as closureSnapshotLines, type TaskClosureSnapshot as ClosureSnapshot, } from '@skrr-ai/data-provider';
@@ -1,17 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.closureSnapshotLines = exports.describeAssessor = void 0;
3
4
  exports.closureReport = closureReport;
4
- exports.describeAssessor = describeAssessor;
5
+ const data_provider_1 = require("@skrr-ai/data-provider");
5
6
  function isUnavailable(closure) {
6
7
  return Boolean(closure && closure.unavailable);
7
8
  }
8
- const SHORT_BLOCKER = {
9
- TASK_RESULT_REQUIRED: 'no Result submitted',
10
- TASK_CURRENT_RESULT_MISSING: 'the current Result does not resolve',
11
- TASK_RESULT_SPEC_VERSION_MISMATCH: 'the Result answers an older specification',
12
- TASK_RESULT_CHANGES_REQUESTED: 'a reviewer requested changes',
13
- TASK_RESULT_REVIEW_REQUIRED: 'an independent accepted Review is required',
14
- };
9
+ // One phrase table, shared with the web through data-provider. Two copies is how
10
+ // the same blocker came to read differently depending on which surface you asked.
11
+ const SHORT_BLOCKER = data_provider_1.CLOSURE_BLOCKER_PHRASE;
15
12
  /**
16
13
  * The full account, for the moment a caller has just written something and is
17
14
  * deciding what to do next.
@@ -85,18 +82,9 @@ function closureReport(closure) {
85
82
  : 'Closing anyway is allowed — all of this is recorded on resolution.closure.');
86
83
  return lines;
87
84
  }
88
- /** `met (agent)` vs `met (you)` — whose judgement settled it, never hidden. */
89
- function describeAssessor(kind) {
90
- if (kind === 'agent')
91
- return 'agent';
92
- if (kind === 'human')
93
- return 'person';
94
- if (kind === 'system')
95
- return 'system';
96
- if (kind === 'integration')
97
- return 'integration';
98
- return 'unattributed';
99
- }
85
+ /** `met (agent)` vs `met (person)` — shared with the web through data-provider. */
86
+ var data_provider_2 = require("@skrr-ai/data-provider");
87
+ Object.defineProperty(exports, "describeAssessor", { enumerable: true, get: function () { return data_provider_2.describeAssessorKind; } });
100
88
  function truncate(value, max) {
101
89
  const flat = value.replace(/\s+/g, ' ').trim();
102
90
  return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;
@@ -104,3 +92,13 @@ function truncate(value, max) {
104
92
  function capitalize(value) {
105
93
  return value.charAt(0).toUpperCase() + value.slice(1);
106
94
  }
95
+ /*
96
+ * The snapshot renderer moved to `@skrr-ai/data-provider`.
97
+ *
98
+ * It lived here, and "here" is `cli/` — so the web could not reach it, and the
99
+ * web is where most people read a finished Task. A single renderer that only one
100
+ * client can import is not a single renderer; it is the first copy. Re-exported
101
+ * under the old names so this module stays the CLI's one door to closure copy.
102
+ */
103
+ var data_provider_3 = require("@skrr-ai/data-provider");
104
+ Object.defineProperty(exports, "closureSnapshotLines", { enumerable: true, get: function () { return data_provider_3.describeClosure; } });
@@ -14,15 +14,25 @@ function renderTaskLifecycleSummary(response, log) {
14
14
  log('Attach one: skrr tasks lifecycle attach <task-id> --pack finding');
15
15
  return;
16
16
  }
17
- log(`Lifecycle: ${lifecycle.status} (v${lifecycle.version}, generation ${lifecycle.generation}, revision ${lifecycle.revision})` +
18
- (lifecycle.packId ? ` — pack ${lifecycle.packId}` : ''));
17
+ // Two different version numbers used to share one label. `v1` next to
18
+ // `pack finding` reads as "finding v1", and `finding` is pack v2 — `version`
19
+ // is the installed definition's WorkflowVersion. Name each one.
20
+ const protocol = lifecycle.packId
21
+ ? `pack ${lifecycle.packId}${lifecycle.packVersion ? ` v${lifecycle.packVersion}` : ''}`
22
+ : `definition ${lifecycle.definitionId}`;
23
+ log(`Lifecycle: ${lifecycle.status} — ${protocol}, protocol version ${lifecycle.version}, generation ${lifecycle.generation}, revision ${lifecycle.revision}`);
19
24
  if (response.run)
20
25
  log(`Run: ${response.run.id} — ${response.run.status}`);
21
26
  for (const stage of response.stages || []) {
22
27
  const marker = stage.key === lifecycle.currentStageKey ? '>' : ' ';
23
- const state = stage.status
24
- ? ` — ${stage.status}${stage.outcome ? `/${stage.outcome}` : ''}`
25
- : '';
28
+ // A reopen marks everything behind its entry stage `skipped` in the NEW
29
+ // run. Saying so unqualified told the reader that work nobody skipped had
30
+ // never happened; say which generation did it instead.
31
+ const state = stage.completedInGeneration
32
+ ? ` — done in generation ${stage.completedInGeneration}${stage.priorOutcome ? `/${stage.priorOutcome}` : ''}`
33
+ : stage.status
34
+ ? ` — ${stage.status}${stage.outcome ? `/${stage.outcome}` : ''}`
35
+ : '';
26
36
  log(`${marker} ${stage.label || stage.key}${state}`);
27
37
  }
28
38
  if (response.gate) {
@@ -43,28 +53,122 @@ function renderTaskLifecycleSummary(response, log) {
43
53
  : undefined,
44
54
  transition.requires?.deliverableRef ? 'deliverable ref' : undefined,
45
55
  ].filter(Boolean);
46
- log(` ${transition.id} -> ${transition.outcome}${transition.label ? ` (${transition.label})` : ''}${needs.length ? ` — needs ${needs.join(', ')}` : ''}`);
56
+ // Lead with what it DOES and say where it goes. This printed
57
+ // `id -> outcome`, and `outcome` is an edge name: at triage that read
58
+ // `accept -> accept`, with nothing to separate the branch that continues
59
+ // to Diagnose from the one that ends the finding.
60
+ const destination = transition.endsLifecycle
61
+ ? 'ends the lifecycle'
62
+ : transition.toStageLabel || transition.toStageKey;
63
+ log(` ${transition.id}${transition.label ? ` — ${transition.label}` : ''}${destination ? ` -> ${destination}` : ''}${needs.length ? ` — needs ${needs.join(', ')}` : ''}`);
64
+ // A copyable skeleton. Naming the update TYPE and a count of evidence
65
+ // told nobody which keys to put where, so every payload shape was
66
+ // guesswork against a contract only the server could see.
67
+ const skeleton = transitionPayloadSkeleton(transition);
68
+ if (skeleton)
69
+ log(` --payload '${skeleton}'`);
47
70
  }
48
71
  }
49
72
  if (response.pendingEffects?.length) {
50
73
  log('');
74
+ const exhausted = response.pendingEffects.filter((effect) => effect.status === 'failed');
51
75
  log(`${response.pendingEffects.length} effect(s) pending repair:`);
52
76
  for (const effect of response.pendingEffects) {
53
- log(` ${effect.kind}${effect.lastError ? ` — ${effect.lastError}` : ''}`);
77
+ // Say whether it is still trying. A row that has given up and a row
78
+ // mid-retry need different things from the reader.
79
+ const state = effect.status === 'failed' ? ' [stopped retrying]' : '';
80
+ log(` ${effect.kind}${state}${effect.attempts ? ` after ${effect.attempts} attempt(s)` : ''}${effect.lastError ? ` — ${effect.lastError}` : ''}`);
81
+ }
82
+ // Any row carrying an error is already actionable — waiting for it to
83
+ // exhaust its retries before naming the repair leaves the reader staring at
84
+ // a stage that cannot move and a transition list that offers nothing.
85
+ if (response.pendingEffects.some((effect) => effect.lastError)) {
86
+ log(exhausted.length
87
+ ? 'Fix what the error names, then re-arm them: skrr tasks lifecycle reconcile <task-id>'
88
+ : 'Still retrying. Fix what the error names, then: skrr tasks lifecycle reconcile <task-id>');
54
89
  }
55
90
  }
56
91
  if (lifecycle.statusDrift) {
57
92
  log(`Status drift: stage expects ${lifecycle.statusDrift.expected}, Task shows ${lifecycle.statusDrift.actual}.`);
58
93
  }
59
94
  }
95
+ /**
96
+ * A copyable `--payload` skeleton for one transition, built from what the
97
+ * server says the transition requires.
98
+ *
99
+ * Deliberately built from the RESPONSE rather than from a table in the CLI: the
100
+ * field list per update type is the server's to own, and a second copy here
101
+ * would drift the moment a pack changed.
102
+ */
103
+ function transitionPayloadSkeleton(transition) {
104
+ const requires = transition.requires;
105
+ if (!requires)
106
+ return undefined;
107
+ const payload = {};
108
+ for (const field of requires.fields || [])
109
+ payload[field] = `<${field}>`;
110
+ if (requires.deliverableRef)
111
+ payload.resourceLinkId = '<resource-link-id>';
112
+ if (requires.updateType) {
113
+ const data = {};
114
+ for (const field of requires.updateFields || []) {
115
+ data[field] = placeholderFor(field, requires.updateFieldShapes?.[field]);
116
+ }
117
+ if (requires.evidence) {
118
+ data.evidenceRefs = [{ kind: 'task', id: '<task-id>' }];
119
+ }
120
+ payload.update = { summary: '<one line about the work>', data };
121
+ }
122
+ return Object.keys(payload).length ? JSON.stringify(payload) : undefined;
123
+ }
124
+ /**
125
+ * A placeholder that has the field's SHAPE, taken from what the server declared.
126
+ * A list field shown as a string led people to write one comma-joined item
127
+ * where they meant several.
128
+ */
129
+ function placeholderFor(field, shape) {
130
+ if (!shape)
131
+ return `<${field}>`;
132
+ if (shape === 'string[]')
133
+ return [`<${field} item>`];
134
+ if (shape === 'reference[]')
135
+ return [];
136
+ if (shape === 'principal')
137
+ return { kind: 'human', userId: '<user-id>' };
138
+ // An enum: show the legal values rather than a name to guess at.
139
+ if (shape.includes('|'))
140
+ return `<${shape}>`;
141
+ return `<${field}>`;
142
+ }
60
143
  /** Render the outcome of a lifecycle transition call. */
61
144
  function renderLifecycleTransitionResult(response, log) {
62
- log(`Transition ${response.status}${response.code ? ` (${response.code})` : ''}.`);
145
+ // A replay is not an apply. Retrying is the NORMAL path here — the default
146
+ // idempotency key is derived, so a re-run of the same command replays — and
147
+ // this printed "Transition applied / effect record_update: applied" either
148
+ // way, so the one question a retry asks (did I just do that, or had I
149
+ // already?) had no answer in the output.
150
+ const replayed = response.idempotent === true;
151
+ // A transition can be `applied` while one of its declared effects did not
152
+ // run. The headline said "Transition applied." and the reader had to notice a
153
+ // per-effect `pending` several lines down, so a capture whose source was
154
+ // never recorded read as a success.
155
+ const owed = (response.effects || []).filter((effect) => effect.status !== 'applied');
156
+ log(`Transition ${response.status}${replayed ? ' (replayed — the recorded outcome, no new work)' : ''}${response.code ? ` (${response.code})` : ''}${owed.length ? ` — ${owed.length} of ${response.effects?.length} effect(s) did NOT run` : ''}.`);
63
157
  if (response.message)
64
158
  log(response.message);
65
159
  for (const effect of response.effects || []) {
66
160
  log(` effect ${effect.kind}: ${effect.status}${effect.ref ? ` -> ${effect.ref}` : ''}${effect.error ? ` — ${effect.error}` : ''}`);
67
161
  }
162
+ // The server names the legal transitions when it refuses an unknown id, and
163
+ // the human renderer dropped them — so a sequencing mistake ("not from this
164
+ // stage") and a typo read identically.
165
+ const allowed = response.details?.allowed;
166
+ if (Array.isArray(allowed) && allowed.length) {
167
+ log(`Legal from this stage: ${allowed.join(', ')}`);
168
+ }
169
+ const actualRevision = response.details?.actualRevision;
170
+ if (actualRevision !== undefined)
171
+ log(`Current revision is ${String(actualRevision)}.`);
68
172
  if (response.gate)
69
173
  log(`Gate: ${response.gate.message}`);
70
174
  if (response.lifecycle) {
@@ -85,7 +189,11 @@ function renderLifecycleHistory(response, log) {
85
189
  const parts = [
86
190
  event.at,
87
191
  event.type,
88
- event.generation !== undefined ? `gen ${event.generation}` : undefined,
192
+ // Name the protocol beside the generation. A Task that wore two packs
193
+ // across a detach and re-attach rendered both passes identically.
194
+ event.generation !== undefined
195
+ ? `gen ${event.generation}${event.packId ? ` (${event.packId})` : ''}`
196
+ : undefined,
89
197
  event.transitionId,
90
198
  event.status,
91
199
  event.outcome,
@@ -1,19 +1,3 @@
1
- /**
2
- * Task reference resolution — turn what a person typed into exactly one task
3
- * id, or an actionable failure.
4
- *
5
- * Distinct from `task-resolver.ts`, which is about WHICH INPUT WINS among the
6
- * positional arg, `--task`, `--from-json` and the daemon runtime context. That
7
- * module does no lookup at all: it picks a string and hands it to the API. This
8
- * one runs after it and answers a different question — what does that string
9
- * refer to?
10
- *
11
- * Two shapes already work without a lookup. A UUID is the canonical id, and an
12
- * `OSK-2423` ref resolves server-side (`getTask` special-cases the pattern in
13
- * api/models/Task.js). A title did not work, which is the gap here: the ref is
14
- * printed in every listing but a person reading a task board out loud has the
15
- * title, not the number.
16
- */
17
1
  export type TaskRef = {
18
2
  id: string;
19
3
  /** The human-readable ref, e.g. `OSK-2423`. */
@@ -23,7 +7,7 @@ export type TaskRef = {
23
7
  };
24
8
  export type TaskResolutionRefFailure = {
25
9
  ok: false;
26
- code: 'NOT_FOUND' | 'AMBIGUOUS';
10
+ code: 'NOT_FOUND' | 'AMBIGUOUS' | 'NOT_A_REFERENCE';
27
11
  query: string;
28
12
  candidates: TaskRef[];
29
13
  };
@@ -1,4 +1,13 @@
1
1
  "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TASK_REF_CLI_ERROR_CODE = void 0;
4
+ exports.directTaskRef = directTaskRef;
5
+ exports.taskRefFrom = taskRefFrom;
6
+ exports.resolveTaskRef = resolveTaskRef;
7
+ exports.describeTask = describeTask;
8
+ exports.describeTaskCandidates = describeTaskCandidates;
9
+ exports.formatTaskRefFailure = formatTaskRefFailure;
10
+ const failed_lookup_1 = require("./failed-lookup");
2
11
  /**
3
12
  * Task reference resolution — turn what a person typed into exactly one task
4
13
  * id, or an actionable failure.
@@ -15,14 +24,6 @@
15
24
  * printed in every listing but a person reading a task board out loud has the
16
25
  * title, not the number.
17
26
  */
18
- Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.TASK_REF_CLI_ERROR_CODE = void 0;
20
- exports.directTaskRef = directTaskRef;
21
- exports.taskRefFrom = taskRefFrom;
22
- exports.resolveTaskRef = resolveTaskRef;
23
- exports.describeTask = describeTask;
24
- exports.describeTaskCandidates = describeTaskCandidates;
25
- exports.formatTaskRefFailure = formatTaskRefFailure;
26
27
  const UUID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
27
28
  /** The server's identifier pattern, relaxed to accept a lowercase prefix. */
28
29
  const IDENTIFIER_RE = /^[A-Za-z]+-\d+$/;
@@ -78,6 +79,11 @@ function resolveTaskRef(query, tasks) {
78
79
  if (!q) {
79
80
  return { ok: false, code: 'NOT_FOUND', query: raw, candidates: tasks };
80
81
  }
82
+ // A failed lookup's output is refused before the title tiers can match it.
83
+ // See `failed-lookup.ts`.
84
+ if ((0, failed_lookup_1.isFailedLookupValue)(raw)) {
85
+ return { ok: false, code: 'NOT_A_REFERENCE', query: raw, candidates: [] };
86
+ }
81
87
  const tiers = [
82
88
  // 1. Exact id.
83
89
  (t) => t.id === raw,
@@ -118,6 +124,9 @@ function describeTaskCandidates(candidates, limit = 10) {
118
124
  return shown.join('\n');
119
125
  }
120
126
  function formatTaskRefFailure(failure, bin = 'skrr') {
127
+ if (failure.code === 'NOT_A_REFERENCE') {
128
+ return (0, failed_lookup_1.describeFailedLookupValue)(failure.query, 'task');
129
+ }
121
130
  if (failure.code === 'AMBIGUOUS') {
122
131
  return (`"${failure.query}" matches ${failure.candidates.length} tasks by title:\n` +
123
132
  `${describeTaskCandidates(failure.candidates)}\n` +
@@ -130,4 +139,5 @@ function formatTaskRefFailure(failure, bin = 'skrr') {
130
139
  exports.TASK_REF_CLI_ERROR_CODE = {
131
140
  AMBIGUOUS: 'TASK_REF_AMBIGUOUS',
132
141
  NOT_FOUND: 'TASK_REF_NOT_FOUND',
142
+ NOT_A_REFERENCE: 'TASK_REF_NOT_A_REFERENCE',
133
143
  };