@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
|
@@ -5,6 +5,7 @@ const data_provider_1 = require("@skrr-ai/data-provider");
|
|
|
5
5
|
const api_fetch_1 = require("../../lib/api-fetch");
|
|
6
6
|
const session_task_endpoints_1 = require("../../lib/session-task-endpoints");
|
|
7
7
|
const base_command_1 = require("../../base-command");
|
|
8
|
+
const task_closure_1 = require("../../lib/task-closure");
|
|
8
9
|
const web_url_1 = require("../../lib/web-url");
|
|
9
10
|
const task_resolver_1 = require("../../lib/task-resolver");
|
|
10
11
|
const projects_1 = require("../../lib/projects");
|
|
@@ -52,6 +53,9 @@ class TasksMove extends base_command_1.BaseCommand {
|
|
|
52
53
|
description: 'Who can resolve the exceptional hold',
|
|
53
54
|
options: ['human', 'agent', 'system', 'external'],
|
|
54
55
|
}),
|
|
56
|
+
force: core_1.Flags.boolean({
|
|
57
|
+
description: "Close past an owner-declared required Review as a non-owner; the override is recorded on the task's resolution",
|
|
58
|
+
}),
|
|
55
59
|
};
|
|
56
60
|
async run() {
|
|
57
61
|
this.requireAuth();
|
|
@@ -100,6 +104,7 @@ class TasksMove extends base_command_1.BaseCommand {
|
|
|
100
104
|
status: flags.status,
|
|
101
105
|
...(flags.reason ? { reason: flags.reason } : {}),
|
|
102
106
|
...(flags['resolution-actor'] ? { resolutionActor: flags['resolution-actor'] } : {}),
|
|
107
|
+
...(flags.force ? { force: true } : {}),
|
|
103
108
|
},
|
|
104
109
|
}));
|
|
105
110
|
updated = res.task;
|
|
@@ -110,6 +115,7 @@ class TasksMove extends base_command_1.BaseCommand {
|
|
|
110
115
|
status: flags.status,
|
|
111
116
|
reason: flags.reason,
|
|
112
117
|
resolutionActor: flags['resolution-actor'],
|
|
118
|
+
force: flags.force === true ? true : undefined,
|
|
113
119
|
});
|
|
114
120
|
}
|
|
115
121
|
}
|
|
@@ -138,6 +144,29 @@ class TasksMove extends base_command_1.BaseCommand {
|
|
|
138
144
|
destinations.push(await this.describeProjectDestination(projectId, t));
|
|
139
145
|
}
|
|
140
146
|
this.log(`Moved task ${t.id ?? t._id ?? taskIdentity.id}${ref ? ` (${ref})` : ''} → ${destinations.join(', ')}`);
|
|
147
|
+
/*
|
|
148
|
+
* Closing is the actor's call — the server does not refuse outstanding
|
|
149
|
+
* work, it records it on `resolution.closure`. If the close just written
|
|
150
|
+
* left things unsettled, say so here so the output and the durable record
|
|
151
|
+
* tell the same story rather than letting "done" launder open items.
|
|
152
|
+
*/
|
|
153
|
+
// Read through the SHARED vocabulary. This carried a local structural cast
|
|
154
|
+
// while `overrode` was missing from `Task['resolution']['closure']` — which
|
|
155
|
+
// is exactly how one surface comes to know a field the type does not. `t` is
|
|
156
|
+
// the loosely-typed receipt, so the narrowing cast stays; what matters is
|
|
157
|
+
// that the shape it names is the one data-provider owns.
|
|
158
|
+
const resolutionClosure = t.resolution?.closure;
|
|
159
|
+
/*
|
|
160
|
+
* Through the shared renderer. This hand-rolled the rendering and pushed
|
|
161
|
+
* blocker CODES at a human — `Closed over TASK_RESULT_REQUIRED`, which is a
|
|
162
|
+
* wire identifier and, read plainly, the opposite of what just happened. The
|
|
163
|
+
* worst instance was the one this batch cares most about: a Task closed over
|
|
164
|
+
* a reviewer's objection printed `TASK_RESULT_CHANGES_REQUESTED`, rendering
|
|
165
|
+
* "somebody looked and objected" as an identifier.
|
|
166
|
+
*/
|
|
167
|
+
for (const sentence of (0, task_closure_1.closureSnapshotLines)(resolutionClosure)) {
|
|
168
|
+
this.log(` ${sentence}`);
|
|
169
|
+
}
|
|
141
170
|
}
|
|
142
171
|
/**
|
|
143
172
|
* Name the project the receipt lands in, resolving its title from the task's
|
|
@@ -7,6 +7,7 @@ const outbox_1 = require("../../../lib/outbox");
|
|
|
7
7
|
const task_resolver_1 = require("../../../lib/task-resolver");
|
|
8
8
|
const web_url_1 = require("../../../lib/web-url");
|
|
9
9
|
const api_fetch_1 = require("../../../lib/api-fetch");
|
|
10
|
+
const task_closure_1 = require("../../../lib/task-closure");
|
|
10
11
|
const session_task_endpoints_1 = require("../../../lib/session-task-endpoints");
|
|
11
12
|
function parseJson(value, label) {
|
|
12
13
|
if (!value)
|
|
@@ -126,7 +127,16 @@ class TasksResultSubmit extends base_command_1.BaseCommand {
|
|
|
126
127
|
const url = (0, web_url_1.taskUrlFrom)(this.cliConfig.baseURL, { id: task.id });
|
|
127
128
|
if (flags.json)
|
|
128
129
|
return this.log(JSON.stringify({ ...result, url }, null, 2));
|
|
129
|
-
|
|
130
|
+
// Say what came back, never what we hope came back.
|
|
131
|
+
//
|
|
132
|
+
// This line used to read "...; it is ready for review." unconditionally,
|
|
133
|
+
// which was false for every Task with an unassessed Expectation — and the
|
|
134
|
+
// managed instructions told the agent to read the status the call returns,
|
|
135
|
+
// which the call did not carry. Submitting a Result is not closing a Task;
|
|
136
|
+
// the response now reports where it stands and this prints exactly that.
|
|
137
|
+
this.log(`Submitted Result v${result.result.version} for ${task.id}.`);
|
|
138
|
+
for (const line of (0, task_closure_1.closureReport)(result.closure))
|
|
139
|
+
this.log(line);
|
|
130
140
|
if (url)
|
|
131
141
|
this.log(`Task: ${url}`);
|
|
132
142
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* Everything in one Space that is waiting on a judgement, in one pass.
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS EXISTS
|
|
6
|
+
* ---------------
|
|
7
|
+
* An agent fans out. One session routinely produces nine Tasks carrying twenty
|
|
8
|
+
* or more Expectations, and every surface for settling them was built for one
|
|
9
|
+
* Task at a time — so the cost of CLOSING the work grew linearly with how well
|
|
10
|
+
* the work was DECOMPOSED, which punishes exactly the decomposition the product
|
|
11
|
+
* wants. Finding what was owed meant knowing that `tasks expectations` exists
|
|
12
|
+
* and running it per Task, having first worked out which Tasks to run it on.
|
|
13
|
+
*
|
|
14
|
+
* This is a read. It changes nothing, it names every outstanding judgement in
|
|
15
|
+
* the Space with the evidence already bound to it, and it prints the exact
|
|
16
|
+
* command that settles each one — so a reviewer can work down a list instead of
|
|
17
|
+
* reconstructing it.
|
|
18
|
+
*/
|
|
19
|
+
export default class TasksReviewQueue extends BaseCommand {
|
|
20
|
+
static description: string;
|
|
21
|
+
static examples: string[];
|
|
22
|
+
static flags: {
|
|
23
|
+
space: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
24
|
+
actionable: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
25
|
+
limit: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
26
|
+
'include-closed': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
27
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
28
|
+
};
|
|
29
|
+
run(): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* An empty queue must not be how you learn a Space id is wrong.
|
|
32
|
+
*
|
|
33
|
+
* A UUID-shaped ref is accepted without a lookup (`base-command` short-circuits
|
|
34
|
+
* on the SHAPE, which is a cheap and correct optimisation nearly everywhere),
|
|
35
|
+
* and the list route deliberately never 404s — an unknown Space falls back to
|
|
36
|
+
* the ACL enumeration and returns an honest empty page. Those two reasonable
|
|
37
|
+
* decisions compose into "Nothing is awaiting a judgement", exit 0, for a
|
|
38
|
+
* Space that does not exist. A typo read as done.
|
|
39
|
+
*
|
|
40
|
+
* So the existence check is paid for ONLY on the path that is about to make
|
|
41
|
+
* the completeness claim — never on the path that found work.
|
|
42
|
+
*/
|
|
43
|
+
private assertSpaceExists;
|
|
44
|
+
}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
+
const base_command_1 = require("../../base-command");
|
|
6
|
+
const task_closure_1 = require("../../lib/task-closure");
|
|
7
|
+
const web_url_1 = require("../../lib/web-url");
|
|
8
|
+
/**
|
|
9
|
+
* Everything in one Space that is waiting on a judgement, in one pass.
|
|
10
|
+
*
|
|
11
|
+
* WHY THIS EXISTS
|
|
12
|
+
* ---------------
|
|
13
|
+
* An agent fans out. One session routinely produces nine Tasks carrying twenty
|
|
14
|
+
* or more Expectations, and every surface for settling them was built for one
|
|
15
|
+
* Task at a time — so the cost of CLOSING the work grew linearly with how well
|
|
16
|
+
* the work was DECOMPOSED, which punishes exactly the decomposition the product
|
|
17
|
+
* wants. Finding what was owed meant knowing that `tasks expectations` exists
|
|
18
|
+
* and running it per Task, having first worked out which Tasks to run it on.
|
|
19
|
+
*
|
|
20
|
+
* This is a read. It changes nothing, it names every outstanding judgement in
|
|
21
|
+
* the Space with the evidence already bound to it, and it prints the exact
|
|
22
|
+
* command that settles each one — so a reviewer can work down a list instead of
|
|
23
|
+
* reconstructing it.
|
|
24
|
+
*/
|
|
25
|
+
class TasksReviewQueue extends base_command_1.BaseCommand {
|
|
26
|
+
static description = 'Every Expectation in a Space still awaiting a judgement, with its evidence and the command that settles it';
|
|
27
|
+
static examples = [
|
|
28
|
+
'<%= config.bin %> tasks review-queue --space <space-id>',
|
|
29
|
+
'<%= config.bin %> tasks review-queue --space <space-id> --json',
|
|
30
|
+
'<%= config.bin %> tasks review-queue --space <space-id> --actionable',
|
|
31
|
+
];
|
|
32
|
+
static flags = {
|
|
33
|
+
space: core_1.Flags.string({ description: 'Space id', required: true }),
|
|
34
|
+
actionable: core_1.Flags.boolean({
|
|
35
|
+
description: 'Only Tasks where a Result is already in — the ones a reviewer can act on',
|
|
36
|
+
}),
|
|
37
|
+
limit: core_1.Flags.integer({ description: 'Maximum Tasks to inspect (default 100)', default: 100 }),
|
|
38
|
+
'include-closed': core_1.Flags.boolean({
|
|
39
|
+
description: 'Also list Tasks already closed — for auditing what was closed over',
|
|
40
|
+
}),
|
|
41
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
42
|
+
};
|
|
43
|
+
async run() {
|
|
44
|
+
this.requireAuth();
|
|
45
|
+
const { flags } = await this.parse(TasksReviewQueue);
|
|
46
|
+
/**
|
|
47
|
+
* `response.data`, read from the TYPE rather than guessed.
|
|
48
|
+
*
|
|
49
|
+
* The first version of this read `response.tasks`, which does not exist —
|
|
50
|
+
* and the failure was silent in the worst possible direction: an empty array
|
|
51
|
+
* printed "Nothing is awaiting a judgement" for a Space with twenty-three
|
|
52
|
+
* unassessed Expectations. A reviewer would have believed they were done.
|
|
53
|
+
*
|
|
54
|
+
* `COMMAND_INDEX.md` warns about exactly this ("read the wrong key and you
|
|
55
|
+
* get an empty result rather than an error, which looks exactly like 'no
|
|
56
|
+
* rows matched'"). So the shape is taken from `TaskListResponse` and a
|
|
57
|
+
* missing envelope is an ERROR, never an empty queue: this command's whole
|
|
58
|
+
* value is telling someone there is nothing left, and it may only say that
|
|
59
|
+
* when it actually looked.
|
|
60
|
+
*/
|
|
61
|
+
/*
|
|
62
|
+
* Follow the cursor — a truncated list is the same silent false negative
|
|
63
|
+
* as a misread envelope, one page later. This command's whole value is
|
|
64
|
+
* "there is nothing left," and a tail it never saw breaks that claim.
|
|
65
|
+
* `--limit` caps how many Tasks get inspected, not how many pages get read.
|
|
66
|
+
*/
|
|
67
|
+
if (flags.limit < 1) {
|
|
68
|
+
// Inspecting zero Tasks and then saying "nothing is owed" is the exact
|
|
69
|
+
// unlooked-for empty answer this command refuses to give.
|
|
70
|
+
this.error('--limit must be at least 1.', { exit: 1 });
|
|
71
|
+
}
|
|
72
|
+
/*
|
|
73
|
+
* oclif's `required: true` asserts the flag was SUPPLIED, not that it says
|
|
74
|
+
* anything. `--space ""` — an unset shell variable, which is how it happens
|
|
75
|
+
* — satisfied it, and the empty string was then dropped from the query
|
|
76
|
+
* string as falsy, so the command silently widened from one Space to every
|
|
77
|
+
* Space the caller can see and reported that as the answer.
|
|
78
|
+
*/
|
|
79
|
+
if (!flags.space.trim()) {
|
|
80
|
+
this.error('--space needs a Space id; it was given an empty value.', { exit: 1 });
|
|
81
|
+
}
|
|
82
|
+
const tasks = [];
|
|
83
|
+
/*
|
|
84
|
+
* Whether the scan actually reached the end.
|
|
85
|
+
*
|
|
86
|
+
* The loop already followed the cursor, and then stopped at `--limit` with
|
|
87
|
+
* `has_more` still true and threw that fact away — so a Space with 95 owed
|
|
88
|
+
* Expectations reported on the first 11 and printed the same sentence it
|
|
89
|
+
* prints for a Space that owes nothing. The comment above states the
|
|
90
|
+
* principle this had to satisfy; nothing recorded whether it had.
|
|
91
|
+
*/
|
|
92
|
+
let truncated = false;
|
|
93
|
+
try {
|
|
94
|
+
let cursor;
|
|
95
|
+
for (;;) {
|
|
96
|
+
const response = await data_provider_1.dataService.listTasks({
|
|
97
|
+
spaceId: flags.space,
|
|
98
|
+
limit: Math.min(100, flags.limit - tasks.length),
|
|
99
|
+
...(cursor ? { cursor } : {}),
|
|
100
|
+
});
|
|
101
|
+
if (!response || !Array.isArray(response.data)) {
|
|
102
|
+
this.error('The task list came back in a shape this command does not recognise, so it cannot ' +
|
|
103
|
+
'say whether anything is owed. Refusing to report an empty queue.', { exit: 1 });
|
|
104
|
+
}
|
|
105
|
+
tasks.push(...response.data);
|
|
106
|
+
if (!response.has_more || !response.next_cursor)
|
|
107
|
+
break;
|
|
108
|
+
if (tasks.length >= flags.limit) {
|
|
109
|
+
truncated = true;
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
cursor = response.next_cursor;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
this.handleApiError(error);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Acceptance is read per Task, and a Task whose acceptance cannot be read is
|
|
121
|
+
* REPORTED rather than dropped. A queue that silently omitted a row would be
|
|
122
|
+
* worse than no queue: the reviewer would believe they had seen everything.
|
|
123
|
+
*/
|
|
124
|
+
const rows = [];
|
|
125
|
+
/*
|
|
126
|
+
* A finished Task is not a worklist item.
|
|
127
|
+
*
|
|
128
|
+
* Closing is the closer's call now, so a Task can reach `done` over
|
|
129
|
+
* Expectations nobody judged — and those rows stayed in the queue forever,
|
|
130
|
+
* captioned in the present tense ("settling these will not close it") about
|
|
131
|
+
* something already closed. Every forced close permanently added noise to
|
|
132
|
+
* the list a reviewer is supposed to work down. `--include-closed` keeps the
|
|
133
|
+
* old view for anyone auditing what was closed over.
|
|
134
|
+
*/
|
|
135
|
+
const CLOSED_STATUS_TYPES = new Set(['completed', 'cancelled']);
|
|
136
|
+
const candidates = tasks.filter((task) => flags['include-closed'] || !CLOSED_STATUS_TYPES.has(String(task.statusType ?? '')));
|
|
137
|
+
const skippedClosed = tasks.length - candidates.length;
|
|
138
|
+
/*
|
|
139
|
+
* Acceptance is one request per Task and there is no batch endpoint, so the
|
|
140
|
+
* serial loop this replaces took 61 seconds on 100 Tasks and printed nothing
|
|
141
|
+
* at all until it finished. Bounded rather than `Promise.all`: 100
|
|
142
|
+
* simultaneous authorized reads hit the same cascade the `/cards` endpoint
|
|
143
|
+
* exists to avoid. Results are written by INDEX so output order stays the
|
|
144
|
+
* list's order regardless of which request returns first.
|
|
145
|
+
*/
|
|
146
|
+
const ACCEPTANCE_CONCURRENCY = 6;
|
|
147
|
+
const settled = new Array(candidates.length).fill(null);
|
|
148
|
+
let next = 0;
|
|
149
|
+
const worker = async () => {
|
|
150
|
+
for (;;) {
|
|
151
|
+
const index = next;
|
|
152
|
+
next += 1;
|
|
153
|
+
if (index >= candidates.length)
|
|
154
|
+
return;
|
|
155
|
+
const task = candidates[index];
|
|
156
|
+
const taskId = String(task.id ?? task._id ?? '');
|
|
157
|
+
if (!taskId)
|
|
158
|
+
continue;
|
|
159
|
+
const base = {
|
|
160
|
+
taskId,
|
|
161
|
+
identifier: String(task.identifier ?? taskId),
|
|
162
|
+
title: String(task.title ?? '(untitled)'),
|
|
163
|
+
status: String(task.status ?? '-'),
|
|
164
|
+
hasResult: Boolean(task.currentResultId),
|
|
165
|
+
};
|
|
166
|
+
try {
|
|
167
|
+
const acceptance = await data_provider_1.dataService.getTaskAcceptance(taskId);
|
|
168
|
+
const awaiting = acceptance.expectations.filter((e) => e.gating && !e.met);
|
|
169
|
+
if (awaiting.length > 0)
|
|
170
|
+
settled[index] = { ...base, awaiting };
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
settled[index] = {
|
|
174
|
+
...base,
|
|
175
|
+
awaiting: [],
|
|
176
|
+
error: error?.message || 'unreadable',
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
await Promise.all(Array.from({ length: Math.min(ACCEPTANCE_CONCURRENCY, candidates.length) }, worker));
|
|
182
|
+
rows.push(...settled.filter((row) => row !== null));
|
|
183
|
+
const visible = flags.actionable ? rows.filter((row) => row.hasResult || row.error) : rows;
|
|
184
|
+
if (flags.json) {
|
|
185
|
+
this.log(JSON.stringify({
|
|
186
|
+
space: flags.space,
|
|
187
|
+
inspected: candidates.length,
|
|
188
|
+
truncated,
|
|
189
|
+
...(skippedClosed > 0 ? { skippedClosed } : {}),
|
|
190
|
+
owedTasks: rows.length,
|
|
191
|
+
tasks: visible,
|
|
192
|
+
}, null, 2));
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
/*
|
|
196
|
+
* "Nothing is owed" may only be said by a scan that reached the end.
|
|
197
|
+
*
|
|
198
|
+
* One sentence used to cover four different states — a clean queue, a
|
|
199
|
+
* truncated scan, a filter that emptied the list, and a Space that does not
|
|
200
|
+
* exist — and in three of them it was false. Each now says its own thing,
|
|
201
|
+
* and the two that cannot support the claim refuse to make it, in the same
|
|
202
|
+
* shape as the misread-envelope guard above.
|
|
203
|
+
*/
|
|
204
|
+
if (truncated && rows.length === 0) {
|
|
205
|
+
this.error(`Inspected only the first ${candidates.length} Task(s) of a longer list in ${flags.space}, ` +
|
|
206
|
+
'so it cannot say whether anything is owed. Refusing to report an empty queue. ' +
|
|
207
|
+
'Re-run with a larger --limit.', { exit: 1 });
|
|
208
|
+
}
|
|
209
|
+
if (rows.length === 0) {
|
|
210
|
+
await this.assertSpaceExists(flags.space);
|
|
211
|
+
this.log(`Nothing in ${flags.space} is awaiting a judgement.`);
|
|
212
|
+
if (skippedClosed > 0) {
|
|
213
|
+
this.log(` (${skippedClosed} closed Task(s) skipped — see them with --include-closed.)`);
|
|
214
|
+
}
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (visible.length === 0) {
|
|
218
|
+
this.log(`${rows.length} Task(s) in ${flags.space} owe judgements, but none has a Result yet — ` +
|
|
219
|
+
're-run without --actionable to see them.');
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
let total = 0;
|
|
223
|
+
for (const row of visible) {
|
|
224
|
+
this.log('');
|
|
225
|
+
this.log(`${row.identifier} ${row.title}`);
|
|
226
|
+
if (row.error) {
|
|
227
|
+
this.log(` could not read its Expectations: ${row.error}`);
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
/*
|
|
231
|
+
* State the fact, not a gate. This read "no Result submitted yet — settling
|
|
232
|
+
* these will not close it", which implied that a Result is what stands
|
|
233
|
+
* between these judgements and a close. Since `56a6ded703` it is not: a
|
|
234
|
+
* Task closes without one and the absence is recorded on
|
|
235
|
+
* `resolution.closure`. What a reviewer needs to know is only that there is
|
|
236
|
+
* no Result to judge the work against yet.
|
|
237
|
+
*/
|
|
238
|
+
if (!row.hasResult) {
|
|
239
|
+
this.log(' no Result submitted yet — nothing to judge the work against');
|
|
240
|
+
}
|
|
241
|
+
for (const expectation of row.awaiting) {
|
|
242
|
+
total += 1;
|
|
243
|
+
this.log(` ${expectation.id} ${expectation.sentence || expectation.text || ''}`);
|
|
244
|
+
/*
|
|
245
|
+
* The judgement itself, not just the KIND of judge.
|
|
246
|
+
*
|
|
247
|
+
* `[last judged by person]` named no person, no decision, no date and no
|
|
248
|
+
* reason — so a reviewer working down this list could see that someone
|
|
249
|
+
* had looked and not what they concluded, which is the one thing they
|
|
250
|
+
* need before looking again. The acceptance projection carries all of it
|
|
251
|
+
* now; this is where it was being dropped.
|
|
252
|
+
*/
|
|
253
|
+
if (expectation.assessedByKind) {
|
|
254
|
+
const decision = expectation.decision || 'judged';
|
|
255
|
+
const when = expectation.assessedAt
|
|
256
|
+
? ` on ${String(expectation.assessedAt).slice(0, 10)}`
|
|
257
|
+
: '';
|
|
258
|
+
const why = expectation.reason ? `: ${expectation.reason}` : '';
|
|
259
|
+
this.log(` ${decision} by ${(0, task_closure_1.describeAssessor)(expectation.assessedByKind)}${when}${why}`);
|
|
260
|
+
}
|
|
261
|
+
if (expectation.evidenceLevel) {
|
|
262
|
+
this.log(` evidence: ${expectation.evidenceLevel}${expectation.requiredEvidence ? ` (asked for ${expectation.requiredEvidence})` : ''}`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const url = (0, web_url_1.taskUrlFrom)(this.cliConfig.baseURL, { id: row.taskId });
|
|
266
|
+
if (url)
|
|
267
|
+
this.log(` ${url}`);
|
|
268
|
+
}
|
|
269
|
+
this.log('');
|
|
270
|
+
this.log(`${total} Expectation(s) awaiting a judgement across ${visible.length} Task(s).`);
|
|
271
|
+
if (truncated) {
|
|
272
|
+
this.log(`Only the first ${candidates.length} Task(s) were inspected and more remain — ` +
|
|
273
|
+
're-run with a larger --limit to see the rest.');
|
|
274
|
+
}
|
|
275
|
+
if (skippedClosed > 0) {
|
|
276
|
+
this.log(`${skippedClosed} closed Task(s) skipped — see them with --include-closed.`);
|
|
277
|
+
}
|
|
278
|
+
this.log('');
|
|
279
|
+
this.log('Settle one: skrr tasks expectations assess <task-id> <expectation-id> \\');
|
|
280
|
+
this.log(' --decision met --reason "..."');
|
|
281
|
+
this.log('Settle a Task: skrr tasks expectations assess <task-id> --all \\');
|
|
282
|
+
this.log(' --decision met --reason "..."');
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* An empty queue must not be how you learn a Space id is wrong.
|
|
286
|
+
*
|
|
287
|
+
* A UUID-shaped ref is accepted without a lookup (`base-command` short-circuits
|
|
288
|
+
* on the SHAPE, which is a cheap and correct optimisation nearly everywhere),
|
|
289
|
+
* and the list route deliberately never 404s — an unknown Space falls back to
|
|
290
|
+
* the ACL enumeration and returns an honest empty page. Those two reasonable
|
|
291
|
+
* decisions compose into "Nothing is awaiting a judgement", exit 0, for a
|
|
292
|
+
* Space that does not exist. A typo read as done.
|
|
293
|
+
*
|
|
294
|
+
* So the existence check is paid for ONLY on the path that is about to make
|
|
295
|
+
* the completeness claim — never on the path that found work.
|
|
296
|
+
*/
|
|
297
|
+
async assertSpaceExists(spaceId) {
|
|
298
|
+
try {
|
|
299
|
+
await data_provider_1.dataService.getSpace(spaceId);
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
// The status rides the error itself here, the way `base-command` reads it
|
|
303
|
+
// (`e.status === 404`) — not on a nested `response`.
|
|
304
|
+
const status = error?.status;
|
|
305
|
+
if (status === 404 || status === 403) {
|
|
306
|
+
this.error(`No Space ${spaceId} is visible to you, so there is nothing to report on. ` +
|
|
307
|
+
'Check the id with `skrr spaces list`.', { exit: 2 });
|
|
308
|
+
}
|
|
309
|
+
// Any other failure is about this read, not about the Space. Let the
|
|
310
|
+
// empty answer stand rather than turning a blip into a false "not found".
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
exports.default = TasksReviewQueue;
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* Where to look next — as COMMANDS, not as facts about the task.
|
|
4
|
+
*
|
|
5
|
+
* These used to print as `What the agent produced: skrr tasks output <ref>`,
|
|
6
|
+
* in the same `Label: value` grammar as every line above them, so the line read
|
|
7
|
+
* as a statement of what the agent had produced. It also printed on tasks no
|
|
8
|
+
* agent had ever run, asserting output that did not exist (OSK-9669). They are
|
|
9
|
+
* now a visibly separate list, and only once a run, a conversation or a Result
|
|
10
|
+
* exists for them to show.
|
|
11
|
+
*/
|
|
12
|
+
export declare function taskPointerLines(t: Record<string, unknown>, ref: string, bin?: string): string[];
|
|
2
13
|
/**
|
|
3
14
|
* The failure rows of `tasks show`, when there are any. (S3 dogfood finding)
|
|
4
15
|
*
|
|
@@ -1,14 +1,43 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.taskPointerLines = taskPointerLines;
|
|
3
4
|
exports.taskFailureLines = taskFailureLines;
|
|
4
5
|
const core_1 = require("@oclif/core");
|
|
5
6
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
6
7
|
const api_fetch_1 = require("../../lib/api-fetch");
|
|
7
8
|
const session_task_endpoints_1 = require("../../lib/session-task-endpoints");
|
|
8
9
|
const base_command_1 = require("../../base-command");
|
|
10
|
+
const task_closure_1 = require("../../lib/task-closure");
|
|
9
11
|
const task_resolver_1 = require("../../lib/task-resolver");
|
|
10
12
|
const web_url_1 = require("../../lib/web-url");
|
|
11
13
|
const html_text_1 = require("../../lib/html-text");
|
|
14
|
+
/**
|
|
15
|
+
* Where to look next — as COMMANDS, not as facts about the task.
|
|
16
|
+
*
|
|
17
|
+
* These used to print as `What the agent produced: skrr tasks output <ref>`,
|
|
18
|
+
* in the same `Label: value` grammar as every line above them, so the line read
|
|
19
|
+
* as a statement of what the agent had produced. It also printed on tasks no
|
|
20
|
+
* agent had ever run, asserting output that did not exist (OSK-9669). They are
|
|
21
|
+
* now a visibly separate list, and only once a run, a conversation or a Result
|
|
22
|
+
* exists for them to show.
|
|
23
|
+
*/
|
|
24
|
+
function taskPointerLines(t, ref, bin = 'skrr') {
|
|
25
|
+
const hasSomethingToShow = Boolean(t.conversationId || t.lastFinalizedRunId || t.checkoutRunId || t.currentResultId);
|
|
26
|
+
if (!hasSomethingToShow)
|
|
27
|
+
return [];
|
|
28
|
+
const pointers = [
|
|
29
|
+
[`${bin} tasks output ${ref}`, 'what the agent produced'],
|
|
30
|
+
];
|
|
31
|
+
if (t.conversationId) {
|
|
32
|
+
pointers.push([`${bin} tasks transcript ${ref}`, 'the full agent transcript']);
|
|
33
|
+
}
|
|
34
|
+
const width = Math.max(...pointers.map(([command]) => command.length));
|
|
35
|
+
return [
|
|
36
|
+
'',
|
|
37
|
+
'See also:',
|
|
38
|
+
...pointers.map(([command, what]) => ` ${command.padEnd(width)} ${what}`),
|
|
39
|
+
];
|
|
40
|
+
}
|
|
12
41
|
/**
|
|
13
42
|
* The failure rows of `tasks show`, when there are any. (S3 dogfood finding)
|
|
14
43
|
*
|
|
@@ -173,6 +202,87 @@ class TasksShow extends base_command_1.BaseCommand {
|
|
|
173
202
|
// question and this is the answer to it.
|
|
174
203
|
for (const line of taskFailureLines(t, this.config.bin))
|
|
175
204
|
this.log(line);
|
|
205
|
+
/*
|
|
206
|
+
* Closing is the actor's call — a Task may be `done` with work still
|
|
207
|
+
* outstanding, and `resolution.closure` is where the server recorded what
|
|
208
|
+
* it stood on at close. Show it so a bare "done" never reads as "clean."
|
|
209
|
+
*/
|
|
210
|
+
const resolution = t.resolution;
|
|
211
|
+
/*
|
|
212
|
+
* Same renderer as the `tasks move` receipt, so the two cannot disagree
|
|
213
|
+
* about a Task they are both describing.
|
|
214
|
+
*
|
|
215
|
+
* This copy showed an owner's ordinary close as an override:
|
|
216
|
+
* `TASK_RESULT_REVIEW_REQUIRED` lands in `blockers` whenever the policy is
|
|
217
|
+
* unsatisfied — including when the owner, who is not bound by the Review
|
|
218
|
+
* they declared, closes it themselves — and this rendered it identically to
|
|
219
|
+
* a genuine forced close. So the only read surface for "was this gate
|
|
220
|
+
* overridden?" could not answer the question.
|
|
221
|
+
*/
|
|
222
|
+
if (resolution?.closure) {
|
|
223
|
+
const sentences = (0, task_closure_1.closureSnapshotLines)(resolution.closure);
|
|
224
|
+
if (sentences.length > 0) {
|
|
225
|
+
this.log(`Resolution: ${resolution.kind ?? '-'} — ${sentences.join(' ')}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/*
|
|
229
|
+
* A Result orphaned by a spec edit is not the same as no Result.
|
|
230
|
+
*
|
|
231
|
+
* Editing a `description` or an Expectation advances `specVersion`, which
|
|
232
|
+
* unsets `currentResultId` by design — the old answer replied to a question
|
|
233
|
+
* that has changed. But every CLI surface then reported the Task as though
|
|
234
|
+
* nothing had ever been submitted, and the prior Result is still there. The
|
|
235
|
+
* web already says this correctly ("No Result answers the current Task spec
|
|
236
|
+
* vN", plus the previous one); the CLI said nothing at all.
|
|
237
|
+
*
|
|
238
|
+
* The extra request is paid only in the ambiguous case — when there is no
|
|
239
|
+
* current Result — and `tasks show` is a detail view, so one call to
|
|
240
|
+
* distinguish "nobody answered" from "the answer is out of date" is worth
|
|
241
|
+
* it. A failed lookup degrades to silence rather than to a claim.
|
|
242
|
+
*/
|
|
243
|
+
const taskSpecVersion = Number(t.specVersion) || 1;
|
|
244
|
+
if (t.currentResultId) {
|
|
245
|
+
this.log(`Result: ${String(t.currentResultId)} (answers spec v${taskSpecVersion})`);
|
|
246
|
+
/*
|
|
247
|
+
* The Review on that Result, with its REASON.
|
|
248
|
+
*
|
|
249
|
+
* Closing over a `changes_requested` Review is allowed and recorded, and
|
|
250
|
+
* the closure line says "a reviewer requested changes" — the verdict. What
|
|
251
|
+
* they asked for lived only on the Review row, which no text surface
|
|
252
|
+
* printed, so the objection survived as a fact and lost its content. One
|
|
253
|
+
* read, on a detail view, only when there is a Result to have been
|
|
254
|
+
* reviewed; a failed read says nothing rather than implying no Review.
|
|
255
|
+
*/
|
|
256
|
+
try {
|
|
257
|
+
const history = await data_provider_1.dataService.listTaskResults(taskIdentity.id);
|
|
258
|
+
const review = (history?.reviews || []).find((row) => row.resultId === String(t.currentResultId));
|
|
259
|
+
if (review) {
|
|
260
|
+
const who = (0, task_closure_1.describeAssessor)(review.reviewedBy?.kind);
|
|
261
|
+
const when = review.reviewedAt ? ` on ${String(review.reviewedAt).slice(0, 10)}` : '';
|
|
262
|
+
const why = review.rationale ? `: ${review.rationale}` : '';
|
|
263
|
+
this.log(`Review: ${review.decision} by ${who}${when}${why}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
// Silence, not "no Review": this read failing is not evidence of absence.
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
let priorLine = 'none submitted';
|
|
272
|
+
try {
|
|
273
|
+
const history = await data_provider_1.dataService.listTaskResults(taskIdentity.id);
|
|
274
|
+
const prior = history?.results?.[0];
|
|
275
|
+
if (prior) {
|
|
276
|
+
priorLine =
|
|
277
|
+
`none answers spec v${taskSpecVersion} — previous v${prior.version} ` +
|
|
278
|
+
`answered spec v${prior.specVersion ?? '?'}`;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
priorLine = 'none answers the current spec (earlier Results could not be read)';
|
|
283
|
+
}
|
|
284
|
+
this.log(`Result: ${priorLine}`);
|
|
285
|
+
}
|
|
176
286
|
this.log(`Executor: ${t.executionMode ?? 'legacy / inferred'}`);
|
|
177
287
|
this.log(`Priority: ${t.priority ?? '-'}`);
|
|
178
288
|
this.log(`Parent: ${t.parentId ?? '-'}`);
|
|
@@ -291,11 +401,36 @@ class TasksShow extends base_command_1.BaseCommand {
|
|
|
291
401
|
}
|
|
292
402
|
}
|
|
293
403
|
const ref = String(t.id ?? t._id ?? taskIdentity.id);
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
404
|
+
/**
|
|
405
|
+
* Where this Task stands, on the surface people already open.
|
|
406
|
+
*
|
|
407
|
+
* `tasks expectations <id>` answers this well and is reachable only if you
|
|
408
|
+
* already know it exists — its one pointer lives in the `--expect` help of
|
|
409
|
+
* `tasks create`, which you read while AUTHORING and not while closing. So
|
|
410
|
+
* an agent that submitted a Result had no cheap way to learn the Task was
|
|
411
|
+
* still owed, and reasonably concluded from the CLI's own output that it was
|
|
412
|
+
* not. Say it here, where the question is actually asked.
|
|
413
|
+
*
|
|
414
|
+
* Read, not recomputed, and never fatal: a Task page must still render when
|
|
415
|
+
* the acceptance read fails, and it must not invent a state it could not
|
|
416
|
+
* fetch.
|
|
417
|
+
*/
|
|
418
|
+
try {
|
|
419
|
+
const acceptance = await data_provider_1.dataService.getTaskAcceptance(ref);
|
|
420
|
+
const gating = acceptance.expectations.filter((e) => e.gating);
|
|
421
|
+
if (gating.length > 0) {
|
|
422
|
+
const settled = gating.filter((e) => e.met).length;
|
|
423
|
+
this.log('');
|
|
424
|
+
this.log(`Expectations: ${settled} of ${gating.length} settled · overall: ${acceptance.state}` +
|
|
425
|
+
(settled < gating.length ? ` — skrr tasks expectations ${ref}` : ''));
|
|
426
|
+
}
|
|
298
427
|
}
|
|
428
|
+
catch {
|
|
429
|
+
// Silent: a Task this caller can VIEW but whose acceptance they cannot
|
|
430
|
+
// read is a permissions shape, not something to shout about mid-page.
|
|
431
|
+
}
|
|
432
|
+
for (const line of taskPointerLines(t, ref, this.config.bin))
|
|
433
|
+
this.log(line);
|
|
299
434
|
}
|
|
300
435
|
}
|
|
301
436
|
exports.default = TasksShow;
|
|
@@ -41,8 +41,13 @@ class TasksTrust extends base_command_1.BaseCommand {
|
|
|
41
41
|
level: core_1.Flags.string({
|
|
42
42
|
options: [...data_provider_1.DELIVERABLE_AUTHORITIES],
|
|
43
43
|
required: true,
|
|
44
|
-
description:
|
|
45
|
-
|
|
44
|
+
description:
|
|
45
|
+
// `observation_backed` is a RETIRED rung name for this domain — the flag
|
|
46
|
+
// rejects it, so the only two values the help explained were one real one
|
|
47
|
+
// and one the command refuses. The four the enum actually accepts:
|
|
48
|
+
'How well evidenced the answer must be: self_reported (the doer says so), ' +
|
|
49
|
+
'human_confirmed (a person confirmed it), system_observed (the platform saw it), ' +
|
|
50
|
+
'external_receipt (a provider receipt proves it).',
|
|
46
51
|
}),
|
|
47
52
|
reason: core_1.Flags.string({
|
|
48
53
|
required: true,
|
|
@@ -10,6 +10,7 @@ export default class TasksUpdate extends BaseCommand {
|
|
|
10
10
|
task: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
11
|
'from-json': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
12
12
|
title: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
13
|
+
yes: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
13
14
|
expect: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
14
15
|
description: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
15
16
|
'description-format': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|