@h-rig/contracts 0.0.6-alpha.157 → 0.0.6-alpha.158

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.
Files changed (126) hide show
  1. package/dist/index.cjs +2340 -6832
  2. package/dist/index.mjs +2116 -6608
  3. package/dist/src/agent-roles.d.ts +8 -0
  4. package/dist/src/browser.d.ts +34 -4
  5. package/dist/src/browser.js +8 -1
  6. package/dist/src/capability-id.d.ts +22 -0
  7. package/dist/src/capability-id.js +8 -0
  8. package/dist/src/cli-output.d.ts +24 -0
  9. package/dist/src/cli-runner.d.ts +43 -0
  10. package/dist/src/cli-runner.js +13 -0
  11. package/dist/src/collab-session-viewer.d.ts +36 -0
  12. package/dist/src/collab-session-viewer.js +13 -0
  13. package/dist/src/config.d.ts +11 -0
  14. package/dist/src/config.js +279 -1098
  15. package/dist/src/control-plane-types.d.ts +41 -1
  16. package/dist/src/control-plane-types.js +9 -25
  17. package/dist/src/dependency-preflight.d.ts +43 -0
  18. package/dist/src/dependency-preflight.js +13 -0
  19. package/dist/src/doctor.d.ts +67 -4
  20. package/dist/src/doctor.js +8 -9
  21. package/dist/src/errors.d.ts +13 -0
  22. package/dist/src/errors.js +17 -0
  23. package/dist/src/github.d.ts +43 -0
  24. package/dist/src/github.js +12 -1
  25. package/dist/src/graph.d.ts +37 -0
  26. package/dist/src/graph.js +13 -0
  27. package/dist/src/guard.d.ts +111 -0
  28. package/dist/src/guard.js +6 -0
  29. package/dist/src/harness-events.d.ts +8 -0
  30. package/dist/src/harness-events.js +1 -0
  31. package/dist/src/help-catalog.d.ts +17 -10
  32. package/dist/src/help-catalog.js +9 -651
  33. package/dist/src/host.d.ts +41 -0
  34. package/dist/src/host.js +13 -0
  35. package/dist/src/identity.d.ts +44 -0
  36. package/dist/src/identity.js +1 -0
  37. package/dist/src/index.d.ts +27 -7
  38. package/dist/src/index.js +2116 -6608
  39. package/dist/src/isolation.d.ts +207 -15
  40. package/dist/src/isolation.js +8 -1
  41. package/dist/src/kernel.d.ts +11 -0
  42. package/dist/src/kernel.js +7 -0
  43. package/dist/src/layout.d.ts +49 -0
  44. package/dist/src/layout.js +10 -0
  45. package/dist/src/lifecycle-capabilities.d.ts +99 -0
  46. package/dist/src/lifecycle-capabilities.js +18 -1
  47. package/dist/src/managed-repos.d.ts +79 -16
  48. package/dist/src/managed-repos.js +12 -1
  49. package/dist/src/memory.d.ts +52 -4
  50. package/dist/src/memory.js +8 -1
  51. package/dist/src/notify.d.ts +46 -0
  52. package/dist/src/notify.js +13 -0
  53. package/dist/src/orchestration.d.ts +0 -3652
  54. package/dist/src/orchestration.js +28 -964
  55. package/dist/src/plugin-hooks.js +22 -3
  56. package/dist/src/plugin.d.ts +47 -0
  57. package/dist/src/plugin.js +24 -3
  58. package/dist/src/prompt.d.ts +29 -0
  59. package/dist/src/prompt.js +13 -0
  60. package/dist/src/provider-instructions.d.ts +26 -4
  61. package/dist/src/provider-instructions.js +8 -1
  62. package/dist/src/provider.js +1 -824
  63. package/dist/src/remote.d.ts +0 -8
  64. package/dist/src/remote.js +229 -1075
  65. package/dist/src/run-discovery.d.ts +79 -0
  66. package/dist/src/run-discovery.js +13 -0
  67. package/dist/src/run-dispatch.d.ts +34 -0
  68. package/dist/src/run-dispatch.js +13 -0
  69. package/dist/src/run-identity.d.ts +47 -0
  70. package/dist/src/run-identity.js +13 -0
  71. package/dist/src/run-journal.d.ts +0 -236
  72. package/dist/src/run-journal.js +249 -1321
  73. package/dist/src/run-read-model.d.ts +234 -0
  74. package/dist/src/run-read-model.js +13 -0
  75. package/dist/src/run-record.d.ts +0 -11
  76. package/dist/src/run-record.js +0 -16
  77. package/dist/src/run-registry-backbone.d.ts +56 -0
  78. package/dist/src/run-registry-backbone.js +13 -0
  79. package/dist/src/run-session-journal.d.ts +1 -25
  80. package/dist/src/run-session-journal.js +0 -1731
  81. package/dist/src/run-status.d.ts +0 -2
  82. package/dist/src/run-status.js +0 -11
  83. package/dist/src/run-timeline.d.ts +0 -3
  84. package/dist/src/run-timeline.js +0 -1498
  85. package/dist/src/runtime-task-context.d.ts +82 -0
  86. package/dist/src/runtime-task-context.js +1 -0
  87. package/dist/src/runtime.js +66 -904
  88. package/dist/src/session-asset-materializer.d.ts +35 -0
  89. package/dist/src/session-asset-materializer.js +13 -0
  90. package/dist/src/setup.d.ts +47 -0
  91. package/dist/src/setup.js +13 -0
  92. package/dist/src/supervisor-journal.js +117 -955
  93. package/dist/src/task-data.d.ts +239 -0
  94. package/dist/src/task-data.js +13 -0
  95. package/dist/src/task-graph-primitives.d.ts +0 -21
  96. package/dist/src/task-graph-primitives.js +0 -318
  97. package/dist/src/task-source.d.ts +65 -0
  98. package/dist/src/task-source.js +12 -0
  99. package/dist/src/task-state-metadata.d.ts +21 -0
  100. package/dist/src/task-state-metadata.js +1 -0
  101. package/dist/src/tool-materializer.d.ts +36 -0
  102. package/dist/src/tool-materializer.js +13 -0
  103. package/dist/src/tool-registry.d.ts +3 -0
  104. package/dist/src/tool-registry.js +58 -0
  105. package/dist/src/toolchain-sources.d.ts +54 -0
  106. package/dist/src/toolchain-sources.js +17 -0
  107. package/dist/src/workflow-journal.d.ts +0 -32
  108. package/dist/src/workflow-journal.js +0 -371
  109. package/dist/src/workspace-config.d.ts +18 -0
  110. package/dist/src/workspace-config.js +13 -0
  111. package/dist/src/workspace.js +73 -911
  112. package/package.json +1 -1
  113. package/dist/src/engine.d.ts +0 -2789
  114. package/dist/src/engine.js +0 -2392
  115. package/dist/src/ipc.d.ts +0 -248
  116. package/dist/src/providerRuntime.d.ts +0 -3949
  117. package/dist/src/providerRuntime.js +0 -1633
  118. package/dist/src/rig.d.ts +0 -783
  119. package/dist/src/rig.js +0 -2537
  120. package/dist/src/server.d.ts +0 -106
  121. package/dist/src/server.js +0 -1056
  122. package/dist/src/serviceFabric.d.ts +0 -62
  123. package/dist/src/serviceFabric.js +0 -1069
  124. package/dist/src/ws.d.ts +0 -747
  125. package/dist/src/ws.js +0 -3126
  126. /package/dist/src/{ipc.js → agent-roles.js} +0 -0
@@ -0,0 +1,239 @@
1
+ /**
2
+ * The TASK-DATA capability seam.
3
+ *
4
+ * Floor-neutral vocab + a single `CapabilityId<TaskDataService>` describing the
5
+ * task-DATA reads and task-command behaviours the lifecycle, scheduler,
6
+ * isolation provisioning, repos, workspace, and CLI surfaces consume. The
7
+ * READ/normalize/validate POLICY behind each method (synchronize task-config,
8
+ * strip metadata, tracker projection, validator dispatch, artifact IO) is owned
9
+ * by `@rig/task-sources-plugin`, which `defineCapability(TASK_DATA_SERVICE_CAPABILITY).provide`s
10
+ * the impl. Consumers `resolve`/`require` it off a built plugin host (or read the
11
+ * boot-installed singleton) WITHOUT importing the provider plugin — this is the
12
+ * seam that replaces the cross-plugin `import("@rig/task-sources-plugin/...")`
13
+ * impl imports (SEAM-ONLY §6.4).
14
+ *
15
+ * Pure: types + one branded id, no behaviour.
16
+ */
17
+ import type { CapabilityId } from "./capability-id";
18
+ import type { TaskConfigEntry, TaskRecord, RegisteredTaskSource, TaskSourceUpdate } from "./task-source";
19
+ import type { TaskRecordReader } from "./isolation";
20
+ import type { RuntimeInstructionProvider } from "./provider-instructions";
21
+ import type { CanonicalTaskLifecycleStatus, TaskStateMetadataEnvelope } from "./task-state-metadata";
22
+ /** Result of a bounded artifact-file read (preview + truncation metadata). */
23
+ export type TaskArtifactReadResult = {
24
+ path: string;
25
+ sizeBytes: number;
26
+ contents: string;
27
+ truncated: boolean;
28
+ maxBytes: number;
29
+ };
30
+ /** One validation category outcome inside a {@link TaskValidationSummary}. */
31
+ export type TaskValidationCategoryResult = {
32
+ category: string;
33
+ status: "pass" | "fail";
34
+ exit_code?: number;
35
+ duration_seconds: number;
36
+ };
37
+ /**
38
+ * The aggregate task-validation outcome a task closeout reads/accepts (the
39
+ * category-rollup shape written to `validation-summary.json` by `taskValidate`).
40
+ * Distinct from the schema-typed run-level `ValidationSummary` in `./validation`.
41
+ */
42
+ export type TaskValidationSummary = {
43
+ status: "pass" | "fail" | "skipped";
44
+ total: number;
45
+ passed: number;
46
+ failed: number;
47
+ categories: TaskValidationCategoryResult[];
48
+ };
49
+ /** A `bd-`/source-id lifecycle status projected from the synced tracker. */
50
+ export type SyncedTrackerStatus = CanonicalTaskLifecycleStatus | "unknown";
51
+ export type SyncedTrackerDependency = {
52
+ issueId: string | null;
53
+ dependsOnId: string | null;
54
+ id?: string | null;
55
+ type: string | null;
56
+ };
57
+ export type SyncedTrackerIssue = {
58
+ id: string;
59
+ title: string | null;
60
+ description: string | null;
61
+ acceptanceCriteria: string | null;
62
+ issueType: string | null;
63
+ status: SyncedTrackerStatus;
64
+ rawStatus: string | null;
65
+ priority: number | null;
66
+ dependencies: SyncedTrackerDependency[];
67
+ };
68
+ export type SyncedTrackerSnapshot = {
69
+ source: "remote" | "local";
70
+ baseOid: string | null;
71
+ issues: SyncedTrackerIssue[];
72
+ taskState: TaskStateMetadataEnvelope;
73
+ };
74
+ /** Optional fallback toggle for synced-tracker reads. */
75
+ export type ReadSyncedTrackerOptions = {
76
+ allowLocalFallback?: boolean;
77
+ };
78
+ /** Result of resolving a single task through the configured task source. */
79
+ export type TaskSourceTaskReadResult = {
80
+ configured: boolean;
81
+ sourceKind: string | null;
82
+ task: TaskRecord | null;
83
+ };
84
+ /** Summary of a `task reopen` operation. */
85
+ export type TaskReopenSummary = {
86
+ mode: "all" | "single";
87
+ requestedTaskId: string | null;
88
+ dryRun: boolean;
89
+ closedFound: number;
90
+ reopened: string[];
91
+ failed: string[];
92
+ skipped: string[];
93
+ };
94
+ /** Identity fields used to resolve a task's source issue. */
95
+ export type SourceTaskIdentity = {
96
+ id?: unknown;
97
+ sourceIssueId?: unknown;
98
+ source_issue_id?: unknown;
99
+ };
100
+ /** Result of pushing a task lifecycle update through the configured source. */
101
+ export type TaskSourceLifecycleUpdateResult = {
102
+ taskId: string;
103
+ updated: boolean;
104
+ source: "plugin" | "compat" | "none" | "server";
105
+ sourceKind: string | null;
106
+ status: unknown;
107
+ projectSync?: unknown;
108
+ };
109
+ /** Input for rendering a task-run lifecycle status comment. */
110
+ export type TaskRunLifecycleCommentInput = {
111
+ runId: string;
112
+ status: string;
113
+ summary: string;
114
+ runtimeWorkspace?: string | null;
115
+ logsDir?: string | null;
116
+ sessionDir?: string | null;
117
+ errorText?: string | null;
118
+ };
119
+ /** Boundary subset of the source-aware task-config reader options. */
120
+ export type SourceAwareTaskConfigReadOptions = {
121
+ configPath?: string;
122
+ allowLocalTaskConfigStatusFallback?: boolean;
123
+ };
124
+ /**
125
+ * The lifecycle status values a run reflects to the task source.
126
+ * Mirrors the type defined in @rig/task-sources-plugin/source-lifecycle —
127
+ * lives here so @rig/run-exec can use it through the TaskDataService seam
128
+ * without a cross-plugin impl import.
129
+ */
130
+ export type RunTaskSourceLifecycleStatus = "running" | "under_review" | "ci_fixing" | "merging" | "closed" | "cancelled" | "needs_attention";
131
+ /**
132
+ * The run identity fields passed when reflecting a run lifecycle event to the
133
+ * task source.
134
+ */
135
+ export type RunTaskSourceLifecycleRun = {
136
+ runId?: string | null;
137
+ taskId?: string | null;
138
+ sourceTask?: unknown;
139
+ worktreePath?: string | null;
140
+ logRoot?: string | null;
141
+ sessionPath?: string | null;
142
+ errorText?: string | null;
143
+ };
144
+ /** Optional overrides for a run lifecycle update. */
145
+ export type RunTaskSourceLifecycleOptions = {
146
+ errorText?: string | null;
147
+ };
148
+ /** Context for building a plugin-backed task-record reader. */
149
+ export type PluginTaskRecordReaderContext = {
150
+ taskSourceRegistry: {
151
+ list(): readonly RegisteredTaskSource[];
152
+ resolveById(id: string): RegisteredTaskSource;
153
+ resolveByKind(kind: string): RegisteredTaskSource;
154
+ };
155
+ };
156
+ /** Options selecting a source for a plugin-backed task-record reader. */
157
+ export type PluginTaskRecordReaderOptions = {
158
+ projectRoot: string;
159
+ sourceId?: string;
160
+ sourceKind?: string;
161
+ };
162
+ /**
163
+ * The task-DATA service contributed by `@rig/task-sources-plugin`. Every method
164
+ * is keyed by `projectRoot` (the service is stateless), so it is safe to install
165
+ * as a boot singleton and read synchronously by substrate consumers.
166
+ */
167
+ export interface TaskDataService {
168
+ currentTaskId(projectRoot: string): string;
169
+ readTaskConfig(projectRoot: string): Record<string, TaskConfigEntry>;
170
+ readSourceTaskConfig(projectRoot: string): Record<string, TaskConfigEntry>;
171
+ lookupTask(projectRoot: string, input: string): string;
172
+ artifactDirForId(projectRoot: string, id: string): string;
173
+ taskInfo(projectRoot: string, taskId?: string, runtimeProviderOverride?: RuntimeInstructionProvider): Promise<void>;
174
+ taskDeps(projectRoot: string, taskId?: string): Promise<void>;
175
+ taskStatus(projectRoot: string): void;
176
+ taskScope(projectRoot: string, expandFiles: boolean, taskId?: string): Promise<void>;
177
+ taskReady(projectRoot: string): Promise<void>;
178
+ taskLookup(projectRoot: string, id: string): string;
179
+ taskRecord(projectRoot: string, type: "decision" | "failure", text: string, taskId?: string): void;
180
+ taskReopen(projectRoot: string, options: {
181
+ all: boolean;
182
+ taskId?: string;
183
+ dryRun?: boolean;
184
+ }): TaskReopenSummary;
185
+ taskValidate(projectRoot: string, taskId?: string, validatorRegistry?: unknown): Promise<boolean>;
186
+ taskArtifacts(projectRoot: string, taskId?: string): void;
187
+ taskArtifactDir(projectRoot: string, taskId?: string): string;
188
+ taskArtifactWrite(projectRoot: string, filename: string, content: string, taskId?: string): void;
189
+ taskArtifactRead(projectRoot: string, filename: string, options?: {
190
+ taskId?: string;
191
+ maxBytes?: number;
192
+ }): TaskArtifactReadResult;
193
+ taskDependencyIds(projectRoot: string, taskId: string): string[];
194
+ changedFilesForTask(projectRoot: string, taskId: string, scoped: boolean): string[];
195
+ pendingFilesForTask(projectRoot: string, taskId: string, scoped: boolean): string[];
196
+ readSourceAwareTaskStatus(projectRoot: string, taskId: string, options?: SourceAwareTaskConfigReadOptions): Promise<unknown>;
197
+ readConfiguredTaskSourceTask(projectRoot: string, taskId: string): Promise<TaskSourceTaskReadResult>;
198
+ updateConfiguredTaskSourceTask(projectRoot: string, input: {
199
+ taskId: string;
200
+ sourceTask?: SourceTaskIdentity | null;
201
+ update: TaskSourceUpdate;
202
+ }): Promise<TaskSourceLifecycleUpdateResult>;
203
+ buildTaskRunLifecycleComment(input: TaskRunLifecycleCommentInput): string;
204
+ /**
205
+ * Compat fallback: push an update to a github-issues-backed task by parsing
206
+ * its `owner/repo#n` source-issue id. Returns false when the id does not match
207
+ * the taskId. Exposed on the seam so the kernel agent-launch executor can apply
208
+ * the source-aware compatibility update without importing the provider plugin.
209
+ */
210
+ updateGithubIssueTaskBySourceIssueId(sourceIssueId: string | null | undefined, taskId: string, update: TaskSourceUpdate): boolean;
211
+ /**
212
+ * Compat fallback: push a status/comment update through the source-aware
213
+ * task-config (github-issues, files, or legacy task-config). Returns false when
214
+ * no writable source is configured. Seam-exposed for the kernel executor.
215
+ */
216
+ updateSourceAwareTaskConfigTask(projectRoot: string, taskId: string, update: TaskSourceUpdate): boolean;
217
+ /**
218
+ * Reflect a run lifecycle event (start/stop/closeout) to the configured task
219
+ * source. Returns null when no taskId is present or no source is configured.
220
+ * Exposed on the seam so @rig/run-exec can call it without importing
221
+ * @rig/task-sources-plugin impl files directly (SEAM-ONLY §6.4).
222
+ */
223
+ updateRunTaskSourceLifecycle(projectRoot: string, run: RunTaskSourceLifecycleRun, status: RunTaskSourceLifecycleStatus, summary: string, options?: RunTaskSourceLifecycleOptions): Promise<TaskSourceLifecycleUpdateResult | null>;
224
+ createLegacyTaskConfigRecordReader(projectRoot: string, options?: {
225
+ configPath?: string;
226
+ }): TaskRecordReader;
227
+ createSourceAwareTaskConfigRecordReader(projectRoot: string, options?: SourceAwareTaskConfigReadOptions): TaskRecordReader;
228
+ createPluginTaskRecordReader(context: PluginTaskRecordReaderContext, options: PluginTaskRecordReaderOptions): TaskRecordReader;
229
+ readSyncedTrackerState(projectRoot: string, deps?: unknown, options?: ReadSyncedTrackerOptions): SyncedTrackerSnapshot;
230
+ listReadyTaskIdsFromTracker(snapshot: SyncedTrackerSnapshot): string[];
231
+ normalizeTaskLifecycleStatus(status: unknown): CanonicalTaskLifecycleStatus | null;
232
+ }
233
+ /** Stable id string for the task-data service capability. */
234
+ export declare const TASK_DATA_SERVICE_CAPABILITY_ID = "task-sources.task-data";
235
+ /**
236
+ * The branded task-data capability id. `defineCapability(TASK_DATA_SERVICE_CAPABILITY)`
237
+ * (provider and consumers, independently) resolves to a `TaskDataService`.
238
+ */
239
+ export declare const TASK_DATA_SERVICE_CAPABILITY: CapabilityId<TaskDataService>;
@@ -0,0 +1,13 @@
1
+ // @bun
2
+ // packages/contracts/src/capability-id.ts
3
+ function makeCapabilityId(id) {
4
+ return id;
5
+ }
6
+
7
+ // packages/contracts/src/task-data.ts
8
+ var TASK_DATA_SERVICE_CAPABILITY_ID = "task-sources.task-data";
9
+ var TASK_DATA_SERVICE_CAPABILITY = makeCapabilityId(TASK_DATA_SERVICE_CAPABILITY_ID);
10
+ export {
11
+ TASK_DATA_SERVICE_CAPABILITY_ID,
12
+ TASK_DATA_SERVICE_CAPABILITY
13
+ };
@@ -44,25 +44,4 @@ export interface TaskDependencyBadgeSummary {
44
44
  readonly dependentCount: number;
45
45
  readonly badges: readonly TaskDependencyBadge[];
46
46
  }
47
- export declare function readTaskMetadataStringList(task: TaskDependencyProjection, key: "dependencies" | "parentChildDeps" | "labels"): string[];
48
- export declare function readTaskBlockingDependencyRefs(task: TaskDependencyProjection): string[];
49
- export declare function readTaskDependencyRefs(task: TaskDependencyProjection): string[];
50
- export declare function readTaskSourceIssueId(task: TaskDependencyProjection): string | null;
51
- export declare function readTaskScope(task: TaskDependencyProjection): string[];
52
47
  export type TaskScopeInput = readonly string[] | TaskDependencyProjection;
53
- export declare function disjointScope(left: TaskScopeInput, right: TaskScopeInput): boolean;
54
- export declare function resolveTaskReference(ref: string, tasksById: ReadonlyMap<string, TaskDependencyProjection>, taskIdByExternalRef: ReadonlyMap<string, string>, taskIdBySourceIssueId: ReadonlyMap<string, string>): string | null;
55
- export declare function buildTaskReferenceIndex<T extends TaskDependencyProjection>(tasks: readonly T[]): {
56
- readonly tasksById: Map<string, T>;
57
- readonly taskIdByExternalRef: Map<string, string>;
58
- readonly taskIdBySourceIssueId: Map<string, string>;
59
- };
60
- export declare function computeTaskBlockingDepths<T extends TaskDependencyProjection>(tasks: readonly T[]): Map<string, number>;
61
- export declare function isTaskTerminalStatus(status: string | null | undefined): boolean;
62
- export declare function computeTaskDependencyBadges(tasks: readonly TaskDependencyProjection[]): Map<string, TaskDependencyBadgeSummary>;
63
- export declare function normalizeTaskStatus(status: unknown): TaskSummary["status"];
64
- export declare function toTaskDependencyProjection(task: TaskProjectionInput): ClientTaskProjection;
65
- export declare function toTaskSummary(task: TaskProjectionInput, defaults?: {
66
- readonly workspaceId?: string;
67
- readonly graphId?: string | null;
68
- }): TaskSummary;
@@ -1,319 +1 @@
1
1
  // @bun
2
- // packages/contracts/src/task-graph-primitives.ts
3
- function isObjectRecord(value) {
4
- return typeof value === "object" && value !== null && !Array.isArray(value);
5
- }
6
- function readStringList(value) {
7
- return Array.isArray(value) ? value.filter((entry) => typeof entry === "string" && entry.length > 0) : [];
8
- }
9
- function unique(values) {
10
- return Array.from(new Set(values));
11
- }
12
- function readTaskMetadataStringList(task, key) {
13
- const taskRecord = task;
14
- const topLevel = readStringList(taskRecord[key]);
15
- if (topLevel.length > 0)
16
- return topLevel;
17
- const metadata = isObjectRecord(task.metadata) ? task.metadata : null;
18
- const metadataList = readStringList(metadata?.[key]);
19
- if (metadataList.length > 0)
20
- return metadataList;
21
- if (key === "dependencies") {
22
- return readStringList(metadata?.deps);
23
- }
24
- return [];
25
- }
26
- function readTaskBlockingDependencyRefs(task) {
27
- return readTaskMetadataStringList(task, "dependencies");
28
- }
29
- function readTaskDependencyRefs(task) {
30
- return unique([
31
- ...readTaskMetadataStringList(task, "dependencies"),
32
- ...readTaskMetadataStringList(task, "parentChildDeps")
33
- ]);
34
- }
35
- function readTaskSourceIssueId(task) {
36
- if (typeof task.sourceIssueId === "string" && task.sourceIssueId.length > 0) {
37
- return task.sourceIssueId;
38
- }
39
- const metadata = isObjectRecord(task.metadata) ? task.metadata : null;
40
- if (typeof metadata?.sourceIssueId === "string" && metadata.sourceIssueId.length > 0) {
41
- return metadata.sourceIssueId;
42
- }
43
- const rigMetadata = isObjectRecord(metadata?._rig) ? metadata._rig : null;
44
- return typeof rigMetadata?.sourceIssueId === "string" && rigMetadata.sourceIssueId.length > 0 ? rigMetadata.sourceIssueId : null;
45
- }
46
- function readTaskScope(task) {
47
- const taskRecord = task;
48
- const topLevel = readStringList(taskRecord.scope);
49
- if (topLevel.length > 0)
50
- return unique(topLevel.map((entry) => entry.trim()).filter((entry) => entry.length > 0));
51
- const metadata = isObjectRecord(task.metadata) ? task.metadata : null;
52
- const metadataScope = readStringList(metadata?.scope);
53
- if (metadataScope.length > 0)
54
- return unique(metadataScope.map((entry) => entry.trim()).filter((entry) => entry.length > 0));
55
- return unique([
56
- ...readStringList(metadata?.files),
57
- ...readStringList(metadata?.paths)
58
- ].map((entry) => entry.trim()).filter((entry) => entry.length > 0));
59
- }
60
- function isScopeList(input) {
61
- return Array.isArray(input);
62
- }
63
- function normalizeScopeInput(input) {
64
- return isScopeList(input) ? unique(input.map((entry) => entry.trim()).filter((entry) => entry.length > 0)) : readTaskScope(input);
65
- }
66
- function disjointScope(left, right) {
67
- const leftScope = new Set(normalizeScopeInput(left));
68
- if (leftScope.size === 0)
69
- return true;
70
- return normalizeScopeInput(right).every((entry) => !leftScope.has(entry));
71
- }
72
- function resolveTaskReference(ref, tasksById, taskIdByExternalRef, taskIdBySourceIssueId) {
73
- if (tasksById.has(ref))
74
- return ref;
75
- return taskIdBySourceIssueId.get(ref) ?? taskIdByExternalRef.get(ref) ?? null;
76
- }
77
- function buildTaskReferenceIndex(tasks) {
78
- return {
79
- tasksById: new Map(tasks.map((task) => [task.id, task])),
80
- taskIdByExternalRef: new Map(tasks.flatMap((task) => task.externalId ? [[task.externalId, task.id]] : [])),
81
- taskIdBySourceIssueId: new Map(tasks.flatMap((task) => {
82
- const sourceIssueId = readTaskSourceIssueId(task);
83
- return sourceIssueId ? [[sourceIssueId, task.id]] : [];
84
- }))
85
- };
86
- }
87
- function computeTaskBlockingDepths(tasks) {
88
- const { tasksById, taskIdByExternalRef, taskIdBySourceIssueId } = buildTaskReferenceIndex(tasks);
89
- const memo = new Map;
90
- const visit = (taskId, stack) => {
91
- const cached = memo.get(taskId);
92
- if (cached !== undefined)
93
- return cached;
94
- if (stack.has(taskId))
95
- return 0;
96
- const task = tasksById.get(taskId);
97
- if (!task)
98
- return 0;
99
- stack.add(taskId);
100
- const blockers = readTaskBlockingDependencyRefs(task).map((ref) => resolveTaskReference(ref, tasksById, taskIdByExternalRef, taskIdBySourceIssueId)).filter((ref) => ref !== null && ref !== taskId);
101
- const depth = blockers.length === 0 ? 0 : Math.max(...blockers.map((blockerId) => visit(blockerId, stack) + 1));
102
- stack.delete(taskId);
103
- memo.set(taskId, depth);
104
- return depth;
105
- };
106
- for (const task of tasks) {
107
- visit(task.id, new Set);
108
- }
109
- return memo;
110
- }
111
- function isTaskTerminalStatus(status) {
112
- switch (status) {
113
- case "closed":
114
- case "completed":
115
- case "done":
116
- case "cancelled":
117
- case "canceled":
118
- return true;
119
- default:
120
- return false;
121
- }
122
- }
123
- function isTaskBlockedStatus(status) {
124
- return status === "blocked";
125
- }
126
- function isTaskRunnableStatus(status) {
127
- if (status === null || status === undefined || status === "")
128
- return true;
129
- if (isTaskTerminalStatus(status) || isTaskBlockedStatus(status))
130
- return false;
131
- switch (status) {
132
- case "ready":
133
- case "open":
134
- case "failed":
135
- return true;
136
- default:
137
- return false;
138
- }
139
- }
140
- function computeTaskDependencyBadges(tasks) {
141
- const index = buildTaskReferenceIndex(tasks);
142
- const blockingDepths = computeTaskBlockingDepths(tasks);
143
- const dependencyIdsByTask = new Map;
144
- const unresolvedRefsByTask = new Map;
145
- const blocksByTask = new Map;
146
- for (const task of tasks) {
147
- const dependencyIds = [];
148
- const unresolvedRefs = [];
149
- for (const ref of readTaskBlockingDependencyRefs(task)) {
150
- const dependencyId = resolveTaskReference(ref, index.tasksById, index.taskIdByExternalRef, index.taskIdBySourceIssueId);
151
- if (dependencyId && dependencyId !== task.id) {
152
- dependencyIds.push(dependencyId);
153
- const blocks = blocksByTask.get(dependencyId);
154
- if (blocks) {
155
- blocks.push(task.id);
156
- } else {
157
- blocksByTask.set(dependencyId, [task.id]);
158
- }
159
- } else {
160
- unresolvedRefs.push(ref);
161
- }
162
- }
163
- dependencyIdsByTask.set(task.id, unique(dependencyIds));
164
- unresolvedRefsByTask.set(task.id, unique(unresolvedRefs));
165
- }
166
- const summaries = new Map;
167
- for (const task of tasks) {
168
- const dependencyIds = dependencyIdsByTask.get(task.id) ?? [];
169
- const unresolvedDependencyRefs = unresolvedRefsByTask.get(task.id) ?? [];
170
- const blockedBy = dependencyIds.filter((dependencyId) => {
171
- const dependency = index.tasksById.get(dependencyId);
172
- return dependency ? !isTaskTerminalStatus(dependency.status) : false;
173
- });
174
- const blocks = unique(blocksByTask.get(task.id) ?? []);
175
- const blocked = isTaskBlockedStatus(task.status) || blockedBy.length > 0;
176
- const ready = isTaskRunnableStatus(task.status) && !blocked;
177
- const badges = [];
178
- if (blocked) {
179
- badges.push({
180
- kind: "blocked",
181
- label: blockedBy.length > 0 ? `blocked \xD7${blockedBy.length}` : "blocked",
182
- description: blockedBy.length > 0 ? `Waiting on ${blockedBy.join(", ")}.` : "Task source marks this task blocked.",
183
- ...blockedBy.length > 0 ? { count: blockedBy.length } : {},
184
- taskIds: blockedBy
185
- });
186
- } else if (ready) {
187
- badges.push({
188
- kind: "ready",
189
- label: "ready",
190
- description: "No open dependencies block this task."
191
- });
192
- }
193
- if (dependencyIds.length > 0 || blocks.length > 0 || unresolvedDependencyRefs.length > 0) {
194
- badges.push({
195
- kind: "dependency",
196
- label: `deps ${dependencyIds.length}/${blocks.length}`,
197
- description: [
198
- dependencyIds.length > 0 ? `Depends on ${dependencyIds.join(", ")}.` : null,
199
- blocks.length > 0 ? `Blocks ${blocks.join(", ")}.` : null,
200
- unresolvedDependencyRefs.length > 0 ? `Unresolved refs: ${unresolvedDependencyRefs.join(", ")}.` : null
201
- ].filter((part) => part !== null).join(" "),
202
- count: dependencyIds.length + blocks.length,
203
- taskIds: unique([...dependencyIds, ...blocks])
204
- });
205
- }
206
- summaries.set(task.id, {
207
- taskId: task.id,
208
- blockingDepth: blockingDepths.get(task.id) ?? 0,
209
- dependencyIds,
210
- unresolvedDependencyRefs,
211
- blockedBy,
212
- blocks,
213
- blocked,
214
- ready,
215
- dependencyCount: dependencyIds.length,
216
- dependentCount: blocks.length,
217
- badges
218
- });
219
- }
220
- return summaries;
221
- }
222
- var TASK_STATUSES = new Set([
223
- "draft",
224
- "open",
225
- "ready",
226
- "queued",
227
- "running",
228
- "in_progress",
229
- "under_review",
230
- "blocked",
231
- "unknown",
232
- "completed",
233
- "failed",
234
- "cancelled",
235
- "closed"
236
- ]);
237
- function stringValue(value) {
238
- return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
239
- }
240
- function stringArray(value) {
241
- return Array.isArray(value) ? value.filter((entry) => typeof entry === "string" && entry.trim().length > 0).map((entry) => entry.trim()) : [];
242
- }
243
- function numberOrNull(value) {
244
- return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : null;
245
- }
246
- function metadataOf(task) {
247
- return isObjectRecord(task.metadata) ? task.metadata : {};
248
- }
249
- function normalizeTaskStatus(status) {
250
- const token = typeof status === "string" ? status.trim().toLowerCase() : "";
251
- if (token === "done")
252
- return "completed";
253
- if (token === "canceled")
254
- return "cancelled";
255
- return TASK_STATUSES.has(token) ? token : "unknown";
256
- }
257
- function toTaskDependencyProjection(task) {
258
- const metadata = metadataOf(task);
259
- return {
260
- id: String(task.id),
261
- title: stringValue(task.title),
262
- status: normalizeTaskStatus(task.status),
263
- priority: numberOrNull(task.priority),
264
- metadata,
265
- externalId: stringValue(task.externalId),
266
- sourceIssueId: stringValue(task.sourceIssueId),
267
- dependencies: stringArray(task.dependencies),
268
- parentChildDeps: stringArray(task.parentChildDeps),
269
- createdAt: stringValue(task.createdAt) ?? "",
270
- updatedAt: stringValue(task.updatedAt) ?? "",
271
- role: stringValue(task.role),
272
- scope: stringArray(task.scope),
273
- validationKeys: stringArray(task.validationKeys),
274
- labels: stringArray(task.labels),
275
- assignees: task.assignees,
276
- assignedTo: task.assignedTo
277
- };
278
- }
279
- function toTaskSummary(task, defaults = {}) {
280
- const projection = toTaskDependencyProjection(task);
281
- const metadata = metadataOf(task);
282
- const createdAt = stringValue(task.createdAt) ?? "1970-01-01T00:00:00.000Z";
283
- const updatedAt = stringValue(task.updatedAt) ?? createdAt;
284
- return {
285
- id: projection.id,
286
- workspaceId: stringValue(task.workspaceId) ?? defaults.workspaceId ?? "workspace",
287
- graphId: stringValue(task.graphId) ?? defaults.graphId ?? null,
288
- externalId: projection.externalId,
289
- title: projection.title ?? projection.id,
290
- description: stringValue(task.description) ?? stringValue(task.body) ?? "",
291
- status: projection.status,
292
- priority: numberOrNull(task.priority),
293
- role: projection.role,
294
- scope: [...projection.scope ?? []],
295
- validationKeys: [...projection.validationKeys ?? []],
296
- ...projection.sourceIssueId ? { sourceIssueId: projection.sourceIssueId } : {},
297
- dependencies: [...projection.dependencies ?? []],
298
- parentChildDeps: [...projection.parentChildDeps ?? []],
299
- metadata,
300
- createdAt,
301
- updatedAt
302
- };
303
- }
304
- export {
305
- toTaskSummary,
306
- toTaskDependencyProjection,
307
- resolveTaskReference,
308
- readTaskSourceIssueId,
309
- readTaskScope,
310
- readTaskMetadataStringList,
311
- readTaskDependencyRefs,
312
- readTaskBlockingDependencyRefs,
313
- normalizeTaskStatus,
314
- isTaskTerminalStatus,
315
- disjointScope,
316
- computeTaskDependencyBadges,
317
- computeTaskBlockingDepths,
318
- buildTaskReferenceIndex
319
- };
@@ -1,4 +1,27 @@
1
+ import type { CapabilityId } from "./capability-id";
1
2
  import type { TaskSourceRegistration } from "./plugin";
3
+ import type { TaskBrowserConfig } from "./browser";
4
+ /**
5
+ * A single entry in the on-disk task-config map (`.rig/task-config.json`).
6
+ * Floor-neutral DATA shape. The READ/normalize POLICY (synchronize, strip
7
+ * metadata, validation-description extraction) is owned by
8
+ * @rig/task-sources-plugin (`task-state`), NOT the floor.
9
+ */
10
+ export type TaskConfigEntry = {
11
+ title?: string;
12
+ status?: string;
13
+ role?: string;
14
+ description?: string;
15
+ acceptance_criteria?: string;
16
+ scope?: string[];
17
+ validation?: string[];
18
+ browser?: TaskBrowserConfig;
19
+ repo_pins?: Record<string, string>;
20
+ criticality?: "core" | "high" | "normal";
21
+ queue_weight?: number;
22
+ creates_repo?: boolean;
23
+ auto_synced?: boolean;
24
+ };
2
25
  /**
3
26
  * A single task record returned by a task source adapter.
4
27
  * Open-ended to allow adapters to include source-specific fields.
@@ -9,6 +32,30 @@ export interface TaskRecord {
9
32
  status: "ready" | "in_progress" | "closed" | "blocked" | "open" | string;
10
33
  [extra: string]: unknown;
11
34
  }
35
+ /**
36
+ * The NORMALIZED, surface-facing task shape (the projection consumers read).
37
+ * The TYPE is floor-neutral vocab and lives here in contracts; the
38
+ * normalization POLICY that produces it (field-mapping a raw `TaskRecord` into
39
+ * this shape — title/body/url/dependency fallback chains) is owned by
40
+ * @rig/task-sources-plugin (`toRigTask`), NOT by the floor.
41
+ */
42
+ export type RigTask = {
43
+ readonly id: string;
44
+ readonly title?: string | null;
45
+ readonly status?: string | null;
46
+ readonly source?: string | null;
47
+ readonly url?: string | null;
48
+ readonly body?: string | null;
49
+ readonly priority?: number | string | null;
50
+ readonly assignedTo?: string | readonly string[] | null;
51
+ readonly assignees?: readonly string[] | null;
52
+ readonly dependencies?: readonly string[] | null;
53
+ readonly parentChildDeps?: readonly string[] | null;
54
+ readonly metadata?: Record<string, unknown> | null;
55
+ readonly [key: string]: unknown;
56
+ };
57
+ /** Alias retained for call sites that accept any task-like projection. */
58
+ export type TaskLike = RigTask;
12
59
  /**
13
60
  * A registered task source adapter — combines the plugin-level registration
14
61
  * metadata with the runtime-callable interface.
@@ -35,3 +82,21 @@ export interface RegisteredTaskSource extends TaskSourceRegistration {
35
82
  updateTask?(id: string, update: TaskSourceUpdate): Promise<void>;
36
83
  create?(input: TaskSourceCreateInput): Promise<TaskSourceCreateResult>;
37
84
  }
85
+ export type TaskIoCreateResult = {
86
+ readonly taskId: string | null;
87
+ readonly source: string;
88
+ readonly result: unknown;
89
+ };
90
+ /**
91
+ * Source-owned task IO projection seam. Providers normalize raw task-source
92
+ * records into RigTask and adapt generic task creation payloads to the
93
+ * configured source; consumers resolve this instead of importing @rig/core
94
+ * task-source glue.
95
+ */
96
+ export interface TaskIoService {
97
+ listTasks(projectRoot: string): Promise<readonly RigTask[]>;
98
+ getTask(projectRoot: string, taskId: string): Promise<RigTask | null>;
99
+ createTask(projectRoot: string, task: Record<string, unknown>): Promise<TaskIoCreateResult>;
100
+ }
101
+ export declare const TASK_IO_SERVICE_CAPABILITY_ID = "task-sources.task-io";
102
+ export declare const TASK_IO_SERVICE_CAPABILITY: CapabilityId<TaskIoService>;