@h-rig/core 0.0.6-alpha.13 → 0.0.6-alpha.130

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/src/index.js CHANGED
@@ -43,11 +43,45 @@ function definePlugin(meta, runtime) {
43
43
  }
44
44
  }
45
45
  }
46
+ const declaredHooks = new Map((validated.contributes?.hooks ?? []).map((h) => [h.id, h]));
47
+ for (const hookId of Object.keys(runtime.hooks ?? {})) {
48
+ const metadata = declaredHooks.get(hookId);
49
+ if (!metadata) {
50
+ throw new Error(`definePlugin(${validated.name}): typed hook "${hookId}" has no matching metadata entry in contributes.hooks`);
51
+ }
52
+ if (metadata.command) {
53
+ throw new Error(`definePlugin(${validated.name}): hook "${hookId}" has both a typed implementation and a command string \u2014 pick one`);
54
+ }
55
+ }
56
+ if (runtime.hooks) {
57
+ for (const h of declaredHooks.values()) {
58
+ if (!runtime.hooks[h.id] && !h.command) {
59
+ throw new Error(`definePlugin(${validated.name}): hook metadata "${h.id}" has no implementation (typed function or command)`);
60
+ }
61
+ }
62
+ }
46
63
  return { ...validated, __runtime: runtime };
47
64
  }
48
65
  // packages/core/src/define-config.ts
49
66
  import { Schema as Schema2 } from "effect";
50
67
  import { RigConfig } from "@rig/contracts";
68
+ function normalizeWorkspaceConfig(raw) {
69
+ const workspace = raw && typeof raw === "object" && !Array.isArray(raw) ? { ...raw } : { mainRepo: "." };
70
+ workspace.checkout = workspace.checkout ?? workspace.isolation ?? "worktree";
71
+ workspace.isolation = workspace.isolation ?? workspace.checkout;
72
+ workspace.sandbox = workspace.sandbox ?? "enforce";
73
+ return workspace;
74
+ }
75
+ function applyConfigDefaults(raw) {
76
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
77
+ return raw;
78
+ const record = raw;
79
+ return {
80
+ ...record,
81
+ plugins: Array.isArray(record.plugins) ? record.plugins : [],
82
+ workspace: normalizeWorkspaceConfig(record.workspace)
83
+ };
84
+ }
51
85
  function defineConfig(cfg) {
52
86
  const runtimeByName = new Map;
53
87
  const plugins = cfg.plugins ?? [];
@@ -56,7 +90,7 @@ function defineConfig(cfg) {
56
90
  runtimeByName.set(plugin.name, plugin.__runtime);
57
91
  }
58
92
  }
59
- const decoded = Schema2.decodeUnknownSync(RigConfig)(cfg);
93
+ const decoded = Schema2.decodeUnknownSync(RigConfig)(applyConfigDefaults(cfg));
60
94
  const decodedPlugins = decoded.plugins.map((p) => {
61
95
  const runtime = runtimeByName.get(p.name);
62
96
  if (!runtime)
@@ -124,6 +158,24 @@ function assertRuntimeMatchesMetadata(plugin) {
124
158
  }
125
159
  }
126
160
  }
161
+ const declaredHooks = new Map((plugin.contributes?.hooks ?? []).map((hook) => [hook.id, hook]));
162
+ const runtimeHooks = plugin.__runtime?.hooks;
163
+ for (const hookId of Object.keys(runtimeHooks ?? {})) {
164
+ const metadata = declaredHooks.get(hookId);
165
+ if (!metadata) {
166
+ throw new Error(`plugin "${plugin.name}" typed hook "${hookId}" has no matching metadata entry in contributes.hooks`);
167
+ }
168
+ if (metadata.command) {
169
+ throw new Error(`plugin "${plugin.name}" hook "${hookId}" has both a typed implementation and a command string \u2014 pick one`);
170
+ }
171
+ }
172
+ if (runtimeHooks) {
173
+ for (const hook of declaredHooks.values()) {
174
+ if (!runtimeHooks[hook.id] && !hook.command) {
175
+ throw new Error(`plugin "${plugin.name}" hook metadata "${hook.id}" has no implementation (typed function or command)`);
176
+ }
177
+ }
178
+ }
127
179
  }
128
180
  function createPluginHost(plugins) {
129
181
  assertUniquePluginNames(plugins);
@@ -257,7 +309,8 @@ function buildRigInitConfigSource(input) {
257
309
  lines.push(` },`);
258
310
  }
259
311
  lines.push(` workspace: { mainRepo: ".", isolation: "worktree" },`);
260
- lines.push(` runtime: { harness: "pi", mode: "yolo" },`);
312
+ const sshTarget = input.sshTarget?.trim();
313
+ lines.push(sshTarget ? ` runtime: { harness: "pi", mode: "yolo", server: { sshTarget: ${JSON.stringify(sshTarget)} } },` : ` runtime: { harness: "pi", mode: "yolo" }, // server.sshTarget unset = local placement`);
261
314
  lines.push(` planning: { mode: "auto" },`);
262
315
  lines.push(` github: {`);
263
316
  lines.push(` issueUpdates: "lifecycle",`);
@@ -283,6 +336,7 @@ import {
283
336
  WorkspaceId,
284
337
  WorktreeId
285
338
  } from "@rig/contracts";
339
+ var CANONICAL_RUNTIME_ADAPTER = "pi";
286
340
  function isRecord(value) {
287
341
  return typeof value === "object" && value !== null;
288
342
  }
@@ -422,7 +476,7 @@ function mapLegacySessionStatusToRunStatus(status) {
422
476
  case "error":
423
477
  return "failed";
424
478
  case "stopped":
425
- return "cancelled";
479
+ return "stopped";
426
480
  default:
427
481
  return "created";
428
482
  }
@@ -458,12 +512,15 @@ function mapTaskStatusFromRunStatus(status, fallback) {
458
512
  case "paused":
459
513
  return "in_progress";
460
514
  case "reviewing":
515
+ case "closing-out":
461
516
  return "under_review";
517
+ case "needs-attention":
518
+ return "blocked";
462
519
  case "completed":
463
520
  return "completed";
464
521
  case "failed":
465
522
  return "ready";
466
- case "cancelled":
523
+ case "stopped":
467
524
  return "cancelled";
468
525
  }
469
526
  }
@@ -647,7 +704,7 @@ function applySyntheticRuntimePreparation(snapshot, event) {
647
704
  ...existingRun,
648
705
  taskId: existingRun.taskId ?? nextTaskId,
649
706
  runKind: existingRun.runKind === "adhoc" && nextTaskId ? "task" : existingRun.runKind,
650
- runtimeAdapter: "rig-native",
707
+ runtimeAdapter: CANONICAL_RUNTIME_ADAPTER,
651
708
  initialPrompt: existingRun.initialPrompt ?? null,
652
709
  executionTarget: existingRun.executionTarget ?? "local",
653
710
  remoteHostId: existingRun.remoteHostId ?? null,
@@ -663,7 +720,7 @@ function applySyntheticRuntimePreparation(snapshot, event) {
663
720
  ...runtimeBase,
664
721
  workspaceId: nextWorkspaceId,
665
722
  runId: runtimeRunId,
666
- adapterKind: "rig-native",
723
+ adapterKind: CANONICAL_RUNTIME_ADAPTER,
667
724
  executionTarget: existingRun.executionTarget ?? "local",
668
725
  remoteHostId: existingRun.remoteHostId ?? null,
669
726
  status: failed ? "failed" : finished ? "prepared" : "starting",
@@ -712,7 +769,7 @@ function applySyntheticRuntimePrepared(snapshot, event) {
712
769
  ...snapshot.runtimes.find((runtime) => runtime.runId === runId) ?? makeRuntimeFromRun(existingRun, event.createdAt),
713
770
  workspaceId: nextWorkspaceId,
714
771
  runId: runtimeRunId,
715
- adapterKind: "rig-native",
772
+ adapterKind: CANONICAL_RUNTIME_ADAPTER,
716
773
  executionTarget: existingRun.executionTarget ?? "local",
717
774
  remoteHostId: existingRun.remoteHostId ?? null,
718
775
  status: "prepared",
@@ -755,7 +812,7 @@ function applyLegacyProjectEvent(snapshot, event) {
755
812
  title,
756
813
  rootPath,
757
814
  sourceKind: "native",
758
- defaultRuntimeAdapter: "codex-app-server",
815
+ defaultRuntimeAdapter: CANONICAL_RUNTIME_ADAPTER,
759
816
  defaultModel: readNullableString(payload, "defaultModel") ?? null,
760
817
  createdAt,
761
818
  updatedAt
@@ -850,7 +907,7 @@ function applyLegacyThreadEvent(snapshot, event) {
850
907
  runtimeMode: "full-access",
851
908
  interactionMode: "default",
852
909
  status: "created",
853
- runtimeAdapter: "codex-app-server",
910
+ runtimeAdapter: CANONICAL_RUNTIME_ADAPTER,
854
911
  model,
855
912
  initialPrompt: null,
856
913
  activeRuntimeId: null,
@@ -1034,7 +1091,7 @@ function applyLegacyThreadEvent(snapshot, event) {
1034
1091
  const providerName = readNullableString(session, "providerName");
1035
1092
  const nextRun = {
1036
1093
  ...existingRun,
1037
- runtimeAdapter: providerName ?? existingRun.runtimeAdapter,
1094
+ runtimeAdapter: CANONICAL_RUNTIME_ADAPTER,
1038
1095
  initialPrompt: existingRun.initialPrompt ?? null,
1039
1096
  activeRuntimeId: runtimeIdFromRunId(asRunId(runId)),
1040
1097
  status: mapLegacySessionStatusToRunStatus(readString(session, "status")),
@@ -1047,7 +1104,7 @@ function applyLegacyThreadEvent(snapshot, event) {
1047
1104
  ...snapshot.runtimes.find((runtime) => runtime.runId === runId) ?? makeRuntimeFromRun(nextRun, sessionUpdatedAt),
1048
1105
  workspaceId: existingRun.workspaceId,
1049
1106
  runId: asRunId(runId),
1050
- adapterKind: providerName ?? existingRun.runtimeAdapter,
1107
+ adapterKind: CANONICAL_RUNTIME_ADAPTER,
1051
1108
  status: mapLegacySessionStatusToRuntimeStatus(readString(session, "status")),
1052
1109
  workspaceDir: existingRun.worktreePath,
1053
1110
  isolationMode: existingRun.worktreePath ? "worktree" : "env",
@@ -1281,7 +1338,7 @@ function applyEngineEvent(snapshot, event) {
1281
1338
  runtimeMode: payload.runtimeMode,
1282
1339
  interactionMode: payload.interactionMode,
1283
1340
  status: "created",
1284
- runtimeAdapter: payload.runtimeAdapter,
1341
+ runtimeAdapter: CANONICAL_RUNTIME_ADAPTER,
1285
1342
  model: payload.model ?? null,
1286
1343
  initialPrompt: payload.initialPrompt ?? null,
1287
1344
  executionTarget: payload.executionTarget ?? (payload.remoteHostId ? "remote" : "local"),
@@ -1313,7 +1370,7 @@ function applyEngineEvent(snapshot, event) {
1313
1370
  ...base,
1314
1371
  runs: patchById(base.runs, payload.runId, (run) => ({
1315
1372
  ...run,
1316
- status: "cancelled",
1373
+ status: "stopped",
1317
1374
  updatedAt: payload.createdAt,
1318
1375
  completedAt: payload.createdAt
1319
1376
  }))
@@ -1977,7 +2034,7 @@ function applyEngineEvent(snapshot, event) {
1977
2034
  runtimeMode: "full-access",
1978
2035
  interactionMode: "default",
1979
2036
  status: "created",
1980
- runtimeAdapter: "rig-native",
2037
+ runtimeAdapter: CANONICAL_RUNTIME_ADAPTER,
1981
2038
  model: null,
1982
2039
  initialPrompt: null,
1983
2040
  activeRuntimeId: runtimeIdFromRunId(asRunId(runId)),
@@ -1997,7 +2054,7 @@ function applyEngineEvent(snapshot, event) {
1997
2054
  workspaceId: asWorkspaceId(workspaceId),
1998
2055
  taskId: asTaskId(taskId),
1999
2056
  runKind: "task",
2000
- runtimeAdapter: "rig-native",
2057
+ runtimeAdapter: CANONICAL_RUNTIME_ADAPTER,
2001
2058
  activeRuntimeId: runtimeIdFromRunId(asRunId(runId)),
2002
2059
  updatedAt: event.createdAt
2003
2060
  });
@@ -2085,10 +2142,40 @@ function projectTaskStatusForGrouping(status) {
2085
2142
  case "in_progress":
2086
2143
  case "under_review":
2087
2144
  return "running";
2145
+ case null:
2146
+ case undefined:
2147
+ case "":
2148
+ return "unknown";
2088
2149
  default:
2089
2150
  return status;
2090
2151
  }
2091
2152
  }
2153
+ function projectRunStatusForTaskGrouping(status) {
2154
+ switch (status) {
2155
+ case "created":
2156
+ case "queued":
2157
+ case "preparing":
2158
+ return "queued";
2159
+ case "running":
2160
+ case "waiting-approval":
2161
+ case "waiting-user-input":
2162
+ case "paused":
2163
+ case "validating":
2164
+ case "reviewing":
2165
+ case "closing-out":
2166
+ return "running";
2167
+ case "needs-attention":
2168
+ return "blocked";
2169
+ case "failed":
2170
+ case "stopped":
2171
+ return "ready";
2172
+ case "completed":
2173
+ return "completed";
2174
+ case null:
2175
+ case undefined:
2176
+ return null;
2177
+ }
2178
+ }
2092
2179
  var STATUS_PRIORITY = [
2093
2180
  "running",
2094
2181
  "blocked",
@@ -2100,11 +2187,31 @@ var STATUS_PRIORITY = [
2100
2187
  "cancelled",
2101
2188
  "completed"
2102
2189
  ];
2103
- function selectTasksGroupedByStatus(snapshot, workspaceId) {
2104
- const tasks = selectTasksByWorkspace(snapshot, workspaceId);
2190
+ function taskIdFromSession(session) {
2191
+ return session.taskId ?? session.record.taskId ?? null;
2192
+ }
2193
+ function latestSessionByTask(sessions) {
2194
+ const byTask = new Map;
2195
+ for (const session of sessions) {
2196
+ const taskId = taskIdFromSession(session);
2197
+ if (!taskId)
2198
+ continue;
2199
+ const existing = byTask.get(taskId);
2200
+ if (!existing || (session.lastEventAt ?? "").localeCompare(existing.lastEventAt ?? "") >= 0) {
2201
+ byTask.set(taskId, session);
2202
+ }
2203
+ }
2204
+ return byTask;
2205
+ }
2206
+ function projectTaskStatusWithSessions(task, sessionsByTask = new Map) {
2207
+ const sessionStatus = projectRunStatusForTaskGrouping(sessionsByTask.get(task.id)?.status);
2208
+ return sessionStatus ?? projectTaskStatusForGrouping(task.status);
2209
+ }
2210
+ function groupTasksByProjectedStatus(tasks, sessions = []) {
2211
+ const sessionsByTask = latestSessionByTask(sessions);
2105
2212
  const byStatus = new Map;
2106
2213
  for (const task of tasks) {
2107
- const projectedStatus = projectTaskStatusForGrouping(task.status);
2214
+ const projectedStatus = projectTaskStatusWithSessions(task, sessionsByTask);
2108
2215
  const group = byStatus.get(projectedStatus);
2109
2216
  if (group) {
2110
2217
  group.push(task);
@@ -2128,6 +2235,69 @@ function selectTasksGroupedByStatus(snapshot, workspaceId) {
2128
2235
  }
2129
2236
  return result;
2130
2237
  }
2238
+ function isProjectionGroupingInput(value) {
2239
+ return Boolean(value && typeof value === "object" && !("snapshotSequence" in value) && Array.isArray(value.tasks));
2240
+ }
2241
+ function selectTasksGroupedByStatus(input, workspaceId) {
2242
+ if (isProjectionGroupingInput(input)) {
2243
+ const filteredTasks = input.workspaceId ? input.tasks.filter((task) => {
2244
+ const workspaceTask = task;
2245
+ return workspaceTask.workspaceId === input.workspaceId;
2246
+ }) : input.tasks;
2247
+ return groupTasksByProjectedStatus(filteredTasks, input.sessions);
2248
+ }
2249
+ const tasks = selectTasksByWorkspace(input, workspaceId ?? null);
2250
+ return groupTasksByProjectedStatus(tasks, []);
2251
+ }
2252
+ function isObjectRecord(value) {
2253
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2254
+ }
2255
+ function normalizeLogin(value) {
2256
+ return value.trim().replace(/^@+/, "").toLowerCase();
2257
+ }
2258
+ function assigneeLoginsFromValue(value) {
2259
+ if (!Array.isArray(value))
2260
+ return [];
2261
+ return value.flatMap((entry) => {
2262
+ if (typeof entry === "string" && entry.trim())
2263
+ return [normalizeLogin(entry)];
2264
+ if (isObjectRecord(entry) && typeof entry.login === "string" && entry.login.trim()) {
2265
+ return [normalizeLogin(entry.login)];
2266
+ }
2267
+ return [];
2268
+ });
2269
+ }
2270
+ function normalizeTaskAssigneeFilter(assignee, currentUserLogin) {
2271
+ const trimmed = assignee?.trim();
2272
+ if (!trimmed)
2273
+ return null;
2274
+ if (trimmed === "@me" || trimmed.toLowerCase() === "me") {
2275
+ return currentUserLogin?.trim() ? normalizeLogin(currentUserLogin) : null;
2276
+ }
2277
+ return normalizeLogin(trimmed);
2278
+ }
2279
+ function readTaskAssigneeLogins(task) {
2280
+ const taskRecord = task;
2281
+ const metadata = isObjectRecord(task.metadata) ? task.metadata : null;
2282
+ const raw = isObjectRecord(metadata?.raw) ? metadata.raw : null;
2283
+ return Array.from(new Set([
2284
+ ...assigneeLoginsFromValue(taskRecord.assignees),
2285
+ ...assigneeLoginsFromValue(metadata?.assignees),
2286
+ ...assigneeLoginsFromValue(raw?.assignees)
2287
+ ]));
2288
+ }
2289
+ function taskMatchesAssigneeFilter(task, assignee, options = {}) {
2290
+ const normalized = normalizeTaskAssigneeFilter(assignee, options.currentUserLogin);
2291
+ if (!normalized)
2292
+ return false;
2293
+ return readTaskAssigneeLogins(task).includes(normalized);
2294
+ }
2295
+ function selectTasksAssignedTo(tasks, assignee, options = {}) {
2296
+ return tasks.filter((task) => taskMatchesAssigneeFilter(task, assignee, options));
2297
+ }
2298
+ function selectTasksAssignedToMe(tasks, currentUserLogin) {
2299
+ return selectTasksAssignedTo(tasks, "@me", currentUserLogin === undefined ? {} : { currentUserLogin });
2300
+ }
2131
2301
  function selectRun(snapshot, runId) {
2132
2302
  if (!runId)
2133
2303
  return null;
@@ -2189,17 +2359,45 @@ function selectUserInputsForWorkspace(snapshot, workspaceId) {
2189
2359
  return (snapshot.userInputs ?? []).filter((request) => runIds.has(request.runId));
2190
2360
  }
2191
2361
  // packages/core/src/taskGraph.ts
2192
- function isObjectRecord(value) {
2362
+ function isObjectRecord2(value) {
2193
2363
  return typeof value === "object" && value !== null && !Array.isArray(value);
2194
2364
  }
2195
- function readTaskMetadataStringList(task, key) {
2196
- const metadata = isObjectRecord(task.metadata) ? task.metadata : null;
2197
- const value = metadata?.[key];
2365
+ function readStringList(value) {
2198
2366
  return Array.isArray(value) ? value.filter((entry) => typeof entry === "string" && entry.length > 0) : [];
2199
2367
  }
2368
+ function unique(values) {
2369
+ return Array.from(new Set(values));
2370
+ }
2371
+ function readTaskMetadataStringList(task, key) {
2372
+ const taskRecord = task;
2373
+ const topLevel = readStringList(taskRecord[key]);
2374
+ if (topLevel.length > 0)
2375
+ return topLevel;
2376
+ const metadata = isObjectRecord2(task.metadata) ? task.metadata : null;
2377
+ const metadataList = readStringList(metadata?.[key]);
2378
+ if (metadataList.length > 0)
2379
+ return metadataList;
2380
+ if (key === "dependencies") {
2381
+ return readStringList(metadata?.deps);
2382
+ }
2383
+ return [];
2384
+ }
2385
+ function readTaskDependencyRefs(task) {
2386
+ return unique([
2387
+ ...readTaskMetadataStringList(task, "dependencies"),
2388
+ ...readTaskMetadataStringList(task, "parentChildDeps")
2389
+ ]);
2390
+ }
2200
2391
  function readTaskSourceIssueId(task) {
2201
- const metadata = isObjectRecord(task.metadata) ? task.metadata : null;
2202
- return typeof metadata?.sourceIssueId === "string" && metadata.sourceIssueId.length > 0 ? metadata.sourceIssueId : null;
2392
+ if (typeof task.sourceIssueId === "string" && task.sourceIssueId.length > 0) {
2393
+ return task.sourceIssueId;
2394
+ }
2395
+ const metadata = isObjectRecord2(task.metadata) ? task.metadata : null;
2396
+ if (typeof metadata?.sourceIssueId === "string" && metadata.sourceIssueId.length > 0) {
2397
+ return metadata.sourceIssueId;
2398
+ }
2399
+ const rigMetadata = isObjectRecord2(metadata?._rig) ? metadata._rig : null;
2400
+ return typeof rigMetadata?.sourceIssueId === "string" && rigMetadata.sourceIssueId.length > 0 ? rigMetadata.sourceIssueId : null;
2203
2401
  }
2204
2402
  function resolveTaskReference(ref, tasksById, taskIdByExternalRef, taskIdBySourceIssueId) {
2205
2403
  if (tasksById.has(ref))
@@ -2229,11 +2427,7 @@ function computeTaskBlockingDepths(tasks) {
2229
2427
  if (!task)
2230
2428
  return 0;
2231
2429
  stack.add(taskId);
2232
- const refs = [
2233
- ...readTaskMetadataStringList(task, "dependencies"),
2234
- ...readTaskMetadataStringList(task, "parentChildDeps")
2235
- ];
2236
- const blockers = refs.map((ref) => resolveTaskReference(ref, tasksById, taskIdByExternalRef, taskIdBySourceIssueId)).filter((ref) => ref !== null && ref !== taskId);
2430
+ const blockers = readTaskDependencyRefs(task).map((ref) => resolveTaskReference(ref, tasksById, taskIdByExternalRef, taskIdBySourceIssueId)).filter((ref) => ref !== null && ref !== taskId);
2237
2431
  const depth = blockers.length === 0 ? 0 : Math.max(...blockers.map((blockerId) => visit(blockerId, stack) + 1));
2238
2432
  stack.delete(taskId);
2239
2433
  memo.set(taskId, depth);
@@ -2244,6 +2438,134 @@ function computeTaskBlockingDepths(tasks) {
2244
2438
  }
2245
2439
  return memo;
2246
2440
  }
2441
+ function isTaskTerminalStatus(status) {
2442
+ switch (status) {
2443
+ case "closed":
2444
+ case "completed":
2445
+ case "done":
2446
+ case "cancelled":
2447
+ case "canceled":
2448
+ return true;
2449
+ default:
2450
+ return false;
2451
+ }
2452
+ }
2453
+ function isTaskBlockedStatus(status) {
2454
+ return status === "blocked";
2455
+ }
2456
+ function isTaskRunnableStatus(status) {
2457
+ if (status === null || status === undefined || status === "")
2458
+ return true;
2459
+ if (isTaskTerminalStatus(status) || isTaskBlockedStatus(status))
2460
+ return false;
2461
+ switch (status) {
2462
+ case "ready":
2463
+ case "open":
2464
+ case "failed":
2465
+ return true;
2466
+ default:
2467
+ return false;
2468
+ }
2469
+ }
2470
+ function priorityValue(task) {
2471
+ return typeof task.priority === "number" && Number.isFinite(task.priority) ? task.priority : Number.MAX_SAFE_INTEGER;
2472
+ }
2473
+ function computeTaskDependencyBadges(tasks) {
2474
+ const index = buildTaskReferenceIndex(tasks);
2475
+ const blockingDepths = computeTaskBlockingDepths(tasks);
2476
+ const dependencyIdsByTask = new Map;
2477
+ const unresolvedRefsByTask = new Map;
2478
+ const blocksByTask = new Map;
2479
+ for (const task of tasks) {
2480
+ const dependencyIds = [];
2481
+ const unresolvedRefs = [];
2482
+ for (const ref of readTaskDependencyRefs(task)) {
2483
+ const dependencyId = resolveTaskReference(ref, index.tasksById, index.taskIdByExternalRef, index.taskIdBySourceIssueId);
2484
+ if (dependencyId && dependencyId !== task.id) {
2485
+ dependencyIds.push(dependencyId);
2486
+ const blocks = blocksByTask.get(dependencyId);
2487
+ if (blocks) {
2488
+ blocks.push(task.id);
2489
+ } else {
2490
+ blocksByTask.set(dependencyId, [task.id]);
2491
+ }
2492
+ } else {
2493
+ unresolvedRefs.push(ref);
2494
+ }
2495
+ }
2496
+ dependencyIdsByTask.set(task.id, unique(dependencyIds));
2497
+ unresolvedRefsByTask.set(task.id, unique(unresolvedRefs));
2498
+ }
2499
+ const summaries = new Map;
2500
+ for (const task of tasks) {
2501
+ const dependencyIds = dependencyIdsByTask.get(task.id) ?? [];
2502
+ const unresolvedDependencyRefs = unresolvedRefsByTask.get(task.id) ?? [];
2503
+ const blockedBy = dependencyIds.filter((dependencyId) => {
2504
+ const dependency = index.tasksById.get(dependencyId);
2505
+ return dependency ? !isTaskTerminalStatus(dependency.status) : false;
2506
+ });
2507
+ const blocks = unique(blocksByTask.get(task.id) ?? []);
2508
+ const blocked = isTaskBlockedStatus(task.status) || blockedBy.length > 0;
2509
+ const ready = isTaskRunnableStatus(task.status) && !blocked;
2510
+ const badges = [];
2511
+ if (blocked) {
2512
+ badges.push({
2513
+ kind: "blocked",
2514
+ label: blockedBy.length > 0 ? `blocked \xD7${blockedBy.length}` : "blocked",
2515
+ description: blockedBy.length > 0 ? `Waiting on ${blockedBy.join(", ")}.` : "Task source marks this task blocked.",
2516
+ ...blockedBy.length > 0 ? { count: blockedBy.length } : {},
2517
+ taskIds: blockedBy
2518
+ });
2519
+ } else if (ready) {
2520
+ badges.push({
2521
+ kind: "ready",
2522
+ label: "ready",
2523
+ description: "No open dependencies block this task."
2524
+ });
2525
+ }
2526
+ if (dependencyIds.length > 0 || blocks.length > 0 || unresolvedDependencyRefs.length > 0) {
2527
+ badges.push({
2528
+ kind: "dependency",
2529
+ label: `deps ${dependencyIds.length}/${blocks.length}`,
2530
+ description: [
2531
+ dependencyIds.length > 0 ? `Depends on ${dependencyIds.join(", ")}.` : null,
2532
+ blocks.length > 0 ? `Blocks ${blocks.join(", ")}.` : null,
2533
+ unresolvedDependencyRefs.length > 0 ? `Unresolved refs: ${unresolvedDependencyRefs.join(", ")}.` : null
2534
+ ].filter((part) => part !== null).join(" "),
2535
+ count: dependencyIds.length + blocks.length,
2536
+ taskIds: unique([...dependencyIds, ...blocks])
2537
+ });
2538
+ }
2539
+ summaries.set(task.id, {
2540
+ taskId: task.id,
2541
+ blockingDepth: blockingDepths.get(task.id) ?? 0,
2542
+ dependencyIds,
2543
+ unresolvedDependencyRefs,
2544
+ blockedBy,
2545
+ blocks,
2546
+ blocked,
2547
+ ready,
2548
+ dependencyCount: dependencyIds.length,
2549
+ dependentCount: blocks.length,
2550
+ badges
2551
+ });
2552
+ }
2553
+ return summaries;
2554
+ }
2555
+ function selectNextReadyTaskByPriority(tasks, options = {}) {
2556
+ const excluded = new Set(options.excludeTaskIds ?? []);
2557
+ const badges = computeTaskDependencyBadges(tasks);
2558
+ const candidates = tasks.filter((task) => !excluded.has(task.id)).filter((task) => options.filter?.(task) ?? true).filter((task) => badges.get(task.id)?.ready === true).toSorted((left, right) => {
2559
+ const priorityDelta = priorityValue(left) - priorityValue(right);
2560
+ if (priorityDelta !== 0)
2561
+ return priorityDelta;
2562
+ const createdDelta = (left.createdAt ?? "").localeCompare(right.createdAt ?? "");
2563
+ if (createdDelta !== 0)
2564
+ return createdDelta;
2565
+ return left.id.localeCompare(right.id);
2566
+ });
2567
+ return candidates[0] ?? null;
2568
+ }
2247
2569
  // packages/core/src/taskGraphCodes.ts
2248
2570
  var TASK_CODE_RE = /^\[([A-Z0-9]+(?:-[A-Z0-9]+)*)\]\s*/;
2249
2571
  function extractTaskCode(title) {
@@ -2283,11 +2605,11 @@ var PALETTE = [
2283
2605
  { bg: "#132c35", border: "#1783a6", edge: "#53c4e5" },
2284
2606
  { bg: "#26310f", border: "#6d9a19", edge: "#a7da42" }
2285
2607
  ];
2286
- function isObjectRecord2(value) {
2608
+ function isObjectRecord3(value) {
2287
2609
  return typeof value === "object" && value !== null && !Array.isArray(value);
2288
2610
  }
2289
2611
  function readIssueType(task) {
2290
- const metadata = isObjectRecord2(task.metadata) ? task.metadata : null;
2612
+ const metadata = isObjectRecord3(task.metadata) ? task.metadata : null;
2291
2613
  return typeof metadata?.issueType === "string" ? metadata.issueType : null;
2292
2614
  }
2293
2615
  function isGraphTask(task) {
@@ -2582,6 +2904,8 @@ export {
2582
2904
  selectTasksForWorkspace,
2583
2905
  selectTasksByWorkspace,
2584
2906
  selectTasksByStatus,
2907
+ selectTasksAssignedToMe,
2908
+ selectTasksAssignedTo,
2585
2909
  selectTask,
2586
2910
  selectRunsForWorkspace,
2587
2911
  selectRunsForTask,
@@ -2590,6 +2914,7 @@ export {
2590
2914
  selectQueueForWorkspace,
2591
2915
  selectPrimaryWorkspace,
2592
2916
  selectPendingApprovals,
2917
+ selectNextReadyTaskByPriority,
2593
2918
  selectGraphsForWorkspace,
2594
2919
  selectApprovalsForWorkspace,
2595
2920
  selectApprovalsForRun,
@@ -2598,13 +2923,21 @@ export {
2598
2923
  resolveTaskReference,
2599
2924
  readTaskSourceIssueId,
2600
2925
  readTaskMetadataStringList,
2926
+ readTaskDependencyRefs,
2927
+ readTaskAssigneeLogins,
2601
2928
  pruneQueueEntries,
2929
+ projectTaskStatusWithSessions,
2930
+ projectTaskStatusForGrouping,
2931
+ projectRunStatusForTaskGrouping,
2602
2932
  pickDefaultWorkspaceId,
2933
+ normalizeTaskAssigneeFilter,
2934
+ isTaskTerminalStatus,
2603
2935
  extractTaskGroupKey,
2604
2936
  extractTaskCode,
2605
2937
  definePlugin,
2606
2938
  defineConfig,
2607
2939
  createPluginHost,
2940
+ computeTaskDependencyBadges,
2608
2941
  computeTaskBlockingDepths,
2609
2942
  buildTaskReferenceIndex,
2610
2943
  buildTaskGraphLayout,
@@ -0,0 +1,2 @@
1
+ import { RigConfig } from "@rig/contracts";
2
+ export declare function loadConfig(cwd: string): Promise<RigConfig>;