toolroll 0.9.85 → 0.9.86
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/CHANGELOG.md +24 -0
- package/dist/agent-fence.d.ts +6 -2
- package/dist/agent-fence.js +3 -2
- package/dist/assignment.js +4 -3
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +31 -29
- package/dist/browser-workspace.d.ts +40 -0
- package/dist/chat-actions.d.ts +11 -1
- package/dist/chat-actions.js +53 -1
- package/dist/chat-channel.js +1 -0
- package/dist/chat-quiet.js +3 -2
- package/dist/claim.d.ts +3 -0
- package/dist/claim.js +4 -1
- package/dist/contracts/chat-actions.d.ts +9 -0
- package/dist/contracts/chat-actions.js +3 -0
- package/dist/contracts/console-api.d.ts +4 -1
- package/dist/contracts/console-api.js +4 -1
- package/dist/contracts/flow-propose.d.ts +4 -1
- package/dist/contracts/flow-propose.js +1 -1
- package/dist/contracts/flow.d.ts +41 -0
- package/dist/contracts/flow.js +4 -2
- package/dist/contracts/lead-tools.d.ts +21 -0
- package/dist/contracts/lead-tools.js +2 -0
- package/dist/contracts/store-json.d.ts +2 -0
- package/dist/contracts/trigger-payloads.d.ts +20 -0
- package/dist/contracts/trigger-payloads.js +4 -0
- package/dist/coordinator.js +1 -0
- package/dist/deploy-gate.js +4 -0
- package/dist/dispatch.d.ts +3 -0
- package/dist/dispatch.js +4 -1
- package/dist/flow-browser.d.ts +103 -0
- package/dist/flow-browser.js +204 -0
- package/dist/flow-code.d.ts +5 -1
- package/dist/flow-code.js +4 -1
- package/dist/flow-engine.js +16 -0
- package/dist/flow-live.js +9 -1
- package/dist/flow-pull-request.js +15 -7
- package/dist/flow-share.js +3 -1
- package/dist/flow-steps.d.ts +9 -1
- package/dist/flow-steps.js +55 -5
- package/dist/flow-triggers.js +55 -0
- package/dist/flows-cli.d.ts +19 -0
- package/dist/flows-cli.js +47 -2
- package/dist/flows-ui.js +11 -2
- package/dist/flows.js +5 -2
- package/dist/lead-tools.js +35 -6
- package/dist/lead-voice.js +16 -5
- package/dist/operate.d.ts +1 -1
- package/dist/operate.js +215 -6
- package/dist/project-delete.js +7 -3
- package/dist/pull-request-flow.js +35 -4
- package/dist/result-follow-ups.js +4 -0
- package/dist/scope.d.ts +5 -0
- package/dist/scope.js +7 -0
- package/dist/server/chat.js +4 -2
- package/dist/server/console.css +29 -0
- package/dist/server/flows.js +15 -0
- package/dist/server/render-pages.d.ts +13 -0
- package/dist/server/render-pages.js +45 -2
- package/dist/server/render-tasks.d.ts +8 -0
- package/dist/server/render-tasks.js +17 -6
- package/dist/server/route-table.js +11 -0
- package/dist/server/task-views.js +5 -0
- package/dist/server/tasks.d.ts +10 -0
- package/dist/server/tasks.js +54 -2
- package/dist/settings-proofs.js +1 -0
- package/dist/store.d.ts +71 -3
- package/dist/store.js +222 -20
- package/dist/surface.js +18 -2
- package/dist/task-archive.d.ts +10 -0
- package/dist/task-archive.js +16 -0
- package/dist/task-control.d.ts +1 -1
- package/dist/tidy.d.ts +130 -0
- package/dist/tidy.js +503 -0
- package/dist/work-index.d.ts +24 -0
- package/dist/work-index.js +52 -30
- package/dist/workspace-ui.d.ts +1 -1
- package/dist/workspace-ui.js +3 -2
- package/package.json +1 -1
package/dist/work-index.d.ts
CHANGED
|
@@ -37,6 +37,13 @@ export type WorkIndexItem = {
|
|
|
37
37
|
evidence: 'recorded';
|
|
38
38
|
/** The viewer's own lead took it on (lead-voice.ts): "<name> is on it.", by the name they gave it, read now. */
|
|
39
39
|
lead?: string;
|
|
40
|
+
/** Put away (v145, task-tidy.md): by whom (a person's name, or tidy), why and when. Only the Archived view lists it. */
|
|
41
|
+
archived?: {
|
|
42
|
+
by: string;
|
|
43
|
+
byKind: 'person' | 'tidy';
|
|
44
|
+
reason: string;
|
|
45
|
+
at: string;
|
|
46
|
+
};
|
|
40
47
|
};
|
|
41
48
|
/** `root`: the evidence root, so a result whose checks were Off can read the release check that covers it. */
|
|
42
49
|
export type WorkIndexOptions = {
|
|
@@ -129,3 +136,20 @@ export declare function workReadyForReview(store: Store, now: Date, access: Work
|
|
|
129
136
|
run: number | null;
|
|
130
137
|
}[];
|
|
131
138
|
};
|
|
139
|
+
/** One row per task family for tidy (docs/plans/task-tidy.md): the Tasks list's own projection, so tidy's "unfinished",
|
|
140
|
+
* "live" and "complete" are the words the list shows. `members` are every version's task_ref ids. */
|
|
141
|
+
export type WorkTidyRow = {
|
|
142
|
+
rootId: string;
|
|
143
|
+
currentId: string;
|
|
144
|
+
title: string;
|
|
145
|
+
repo: string | null;
|
|
146
|
+
state: TaskState;
|
|
147
|
+
code: string;
|
|
148
|
+
live: boolean;
|
|
149
|
+
archived: boolean;
|
|
150
|
+
broken: boolean;
|
|
151
|
+
updatedAt: string;
|
|
152
|
+
members: number[];
|
|
153
|
+
memberIds: string[];
|
|
154
|
+
};
|
|
155
|
+
export declare function workTidyRows(store: Store, now: Date, access: WorkSummaryAccess): WorkTidyRow[];
|
package/dist/work-index.js
CHANGED
|
@@ -22,10 +22,12 @@ import { ASKS, NEED_ASK, NEEDS, askChipOf, failedAttemptSentence, processNeedOf,
|
|
|
22
22
|
import { LEAD_CLAIM_SQL, LEAD_IDLE_MS } from './lead-voice.js';
|
|
23
23
|
export const WORK_INDEX_PAGE_LIMIT = 40;
|
|
24
24
|
export const WORK_INDEX_MAX_LIMIT = 100;
|
|
25
|
-
const EMPTY = { all: 0, 'needs-you': 0, running: 0, completed: 0 };
|
|
25
|
+
const EMPTY = { all: 0, 'needs-you': 0, running: 0, completed: 0, archived: 0 };
|
|
26
26
|
const NO_GROUPS = { decide: 0, review: 0, unblock: 0, building: 0, rest: 0 };
|
|
27
27
|
const FAMILY_PROBLEM = 'Task history is unavailable or incomplete. This task is shown separately.';
|
|
28
|
-
const VIEWS = ['all', 'needs-you', 'running', 'completed'];
|
|
28
|
+
const VIEWS = ['all', 'needs-you', 'running', 'completed', 'archived'];
|
|
29
|
+
/** The family's current version is put away (v145): it waits on nobody and only the Archived view lists it. */
|
|
30
|
+
const ARCHIVED = `EXISTS(SELECT 1 FROM task_archive ta WHERE ta.task_ref=c.ref_id)`;
|
|
29
31
|
const n = (row, key) => Number(row[key] ?? 0);
|
|
30
32
|
const s = (row, key) => row[key] == null ? null : String(row[key]);
|
|
31
33
|
/** The running agent's oldest open question (agent-board.ts), from its open newest attempt only. */
|
|
@@ -93,24 +95,25 @@ const PROJECTION = `WITH RECURSIVE admitted AS MATERIALIZED (
|
|
|
93
95
|
(SELECT id FROM run WHERE task_ref=a.ref_id AND outcome IS NULL ORDER BY id DESC LIMIT 1) unfinished,
|
|
94
96
|
CASE WHEN a.state='done' THEN (SELECT id FROM run WHERE task_ref=a.ref_id AND finished_at IS NOT NULL AND role IN ('builder','scout') ORDER BY id DESC LIMIT 1) END result_id,
|
|
95
97
|
(SELECT h.id FROM hold h WHERE h.task_ref=a.ref_id AND (h.until IS NULL OR h.until>$now) ORDER BY h.held_at,h.id LIMIT 1) hold_id,
|
|
96
|
-
q.decision_id,${AGENT_ASK} agent_ask,(cu.task_ref IS NOT NULL OR a.ref_id IN (SELECT value FROM json_each($workspaceCustody)))
|
|
98
|
+
q.decision_id,${AGENT_ASK} agent_ask,EXISTS(SELECT 1 FROM task_archive ta WHERE ta.task_ref=a.ref_id) member_archived,(cu.task_ref IS NOT NULL OR a.ref_id IN (SELECT value FROM json_each($workspaceCustody)))
|
|
97
99
|
AND a.ref_id NOT IN (SELECT value FROM json_each($settledCustody)) custody_unresolved
|
|
98
100
|
FROM admitted a LEFT JOIN lineage l ON l.ref_id=a.ref_id
|
|
99
101
|
LEFT JOIN questions q ON q.task_ref=a.ref_id LEFT JOIN custody cu ON cu.task_ref=a.ref_id
|
|
100
102
|
), family_heads AS MATERIALIZED (
|
|
101
103
|
SELECT root_ref,COUNT(*) version_count,MAX(updated_at) family_updated,
|
|
102
104
|
CAST(substr(MAX((CASE WHEN ref_id=root_ref THEN '0' ELSE '1' END)||created_at||printf('%020d',ref_id)),-20) AS INTEGER) current_ref,
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
MAX(live_lease IS NOT NULL)
|
|
105
|
+
-- A put-away version (v145) is history: it never counts as an earlier active version or brings its question along.
|
|
106
|
+
SUM(NOT member_archived AND (state IN ('queued','running') OR live_lease IS NOT NULL OR unfinished IS NOT NULL OR custody_unresolved)) active_count,
|
|
107
|
+
MIN(CASE WHEN NOT member_archived AND (state IN ('queued','running') OR live_lease IS NOT NULL OR unfinished IS NOT NULL OR custody_unresolved) THEN ref_id END) first_active,
|
|
108
|
+
MAX(CASE WHEN NOT member_archived AND (state IN ('queued','running') OR live_lease IS NOT NULL OR unfinished IS NOT NULL OR custody_unresolved) THEN ref_id END) last_active,
|
|
109
|
+
MAX(live_lease IS NOT NULL) family_running,MIN(CASE WHEN NOT member_archived THEN decision_id END) question_id
|
|
107
110
|
FROM members GROUP BY root_ref
|
|
108
111
|
), ordered AS MATERIALIZED (
|
|
109
112
|
SELECT m.*,CASE WHEN m.ref_id=f.current_ref THEN 1 ELSE 2 END version_rank
|
|
110
113
|
FROM members m JOIN family_heads f USING(root_ref)
|
|
111
114
|
), families AS MATERIALIZED (
|
|
112
115
|
SELECT f.root_ref,f.version_count,f.family_updated,f.family_running,
|
|
113
|
-
f.active_count-(c.state IN ('queued','running') OR c.live_lease IS NOT NULL OR c.unfinished IS NOT NULL OR c.custody_unresolved) earlier_active,
|
|
116
|
+
f.active_count-(NOT c.member_archived AND (c.state IN ('queued','running') OR c.live_lease IS NOT NULL OR c.unfinished IS NOT NULL OR c.custody_unresolved)) earlier_active,
|
|
114
117
|
earlier.id earlier_id,COALESCE(c.decision_id,f.question_id) question_id
|
|
115
118
|
FROM family_heads f JOIN members c ON c.ref_id=f.current_ref
|
|
116
119
|
LEFT JOIN admitted earlier ON earlier.ref_id=CASE WHEN f.first_active=f.current_ref THEN f.last_active ELSE f.first_active END
|
|
@@ -236,8 +239,9 @@ const PROJECTION = `WITH RECURSIVE admitted AS MATERIALIZED (
|
|
|
236
239
|
SELECT c.*,CASE WHEN code IN ('cancelled','complete') THEN 0 ELSE ${LEAD_CLAIM_SQL} END lead_claim FROM classified c
|
|
237
240
|
), ranked AS MATERIALIZED (
|
|
238
241
|
-- A task the person's lead is on (lead-voice.ts) waits on nobody: it leaves Needs you until the claim ends or lapses.
|
|
239
|
-
SELECT c.*,code NOT IN ('cancelled','complete','running','updating','retry-scheduled','waiting-dependency','worker-at-capacity','planning-ready','scouting-ready','queued') AND NOT ${CUSTODY_WAITS} AND lead_claim<>1 needs,
|
|
240
|
-
code NOT IN ('cancelled','complete','running','updating','retry-scheduled','waiting-dependency','worker-at-capacity','planning-ready','scouting-ready','queued') AND NOT ${CUSTODY_WAITS} person_need,
|
|
242
|
+
SELECT c.*,code NOT IN ('cancelled','complete','running','updating','retry-scheduled','waiting-dependency','worker-at-capacity','planning-ready','scouting-ready','queued') AND NOT ${CUSTODY_WAITS} AND lead_claim<>1 AND NOT ${ARCHIVED} needs,
|
|
243
|
+
code NOT IN ('cancelled','complete','running','updating','retry-scheduled','waiting-dependency','worker-at-capacity','planning-ready','scouting-ready','queued') AND NOT ${CUSTODY_WAITS} AND NOT ${ARCHIVED} person_need,
|
|
244
|
+
${ARCHIVED} archived,
|
|
241
245
|
CASE WHEN code='complete' THEN 3 WHEN code='cancelled' THEN 4 WHEN code='running' THEN 1
|
|
242
246
|
WHEN ${CUSTODY_WAITS} OR code IN ('updating','retry-scheduled','waiting-dependency','worker-at-capacity','planning-ready','scouting-ready','queued') THEN 2 ELSE 0 END rank,
|
|
243
247
|
${ASK_RANK} ask_rank,
|
|
@@ -329,11 +333,13 @@ function parameters(now, access, options, custody) {
|
|
|
329
333
|
$leadOf: access.principal === 'operator' && access.viewer != null && access.viewer !== '' ? `lead for ${access.viewer}` : null };
|
|
330
334
|
}
|
|
331
335
|
function counts(row) {
|
|
332
|
-
return { all: n(row, 'all_count'), 'needs-you': n(row, 'needs_count'), running: n(row, 'running_count'), completed: n(row, 'completed_count') };
|
|
336
|
+
return { all: n(row, 'all_count'), 'needs-you': n(row, 'needs_count'), running: n(row, 'running_count'), completed: n(row, 'completed_count'), archived: n(row, 'archived_count') };
|
|
333
337
|
}
|
|
334
|
-
|
|
335
|
-
const
|
|
336
|
-
+ `COALESCE(SUM(
|
|
338
|
+
// Put-away families (v145) count only as archived.
|
|
339
|
+
const TOTALS = `COALESCE(SUM(archived=0),0) all_count,COALESCE(SUM(needs),0) needs_count,COALESCE(SUM(family_running AND archived=0),0) running_count,`
|
|
340
|
+
+ `COALESCE(SUM(code='complete' AND archived=0),0) completed_count,COALESCE(SUM(archived),0) archived_count`;
|
|
341
|
+
const GROUP_TOTALS = `COALESCE(SUM(rank=0 AND ask_rank=0 AND archived=0),0) decide_count,COALESCE(SUM(rank=0 AND ask_rank=1 AND archived=0),0) review_count,COALESCE(SUM(rank=0 AND ask_rank=2 AND archived=0),0) unblock_count,`
|
|
342
|
+
+ `COALESCE(SUM(rank=1 AND archived=0),0) building_count,COALESCE(SUM(rank>1 AND archived=0),0) rest_count`;
|
|
337
343
|
function groupCounts(row) {
|
|
338
344
|
return { decide: n(row, 'decide_count'), review: n(row, 'review_count'), unblock: n(row, 'unblock_count'), building: n(row, 'building_count'), rest: n(row, 'rest_count') };
|
|
339
345
|
}
|
|
@@ -383,18 +389,20 @@ function readWorkIndexPage(store, now, access, options, taskId = null) {
|
|
|
383
389
|
const view = VIEWS.includes(options.view ?? 'all') ? options.view ?? 'all' : 'all';
|
|
384
390
|
const limit = Number.isFinite(options.limit) ? Math.max(1, Math.min(WORK_INDEX_MAX_LIMIT, Math.floor(options.limit))) : WORK_INDEX_PAGE_LIMIT;
|
|
385
391
|
const scope = cursorScope(access, options, view), cursor = readCursor(options.cursor, scope);
|
|
386
|
-
const filter = view === 'needs-you' ? 'needs=1' : view === 'running' ? 'family_running=1' : view === 'completed' ? "code='complete'" : '
|
|
392
|
+
const filter = view === 'archived' ? 'archived=1' : view === 'needs-you' ? 'needs=1' : view === 'running' ? 'family_running=1 AND archived=0' : view === 'completed' ? "code='complete' AND archived=0" : 'archived=0';
|
|
387
393
|
const rows = prepared(store, `${projection}, selected_page AS MATERIALIZED (
|
|
388
|
-
SELECT * FROM ranked WHERE ${filter} AND ($taskId IS NULL OR root_ref IN (SELECT root_ref FROM members WHERE id=$taskId)) AND ($roots IS NULL OR root_id IN (SELECT value FROM json_each($roots))) AND ($cursorRoot=0 OR
|
|
394
|
+
SELECT * FROM ranked WHERE ($taskId IS NOT NULL OR ${filter}) AND ($taskId IS NULL OR root_ref IN (SELECT root_ref FROM members WHERE id=$taskId)) AND ($roots IS NULL OR root_id IN (SELECT value FROM json_each($roots))) AND ($cursorRoot=0 OR
|
|
389
395
|
${ORDER}>$cursorRank OR (${ORDER}=$cursorRank AND (sort_at<$cursorAt OR (sort_at=$cursorAt AND root_ref<$cursorRoot))))
|
|
390
396
|
ORDER BY ${ORDER},sort_at DESC,root_ref DESC LIMIT $limit
|
|
391
397
|
), page AS (SELECT p.*,COALESCE(p.result_id,(SELECT id FROM run WHERE task_ref=p.ref_id AND finished_at IS NOT NULL AND role IN ('builder','scout') ORDER BY id DESC LIMIT 1)) page_result_id FROM selected_page p), totals AS (SELECT ${TOTALS},${GROUP_TOTALS} FROM ranked), project_totals AS (
|
|
392
|
-
SELECT repo,${TOTALS},SUM(state='queued' AND family_running=0) queued,
|
|
393
|
-
SUM(state='done' AND family_running=0 AND updated_at>=$recent) done_recently FROM ranked GROUP BY repo
|
|
398
|
+
SELECT repo,${TOTALS},SUM(state='queued' AND family_running=0 AND archived=0) queued,
|
|
399
|
+
SUM(state='done' AND family_running=0 AND archived=0 AND updated_at>=$recent) done_recently FROM ranked GROUP BY repo
|
|
394
400
|
)
|
|
395
401
|
SELECT 0 record_kind,totals.*,(SELECT json_group_array(json_object('repo',repo,'all_count',all_count,'needs_count',needs_count,
|
|
396
|
-
'running_count',running_count,'completed_count',completed_count,'queued',queued,'done_recently',done_recently)) FROM project_totals) row_json FROM totals
|
|
397
|
-
UNION ALL SELECT 1,0,0,0,0,0,0,0,0,0,json_object('
|
|
402
|
+
'running_count',running_count,'completed_count',completed_count,'archived_count',archived_count,'queued',queued,'done_recently',done_recently)) FROM project_totals) row_json FROM totals
|
|
403
|
+
UNION ALL SELECT 1,0,0,0,0,0,0,0,0,0,0,json_object('archived',archived,'archived_by',(SELECT by FROM task_archive WHERE task_ref=page.ref_id),
|
|
404
|
+
'archived_kind',(SELECT by_kind FROM task_archive WHERE task_ref=page.ref_id),'archived_reason',(SELECT reason FROM task_archive WHERE task_ref=page.ref_id),
|
|
405
|
+
'archived_at',(SELECT at FROM task_archive WHERE task_ref=page.ref_id),'root_ref',root_ref,'root_id',root_id,'id',id,'root_title',root_title,'repo',repo,
|
|
398
406
|
'state',state,'created_at',created_at,'family_updated',family_updated,'version_count',version_count,'earlier_active',earlier_active,
|
|
399
407
|
'earlier_id',earlier_id,'broken',broken,'live_run',live_run,'result_id',page_result_id,'result_outcome',(SELECT outcome FROM run WHERE id=page_result_id),'attempt_reason',(SELECT substr(reason,1,1000) FROM run WHERE task_ref IN (SELECT ref_id FROM members WHERE root_ref=page.root_ref) AND (finished_at IS NOT NULL OR outcome IS NOT NULL) AND role NOT IN ('planner','reviewer') ORDER BY id DESC LIMIT 1),
|
|
400
408
|
'publication_url',(SELECT pr_url FROM publication WHERE run=page_result_id),
|
|
@@ -434,8 +442,8 @@ function readWorkIndexPage(store, now, access, options, taskId = null) {
|
|
|
434
442
|
}
|
|
435
443
|
export function workCountsByProject(store, now, access) {
|
|
436
444
|
const projection = registerValidators(store);
|
|
437
|
-
return store.handle.prepare(`${projection} SELECT repo,${TOTALS},SUM(state='queued' AND family_running=0) queued,
|
|
438
|
-
SUM(state='done' AND family_running=0 AND updated_at>=$recent) done_recently FROM ranked GROUP BY repo ORDER BY repo`)
|
|
445
|
+
return store.handle.prepare(`${projection} SELECT repo,${TOTALS},SUM(state='queued' AND family_running=0 AND archived=0) queued,
|
|
446
|
+
SUM(state='done' AND family_running=0 AND archived=0 AND updated_at>=$recent) done_recently FROM ranked GROUP BY repo ORDER BY repo`)
|
|
439
447
|
.all({ ...parameters(now, access, {}, custodyReadings(store)), $recent: new Date(now.getTime() - 86_400_000).toISOString() })
|
|
440
448
|
.map(row => ({ repo: s(row, 'repo'), totals: counts(row), queued: n(row, 'queued'), doneRecently: n(row, 'done_recently') }));
|
|
441
449
|
}
|
|
@@ -447,7 +455,7 @@ export function workStateRows(store, now, access) {
|
|
|
447
455
|
COALESCE((SELECT created_at FROM decision WHERE id=question_id),''),COALESCE((SELECT asked_at FROM agent_question WHERE id=agent_ask),''),
|
|
448
456
|
COALESCE((SELECT held_at FROM hold WHERE id=hold_id),''),COALESCE((SELECT requested_at FROM run_stop WHERE run=stop_run),'')),''),sort_at) ask_at,
|
|
449
457
|
COALESCE(live_run,(SELECT run FROM decision WHERE id=question_id),(SELECT run FROM agent_question WHERE id=agent_ask)) ask_run,
|
|
450
|
-
(SELECT json_group_array(m.ref_id) FROM members m WHERE m.root_ref=ranked.root_ref) members FROM ranked`)
|
|
458
|
+
(SELECT json_group_array(m.ref_id) FROM members m WHERE m.root_ref=ranked.root_ref) members FROM ranked WHERE archived=0`)
|
|
451
459
|
.all(parameters(now, access, {}, custodyReadings(store)))
|
|
452
460
|
.map(row => ({ repo: s(row, 'repo'), rootId: String(row['root_id']), code: String(row['code']), needs: n(row, 'needs') === 1, personNeed: n(row, 'person_need') === 1,
|
|
453
461
|
leadClaim: n(row, 'lead_claim') === 1, liveRun: row['live_run'] == null ? null : n(row, 'live_run'), unfinished: row['unfinished'] == null ? null : n(row, 'unfinished'),
|
|
@@ -458,8 +466,8 @@ export function workStateRows(store, now, access) {
|
|
|
458
466
|
* attempts are aggregated in SQLite, never loaded as an unbounded history. */
|
|
459
467
|
export function workOutcomeRows(store, now, access, project, since, limit) {
|
|
460
468
|
return store.handle.prepare(`${registerValidators(store)}, selected AS MATERIALIZED (
|
|
461
|
-
SELECT * FROM ranked WHERE code='ready-to-check' OR code='history-problem'
|
|
462
|
-
OR (code='complete' AND checked_at >= $since AND checked_at <= $now)
|
|
469
|
+
SELECT * FROM ranked WHERE archived=0 AND (code='ready-to-check' OR code='history-problem'
|
|
470
|
+
OR (code='complete' AND checked_at >= $since AND checked_at <= $now))
|
|
463
471
|
ORDER BY sort_at DESC,root_ref DESC LIMIT $outcomeLimit
|
|
464
472
|
), amounts AS (
|
|
465
473
|
-- reported-usage.ts runAmountOf, row for row: only evidenced billing on a run whose cost was reported is known;
|
|
@@ -701,12 +709,14 @@ function itemOf(row, principal, probe, leadName, readiness, readable = false) {
|
|
|
701
709
|
if (asked !== null)
|
|
702
710
|
detail = `The agent asks: ${asked}`;
|
|
703
711
|
}
|
|
704
|
-
const
|
|
705
|
-
|
|
712
|
+
const archived = n(row, 'archived') === 1 ? { by: String(row['archived_by'] ?? ''), byKind: row['archived_kind'] === 'tidy' ? 'tidy' : 'person',
|
|
713
|
+
reason: String(row['archived_reason'] ?? ''), at: String(row['archived_at'] ?? '') } : null;
|
|
714
|
+
const views = archived !== null ? ['archived'] : ['all'];
|
|
715
|
+
if (archived === null && need)
|
|
706
716
|
views.push('needs-you');
|
|
707
|
-
if (running)
|
|
717
|
+
if (archived === null && running)
|
|
708
718
|
views.push('running');
|
|
709
|
-
if (code === 'complete')
|
|
719
|
+
if (archived === null && code === 'complete')
|
|
710
720
|
views.push('completed');
|
|
711
721
|
return { rootId: String(row['root_id']), activeTaskId: id, title: String(row['root_title']), repo: s(row, 'repo'),
|
|
712
722
|
state: String(row['state']), assignmentState, createdAt: String(row['created_at']), updatedAt: String(row['sort_at']),
|
|
@@ -718,5 +728,17 @@ function itemOf(row, principal, probe, leadName, readiness, readable = false) {
|
|
|
718
728
|
ask: need ? ASKS[n(row, 'ask_rank')] ?? 'unblock' : null,
|
|
719
729
|
chip: need ? askChipOf({ headline: shared.headline, need: shared.need?.key ?? null, planChanged, mismatch: verdict === 'refuted' && n(row, 'proof_failed_check') !== 1, ask: ASKS[n(row, 'ask_rank')] ?? 'unblock' }) : null,
|
|
720
730
|
primaryAction, completion: code === 'complete' ? { actor: String(row['checked_actor']), at: String(row['checked_at']), digest: String(row['checked_digest']), ...(landed === null ? {} : { landed }) } : null,
|
|
721
|
-
evidence: 'recorded', ...(lead === 'on-it' ? { lead: leadOnIt(leadName) } : {}) };
|
|
731
|
+
evidence: 'recorded', ...(lead === 'on-it' ? { lead: leadOnIt(leadName) } : {}), ...(archived === null ? {} : { archived }) };
|
|
732
|
+
}
|
|
733
|
+
export function workTidyRows(store, now, access) {
|
|
734
|
+
const projection = registerValidators(store);
|
|
735
|
+
return store.handle.prepare(`${projection} SELECT root_id,id,root_title,repo,state,code,archived,broken,family_updated,
|
|
736
|
+
(family_running OR live_lease IS NOT NULL OR unfinished IS NOT NULL OR custody_unresolved OR stop_run IS NOT NULL AND stop_settled IS NULL OR state='running') live,
|
|
737
|
+
(SELECT json_group_array(m.ref_id) FROM members m WHERE m.root_ref=ranked.root_ref) members,
|
|
738
|
+
(SELECT json_group_array(m.id) FROM members m WHERE m.root_ref=ranked.root_ref) member_ids FROM ranked`)
|
|
739
|
+
.all(parameters(now, access, {}, custodyReadings(store)))
|
|
740
|
+
.map(row => ({ rootId: String(row['root_id']), currentId: String(row['id']), title: String(row['root_title']), repo: s(row, 'repo'),
|
|
741
|
+
state: String(row['state']), code: String(row['code']), live: n(row, 'live') === 1, archived: n(row, 'archived') === 1, broken: n(row, 'broken') === 1,
|
|
742
|
+
updatedAt: String(row['family_updated'] ?? ''), members: JSON.parse(String(row['members'] ?? '[]')).map(Number),
|
|
743
|
+
memberIds: JSON.parse(String(row['member_ids'] ?? '[]')).map(String) }));
|
|
722
744
|
}
|
package/dist/workspace-ui.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ import { type ChecksFact } from "./task-status.js";
|
|
|
26
26
|
import { type Html } from "./html.js";
|
|
27
27
|
/** The Work destination's views — shortcuts over the same rows, never a
|
|
28
28
|
* persisted state. All is the default. */
|
|
29
|
-
export type WorkView = "all" | "needs-you" | "running" | "completed";
|
|
29
|
+
export type WorkView = "all" | "needs-you" | "running" | "completed" | "archived";
|
|
30
30
|
export declare const WORK_VIEWS: readonly {
|
|
31
31
|
key: WorkView;
|
|
32
32
|
label: string;
|
package/dist/workspace-ui.js
CHANGED
|
@@ -27,9 +27,10 @@ export const WORK_VIEWS = [
|
|
|
27
27
|
{ key: "needs-you", label: "Needs you", hint: "Tasks waiting on an answer, approval, or your inspection.", empty: "Nothing needs you right now. Queued and running work continues on its own." },
|
|
28
28
|
{ key: "running", label: "Building", hint: "Attempts a builder owns right now.", empty: "Nothing is building right now. Approved tasks start when a builder with capacity is connected." },
|
|
29
29
|
{ key: "completed", label: "Complete", hint: "Tasks the lead or user has marked complete. Recorded check results remain available.", empty: "No tasks have been marked complete in this view." },
|
|
30
|
+
{ key: "archived", label: "Archived", hint: "Tasks put away by you or by tidy. Their history and results are kept.", empty: "Nothing is put away." },
|
|
30
31
|
];
|
|
31
32
|
export function parseWorkView(raw) {
|
|
32
|
-
return raw === "needs-you" || raw === "running" || raw === "completed" ? raw : "all";
|
|
33
|
+
return raw === "needs-you" || raw === "running" || raw === "completed" || raw === "archived" ? raw : "all";
|
|
33
34
|
}
|
|
34
35
|
/** The review facts from the store's bounded retry projection — the same
|
|
35
36
|
* reading `diagnoseTaskDispatch` makes, so every surface starts from one
|
|
@@ -525,7 +526,7 @@ function workStatusWordsOf(facts, resultDisplay) {
|
|
|
525
526
|
}
|
|
526
527
|
/** The counts each view tab wears — from the same rows the page lists. */
|
|
527
528
|
export function workCounts(rows) {
|
|
528
|
-
const counts = { all: 0, "needs-you": 0, running: 0, completed: 0 };
|
|
529
|
+
const counts = { all: 0, "needs-you": 0, running: 0, completed: 0, archived: 0 };
|
|
529
530
|
for (const row of rows)
|
|
530
531
|
for (const view of row.views)
|
|
531
532
|
counts[view] += 1;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolroll",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.86",
|
|
4
4
|
"description": "A control plane for unattended coding agents — queue tasks, walk away, come back to pull requests. Agents build in leased worktrees, never touch your default branch, and interrupt you only for decisions that need a human.",
|
|
5
5
|
"directories": {
|
|
6
6
|
"doc": "docs"
|