@skrr-ai/cli 0.1.36 → 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.
- package/README.md +17 -4
- package/bin/dev-fallback.js +167 -4
- package/dist/base-command.js +46 -2
- package/dist/commands/agents/actions/create.d.ts +5 -0
- package/dist/commands/agents/actions/create.js +42 -5
- package/dist/commands/agents/actions/delete.d.ts +1 -0
- package/dist/commands/agents/actions/delete.js +7 -0
- package/dist/commands/agents/actions/update.d.ts +5 -0
- package/dist/commands/agents/actions/update.js +27 -1
- package/dist/commands/agents/api-actions/add.d.ts +41 -0
- package/dist/commands/agents/api-actions/add.js +205 -0
- package/dist/commands/agents/api-actions/index.d.ts +39 -0
- package/dist/commands/agents/api-actions/index.js +103 -0
- package/dist/commands/agents/api-actions/remove.d.ts +14 -0
- package/dist/commands/agents/api-actions/remove.js +36 -0
- package/dist/commands/agents/avatar/default/apply.d.ts +25 -0
- package/dist/commands/agents/avatar/default/apply.js +56 -0
- package/dist/commands/agents/avatar/default/index.d.ts +29 -0
- package/dist/commands/agents/avatar/default/index.js +61 -0
- package/dist/commands/agents/avatar/default/set.d.ts +24 -0
- package/dist/commands/agents/avatar/default/set.js +120 -0
- package/dist/commands/agents/avatar/library/delete.d.ts +20 -0
- package/dist/commands/agents/avatar/library/delete.js +47 -0
- package/dist/commands/agents/avatar/library/index.d.ts +16 -0
- package/dist/commands/agents/avatar/library/index.js +56 -0
- package/dist/commands/agents/avatar/presets.d.ts +19 -0
- package/dist/commands/agents/avatar/presets.js +56 -0
- package/dist/commands/agents/avatar/upload.js +7 -1
- package/dist/commands/agents/categories/create.d.ts +14 -0
- package/dist/commands/agents/categories/create.js +46 -0
- package/dist/commands/agents/categories/delete.d.ts +13 -0
- package/dist/commands/agents/categories/delete.js +41 -0
- package/dist/commands/agents/categories/index.d.ts +36 -0
- package/dist/commands/agents/categories/index.js +135 -0
- package/dist/commands/agents/categories/update.d.ts +22 -0
- package/dist/commands/agents/categories/update.js +59 -0
- package/dist/commands/agents/chat.d.ts +21 -0
- package/dist/commands/agents/chat.js +94 -7
- package/dist/commands/agents/create.d.ts +10 -0
- package/dist/commands/agents/create.js +64 -3
- package/dist/commands/agents/ensure-default.d.ts +27 -0
- package/dist/commands/agents/ensure-default.js +65 -0
- package/dist/commands/agents/list.d.ts +15 -0
- package/dist/commands/agents/list.js +31 -1
- package/dist/commands/agents/mute.d.ts +16 -0
- package/dist/commands/agents/mute.js +38 -0
- package/dist/commands/agents/pin.d.ts +16 -0
- package/dist/commands/agents/pin.js +38 -0
- package/dist/commands/agents/scene-background/upload.d.ts +30 -0
- package/dist/commands/agents/scene-background/upload.js +97 -0
- package/dist/commands/agents/show.js +13 -0
- package/dist/commands/agents/tools/auth.d.ts +19 -0
- package/dist/commands/agents/tools/auth.js +41 -0
- package/dist/commands/agents/tools/calls.d.ts +36 -0
- package/dist/commands/agents/tools/calls.js +117 -0
- package/dist/commands/agents/tools/index.d.ts +20 -0
- package/dist/commands/agents/tools/index.js +77 -0
- package/dist/commands/agents/unmute.d.ts +16 -0
- package/dist/commands/agents/unmute.js +38 -0
- package/dist/commands/agents/unpin.d.ts +16 -0
- package/dist/commands/agents/unpin.js +38 -0
- package/dist/commands/agents/update.d.ts +12 -0
- package/dist/commands/agents/update.js +74 -3
- package/dist/commands/code/{oversky-agent.d.ts → skrr-agent.d.ts} +3 -3
- package/dist/commands/code/{oversky-agent.js → skrr-agent.js} +11 -8
- package/dist/commands/convos/messages.d.ts +13 -0
- package/dist/commands/convos/messages.js +40 -16
- package/dist/commands/daemon/index.js +8 -1
- package/dist/commands/daemon/logs.d.ts +26 -0
- package/dist/commands/daemon/logs.js +56 -0
- package/dist/commands/daemon/uninstall.js +1 -1
- package/dist/commands/followups/act.d.ts +22 -0
- package/dist/commands/followups/act.js +103 -0
- package/dist/commands/followups/cancel.d.ts +20 -0
- package/dist/commands/followups/cancel.js +50 -0
- package/dist/commands/followups/checkin.d.ts +27 -0
- package/dist/commands/followups/checkin.js +107 -0
- package/dist/commands/followups/list.d.ts +24 -0
- package/dist/commands/followups/list.js +90 -0
- package/dist/commands/followups/observability.d.ts +23 -0
- package/dist/commands/followups/observability.js +114 -0
- package/dist/commands/followups/remind.d.ts +26 -0
- package/dist/commands/followups/remind.js +106 -0
- package/dist/commands/followups/reschedule.d.ts +15 -0
- package/dist/commands/followups/reschedule.js +48 -0
- package/dist/commands/followups/resolve.d.ts +23 -0
- package/dist/commands/followups/resolve.js +54 -0
- package/dist/commands/followups/show.d.ts +12 -0
- package/dist/commands/followups/show.js +46 -0
- package/dist/commands/followups/watch.d.ts +51 -0
- package/dist/commands/followups/watch.js +211 -0
- package/dist/commands/goals/labels/add.js +19 -2
- package/dist/commands/goals/labels/remove.js +22 -2
- package/dist/commands/harnesses/forget.js +28 -0
- package/dist/commands/harnesses/install.d.ts +41 -0
- package/dist/commands/harnesses/install.js +165 -0
- package/dist/commands/harnesses/installers.d.ts +45 -0
- package/dist/commands/harnesses/installers.js +155 -0
- package/dist/commands/harnesses/list.d.ts +82 -1
- package/dist/commands/harnesses/list.js +104 -12
- package/dist/commands/harnesses/models.js +10 -1
- package/dist/commands/harnesses/show.d.ts +15 -0
- package/dist/commands/harnesses/show.js +44 -3
- package/dist/commands/harnesses/update.js +1 -1
- package/dist/commands/harnesses/usage.d.ts +25 -0
- package/dist/commands/harnesses/usage.js +24 -2
- package/dist/commands/instructions/status.js +13 -1
- package/dist/commands/labels/list.d.ts +24 -1
- package/dist/commands/labels/list.js +62 -19
- package/dist/commands/machines/dedicated/catalog.js +4 -15
- package/dist/commands/machines/dedicated/create.d.ts +8 -0
- package/dist/commands/machines/dedicated/create.js +58 -1
- package/dist/commands/machines/dedicated/destroy.js +18 -4
- package/dist/commands/machines/dedicated/list.js +9 -6
- package/dist/commands/machines/hosted/list.js +12 -0
- package/dist/commands/machines/list.js +11 -0
- package/dist/commands/machines/show.d.ts +1 -0
- package/dist/commands/machines/show.js +40 -11
- package/dist/commands/memory/governance/index.d.ts +21 -0
- package/dist/commands/memory/governance/index.js +64 -0
- package/dist/commands/memory/governance/set.d.ts +24 -0
- package/dist/commands/memory/governance/set.js +95 -0
- package/dist/commands/memory/provenance.d.ts +18 -0
- package/dist/commands/memory/provenance.js +66 -0
- package/dist/commands/profiles/list.d.ts +23 -0
- package/dist/commands/profiles/list.js +96 -0
- package/dist/commands/search/skills.d.ts +11 -1
- package/dist/commands/search/skills.js +26 -8
- package/dist/commands/skills/details.d.ts +2 -0
- package/dist/commands/skills/details.js +24 -1
- package/dist/commands/skills/import-as-actions.d.ts +32 -0
- package/dist/commands/skills/import-as-actions.js +175 -0
- package/dist/commands/skills/install.d.ts +2 -0
- package/dist/commands/skills/install.js +24 -1
- package/dist/commands/skills/invocable.js +6 -2
- package/dist/commands/skills/local.d.ts +40 -0
- package/dist/commands/skills/local.js +160 -0
- package/dist/commands/skills/search.d.ts +11 -1
- package/dist/commands/skills/search.js +29 -8
- package/dist/commands/spaces/actions/add.js +23 -5
- package/dist/commands/spaces/actions/available.js +3 -0
- package/dist/commands/spaces/actions/list.d.ts +5 -0
- package/dist/commands/spaces/actions/list.js +49 -3
- package/dist/commands/spaces/actions/run.d.ts +28 -0
- package/dist/commands/spaces/actions/run.js +146 -0
- package/dist/commands/spaces/actions/update.js +27 -5
- package/dist/commands/spaces/create.d.ts +3 -0
- package/dist/commands/spaces/create.js +32 -2
- package/dist/commands/spaces/label-summaries.d.ts +27 -0
- package/dist/commands/spaces/label-summaries.js +64 -0
- package/dist/commands/spaces/labels/add.js +19 -2
- package/dist/commands/spaces/labels/remove.js +22 -2
- package/dist/commands/spaces/show.js +2 -0
- package/dist/commands/spaces/task-rollups.d.ts +5 -0
- package/dist/commands/spaces/task-rollups.js +15 -4
- package/dist/commands/spaces/update.d.ts +5 -0
- package/dist/commands/spaces/update.js +41 -4
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.d.ts +11 -0
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +105 -0
- package/dist/commands/tasks/actions/attach.js +32 -7
- package/dist/commands/tasks/complete.d.ts +1 -0
- package/dist/commands/tasks/complete.js +21 -1
- package/dist/commands/tasks/create.d.ts +3 -0
- package/dist/commands/tasks/create.js +34 -2
- package/dist/commands/tasks/events/append.js +29 -6
- package/dist/commands/tasks/expectations/assess.d.ts +12 -0
- package/dist/commands/tasks/expectations/assess.js +123 -14
- package/dist/commands/tasks/expectations.js +95 -17
- package/dist/commands/tasks/follow-up.js +2 -2
- package/dist/commands/tasks/labels/attach.js +20 -3
- package/dist/commands/tasks/labels/detach.js +21 -3
- package/dist/commands/tasks/lifecycle/attach.d.ts +14 -0
- package/dist/commands/tasks/lifecycle/attach.js +47 -0
- package/dist/commands/tasks/lifecycle/definitions.d.ts +11 -0
- package/dist/commands/tasks/lifecycle/definitions.js +59 -0
- package/dist/commands/tasks/lifecycle/detach.d.ts +19 -0
- package/dist/commands/tasks/lifecycle/detach.js +72 -0
- package/dist/commands/tasks/lifecycle/history.d.ts +13 -0
- package/dist/commands/tasks/lifecycle/history.js +38 -0
- package/dist/commands/tasks/lifecycle/migrate.d.ts +14 -0
- package/dist/commands/tasks/lifecycle/migrate.js +68 -0
- package/dist/commands/tasks/lifecycle/reconcile.d.ts +11 -0
- package/dist/commands/tasks/lifecycle/reconcile.js +27 -0
- package/dist/commands/tasks/lifecycle/reopen.d.ts +15 -0
- package/dist/commands/tasks/lifecycle/reopen.js +71 -0
- package/dist/commands/tasks/lifecycle/show.d.ts +11 -0
- package/dist/commands/tasks/lifecycle/show.js +27 -0
- package/dist/commands/tasks/lifecycle/start.d.ts +12 -0
- package/dist/commands/tasks/lifecycle/start.js +30 -0
- package/dist/commands/tasks/lifecycle/transition.d.ts +15 -0
- package/dist/commands/tasks/lifecycle/transition.js +109 -0
- package/dist/commands/tasks/list.js +16 -9
- package/dist/commands/tasks/move.d.ts +1 -0
- package/dist/commands/tasks/move.js +29 -0
- package/dist/commands/tasks/result/submit.js +11 -1
- package/dist/commands/tasks/review-queue.d.ts +44 -0
- package/dist/commands/tasks/review-queue.js +314 -0
- package/dist/commands/tasks/show.d.ts +11 -0
- package/dist/commands/tasks/show.js +139 -4
- package/dist/commands/tasks/trust.js +7 -2
- package/dist/commands/tasks/update.d.ts +1 -0
- package/dist/commands/tasks/update.js +83 -0
- package/dist/commands/tasks/updates/add.js +1 -1
- package/dist/commands/token/list.d.ts +22 -0
- package/dist/commands/token/list.js +68 -0
- package/dist/commands/token/revoke.d.ts +23 -0
- package/dist/commands/token/revoke.js +53 -0
- package/dist/lib/agent-actions.d.ts +92 -11
- package/dist/lib/agent-actions.js +171 -25
- package/dist/lib/agent-config.d.ts +11 -0
- package/dist/lib/agent-config.js +85 -3
- package/dist/lib/agent-pin-mute.d.ts +29 -0
- package/dist/lib/agent-pin-mute.js +30 -0
- package/dist/lib/agent-visual-refs.d.ts +33 -0
- package/dist/lib/agent-visual-refs.js +267 -0
- package/dist/lib/agentic-stream.d.ts +6 -0
- package/dist/lib/agentic-stream.js +34 -3
- package/dist/lib/assignee-resolver.d.ts +1 -1
- package/dist/lib/assignee-resolver.js +8 -0
- package/dist/lib/bulk-task-targets.d.ts +12 -0
- package/dist/lib/bulk-task-targets.js +34 -1
- package/dist/lib/cli-installers.d.ts +130 -0
- package/dist/lib/cli-installers.js +145 -0
- package/dist/lib/command-miss.js +55 -7
- package/dist/lib/dedicated-lease-command.d.ts +13 -0
- package/dist/lib/dedicated-lease-command.js +22 -1
- package/dist/lib/dedicated-machines.d.ts +95 -1
- package/dist/lib/dedicated-machines.js +236 -2
- package/dist/lib/failed-lookup.d.ts +3 -0
- package/dist/lib/failed-lookup.js +40 -0
- package/dist/lib/first-party-harness-agent.js +16 -2
- package/dist/lib/first-party-harness-doctor.d.ts +15 -0
- package/dist/lib/first-party-harness-doctor.js +126 -27
- package/dist/lib/followups.d.ts +115 -0
- package/dist/lib/followups.js +127 -0
- package/dist/lib/harnesses.d.ts +8 -0
- package/dist/lib/instruction-input.d.ts +19 -1
- package/dist/lib/instruction-input.js +52 -1
- package/dist/lib/label-ref.d.ts +95 -0
- package/dist/lib/label-ref.js +163 -0
- package/dist/lib/label-scope.d.ts +17 -2
- package/dist/lib/label-scope.js +27 -7
- package/dist/lib/local-skills.d.ts +98 -0
- package/dist/lib/local-skills.js +195 -0
- package/dist/lib/machines.d.ts +10 -10
- package/dist/lib/machines.js +23 -1
- package/dist/lib/search-query.d.ts +19 -0
- package/dist/lib/search-query.js +35 -0
- package/dist/lib/space-custom-actions.d.ts +72 -0
- package/dist/lib/space-custom-actions.js +117 -0
- package/dist/lib/space-resolver.d.ts +1 -21
- package/dist/lib/space-resolver.js +19 -10
- package/dist/lib/task-closure.d.ts +33 -0
- package/dist/lib/task-closure.js +104 -0
- package/dist/lib/task-lifecycle-output.d.ts +14 -0
- package/dist/lib/task-lifecycle-output.js +209 -0
- package/dist/lib/task-ref-resolver.d.ts +1 -17
- package/dist/lib/task-ref-resolver.js +18 -8
- package/dist/lib/tasks.d.ts +3 -0
- package/dist/lib/tasks.js +40 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.js +4 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.js +4 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +5559 -4897
- package/oclif.manifest.json +33890 -28690
- package/package.json +24 -6
|
@@ -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
|
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { TaskClosureEvaluation } from '@skrr-ai/data-provider';
|
|
2
|
+
/**
|
|
3
|
+
* Render "where does this Task actually stand" for every surface that should
|
|
4
|
+
* say it.
|
|
5
|
+
*
|
|
6
|
+
* ONE renderer, because the failure this exists to fix was several surfaces each
|
|
7
|
+
* asserting a closure state none of them had checked: `tasks result submit`
|
|
8
|
+
* printed a hard-coded "it is ready for review", the server wrote a
|
|
9
|
+
* `ready_for_review` Update to match, and the managed instructions told the
|
|
10
|
+
* agent to read a status the response did not carry. Three confident voices,
|
|
11
|
+
* one unchecked claim.
|
|
12
|
+
*
|
|
13
|
+
* So the rule here is narrow and absolute: this function says only what the
|
|
14
|
+
* evaluation says. If the evaluation is absent or could not run, it says THAT —
|
|
15
|
+
* it never falls back to an optimistic sentence, because the optimistic sentence
|
|
16
|
+
* is the bug.
|
|
17
|
+
*/
|
|
18
|
+
export type ClosureLike = TaskClosureEvaluation | {
|
|
19
|
+
unavailable: true;
|
|
20
|
+
reason?: string;
|
|
21
|
+
} | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* The full account, for the moment a caller has just written something and is
|
|
24
|
+
* deciding what to do next.
|
|
25
|
+
*
|
|
26
|
+
* Every unmet Expectation is NAMED. The ids alone (`e1`, `e2`) are what the
|
|
27
|
+
* gate's own details carried for a while, and they are unusable on their own —
|
|
28
|
+
* the whole point is to be able to act without a second lookup.
|
|
29
|
+
*/
|
|
30
|
+
export declare function closureReport(closure: ClosureLike): 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';
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.closureSnapshotLines = exports.describeAssessor = void 0;
|
|
4
|
+
exports.closureReport = closureReport;
|
|
5
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
6
|
+
function isUnavailable(closure) {
|
|
7
|
+
return Boolean(closure && closure.unavailable);
|
|
8
|
+
}
|
|
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;
|
|
12
|
+
/**
|
|
13
|
+
* The full account, for the moment a caller has just written something and is
|
|
14
|
+
* deciding what to do next.
|
|
15
|
+
*
|
|
16
|
+
* Every unmet Expectation is NAMED. The ids alone (`e1`, `e2`) are what the
|
|
17
|
+
* gate's own details carried for a while, and they are unusable on their own —
|
|
18
|
+
* the whole point is to be able to act without a second lookup.
|
|
19
|
+
*/
|
|
20
|
+
function closureReport(closure) {
|
|
21
|
+
if (!closure)
|
|
22
|
+
return ['Closure state: not reported by this call.'];
|
|
23
|
+
if (isUnavailable(closure)) {
|
|
24
|
+
return [
|
|
25
|
+
'Closure state could not be evaluated. That is a statement about this read,',
|
|
26
|
+
'not about the work — run `skrr tasks expectations <task-id>` to ask directly.',
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
const lines = [];
|
|
30
|
+
const exp = closure.expectations;
|
|
31
|
+
/*
|
|
32
|
+
* The degraded note comes FIRST, and before the closable shortcut.
|
|
33
|
+
*
|
|
34
|
+
* An unreadable assessment ledger makes the gate fail OPEN — deliberately, so
|
|
35
|
+
* a Mongo blip cannot create a Task nothing can close — which means `closable`
|
|
36
|
+
* can be true precisely because a check did not run. Reporting only "nothing
|
|
37
|
+
* is outstanding" there would launder an infrastructure failure into a clean
|
|
38
|
+
* bill of health, which is the same class of silence this whole file exists to
|
|
39
|
+
* remove.
|
|
40
|
+
*/
|
|
41
|
+
if (exp?.degraded === 'assessments_unreadable' || closure.degraded === 'assessments_unreadable') {
|
|
42
|
+
lines.push('Expectation assessments could not be read; that check was skipped, not passed.');
|
|
43
|
+
}
|
|
44
|
+
if (closure.closable) {
|
|
45
|
+
lines.push('Nothing is outstanding — this Task can close.');
|
|
46
|
+
return lines;
|
|
47
|
+
}
|
|
48
|
+
if (exp && exp.total > 0) {
|
|
49
|
+
/*
|
|
50
|
+
* "Settled," not "met" — a waived Expectation was judged no longer owed,
|
|
51
|
+
* which is a different fact from done. The count names waivers when any
|
|
52
|
+
* exist so a scope change never reads as completed work.
|
|
53
|
+
*/
|
|
54
|
+
const settled = exp.settledCount ?? exp.settled?.length ?? exp.met;
|
|
55
|
+
const waivedNote = exp.waived ? ` (${exp.waived} waived)` : '';
|
|
56
|
+
lines.push(`Expectations: ${settled} of ${exp.total} settled${waivedNote}.`);
|
|
57
|
+
for (const row of exp.unmet) {
|
|
58
|
+
lines.push(` ${row.id} ${truncate(row.sentence || row.text || '(no text)', 76)}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
for (const blocker of closure.blockers) {
|
|
62
|
+
if (blocker.code === 'TASK_EXPECTATIONS_NOT_MET')
|
|
63
|
+
continue;
|
|
64
|
+
lines.push(SHORT_BLOCKER[blocker.code] ? capitalize(SHORT_BLOCKER[blocker.code]) + '.' : blocker.message);
|
|
65
|
+
}
|
|
66
|
+
if (exp && exp.unmet.length > 0) {
|
|
67
|
+
lines.push('');
|
|
68
|
+
lines.push('Settle each with `skrr tasks expectations assess <task-id> <expectation-id>');
|
|
69
|
+
lines.push(' --decision met|waived --reason "..."`, or review the whole space with');
|
|
70
|
+
lines.push(' `skrr tasks review-queue --space <space-id>`.');
|
|
71
|
+
}
|
|
72
|
+
/*
|
|
73
|
+
* Everything else is advisory — stamped onto `resolution.closure` if the
|
|
74
|
+
* Task closes over it. The one refusal left is an owner-declared required
|
|
75
|
+
* Review, and only for someone who is not the owner; when that blocker is
|
|
76
|
+
* present, say the narrower truth.
|
|
77
|
+
*/
|
|
78
|
+
const reviewRequired = closure.blockers.some((b) => b.code === 'TASK_RESULT_REVIEW_REQUIRED');
|
|
79
|
+
lines.push('');
|
|
80
|
+
lines.push(reviewRequired
|
|
81
|
+
? 'Only an accepted independent Review — or the Task owner closing directly — settles this. The rest is recorded on resolution.closure.'
|
|
82
|
+
: 'Closing anyway is allowed — all of this is recorded on resolution.closure.');
|
|
83
|
+
return lines;
|
|
84
|
+
}
|
|
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; } });
|
|
88
|
+
function truncate(value, max) {
|
|
89
|
+
const flat = value.replace(/\s+/g, ' ').trim();
|
|
90
|
+
return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;
|
|
91
|
+
}
|
|
92
|
+
function capitalize(value) {
|
|
93
|
+
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
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; } });
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TaskLifecycleHistoryResponse, TaskLifecycleResponse, TaskLifecycleTransitionResponse } from '@skrr-ai/data-provider';
|
|
2
|
+
/**
|
|
3
|
+
* Render the Task Lifecycle response — the projection, its stages in protocol
|
|
4
|
+
* order, and the transitions the waiting stage currently declares.
|
|
5
|
+
*/
|
|
6
|
+
export declare function renderTaskLifecycleSummary(response: TaskLifecycleResponse, log: (line: string) => void): void;
|
|
7
|
+
/** Render the outcome of a lifecycle transition call. */
|
|
8
|
+
export declare function renderLifecycleTransitionResult(response: TaskLifecycleTransitionResponse, log: (line: string) => void): void;
|
|
9
|
+
/**
|
|
10
|
+
* Render the durable lifecycle event stream — every generation's transitions,
|
|
11
|
+
* gates and run events, newest first. `lifecycle show` answers where the Task
|
|
12
|
+
* IS; this answers how it got there.
|
|
13
|
+
*/
|
|
14
|
+
export declare function renderLifecycleHistory(response: TaskLifecycleHistoryResponse, log: (line: string) => void): void;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderTaskLifecycleSummary = renderTaskLifecycleSummary;
|
|
4
|
+
exports.renderLifecycleTransitionResult = renderLifecycleTransitionResult;
|
|
5
|
+
exports.renderLifecycleHistory = renderLifecycleHistory;
|
|
6
|
+
/**
|
|
7
|
+
* Render the Task Lifecycle response — the projection, its stages in protocol
|
|
8
|
+
* order, and the transitions the waiting stage currently declares.
|
|
9
|
+
*/
|
|
10
|
+
function renderTaskLifecycleSummary(response, log) {
|
|
11
|
+
const lifecycle = response.lifecycle;
|
|
12
|
+
if (!lifecycle) {
|
|
13
|
+
log('No lifecycle is attached to this Task.');
|
|
14
|
+
log('Attach one: skrr tasks lifecycle attach <task-id> --pack finding');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
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}`);
|
|
24
|
+
if (response.run)
|
|
25
|
+
log(`Run: ${response.run.id} — ${response.run.status}`);
|
|
26
|
+
for (const stage of response.stages || []) {
|
|
27
|
+
const marker = stage.key === lifecycle.currentStageKey ? '>' : ' ';
|
|
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
|
+
: '';
|
|
36
|
+
log(`${marker} ${stage.label || stage.key}${state}`);
|
|
37
|
+
}
|
|
38
|
+
if (response.gate) {
|
|
39
|
+
log('');
|
|
40
|
+
log(`Closure gate: ${response.gate.message}`);
|
|
41
|
+
}
|
|
42
|
+
const transitions = response.allowedTransitions || [];
|
|
43
|
+
const waiting = response.stage?.waitingFor;
|
|
44
|
+
if (response.stage && transitions.length) {
|
|
45
|
+
log('');
|
|
46
|
+
log(`Stage "${response.stage.nodeKey}" is waiting${waiting?.nextActor ? ` on ${waiting.nextActor}` : ''}. Legal transitions:`);
|
|
47
|
+
for (const transition of transitions) {
|
|
48
|
+
const needs = [
|
|
49
|
+
...(transition.requires?.fields || []).map((f) => `payload.${f}`),
|
|
50
|
+
transition.requires?.updateType ? `${transition.requires.updateType} update` : undefined,
|
|
51
|
+
transition.requires?.evidence
|
|
52
|
+
? `${transition.requires.evidence} evidence ref(s)`
|
|
53
|
+
: undefined,
|
|
54
|
+
transition.requires?.deliverableRef ? 'deliverable ref' : undefined,
|
|
55
|
+
].filter(Boolean);
|
|
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}'`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (response.pendingEffects?.length) {
|
|
73
|
+
log('');
|
|
74
|
+
const exhausted = response.pendingEffects.filter((effect) => effect.status === 'failed');
|
|
75
|
+
log(`${response.pendingEffects.length} effect(s) pending repair:`);
|
|
76
|
+
for (const effect of response.pendingEffects) {
|
|
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>');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (lifecycle.statusDrift) {
|
|
92
|
+
log(`Status drift: stage expects ${lifecycle.statusDrift.expected}, Task shows ${lifecycle.statusDrift.actual}.`);
|
|
93
|
+
}
|
|
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
|
+
}
|
|
143
|
+
/** Render the outcome of a lifecycle transition call. */
|
|
144
|
+
function renderLifecycleTransitionResult(response, log) {
|
|
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` : ''}.`);
|
|
157
|
+
if (response.message)
|
|
158
|
+
log(response.message);
|
|
159
|
+
for (const effect of response.effects || []) {
|
|
160
|
+
log(` effect ${effect.kind}: ${effect.status}${effect.ref ? ` -> ${effect.ref}` : ''}${effect.error ? ` — ${effect.error}` : ''}`);
|
|
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)}.`);
|
|
172
|
+
if (response.gate)
|
|
173
|
+
log(`Gate: ${response.gate.message}`);
|
|
174
|
+
if (response.lifecycle) {
|
|
175
|
+
log(`Lifecycle: ${response.lifecycle.status}, stage ${response.lifecycle.currentStageKey ?? '—'}, revision ${response.lifecycle.revision}.`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Render the durable lifecycle event stream — every generation's transitions,
|
|
180
|
+
* gates and run events, newest first. `lifecycle show` answers where the Task
|
|
181
|
+
* IS; this answers how it got there.
|
|
182
|
+
*/
|
|
183
|
+
function renderLifecycleHistory(response, log) {
|
|
184
|
+
if (!response.events.length) {
|
|
185
|
+
log('No lifecycle events recorded for this Task.');
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
for (const event of response.events) {
|
|
189
|
+
const parts = [
|
|
190
|
+
event.at,
|
|
191
|
+
event.type,
|
|
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,
|
|
197
|
+
event.transitionId,
|
|
198
|
+
event.status,
|
|
199
|
+
event.outcome,
|
|
200
|
+
event.code,
|
|
201
|
+
].filter(Boolean);
|
|
202
|
+
log(parts.join(' '));
|
|
203
|
+
if (event.message)
|
|
204
|
+
log(` ${event.message}`);
|
|
205
|
+
}
|
|
206
|
+
if (response.truncated) {
|
|
207
|
+
log(`— truncated at the event limit; re-query with a higher --limit or --before.`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -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
|
};
|
package/dist/lib/tasks.d.ts
CHANGED
|
@@ -66,6 +66,9 @@ export type TaskCreateFlagValues = {
|
|
|
66
66
|
tag?: string[];
|
|
67
67
|
'label-id'?: string[];
|
|
68
68
|
worktree?: boolean;
|
|
69
|
+
'lifecycle-definition'?: string;
|
|
70
|
+
'lifecycle-version'?: string;
|
|
71
|
+
'lifecycle-pack'?: string;
|
|
69
72
|
};
|
|
70
73
|
/**
|
|
71
74
|
* Map the tri-state `--worktree` flag to the `executionIsolation` value.
|