@mu-crew/mu 4.1.1 → 4.2.1
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/dist/{chunk-L7I3BLXP.js → chunk-4ZWBLTZK.js} +1512 -411
- package/dist/chunk-4ZWBLTZK.js.map +1 -0
- package/dist/{chunk-DEYBQDTO.js → chunk-FVRIKUBR.js} +2 -2
- package/dist/{chunk-B74N2EAS.js → chunk-RJQNDFBU.js} +8 -4
- package/dist/chunk-RJQNDFBU.js.map +1 -0
- package/dist/{chunk-LBBZAG5C.js → chunk-U2QLTREB.js} +26 -23
- package/dist/chunk-U2QLTREB.js.map +1 -0
- package/dist/{cli-H2PWJAJN.js → cli-H3VVCP7M.js} +146 -31
- package/dist/cli-H3VVCP7M.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/{errors-G5IVXSMY.js → errors-MDQZHB42.js} +8 -2
- package/dist/extension/mu-pi.js +20 -3
- package/dist/extension/mu-pi.js.map +1 -1
- package/dist/index.d.ts +2574 -2288
- package/dist/index.js +58 -4
- package/dist/index.js.map +1 -1
- package/dist/{tui-EN2CDP6G.js → tui-5ZARE7RS.js} +14 -15
- package/dist/tui-5ZARE7RS.js.map +1 -0
- package/docs/ARCHITECTURE.md +15 -8
- package/docs/VOCABULARY.md +14 -6
- package/docs/guide/remote.md +113 -4
- package/docs/guide/sql.md +1 -1
- package/docs/reference/env.md +1 -0
- package/package.json +1 -1
- package/skills/mu/recipes/remote-workers.md +7 -6
- package/dist/chunk-B74N2EAS.js.map +0 -1
- package/dist/chunk-L7I3BLXP.js.map +0 -1
- package/dist/chunk-LBBZAG5C.js.map +0 -1
- package/dist/cli-H2PWJAJN.js.map +0 -1
- package/dist/tui-EN2CDP6G.js.map +0 -1
- /package/dist/{chunk-DEYBQDTO.js.map → chunk-FVRIKUBR.js.map} +0 -0
- /package/dist/{errors-G5IVXSMY.js.map → errors-MDQZHB42.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createRequire as __muCreateRequire } from "node:module"; const require
|
|
|
2
2
|
import {
|
|
3
3
|
STALLED_TOOL_MS,
|
|
4
4
|
loadDashboard
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-U2QLTREB.js";
|
|
6
6
|
import {
|
|
7
7
|
AGENT_STATE_GLYPH,
|
|
8
8
|
DEFAULT_CTL_STUCK_AFTER_MS,
|
|
@@ -64,7 +64,7 @@ import {
|
|
|
64
64
|
transitionActionReceipt,
|
|
65
65
|
waitForEvents,
|
|
66
66
|
waitWithActions
|
|
67
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-RJQNDFBU.js";
|
|
68
68
|
import {
|
|
69
69
|
COURSE_CHECK_AGE_MS,
|
|
70
70
|
COURSE_CHECK_CLOSED,
|
|
@@ -137,7 +137,7 @@ import {
|
|
|
137
137
|
syncEnabled,
|
|
138
138
|
syncPass,
|
|
139
139
|
verifyAgainstManifest
|
|
140
|
-
} from "./chunk-
|
|
140
|
+
} from "./chunk-FVRIKUBR.js";
|
|
141
141
|
import {
|
|
142
142
|
AgentAbortNeedsCtlError,
|
|
143
143
|
AgentAbortTimeoutError,
|
|
@@ -164,6 +164,11 @@ import {
|
|
|
164
164
|
CAPTURE_TRIGGER_DDL,
|
|
165
165
|
CAPTURE_VERSION,
|
|
166
166
|
CURRENT_SCHEMA_VERSION,
|
|
167
|
+
CarrierJobKeptError,
|
|
168
|
+
CarrierJobUnresolvedError,
|
|
169
|
+
CarrierJobUnstoppedError,
|
|
170
|
+
CarrierStopFailedError,
|
|
171
|
+
CarrierStopRefusedError,
|
|
167
172
|
ClaimerNotRegisteredError,
|
|
168
173
|
CloseNeedsEvidenceError,
|
|
169
174
|
CrossWorkstreamEdgeError,
|
|
@@ -178,11 +183,13 @@ import {
|
|
|
178
183
|
GroupNotFoundError,
|
|
179
184
|
HOST_ENV_KEYS,
|
|
180
185
|
HOST_PLACEHOLDERS,
|
|
186
|
+
HOST_TRANSPORTS,
|
|
181
187
|
HlcOverflowError,
|
|
182
188
|
HlcParseError,
|
|
183
189
|
HostChannelBusyError,
|
|
184
190
|
HostCheckFailedError,
|
|
185
191
|
HostExistsError,
|
|
192
|
+
HostHandbackError,
|
|
186
193
|
HostInUseError,
|
|
187
194
|
HostNotFoundError,
|
|
188
195
|
HostProfileError,
|
|
@@ -190,6 +197,10 @@ import {
|
|
|
190
197
|
HostTemplateError,
|
|
191
198
|
HumanTaskError,
|
|
192
199
|
InvalidSubstateError,
|
|
200
|
+
JOB_HANDLE_RE,
|
|
201
|
+
LeaseJobInvalidError,
|
|
202
|
+
LeaseJobTimeoutError,
|
|
203
|
+
LeaseJobUnreadableError,
|
|
193
204
|
LogKindReservedError,
|
|
194
205
|
MACHINE_LOCAL_ENTITIES,
|
|
195
206
|
MACHINE_LOCAL_TABLES,
|
|
@@ -252,6 +263,7 @@ import {
|
|
|
252
263
|
WorktreeHeldError,
|
|
253
264
|
WorktreePathNotEmptyError,
|
|
254
265
|
WorktreeVcsRequiredError,
|
|
266
|
+
abandonCarrierJob,
|
|
255
267
|
abortAgent,
|
|
256
268
|
acceptTask,
|
|
257
269
|
activeMux,
|
|
@@ -267,6 +279,7 @@ import {
|
|
|
267
279
|
assertRevision,
|
|
268
280
|
assertValidPaneId,
|
|
269
281
|
beginWait,
|
|
282
|
+
bindCarrierJobAgent,
|
|
270
283
|
bindHostChannel,
|
|
271
284
|
capture,
|
|
272
285
|
captureTriggersCurrent,
|
|
@@ -294,12 +307,16 @@ import {
|
|
|
294
307
|
envVarNameForCli,
|
|
295
308
|
expandHostTemplate,
|
|
296
309
|
expectsCtl,
|
|
310
|
+
fillCarrierJob,
|
|
297
311
|
finishDelegate,
|
|
298
312
|
forgetWorktree,
|
|
299
313
|
formatHlc,
|
|
300
314
|
formatPair,
|
|
301
315
|
getAgent,
|
|
302
316
|
getAgentByPane,
|
|
317
|
+
getCarrierJob,
|
|
318
|
+
getCarrierJobByAgent,
|
|
319
|
+
getCarrierJobByName,
|
|
303
320
|
getDelegateCall,
|
|
304
321
|
getHost,
|
|
305
322
|
getPrerequisites,
|
|
@@ -310,6 +327,7 @@ import {
|
|
|
310
327
|
getWorktreeAt,
|
|
311
328
|
getWorktreeFor,
|
|
312
329
|
hostEnvWords,
|
|
330
|
+
hostMuleStarter,
|
|
313
331
|
hostStarter,
|
|
314
332
|
idFromTitle,
|
|
315
333
|
idFromTitleVerbose,
|
|
@@ -328,6 +346,8 @@ import {
|
|
|
328
346
|
latestSeq,
|
|
329
347
|
listAgents,
|
|
330
348
|
listBlocked,
|
|
349
|
+
listCarrierJobs,
|
|
350
|
+
listCarrierJobsByName,
|
|
331
351
|
listDelegates,
|
|
332
352
|
listDelegatesOf,
|
|
333
353
|
listGoals,
|
|
@@ -347,11 +367,13 @@ import {
|
|
|
347
367
|
listWorktrees,
|
|
348
368
|
locksDir,
|
|
349
369
|
mapLegacyStatus,
|
|
370
|
+
markCarrierLaunch,
|
|
350
371
|
markDelegate,
|
|
351
372
|
murmurAvailable,
|
|
352
373
|
muxByName,
|
|
353
374
|
mux_exports,
|
|
354
375
|
nextHlc,
|
|
376
|
+
noteCarrierJob,
|
|
355
377
|
observationFromReading,
|
|
356
378
|
observeAgentStates,
|
|
357
379
|
openDb,
|
|
@@ -360,6 +382,7 @@ import {
|
|
|
360
382
|
parkTask,
|
|
361
383
|
parseHlc,
|
|
362
384
|
parseVerdict,
|
|
385
|
+
placeholderUses,
|
|
363
386
|
previewClose,
|
|
364
387
|
readAgent,
|
|
365
388
|
readAgentStates,
|
|
@@ -370,11 +393,13 @@ import {
|
|
|
370
393
|
receiveHlc,
|
|
371
394
|
reclaimWorktreePath,
|
|
372
395
|
reconcile,
|
|
396
|
+
recordCarrierPane,
|
|
373
397
|
recordCursors,
|
|
374
398
|
recoveriesFor,
|
|
375
399
|
registerDelegateCall,
|
|
376
400
|
registerOwnedWait,
|
|
377
401
|
registerWorktree,
|
|
402
|
+
releaseCarrierJob,
|
|
378
403
|
releaseHostChannel,
|
|
379
404
|
releaseHostChannelsForAgent,
|
|
380
405
|
releaseTask,
|
|
@@ -383,6 +408,7 @@ import {
|
|
|
383
408
|
removeHost,
|
|
384
409
|
removeWorktree,
|
|
385
410
|
reparentTask,
|
|
411
|
+
reserveCarrierJob,
|
|
386
412
|
reserveHostChannel,
|
|
387
413
|
resetCommandResolverForTests,
|
|
388
414
|
resetMux,
|
|
@@ -393,6 +419,7 @@ import {
|
|
|
393
419
|
resolveCliCommandWithSource,
|
|
394
420
|
resolvePair,
|
|
395
421
|
runHostTemplate,
|
|
422
|
+
runStop,
|
|
396
423
|
selectRemoteRecovery,
|
|
397
424
|
selectTaskNotes,
|
|
398
425
|
sendToAgent,
|
|
@@ -430,7 +457,7 @@ import {
|
|
|
430
457
|
worktreePath,
|
|
431
458
|
worktreeState,
|
|
432
459
|
worktreesRoot
|
|
433
|
-
} from "./chunk-
|
|
460
|
+
} from "./chunk-4ZWBLTZK.js";
|
|
434
461
|
import {
|
|
435
462
|
defaultStateDir
|
|
436
463
|
} from "./chunk-PZ5GOCWH.js";
|
|
@@ -581,6 +608,11 @@ export {
|
|
|
581
608
|
COURSE_CHECK_AGE_MS,
|
|
582
609
|
COURSE_CHECK_CLOSED,
|
|
583
610
|
CURRENT_SCHEMA_VERSION,
|
|
611
|
+
CarrierJobKeptError,
|
|
612
|
+
CarrierJobUnresolvedError,
|
|
613
|
+
CarrierJobUnstoppedError,
|
|
614
|
+
CarrierStopFailedError,
|
|
615
|
+
CarrierStopRefusedError,
|
|
584
616
|
ClaimerNotRegisteredError,
|
|
585
617
|
CloseNeedsEvidenceError,
|
|
586
618
|
CrossWorkstreamEdgeError,
|
|
@@ -603,12 +635,14 @@ export {
|
|
|
603
635
|
GroupNotFoundError,
|
|
604
636
|
HOST_ENV_KEYS,
|
|
605
637
|
HOST_PLACEHOLDERS,
|
|
638
|
+
HOST_TRANSPORTS,
|
|
606
639
|
HazardFailError,
|
|
607
640
|
HlcOverflowError,
|
|
608
641
|
HlcParseError,
|
|
609
642
|
HostChannelBusyError,
|
|
610
643
|
HostCheckFailedError,
|
|
611
644
|
HostExistsError,
|
|
645
|
+
HostHandbackError,
|
|
612
646
|
HostInUseError,
|
|
613
647
|
HostNotFoundError,
|
|
614
648
|
HostProfileError,
|
|
@@ -617,8 +651,12 @@ export {
|
|
|
617
651
|
HumanNeededInvalidError,
|
|
618
652
|
HumanTaskError,
|
|
619
653
|
InvalidSubstateError,
|
|
654
|
+
JOB_HANDLE_RE,
|
|
620
655
|
KNOWN_INTENTS,
|
|
621
656
|
KNOWN_VERBS,
|
|
657
|
+
LeaseJobInvalidError,
|
|
658
|
+
LeaseJobTimeoutError,
|
|
659
|
+
LeaseJobUnreadableError,
|
|
622
660
|
LogKindReservedError,
|
|
623
661
|
MACHINE_LOCAL_ENTITIES,
|
|
624
662
|
MACHINE_LOCAL_TABLES,
|
|
@@ -712,6 +750,7 @@ export {
|
|
|
712
750
|
WorktreeHeldError,
|
|
713
751
|
WorktreePathNotEmptyError,
|
|
714
752
|
WorktreeVcsRequiredError,
|
|
753
|
+
abandonCarrierJob,
|
|
715
754
|
abortAgent,
|
|
716
755
|
acceptTask,
|
|
717
756
|
activeMux,
|
|
@@ -739,6 +778,7 @@ export {
|
|
|
739
778
|
authorizeTasks,
|
|
740
779
|
autoPermitted,
|
|
741
780
|
beginWait,
|
|
781
|
+
bindCarrierJobAgent,
|
|
742
782
|
bindHostChannel,
|
|
743
783
|
buildTaskBrief,
|
|
744
784
|
callerWorkstreams,
|
|
@@ -788,6 +828,7 @@ export {
|
|
|
788
828
|
executeNext,
|
|
789
829
|
expandHostTemplate,
|
|
790
830
|
expectsCtl,
|
|
831
|
+
fillCarrierJob,
|
|
791
832
|
findCaseCollisions,
|
|
792
833
|
finishDelegate,
|
|
793
834
|
flushSegment,
|
|
@@ -799,6 +840,9 @@ export {
|
|
|
799
840
|
getAgent,
|
|
800
841
|
getAgentByPane,
|
|
801
842
|
getAutoConfig,
|
|
843
|
+
getCarrierJob,
|
|
844
|
+
getCarrierJobByAgent,
|
|
845
|
+
getCarrierJobByName,
|
|
802
846
|
getDelegateCall,
|
|
803
847
|
getHost,
|
|
804
848
|
getParallelTracks,
|
|
@@ -811,6 +855,7 @@ export {
|
|
|
811
855
|
getWorktreeAt,
|
|
812
856
|
getWorktreeFor,
|
|
813
857
|
hostEnvWords,
|
|
858
|
+
hostMuleStarter,
|
|
814
859
|
hostStarter,
|
|
815
860
|
idFromTitle,
|
|
816
861
|
idFromTitleVerbose,
|
|
@@ -832,6 +877,8 @@ export {
|
|
|
832
877
|
latestSeq,
|
|
833
878
|
listAgents,
|
|
834
879
|
listBlocked,
|
|
880
|
+
listCarrierJobs,
|
|
881
|
+
listCarrierJobsByName,
|
|
835
882
|
listDelegates,
|
|
836
883
|
listDelegatesOf,
|
|
837
884
|
listGoals,
|
|
@@ -855,12 +902,14 @@ export {
|
|
|
855
902
|
localMachineId,
|
|
856
903
|
locksDir,
|
|
857
904
|
mapLegacyStatus,
|
|
905
|
+
markCarrierLaunch,
|
|
858
906
|
markDelegate,
|
|
859
907
|
migratePi,
|
|
860
908
|
murmurAvailable,
|
|
861
909
|
mux_exports as mux,
|
|
862
910
|
muxByName,
|
|
863
911
|
nextHlc,
|
|
912
|
+
noteCarrierJob,
|
|
864
913
|
observationFromReading,
|
|
865
914
|
observeAgentStates,
|
|
866
915
|
opSubject,
|
|
@@ -875,6 +924,7 @@ export {
|
|
|
875
924
|
parseVerdict,
|
|
876
925
|
peerStatuses,
|
|
877
926
|
pendingAttempts,
|
|
927
|
+
placeholderUses,
|
|
878
928
|
planAttempt,
|
|
879
929
|
previewClose,
|
|
880
930
|
probeFilesystem,
|
|
@@ -889,12 +939,14 @@ export {
|
|
|
889
939
|
receiveHlc,
|
|
890
940
|
reclaimWorktreePath,
|
|
891
941
|
reconcile,
|
|
942
|
+
recordCarrierPane,
|
|
892
943
|
recordCursors,
|
|
893
944
|
recordHumanNeeded,
|
|
894
945
|
recoveriesFor,
|
|
895
946
|
registerDelegateCall,
|
|
896
947
|
registerOwnedWait,
|
|
897
948
|
registerWorktree,
|
|
949
|
+
releaseCarrierJob,
|
|
898
950
|
releaseHostChannel,
|
|
899
951
|
releaseHostChannelsForAgent,
|
|
900
952
|
releaseStall,
|
|
@@ -913,6 +965,7 @@ export {
|
|
|
913
965
|
reparentTask,
|
|
914
966
|
reserveActionReceipt,
|
|
915
967
|
reserveAttempt,
|
|
968
|
+
reserveCarrierJob,
|
|
916
969
|
reserveHostChannel,
|
|
917
970
|
resetCommandResolverForTests,
|
|
918
971
|
resetMux,
|
|
@@ -925,6 +978,7 @@ export {
|
|
|
925
978
|
resolvePair,
|
|
926
979
|
resolvePeerRef,
|
|
927
980
|
runHostTemplate,
|
|
981
|
+
runStop,
|
|
928
982
|
saveResume,
|
|
929
983
|
segmentLineCount,
|
|
930
984
|
segmentPath,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tracks.ts"],"sourcesContent":["// mu — parallel-track detection via union-find with diamond merge.\n//\n// Port of a parallel-tracks union-find algorithm cribbed from a\n// prior internal multi-agent runtime. The killer feature: when two goals share a prerequisite, their subgraphs\n// overlap and they collapse into ONE track, so two agents are never\n// assigned tasks that share a dependency.\n//\n// goal_a goal_b goal_a goal_b\n// \\ / \\ /\n// shared → shared (1 track)\n// | |\n// leaf leaf\n//\n// Algorithm:\n// 1. Get all open goals (tasks with no outgoing edges, not CLOSED).\n// 2. In one recursive query, compute each goal's prerequisite subgraph\n// (everything transitively reachable via reverse edges).\n// 3. Build union-find: merge goals while observing shared tasks.\n// 4. Each connected component is one Track.\n\nimport { compareStrings } from \"./compare.js\";\nimport type { Db } from \"./db.js\";\nimport { listGoals, listReady, type TaskRow } from \"./tasks.js\";\n\nexport interface Track {\n /** Goal tasks (no outgoing edges) belonging to this track. */\n roots: TaskRow[];\n /** Every task id reachable as a prerequisite of any root in this track. */\n taskIds: ReadonlySet<string>;\n /** Number of READY tasks (per the SQL view) within this track's subgraph. */\n readyCount: number;\n /** True when every non-CLOSED task in the track is OPEN/parked: the\n * track holds work, but none of it is schedulable. */\n parked: boolean;\n}\n\n/**\n * Identify independent task subtrees suitable for parallel assignment\n * within a workstream. Open goals only; CLOSED goals are excluded as\n * they no longer represent work to schedule.\n *\n * Scoping: only goals belonging to `workstream` are considered.\n * Cross-workstream edges are forbidden by addTask, so a goal's\n * prerequisite subgraph is naturally workstream-internal.\n */\nexport function getParallelTracks(db: Db, workstream: string): Track[] {\n // listGoals already filters via the SQL view (status <> CLOSED),\n // but defence-in-depth: a stale db snapshot or future view tweak\n // shouldn't let closed goals leak into track count.\n const goals = listGoals(db, workstream).filter((g) => g.status !== \"CLOSED\");\n if (goals.length === 0) return [];\n\n // 2. Compute every goal's prerequisite subgraph in one traversal.\n // Running one recursive query per goal made the TUI's fast tick scale\n // with the number of goals. The goal id carried through this CTE keeps\n // the same inclusive per-goal sets in one SQLite round-trip.\n const reach = db\n .prepare(\n `WITH RECURSIVE\n active_goals(id, local_id) AS (\n SELECT g.id, g.local_id\n FROM goals g\n JOIN workstreams ws ON ws.id = g.workstream_id\n WHERE ws.name = ?\n ),\n reach(goal_id, node_id) AS (\n SELECT id, id FROM active_goals\n UNION\n SELECT r.goal_id, e.from_task_id\n FROM reach r\n JOIN task_edges e ON e.to_task_id = r.node_id\n )\n SELECT goal.local_id AS goal_id, node.local_id AS task_id,\n node.status AS status, node.substate AS substate\n FROM reach r\n JOIN tasks goal ON goal.id = r.goal_id\n JOIN tasks node ON node.id = r.node_id`,\n )\n .all(workstream) as Array<{\n goal_id: string;\n task_id: string;\n status: string;\n substate: string;\n }>;\n\n const subgraphs = new Map(goals.map((goal) => [goal.name, new Set<string>()]));\n const uf = new UnionFind(goals.map((goal) => goal.name));\n const firstGoalByTask = new Map<string, string>();\n // Substate of every non-CLOSED task reached, for the per-track `parked` flag.\n const openSubstate = new Map<string, string>();\n for (const row of reach) {\n if (row.status !== \"CLOSED\") openSubstate.set(row.task_id, row.substate);\n subgraphs.get(row.goal_id)?.add(row.task_id);\n const firstGoal = firstGoalByTask.get(row.task_id);\n if (firstGoal === undefined) firstGoalByTask.set(row.task_id, row.goal_id);\n else uf.union(firstGoal, row.goal_id);\n }\n\n // 4. Group goals + subgraph task ids by union-find root.\n const componentTaskIds = new Map<string, Set<string>>();\n const componentRoots = new Map<string, TaskRow[]>();\n for (const goal of goals) {\n const root = uf.find(goal.name);\n let bucket = componentTaskIds.get(root);\n if (!bucket) {\n bucket = new Set<string>();\n componentTaskIds.set(root, bucket);\n componentRoots.set(root, []);\n }\n componentRoots.get(root)?.push(goal);\n const sub = subgraphs.get(goal.name);\n if (sub) {\n for (const id of sub) bucket.add(id);\n }\n }\n\n // 5. Compute ready counts per track.\n const readyIds = new Set(listReady(db, workstream).map((t) => t.name));\n const tracks: Track[] = [];\n for (const [root, taskIds] of componentTaskIds) {\n const trackRoots = componentRoots.get(root) ?? [];\n let readyCount = 0;\n let openCount = 0;\n let parkedCount = 0;\n for (const id of taskIds) {\n if (readyIds.has(id)) readyCount++;\n const sub = openSubstate.get(id);\n if (sub === undefined) continue;\n openCount++;\n if (sub === \"parked\") parkedCount++;\n }\n const parked = openCount > 0 && parkedCount === openCount;\n tracks.push({ roots: trackRoots, taskIds, readyCount, parked });\n }\n\n // Stable order: by primary root's localId so output is deterministic.\n tracks.sort((a, b) => {\n const an = a.roots[0]?.name ?? \"\";\n const bn = b.roots[0]?.name ?? \"\";\n return compareStrings(an, bn);\n });\n return tracks;\n}\n\nclass UnionFind {\n private readonly parent = new Map<string, string>();\n private readonly rank = new Map<string, number>();\n\n constructor(items: readonly string[]) {\n for (const item of items) {\n this.parent.set(item, item);\n this.rank.set(item, 0);\n }\n }\n\n find(x: string): string {\n let root = x;\n while (true) {\n const next = this.parent.get(root);\n if (next === undefined || next === root) break;\n root = next;\n }\n // Path compression.\n let curr = x;\n while (curr !== root) {\n const next = this.parent.get(curr);\n if (next === undefined) break;\n this.parent.set(curr, root);\n curr = next;\n }\n return root;\n }\n\n union(a: string, b: string): void {\n const rootA = this.find(a);\n const rootB = this.find(b);\n if (rootA === rootB) return;\n const rankA = this.rank.get(rootA) ?? 0;\n const rankB = this.rank.get(rootB) ?? 0;\n if (rankA < rankB) {\n this.parent.set(rootA, rootB);\n } else if (rankA > rankB) {\n this.parent.set(rootB, rootA);\n } else {\n this.parent.set(rootB, rootA);\n this.rank.set(rootA, rankA + 1);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/tracks.ts"],"sourcesContent":["// mu — parallel-track detection via union-find with diamond merge.\n//\n// Port of a parallel-tracks union-find algorithm cribbed from a\n// prior internal multi-agent runtime. The killer feature: when two goals share a prerequisite, their subgraphs\n// overlap and they collapse into ONE track, so two agents are never\n// assigned tasks that share a dependency.\n//\n// goal_a goal_b goal_a goal_b\n// \\ / \\ /\n// shared → shared (1 track)\n// | |\n// leaf leaf\n//\n// Algorithm:\n// 1. Get all open goals (tasks with no outgoing edges, not CLOSED).\n// 2. In one recursive query, compute each goal's prerequisite subgraph\n// (everything transitively reachable via reverse edges).\n// 3. Build union-find: merge goals while observing shared tasks.\n// 4. Each connected component is one Track.\n\nimport { compareStrings } from \"./compare.js\";\nimport type { Db } from \"./db.js\";\nimport { listGoals, listReady, type TaskRow } from \"./tasks.js\";\n\nexport interface Track {\n /** Goal tasks (no outgoing edges) belonging to this track. */\n roots: TaskRow[];\n /** Every task id reachable as a prerequisite of any root in this track. */\n taskIds: ReadonlySet<string>;\n /** Number of READY tasks (per the SQL view) within this track's subgraph. */\n readyCount: number;\n /** True when every non-CLOSED task in the track is OPEN/parked: the\n * track holds work, but none of it is schedulable. */\n parked: boolean;\n}\n\n/**\n * Identify independent task subtrees suitable for parallel assignment\n * within a workstream. Open goals only; CLOSED goals are excluded as\n * they no longer represent work to schedule.\n *\n * Scoping: only goals belonging to `workstream` are considered.\n * Cross-workstream edges are forbidden by addTask, so a goal's\n * prerequisite subgraph is naturally workstream-internal.\n */\nexport function getParallelTracks(db: Db, workstream: string): Track[] {\n // listGoals already filters via the SQL view (status <> CLOSED),\n // but defence-in-depth: a stale db snapshot or future view tweak\n // shouldn't let closed goals leak into track count.\n const goals = listGoals(db, workstream).filter((g) => g.status !== \"CLOSED\");\n if (goals.length === 0) return [];\n\n // 2. Compute every goal's prerequisite subgraph in one traversal.\n // Running one recursive query per goal made the TUI's fast tick scale\n // with the number of goals. The goal id carried through this CTE keeps\n // the same inclusive per-goal sets in one SQLite round-trip.\n const reach = db\n .prepare(\n `WITH RECURSIVE\n active_goals(id, local_id) AS (\n SELECT g.id, g.local_id\n FROM goals g\n JOIN workstreams ws ON ws.id = g.workstream_id\n WHERE ws.name = ?\n ),\n reach(goal_id, node_id) AS (\n SELECT id, id FROM active_goals\n UNION\n SELECT r.goal_id, e.from_task_id\n FROM reach r\n JOIN task_edges e ON e.to_task_id = r.node_id\n )\n SELECT goal.local_id AS goal_id, node.local_id AS task_id,\n node.status AS status, node.substate AS substate\n FROM reach r\n JOIN tasks goal ON goal.id = r.goal_id\n JOIN tasks node ON node.id = r.node_id`,\n )\n .all(workstream) as Array<{\n goal_id: string;\n task_id: string;\n status: string;\n substate: string;\n }>;\n\n const subgraphs = new Map(goals.map((goal) => [goal.name, new Set<string>()]));\n const uf = new UnionFind(goals.map((goal) => goal.name));\n const firstGoalByTask = new Map<string, string>();\n // Substate of every non-CLOSED task reached, for the per-track `parked` flag.\n const openSubstate = new Map<string, string>();\n for (const row of reach) {\n if (row.status !== \"CLOSED\") openSubstate.set(row.task_id, row.substate);\n subgraphs.get(row.goal_id)?.add(row.task_id);\n const firstGoal = firstGoalByTask.get(row.task_id);\n if (firstGoal === undefined) firstGoalByTask.set(row.task_id, row.goal_id);\n else uf.union(firstGoal, row.goal_id);\n }\n\n // 4. Group goals + subgraph task ids by union-find root.\n const componentTaskIds = new Map<string, Set<string>>();\n const componentRoots = new Map<string, TaskRow[]>();\n for (const goal of goals) {\n const root = uf.find(goal.name);\n let bucket = componentTaskIds.get(root);\n if (!bucket) {\n bucket = new Set<string>();\n componentTaskIds.set(root, bucket);\n componentRoots.set(root, []);\n }\n componentRoots.get(root)?.push(goal);\n const sub = subgraphs.get(goal.name);\n if (sub) {\n for (const id of sub) bucket.add(id);\n }\n }\n\n // 5. Compute ready counts per track.\n const readyIds = new Set(listReady(db, workstream).map((t) => t.name));\n const tracks: Track[] = [];\n for (const [root, taskIds] of componentTaskIds) {\n const trackRoots = componentRoots.get(root) ?? [];\n let readyCount = 0;\n let openCount = 0;\n let parkedCount = 0;\n for (const id of taskIds) {\n if (readyIds.has(id)) readyCount++;\n const sub = openSubstate.get(id);\n if (sub === undefined) continue;\n openCount++;\n if (sub === \"parked\") parkedCount++;\n }\n const parked = openCount > 0 && parkedCount === openCount;\n tracks.push({ roots: trackRoots, taskIds, readyCount, parked });\n }\n\n // Stable order: by primary root's localId so output is deterministic.\n tracks.sort((a, b) => {\n const an = a.roots[0]?.name ?? \"\";\n const bn = b.roots[0]?.name ?? \"\";\n return compareStrings(an, bn);\n });\n return tracks;\n}\n\nclass UnionFind {\n private readonly parent = new Map<string, string>();\n private readonly rank = new Map<string, number>();\n\n constructor(items: readonly string[]) {\n for (const item of items) {\n this.parent.set(item, item);\n this.rank.set(item, 0);\n }\n }\n\n find(x: string): string {\n let root = x;\n while (true) {\n const next = this.parent.get(root);\n if (next === undefined || next === root) break;\n root = next;\n }\n // Path compression.\n let curr = x;\n while (curr !== root) {\n const next = this.parent.get(curr);\n if (next === undefined) break;\n this.parent.set(curr, root);\n curr = next;\n }\n return root;\n }\n\n union(a: string, b: string): void {\n const rootA = this.find(a);\n const rootB = this.find(b);\n if (rootA === rootB) return;\n const rankA = this.rank.get(rootA) ?? 0;\n const rankB = this.rank.get(rootB) ?? 0;\n if (rankA < rankB) {\n this.parent.set(rootA, rootB);\n } else if (rankA > rankB) {\n this.parent.set(rootB, rootA);\n } else {\n this.parent.set(rootB, rootA);\n this.rank.set(rootA, rankA + 1);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
formatElapsed,
|
|
4
4
|
loadDashboard,
|
|
5
5
|
matches
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-U2QLTREB.js";
|
|
7
7
|
import {
|
|
8
8
|
KNOWN_VERBS,
|
|
9
9
|
ambientIngest,
|
|
10
10
|
currentCallers,
|
|
11
11
|
parseOpKey,
|
|
12
12
|
syncEnabled
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-FVRIKUBR.js";
|
|
14
14
|
import {
|
|
15
15
|
DEFAULT_SUBSTATE,
|
|
16
16
|
TASK_STATUSES,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
spawnerFromEnv,
|
|
28
28
|
tmuxAttachMode,
|
|
29
29
|
verdictLineLabel
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-4ZWBLTZK.js";
|
|
31
31
|
import "./chunk-PZ5GOCWH.js";
|
|
32
32
|
|
|
33
33
|
// src/cli/tui/index.ts
|
|
@@ -667,8 +667,8 @@ function taskLine(t) {
|
|
|
667
667
|
function useYank() {
|
|
668
668
|
const { stdout } = useStdout();
|
|
669
669
|
return async (target, all = false) => {
|
|
670
|
-
const plan = target.kind === "scrollback" ? await planAttach(target) : null;
|
|
671
|
-
const command = copyCommand(target, { all, attachLine: plan?.line ?? null });
|
|
670
|
+
const plan = typeof target !== "string" && target.kind === "scrollback" ? await planAttach(target) : null;
|
|
671
|
+
const command = typeof target === "string" ? target : copyCommand(target, { all, attachLine: plan?.line ?? null });
|
|
672
672
|
const y = yankSequence(command);
|
|
673
673
|
const why = plan !== null && !plan.ok ? ` (attach unavailable: ${plan.reason})` : "";
|
|
674
674
|
if (!y.ok) return `not copied (${y.why}): ${command}${why}`;
|
|
@@ -1240,17 +1240,16 @@ function attentionStrip(attention, ws) {
|
|
|
1240
1240
|
])
|
|
1241
1241
|
];
|
|
1242
1242
|
}
|
|
1243
|
-
var attentionRole = (a) => a.kind === "dead"
|
|
1243
|
+
var attentionRole = (a) => a.kind === "dead" ? "bad" : "warn";
|
|
1244
1244
|
function attentionRows(snap, ws) {
|
|
1245
1245
|
return snap.attention.map((a) => {
|
|
1246
1246
|
const agent = snap.agents.find((x) => x.key === a.target);
|
|
1247
1247
|
const id = a.kind === "human" || a.kind === "delegate" ? a.target?.slice((a.workstream?.length ?? 0) + 1) : void 0;
|
|
1248
1248
|
const drill = agent ? scrollbackOf(agent) : a.workstream !== null && id ? { kind: "notes", workstream: a.workstream, id, title: a.text } : void 0;
|
|
1249
|
-
return rowOf(
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
);
|
|
1249
|
+
return rowOf(a.key, [{ text: attentionLabel(a, ws), role: attentionRole(a) }], {
|
|
1250
|
+
...drill ? { drill } : {},
|
|
1251
|
+
...a.fix !== void 0 ? { fix: a.fix } : {}
|
|
1252
|
+
});
|
|
1254
1253
|
});
|
|
1255
1254
|
}
|
|
1256
1255
|
function waveText(w) {
|
|
@@ -1392,7 +1391,7 @@ var fasterTick = (ms) => clampTick(Math.floor(ms / 2));
|
|
|
1392
1391
|
var slowerTick = (ms) => clampTick(ms * 2);
|
|
1393
1392
|
var snapshotKey = (s) => JSON.stringify(
|
|
1394
1393
|
s,
|
|
1395
|
-
(k, v) => k === "elapsed_ms" && typeof v === "number" ? Math.floor(v / 1e3) : v
|
|
1394
|
+
(k, v) => (k === "elapsed_ms" || k === "quiet_ms") && typeof v === "number" ? Math.floor(v / 1e3) : v
|
|
1396
1395
|
);
|
|
1397
1396
|
function useSnapshot(runtime, query, pollMs, slowMs = SLOW_TICK_MS) {
|
|
1398
1397
|
const [state, setState] = useState2({
|
|
@@ -1481,7 +1480,7 @@ function layout(rows, lines = FIXED_BY_PRIORITY) {
|
|
|
1481
1480
|
return { shown, height: Math.max(0, rows - TOP_LINES - shown.size) };
|
|
1482
1481
|
}
|
|
1483
1482
|
var HINT_HEAD = `\u2190/\u2192 tab q quit [/] workstream ${NAV_HINT} move`;
|
|
1484
|
-
var HINT_OVERVIEW = `${HINT_HEAD} Enter open y copy +/- rate`;
|
|
1483
|
+
var HINT_OVERVIEW = `${HINT_HEAD} Enter open y copy fix +/- rate`;
|
|
1485
1484
|
var HINT = `${HINT_HEAD} Enter open / filter c clear y copy +/- rate`;
|
|
1486
1485
|
var HINT_TASKS = `${HINT_HEAD} Enter open s sort o status / filter c clear y copy +/- rate`;
|
|
1487
1486
|
var hintAgents = (attachKey) => `${HINT_HEAD} Enter scrollback ${attachKey} / filter c clear y copy +/- rate`;
|
|
@@ -1660,7 +1659,7 @@ function App({
|
|
|
1660
1659
|
const target = all[sel]?.drill;
|
|
1661
1660
|
if (target?.kind === "scrollback") void attach(target);
|
|
1662
1661
|
} else if (input === "y") {
|
|
1663
|
-
const target = all[sel]?.drill;
|
|
1662
|
+
const target = all[sel]?.fix ?? all[sel]?.drill;
|
|
1664
1663
|
if (target !== void 0) void yank(target).then(setFlash);
|
|
1665
1664
|
}
|
|
1666
1665
|
},
|
|
@@ -1845,4 +1844,4 @@ async function runDashboard(opts) {
|
|
|
1845
1844
|
export {
|
|
1846
1845
|
runDashboard
|
|
1847
1846
|
};
|
|
1848
|
-
//# sourceMappingURL=tui-
|
|
1847
|
+
//# sourceMappingURL=tui-5ZARE7RS.js.map
|