@h-rig/core 0.0.6-alpha.14 → 0.0.6-alpha.141

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.
@@ -0,0 +1,105 @@
1
+ import type { BlockerClassifierRegistration, CliCommandRegistration, HookImplementation, PanelRegistration, ProductCapabilityRegistration, RegisteredTaskSource, RigConfig, RigPlugin, StageRun, TaskSourceConfig, TaskSourceRegistration, ValidatorRegistration } from "@rig/contracts";
2
+ export interface ValidatorResult {
3
+ id: string;
4
+ passed: boolean;
5
+ summary: string;
6
+ details?: string;
7
+ }
8
+ export interface ValidatorContext {
9
+ taskId: string;
10
+ workspaceRoot: string;
11
+ scope: readonly string[];
12
+ monorepoRoot?: string;
13
+ artifactsDir?: string;
14
+ taskConfig?: unknown;
15
+ }
16
+ export interface RegisteredValidator extends ValidatorRegistration {
17
+ run(ctx: ValidatorContext): Promise<ValidatorResult>;
18
+ }
19
+ /**
20
+ * Project context handed to task-source factories at instantiation. The
21
+ * server process's cwd is NOT necessarily the project root (workspace-spawned
22
+ * servers run from the engine checkout), so factories that touch the
23
+ * filesystem must resolve relative config paths against `projectRoot`,
24
+ * never cwd.
25
+ */
26
+ export interface TaskSourceFactoryContext {
27
+ projectRoot: string;
28
+ /**
29
+ * Full project config for adapters that need source-adjacent top-level
30
+ * settings (for example github.projects). Factories should still treat
31
+ * TaskSourceConfig as the primary adapter config.
32
+ */
33
+ rigConfig?: RigConfig;
34
+ }
35
+ /**
36
+ * Executable task-source factory contributed by a plugin. A plugin
37
+ * registers a TaskSourceRegistration metadata entry (with `id` and `kind`)
38
+ * AND a factory here that turns a TaskSourceConfig into a RegisteredTaskSource.
39
+ *
40
+ * `kind` is matched against `config.taskSource.kind` at boot. The first
41
+ * matching plugin factory wins; if multiple plugins claim the same kind,
42
+ * `createPluginHost` throws a duplicate-kind error.
43
+ */
44
+ export interface TaskSourceFactoryEntry extends TaskSourceRegistration {
45
+ factory(config: TaskSourceConfig, context?: TaskSourceFactoryContext): RegisteredTaskSource;
46
+ }
47
+ export interface RuntimeFeatureCapability extends ProductCapabilityRegistration {
48
+ run?: (input: unknown) => Promise<unknown> | unknown;
49
+ }
50
+ export interface RuntimePanelProducer extends PanelRegistration {
51
+ produce?: (context?: unknown) => Promise<unknown> | unknown;
52
+ }
53
+ export interface RuntimeBlockerClassifier extends BlockerClassifierRegistration {
54
+ classify(input: unknown): Promise<unknown> | unknown;
55
+ }
56
+ export interface RuntimeCliContext {
57
+ projectRoot: string;
58
+ outputMode?: string;
59
+ dryRun?: boolean;
60
+ }
61
+ export interface RuntimeCliCommand extends CliCommandRegistration {
62
+ run(context: RuntimeCliContext, args: readonly string[]): Promise<unknown> | unknown;
63
+ }
64
+ export interface RigPluginRuntime {
65
+ validators?: readonly RegisteredValidator[];
66
+ taskSources?: readonly TaskSourceFactoryEntry[];
67
+ /**
68
+ * Typed hook implementations keyed by hook id. Each key must match a
69
+ * declared `contributes.hooks` entry on the same plugin. A typed hook and
70
+ * a metadata `command` string are mutually exclusive per hook — and when
71
+ * this channel is present, every declared hook must be implemented one way
72
+ * or the other (same all-or-none rule as validators). The runtime's
73
+ * hook-materializer generates the shim command that routes Claude Code's
74
+ * hook invocation to the typed function (see
75
+ * `@rig/runtime/control-plane/hook-runner`).
76
+ */
77
+ hooks?: Record<string, HookImplementation>;
78
+ /**
79
+ * Executable stage implementations keyed by stage id — the runtime counterpart
80
+ * to `contributes.stageMutations` (which carries only the ordering descriptor).
81
+ * When a plugin inserts/replaces a stage, its `run(ctx)` lives here. The plugin
82
+ * host flattens these (`listStageExecutors()`) so the kernel's stage runner can
83
+ * execute plugin-contributed stages (e.g. the docs-drift pre-merge gate).
84
+ */
85
+ stages?: Record<string, StageRun>;
86
+ /**
87
+ * Executable product-capability registrations. This is deliberately separate
88
+ * from `capabilities`: that map is reserved for the five kernel provider
89
+ * capability tags resolved by `@rig/kernel-seed`.
90
+ */
91
+ featureCapabilities?: readonly RuntimeFeatureCapability[];
92
+ panels?: readonly RuntimePanelProducer[];
93
+ blockerClassifiers?: readonly RuntimeBlockerClassifier[];
94
+ cliCommands?: readonly RuntimeCliCommand[];
95
+ /**
96
+ * Executable kernel-capability providers keyed by **capability tag**
97
+ * (`transport`, `journal`, …) — the same shape the kernel-seed resolver reads
98
+ * via `plugin.runtime.capabilities[tag]`. Which tags a plugin provides is
99
+ * declared by the top-level `provides: CapabilityTag[]`; this holds the impls.
100
+ */
101
+ capabilities?: Record<string, unknown>;
102
+ }
103
+ export type RigPluginWithRuntime = RigPlugin & {
104
+ __runtime?: RigPluginRuntime;
105
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Pure builder that turns a small input shape into the source text of a
3
+ * `rig.config.ts` file. Shared between the CLI `rig init` wizard and the
4
+ * desktop app's in-app setup wizard so both surfaces produce identical
5
+ * output.
6
+ *
7
+ * Pure — no fs, no node, no imports outside this file. Safe to bundle into
8
+ * a renderer (Vite, esbuild, webpack).
9
+ */
10
+ export type RigInitConfigInput = {
11
+ projectName: string;
12
+ projectRepo?: string;
13
+ taskSource: {
14
+ kind: "github-issues";
15
+ owner: string;
16
+ repo: string;
17
+ assignee?: string;
18
+ } | {
19
+ kind: "files";
20
+ path: string;
21
+ };
22
+ useStandardPlugin: boolean;
23
+ /**
24
+ * Remote run placement (ssh target, e.g. `ubuntu@host`). Omit / empty = local
25
+ * placement (runs execute where `rig` starts) — the default. Surfaced as a
26
+ * dedicated `rig init` step; written to `runtime.server.sshTarget`.
27
+ */
28
+ sshTarget?: string;
29
+ };
30
+ export declare function buildRigInitConfigSource(input: RigInitConfigInput): string;
@@ -2,22 +2,25 @@
2
2
  // packages/core/src/rig-init-builder.ts
3
3
  function buildRigInitConfigSource(input) {
4
4
  const lines = [`import { defineConfig } from "@rig/core";`];
5
- if (input.useStandardPlugin && input.taskSource.kind === "github-issues") {
6
- lines.push(`import standard, { createStateGitHubCredentialProvider } from "@rig/standard-plugin";`);
7
- } else if (input.useStandardPlugin) {
8
- lines.push(`import standard from "@rig/standard-plugin";`);
5
+ if (input.useStandardPlugin) {
6
+ lines.push(`import { standardProjectPlugins } from "@rig/standard-plugin/bundle";`);
7
+ if (input.taskSource.kind === "github-issues") {
8
+ lines.push(`import { createStateGitHubCredentialProvider } from "@rig/standard-plugin";`);
9
+ }
9
10
  }
10
11
  lines.push(``, `export default defineConfig({`);
11
12
  const projectRepo = input.projectRepo ?? (input.taskSource.kind === "github-issues" ? `${input.taskSource.owner}/${input.taskSource.repo}` : undefined);
12
13
  lines.push(projectRepo ? ` project: { name: ${JSON.stringify(input.projectName)}, repo: ${JSON.stringify(projectRepo)} },` : ` project: { name: ${JSON.stringify(input.projectName)} },`);
13
14
  if (input.useStandardPlugin && input.taskSource.kind === "github-issues") {
14
- lines.push(` plugins: [standard({`);
15
- lines.push(` githubCredentialProvider: createStateGitHubCredentialProvider(),`);
16
- lines.push(` githubWorkspaceId: ${JSON.stringify(`${input.taskSource.owner}/${input.taskSource.repo}`)},`);
17
- lines.push(` githubUserId: process.env.RIG_GITHUB_USER_ID ?? "server-selected-user",`);
15
+ lines.push(` plugins: [...standardProjectPlugins({`);
16
+ lines.push(` standard: {`);
17
+ lines.push(` githubCredentialProvider: createStateGitHubCredentialProvider(),`);
18
+ lines.push(` githubWorkspaceId: ${JSON.stringify(`${input.taskSource.owner}/${input.taskSource.repo}`)},`);
19
+ lines.push(` githubUserId: process.env.RIG_GITHUB_USER_ID ?? "server-selected-user",`);
20
+ lines.push(` },`);
18
21
  lines.push(` })],`);
19
22
  } else {
20
- lines.push(` plugins: [${input.useStandardPlugin ? "standard()" : ""}],`);
23
+ lines.push(` plugins: [${input.useStandardPlugin ? "...standardProjectPlugins()" : ""}],`);
21
24
  }
22
25
  if (input.taskSource.kind === "github-issues") {
23
26
  lines.push(` taskSource: {`);
@@ -37,7 +40,8 @@ function buildRigInitConfigSource(input) {
37
40
  lines.push(` },`);
38
41
  }
39
42
  lines.push(` workspace: { mainRepo: ".", isolation: "worktree" },`);
40
- lines.push(` runtime: { harness: "pi", mode: "yolo" },`);
43
+ const sshTarget = input.sshTarget?.trim();
44
+ lines.push(sshTarget ? ` runtime: { harness: "pi", mode: "yolo", server: { sshTarget: ${JSON.stringify(sshTarget)} } },` : ` runtime: { harness: "pi", mode: "yolo" }, // server.sshTarget unset = local placement`);
41
45
  lines.push(` planning: { mode: "auto" },`);
42
46
  lines.push(` github: {`);
43
47
  lines.push(` issueUpdates: "lifecycle",`);
@@ -0,0 +1,220 @@
1
+ import type { ArtifactSummary, ApprovalSummary, EngineReadModel, GraphSummary, QueueEntry, RemoteConnectionSummary, RemoteEndpoint, RunId, RunJournalProjection, RunStatus, RunSummary, TaskId, TaskStatus, TaskSummary, UserInputRequestSummary, WorkspaceId, WorkspaceSummary } from "@rig/contracts";
2
+ import type { TaskDependencyProjection } from "./taskGraph";
3
+ export declare function selectWorkspaces(snapshot: EngineReadModel | null): readonly WorkspaceSummary[];
4
+ export declare function selectPrimaryWorkspace(snapshot: EngineReadModel | null): WorkspaceSummary | null;
5
+ export declare function pickDefaultWorkspaceId(snapshot: EngineReadModel | null): WorkspaceId | null;
6
+ export declare function selectWorkspace(snapshot: EngineReadModel | null, workspaceId: WorkspaceId | null): WorkspaceSummary | null;
7
+ export declare function selectTask(snapshot: EngineReadModel | null, taskId: TaskId | null): TaskSummary | null;
8
+ export declare function selectTasksByWorkspace(snapshot: EngineReadModel | null, workspaceId: WorkspaceId | null): TaskSummary[];
9
+ export declare const selectTasksForWorkspace: typeof selectTasksByWorkspace;
10
+ export declare function selectTasksByStatus(snapshot: EngineReadModel | null, status: TaskStatus): TaskSummary[];
11
+ export type RigTaskSessionProjection = Pick<RunJournalProjection, "record" | "status" | "lastEventAt"> & {
12
+ readonly taskId?: string | null;
13
+ };
14
+ export interface RigTaskStatusGroupingInput<T extends TaskDependencyProjection = TaskDependencyProjection> {
15
+ readonly tasks: readonly T[];
16
+ readonly sessions?: readonly RigTaskSessionProjection[];
17
+ readonly workspaceId?: string | null;
18
+ }
19
+ export interface RigTaskStatusGroup<T extends TaskDependencyProjection = TaskDependencyProjection> {
20
+ readonly status: string;
21
+ readonly tasks: readonly T[];
22
+ }
23
+ export declare function projectTaskStatusForGrouping(status: string | null | undefined): string;
24
+ export declare function projectRunStatusForTaskGrouping(status: RunStatus | null | undefined): string | null;
25
+ export declare function projectTaskStatusWithSessions(task: TaskDependencyProjection, sessionsByTask?: ReadonlyMap<string, RigTaskSessionProjection>): string;
26
+ export declare function selectTasksGroupedByStatus(snapshot: EngineReadModel | null, workspaceId: WorkspaceId | null): Array<{
27
+ status: string;
28
+ tasks: readonly TaskSummary[];
29
+ }>;
30
+ export declare function selectTasksGroupedByStatus<T extends TaskDependencyProjection>(input: RigTaskStatusGroupingInput<T>): Array<RigTaskStatusGroup<T>>;
31
+ export declare function normalizeTaskAssigneeFilter(assignee: string | null | undefined, currentUserLogin?: string | null): string | null;
32
+ export declare function readTaskAssigneeLogins(task: TaskDependencyProjection): readonly string[];
33
+ export declare function taskMatchesAssigneeFilter(task: TaskDependencyProjection, assignee: string | null | undefined, options?: {
34
+ readonly currentUserLogin?: string | null;
35
+ }): boolean;
36
+ export declare function selectTasksAssignedTo<T extends TaskDependencyProjection>(tasks: readonly T[], assignee: string | null | undefined, options?: {
37
+ readonly currentUserLogin?: string | null;
38
+ }): T[];
39
+ export declare function selectTasksAssignedToMe<T extends TaskDependencyProjection>(tasks: readonly T[], currentUserLogin: string | null | undefined): T[];
40
+ export declare function selectRun(snapshot: EngineReadModel | null, runId: RunId | null): RunSummary | null;
41
+ export declare function selectRunsByTask(snapshot: EngineReadModel | null, taskId: TaskId | null): RunSummary[];
42
+ export declare const selectRunsForTask: typeof selectRunsByTask;
43
+ export declare function selectRunsForWorkspace(snapshot: EngineReadModel | null, workspaceId: WorkspaceId | null): RunSummary[];
44
+ export declare function selectAdhocRuns(snapshot: EngineReadModel | null): RunSummary[];
45
+ export declare function selectAdhocRunsForWorkspace(snapshot: EngineReadModel | null, workspaceId: WorkspaceId | null): RunSummary[];
46
+ export declare function selectGraphsForWorkspace(snapshot: EngineReadModel | null, workspaceId: WorkspaceId | null): GraphSummary[];
47
+ export declare function selectQueueForWorkspace(snapshot: EngineReadModel | null, workspaceId: WorkspaceId | null): QueueEntry[];
48
+ export declare function selectPendingApprovals(snapshot: EngineReadModel | null): ApprovalSummary[];
49
+ export declare function selectApprovalsForRun(snapshot: EngineReadModel | null, runId: RunId | null): ApprovalSummary[];
50
+ export declare function selectPendingApprovalsForRun(snapshot: EngineReadModel | null, runId: RunId | null): ApprovalSummary[];
51
+ export declare function selectApprovalsForWorkspace(snapshot: EngineReadModel | null, workspaceId: WorkspaceId | null): ApprovalSummary[];
52
+ export declare function selectUserInputsForRun(snapshot: EngineReadModel | null, runId: RunId | null): UserInputRequestSummary[];
53
+ export declare function selectPendingUserInputs(snapshot: EngineReadModel | null): UserInputRequestSummary[];
54
+ export declare function selectPendingUserInputsForRun(snapshot: EngineReadModel | null, runId: RunId | null): UserInputRequestSummary[];
55
+ export declare function selectUserInputsForWorkspace(snapshot: EngineReadModel | null, workspaceId: WorkspaceId | null): UserInputRequestSummary[];
56
+ export declare function selectRuntimeForRun(snapshot: EngineReadModel | null, runId: RunId | null): {
57
+ readonly id: string & import("effect/Brand").Brand<"EngineRuntimeId">;
58
+ readonly updatedAt: string;
59
+ readonly status: "starting" | "running" | "interrupted" | "failed" | "prepared" | "exited" | "destroyed";
60
+ readonly startedAt: string | null;
61
+ readonly pid: number | null;
62
+ readonly stateDir: string | null;
63
+ readonly workspaceId: string & import("effect/Brand").Brand<"WorkspaceId">;
64
+ readonly adapterKind: "pi";
65
+ readonly workspaceDir: string | null;
66
+ readonly homeDir: string | null;
67
+ readonly tmpDir: string | null;
68
+ readonly cacheDir: string | null;
69
+ readonly logsDir: string | null;
70
+ readonly sessionDir: string | null;
71
+ readonly sessionLogPath: string | null;
72
+ readonly exitedAt: string | null;
73
+ readonly runId: string & import("effect/Brand").Brand<"RunId">;
74
+ readonly sandboxMode: "read-only" | "workspace-write" | "danger-full-access";
75
+ readonly isolationMode: "none" | "env" | "worktree";
76
+ readonly executionTarget?: "remote" | "local" | undefined;
77
+ readonly remoteHostId?: string | null | undefined;
78
+ } | null;
79
+ export declare function selectLatestRuntimeForTask(snapshot: EngineReadModel | null, taskId: TaskId | null): {
80
+ readonly id: string & import("effect/Brand").Brand<"EngineRuntimeId">;
81
+ readonly updatedAt: string;
82
+ readonly status: "starting" | "running" | "interrupted" | "failed" | "prepared" | "exited" | "destroyed";
83
+ readonly startedAt: string | null;
84
+ readonly pid: number | null;
85
+ readonly stateDir: string | null;
86
+ readonly workspaceId: string & import("effect/Brand").Brand<"WorkspaceId">;
87
+ readonly adapterKind: "pi";
88
+ readonly workspaceDir: string | null;
89
+ readonly homeDir: string | null;
90
+ readonly tmpDir: string | null;
91
+ readonly cacheDir: string | null;
92
+ readonly logsDir: string | null;
93
+ readonly sessionDir: string | null;
94
+ readonly sessionLogPath: string | null;
95
+ readonly exitedAt: string | null;
96
+ readonly runId: string & import("effect/Brand").Brand<"RunId">;
97
+ readonly sandboxMode: "read-only" | "workspace-write" | "danger-full-access";
98
+ readonly isolationMode: "none" | "env" | "worktree";
99
+ readonly executionTarget?: "remote" | "local" | undefined;
100
+ readonly remoteHostId?: string | null | undefined;
101
+ } | null;
102
+ export declare function selectActionsForTask(snapshot: EngineReadModel | null, taskId: TaskId | null): {
103
+ readonly id: string & import("effect/Brand").Brand<"ActionId">;
104
+ readonly title: string;
105
+ readonly completedAt: string | null;
106
+ readonly payload: unknown;
107
+ readonly startedAt: string;
108
+ readonly state: string;
109
+ readonly messageId: (string & import("effect/Brand").Brand<"MessageId">) | null;
110
+ readonly runId: string & import("effect/Brand").Brand<"RunId">;
111
+ readonly detail: string | null;
112
+ readonly actionType: string;
113
+ }[];
114
+ export declare function selectApprovalsForTask(snapshot: EngineReadModel | null, taskId: TaskId | null): {
115
+ readonly id: string;
116
+ readonly createdAt: string;
117
+ readonly status: "pending" | "resolved";
118
+ readonly payload: unknown;
119
+ readonly runId: string & import("effect/Brand").Brand<"RunId">;
120
+ readonly actionId: string | null;
121
+ readonly resolvedAt: string | null;
122
+ readonly requestKind: string;
123
+ }[];
124
+ export declare function selectUserInputsForTask(snapshot: EngineReadModel | null, taskId: TaskId | null): {
125
+ readonly id: string;
126
+ readonly createdAt: string;
127
+ readonly status: "pending" | "resolved";
128
+ readonly payload: unknown;
129
+ readonly runId: string & import("effect/Brand").Brand<"RunId">;
130
+ readonly resolvedAt: string | null;
131
+ }[];
132
+ export declare function selectValidationsForRun(snapshot: EngineReadModel | null, runId: RunId | null): {
133
+ readonly id: string & import("effect/Brand").Brand<"ValidationResultId">;
134
+ readonly status: "running" | "pending" | "failed" | "passed" | "skipped";
135
+ readonly completedAt: string | null;
136
+ readonly startedAt: string;
137
+ readonly taskId: (string & import("effect/Brand").Brand<"TaskId">) | null;
138
+ readonly runId: string & import("effect/Brand").Brand<"RunId">;
139
+ readonly validatorKey: string;
140
+ readonly output: unknown;
141
+ }[];
142
+ export declare function selectValidationsForTask(snapshot: EngineReadModel | null, taskId: TaskId | null): {
143
+ readonly id: string & import("effect/Brand").Brand<"ValidationResultId">;
144
+ readonly status: "running" | "pending" | "failed" | "passed" | "skipped";
145
+ readonly completedAt: string | null;
146
+ readonly startedAt: string;
147
+ readonly taskId: (string & import("effect/Brand").Brand<"TaskId">) | null;
148
+ readonly runId: string & import("effect/Brand").Brand<"RunId">;
149
+ readonly validatorKey: string;
150
+ readonly output: unknown;
151
+ }[];
152
+ export declare function selectFailedValidations(snapshot: EngineReadModel | null, runId: RunId | null): {
153
+ readonly id: string & import("effect/Brand").Brand<"ValidationResultId">;
154
+ readonly status: "running" | "pending" | "failed" | "passed" | "skipped";
155
+ readonly completedAt: string | null;
156
+ readonly startedAt: string;
157
+ readonly taskId: (string & import("effect/Brand").Brand<"TaskId">) | null;
158
+ readonly runId: string & import("effect/Brand").Brand<"RunId">;
159
+ readonly validatorKey: string;
160
+ readonly output: unknown;
161
+ }[];
162
+ export declare function selectReviewsForRun(snapshot: EngineReadModel | null, runId: RunId | null): {
163
+ readonly id: string & import("effect/Brand").Brand<"ReviewResultId">;
164
+ readonly createdAt: string;
165
+ readonly status: "running" | "error" | "rejected" | "pending" | "approved";
166
+ readonly completedAt: string | null;
167
+ readonly summary: string | null;
168
+ readonly provider: string;
169
+ readonly mode: "required" | "off" | "advisory";
170
+ readonly taskId: (string & import("effect/Brand").Brand<"TaskId">) | null;
171
+ readonly runId: string & import("effect/Brand").Brand<"RunId">;
172
+ readonly output: unknown;
173
+ }[];
174
+ export declare function selectReviewsForTask(snapshot: EngineReadModel | null, taskId: TaskId | null): {
175
+ readonly id: string & import("effect/Brand").Brand<"ReviewResultId">;
176
+ readonly createdAt: string;
177
+ readonly status: "running" | "error" | "rejected" | "pending" | "approved";
178
+ readonly completedAt: string | null;
179
+ readonly summary: string | null;
180
+ readonly provider: string;
181
+ readonly mode: "required" | "off" | "advisory";
182
+ readonly taskId: (string & import("effect/Brand").Brand<"TaskId">) | null;
183
+ readonly runId: string & import("effect/Brand").Brand<"RunId">;
184
+ readonly output: unknown;
185
+ }[];
186
+ export declare function selectArtifactsForRun(snapshot: EngineReadModel | null, runId: RunId | null): ArtifactSummary[];
187
+ export declare function selectArtifactsForTask(snapshot: EngineReadModel | null, taskId: TaskId | null): ArtifactSummary[];
188
+ export declare function selectPolicyDecisionsForTask(snapshot: EngineReadModel | null, taskId: TaskId | null): {
189
+ readonly id: string;
190
+ readonly createdAt: string;
191
+ readonly decision: "allow" | "block" | "warn";
192
+ readonly mode: "observe" | "off" | "enforce";
193
+ readonly runId: string & import("effect/Brand").Brand<"RunId">;
194
+ readonly actionId: (string & import("effect/Brand").Brand<"ActionId">) | null;
195
+ readonly reason: string;
196
+ readonly matchedRules: readonly string[];
197
+ }[];
198
+ export declare function selectRemoteEndpoints(snapshot: EngineReadModel | null): readonly RemoteEndpoint[];
199
+ export declare function selectRemoteConnections(snapshot: EngineReadModel | null): readonly RemoteConnectionSummary[];
200
+ export declare function selectRemoteEndpoint(snapshot: EngineReadModel | null, endpointId: string | null): {
201
+ readonly id: string & import("effect/Brand").Brand<"RemoteEndpointId">;
202
+ readonly port: number;
203
+ readonly host: string;
204
+ readonly lastConnectedAt: string | null;
205
+ readonly alias: string;
206
+ readonly token: string;
207
+ readonly addedAt: string;
208
+ readonly tokenConfigured?: boolean | undefined;
209
+ readonly autoConnect?: boolean | undefined;
210
+ } | null;
211
+ export declare function selectRemoteConnection(snapshot: EngineReadModel | null, endpointId: string | null): {
212
+ readonly error: string | null;
213
+ readonly status: "error" | "disconnected" | "connecting" | "authenticating" | "connected" | "reconnecting";
214
+ readonly endpointId: string & import("effect/Brand").Brand<"RemoteEndpointId">;
215
+ readonly connectedAt: string | null;
216
+ readonly tokenExpiresAt: string | null;
217
+ readonly latencyMs: number | null;
218
+ readonly subscribedEvents: readonly string[];
219
+ } | null;
220
+ export declare function selectConnectedRemoteCount(snapshot: EngineReadModel | null): number;
@@ -39,10 +39,40 @@ function projectTaskStatusForGrouping(status) {
39
39
  case "in_progress":
40
40
  case "under_review":
41
41
  return "running";
42
+ case null:
43
+ case undefined:
44
+ case "":
45
+ return "unknown";
42
46
  default:
43
47
  return status;
44
48
  }
45
49
  }
50
+ function projectRunStatusForTaskGrouping(status) {
51
+ switch (status) {
52
+ case "created":
53
+ case "queued":
54
+ case "preparing":
55
+ return "queued";
56
+ case "running":
57
+ case "waiting-approval":
58
+ case "waiting-user-input":
59
+ case "paused":
60
+ case "validating":
61
+ case "reviewing":
62
+ case "closing-out":
63
+ return "running";
64
+ case "needs-attention":
65
+ return "blocked";
66
+ case "failed":
67
+ case "stopped":
68
+ return "ready";
69
+ case "completed":
70
+ return "completed";
71
+ case null:
72
+ case undefined:
73
+ return null;
74
+ }
75
+ }
46
76
  var STATUS_PRIORITY = [
47
77
  "running",
48
78
  "blocked",
@@ -54,11 +84,31 @@ var STATUS_PRIORITY = [
54
84
  "cancelled",
55
85
  "completed"
56
86
  ];
57
- function selectTasksGroupedByStatus(snapshot, workspaceId) {
58
- const tasks = selectTasksByWorkspace(snapshot, workspaceId);
87
+ function taskIdFromSession(session) {
88
+ return session.taskId ?? session.record.taskId ?? null;
89
+ }
90
+ function latestSessionByTask(sessions) {
91
+ const byTask = new Map;
92
+ for (const session of sessions) {
93
+ const taskId = taskIdFromSession(session);
94
+ if (!taskId)
95
+ continue;
96
+ const existing = byTask.get(taskId);
97
+ if (!existing || (session.lastEventAt ?? "").localeCompare(existing.lastEventAt ?? "") >= 0) {
98
+ byTask.set(taskId, session);
99
+ }
100
+ }
101
+ return byTask;
102
+ }
103
+ function projectTaskStatusWithSessions(task, sessionsByTask = new Map) {
104
+ const sessionStatus = projectRunStatusForTaskGrouping(sessionsByTask.get(task.id)?.status);
105
+ return sessionStatus ?? projectTaskStatusForGrouping(task.status);
106
+ }
107
+ function groupTasksByProjectedStatus(tasks, sessions = []) {
108
+ const sessionsByTask = latestSessionByTask(sessions);
59
109
  const byStatus = new Map;
60
110
  for (const task of tasks) {
61
- const projectedStatus = projectTaskStatusForGrouping(task.status);
111
+ const projectedStatus = projectTaskStatusWithSessions(task, sessionsByTask);
62
112
  const group = byStatus.get(projectedStatus);
63
113
  if (group) {
64
114
  group.push(task);
@@ -82,6 +132,69 @@ function selectTasksGroupedByStatus(snapshot, workspaceId) {
82
132
  }
83
133
  return result;
84
134
  }
135
+ function isProjectionGroupingInput(value) {
136
+ return Boolean(value && typeof value === "object" && !("snapshotSequence" in value) && Array.isArray(value.tasks));
137
+ }
138
+ function selectTasksGroupedByStatus(input, workspaceId) {
139
+ if (isProjectionGroupingInput(input)) {
140
+ const filteredTasks = input.workspaceId ? input.tasks.filter((task) => {
141
+ const workspaceTask = task;
142
+ return workspaceTask.workspaceId === input.workspaceId;
143
+ }) : input.tasks;
144
+ return groupTasksByProjectedStatus(filteredTasks, input.sessions);
145
+ }
146
+ const tasks = selectTasksByWorkspace(input, workspaceId ?? null);
147
+ return groupTasksByProjectedStatus(tasks, []);
148
+ }
149
+ function isObjectRecord(value) {
150
+ return typeof value === "object" && value !== null && !Array.isArray(value);
151
+ }
152
+ function normalizeLogin(value) {
153
+ return value.trim().replace(/^@+/, "").toLowerCase();
154
+ }
155
+ function assigneeLoginsFromValue(value) {
156
+ if (!Array.isArray(value))
157
+ return [];
158
+ return value.flatMap((entry) => {
159
+ if (typeof entry === "string" && entry.trim())
160
+ return [normalizeLogin(entry)];
161
+ if (isObjectRecord(entry) && typeof entry.login === "string" && entry.login.trim()) {
162
+ return [normalizeLogin(entry.login)];
163
+ }
164
+ return [];
165
+ });
166
+ }
167
+ function normalizeTaskAssigneeFilter(assignee, currentUserLogin) {
168
+ const trimmed = assignee?.trim();
169
+ if (!trimmed)
170
+ return null;
171
+ if (trimmed === "@me" || trimmed.toLowerCase() === "me") {
172
+ return currentUserLogin?.trim() ? normalizeLogin(currentUserLogin) : null;
173
+ }
174
+ return normalizeLogin(trimmed);
175
+ }
176
+ function readTaskAssigneeLogins(task) {
177
+ const taskRecord = task;
178
+ const metadata = isObjectRecord(task.metadata) ? task.metadata : null;
179
+ const raw = isObjectRecord(metadata?.raw) ? metadata.raw : null;
180
+ return Array.from(new Set([
181
+ ...assigneeLoginsFromValue(taskRecord.assignees),
182
+ ...assigneeLoginsFromValue(metadata?.assignees),
183
+ ...assigneeLoginsFromValue(raw?.assignees)
184
+ ]));
185
+ }
186
+ function taskMatchesAssigneeFilter(task, assignee, options = {}) {
187
+ const normalized = normalizeTaskAssigneeFilter(assignee, options.currentUserLogin);
188
+ if (!normalized)
189
+ return false;
190
+ return readTaskAssigneeLogins(task).includes(normalized);
191
+ }
192
+ function selectTasksAssignedTo(tasks, assignee, options = {}) {
193
+ return tasks.filter((task) => taskMatchesAssigneeFilter(task, assignee, options));
194
+ }
195
+ function selectTasksAssignedToMe(tasks, currentUserLogin) {
196
+ return selectTasksAssignedTo(tasks, "@me", currentUserLogin === undefined ? {} : { currentUserLogin });
197
+ }
85
198
  function selectRun(snapshot, runId) {
86
199
  if (!runId)
87
200
  return null;
@@ -247,6 +360,7 @@ function selectConnectedRemoteCount(snapshot) {
247
360
  return selectRemoteConnections(snapshot).filter((connection) => connection.status === "connected").length;
248
361
  }
249
362
  export {
363
+ taskMatchesAssigneeFilter,
250
364
  selectWorkspaces,
251
365
  selectWorkspace,
252
366
  selectValidationsForTask,
@@ -258,6 +372,8 @@ export {
258
372
  selectTasksForWorkspace,
259
373
  selectTasksByWorkspace,
260
374
  selectTasksByStatus,
375
+ selectTasksAssignedToMe,
376
+ selectTasksAssignedTo,
261
377
  selectTask,
262
378
  selectRuntimeForRun,
263
379
  selectRunsForWorkspace,
@@ -289,5 +405,10 @@ export {
289
405
  selectAdhocRunsForWorkspace,
290
406
  selectAdhocRuns,
291
407
  selectActionsForTask,
292
- pickDefaultWorkspaceId
408
+ readTaskAssigneeLogins,
409
+ projectTaskStatusWithSessions,
410
+ projectTaskStatusForGrouping,
411
+ projectRunStatusForTaskGrouping,
412
+ pickDefaultWorkspaceId,
413
+ normalizeTaskAssigneeFilter
293
414
  };
@@ -0,0 +1,6 @@
1
+ import type { AssigneeRollup as ContractAssigneeRollup, BlockerClass as ContractBlockerClass, EpicRollup as ContractEpicRollup, RunJournalProjection, TaskSummary } from "@rig/contracts";
2
+ export type BlockerClass = ContractBlockerClass;
3
+ export type EpicRollup = ContractEpicRollup;
4
+ export type AssigneeRollup = ContractAssigneeRollup;
5
+ export declare function rollupByEpic(tasks: readonly TaskSummary[], classifications?: ReadonlyMap<string, BlockerClass>): readonly EpicRollup[];
6
+ export declare function rollupByAssignee(tasks: readonly TaskSummary[], runs: readonly RunJournalProjection[]): readonly AssigneeRollup[];