@jmoyers/harness 0.1.10 → 0.1.20
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/README.md +31 -35
- package/package.json +31 -11
- package/packages/harness-ai/src/anthropic-protocol.ts +68 -68
- package/packages/harness-ai/src/stream-text.ts +13 -91
- package/packages/harness-ui/src/frame-primitives.ts +158 -0
- package/packages/harness-ui/src/index.ts +18 -0
- package/packages/harness-ui/src/interaction/conversation-input-forwarder.ts +221 -0
- package/packages/harness-ui/src/interaction/conversation-selection-input.ts +213 -0
- package/packages/harness-ui/src/interaction/global-shortcut-input.ts +172 -0
- package/{src/ui → packages/harness-ui/src/interaction}/input-preflight.ts +10 -12
- package/{src/ui → packages/harness-ui/src/interaction}/input-token-router.ts +120 -69
- package/packages/harness-ui/src/interaction/input.ts +420 -0
- package/packages/harness-ui/src/interaction/left-nav-input.ts +166 -0
- package/{src/ui → packages/harness-ui/src/interaction}/main-pane-pointer-input.ts +91 -23
- package/{src/ui → packages/harness-ui/src/interaction}/pointer-routing-input.ts +112 -48
- package/packages/harness-ui/src/interaction/rail-pointer-input.ts +62 -0
- package/packages/harness-ui/src/interaction/repository-fold-input.ts +118 -0
- package/packages/harness-ui/src/kit.ts +476 -0
- package/packages/harness-ui/src/layout.ts +238 -0
- package/{src/ui/modals/manager.ts → packages/harness-ui/src/modal-manager.ts} +94 -64
- package/{src/ui → packages/harness-ui/src}/screen.ts +53 -26
- package/packages/harness-ui/src/surface.ts +252 -0
- package/packages/harness-ui/src/text-layout.ts +210 -0
- package/packages/nim-core/src/contracts.ts +239 -0
- package/packages/nim-core/src/event-store.ts +299 -0
- package/packages/nim-core/src/events.ts +53 -0
- package/packages/nim-core/src/index.ts +9 -0
- package/packages/nim-core/src/provider-router.ts +129 -0
- package/packages/nim-core/src/providers/anthropic-driver.ts +291 -0
- package/packages/nim-core/src/runtime-factory.ts +49 -0
- package/packages/nim-core/src/runtime.ts +1797 -0
- package/packages/nim-core/src/session-store.ts +516 -0
- package/packages/nim-core/src/telemetry.ts +48 -0
- package/packages/nim-test-tui/src/index.ts +150 -0
- package/packages/nim-ui-core/src/index.ts +1 -0
- package/packages/nim-ui-core/src/projection.ts +87 -0
- package/scripts/codex-live-mux-runtime.ts +2 -3721
- package/scripts/control-plane-daemon.ts +24 -2
- package/scripts/harness-bin.js +5 -0
- package/scripts/harness-commands.ts +300 -0
- package/scripts/harness-runtime.ts +82 -0
- package/scripts/harness.ts +33 -3007
- package/scripts/nim-tui-smoke.ts +748 -0
- package/src/cli/auth/runtime.ts +948 -0
- package/src/cli/default-gateway-pointer.ts +193 -0
- package/src/cli/gateway/runtime.ts +1872 -0
- package/src/cli/parsing/flags.ts +23 -0
- package/src/cli/parsing/session.ts +42 -0
- package/src/cli/runtime/context.ts +193 -0
- package/src/cli/runtime-app/application.ts +392 -0
- package/src/cli/runtime-infra/gateway-control.ts +729 -0
- package/{scripts/harness-inspector.ts → src/cli/workflows/inspector.ts} +14 -11
- package/src/cli/workflows/runtime.ts +965 -0
- package/src/clients/tui/left-rail-interactions.ts +519 -0
- package/src/clients/tui/main-pane-interactions.ts +509 -0
- package/src/clients/tui/modal-input-routing.ts +71 -0
- package/src/clients/tui/render-snapshot-adapter.ts +88 -0
- package/src/clients/web/synced-selectors.ts +132 -0
- package/src/codex/live-session.ts +82 -29
- package/src/config/config-core.ts +361 -10
- package/src/config/harness-paths.ts +4 -7
- package/src/config/harness-runtime-migration.ts +142 -19
- package/src/config/harness.config.template.jsonc +33 -0
- package/src/config/secrets-core.ts +92 -4
- package/src/control-plane/agent-realtime-api.ts +82 -427
- package/src/control-plane/prompt/thread-title-namer.ts +49 -23
- package/src/control-plane/session-summary.ts +10 -81
- package/src/control-plane/status/reducer-base.ts +12 -12
- package/src/control-plane/status/reducers/claude-status-reducer.ts +3 -3
- package/src/control-plane/status/reducers/codex-status-reducer.ts +4 -4
- package/src/control-plane/status/reducers/cursor-status-reducer.ts +3 -3
- package/src/control-plane/stream-client.ts +12 -2
- package/src/control-plane/stream-command-parser.ts +83 -143
- package/src/control-plane/stream-protocol.ts +53 -37
- package/src/control-plane/stream-server-background.ts +18 -2
- package/src/control-plane/stream-server-command.ts +376 -69
- package/src/control-plane/stream-server-session-runtime.ts +3 -2
- package/src/control-plane/stream-server.ts +943 -80
- package/src/control-plane/stream-session-runtime-types.ts +41 -0
- package/src/{mux/live-mux/control-plane-records.ts → core/contracts/records.ts} +24 -97
- package/src/core/state/observed-stream-cursor.ts +43 -0
- package/src/core/state/synced-observed-state.ts +273 -0
- package/src/core/store/harness-synced-store.ts +81 -0
- package/src/diff/budget.ts +136 -0
- package/src/diff/build.ts +289 -0
- package/src/diff/chunker.ts +146 -0
- package/src/diff/git-invoke.ts +315 -0
- package/src/diff/git-parse.ts +472 -0
- package/src/diff/hash.ts +70 -0
- package/src/diff/index.ts +24 -0
- package/src/diff/normalize.ts +134 -0
- package/src/diff/types.ts +178 -0
- package/src/diff-ui/args.ts +346 -0
- package/src/diff-ui/commands.ts +123 -0
- package/src/diff-ui/finder.ts +94 -0
- package/src/diff-ui/highlight.ts +127 -0
- package/src/diff-ui/index.ts +2 -0
- package/src/diff-ui/model.ts +141 -0
- package/src/diff-ui/pager.ts +412 -0
- package/src/diff-ui/render.ts +337 -0
- package/src/diff-ui/runtime.ts +379 -0
- package/src/diff-ui/state.ts +224 -0
- package/src/diff-ui/types.ts +236 -0
- package/src/domain/conversations.ts +11 -7
- package/src/domain/workspace.ts +76 -4
- package/src/mux/control-plane-op-queue.ts +93 -7
- package/src/mux/conversation-rail.ts +28 -71
- package/src/mux/dual-pane-core.ts +13 -13
- package/src/mux/harness-core-ui.ts +313 -42
- package/src/mux/input-shortcuts.ts +22 -112
- package/src/mux/keybinding-catalog.ts +340 -0
- package/src/mux/keybinding-registry.ts +103 -0
- package/src/mux/live-mux/command-menu-open-in.ts +280 -0
- package/src/mux/live-mux/command-menu.ts +167 -4
- package/src/mux/live-mux/conversation-state.ts +13 -0
- package/src/mux/live-mux/directory-resolution.ts +1 -1
- package/src/mux/live-mux/git-parsing.ts +16 -0
- package/src/mux/live-mux/git-snapshot.ts +33 -2
- package/src/mux/live-mux/global-shortcut-handlers.ts +6 -0
- package/src/mux/live-mux/home-pane-drop.ts +1 -1
- package/src/mux/live-mux/home-pane-pointer.ts +10 -0
- package/src/mux/live-mux/input-forwarding.ts +59 -2
- package/src/mux/live-mux/left-nav-activation.ts +124 -7
- package/src/mux/live-mux/left-nav.ts +35 -0
- package/src/mux/live-mux/link-click.ts +292 -0
- package/src/mux/live-mux/modal-command-menu-handler.ts +46 -9
- package/src/mux/live-mux/modal-conversation-handlers.ts +5 -1
- package/src/mux/live-mux/modal-input-reducers.ts +106 -8
- package/src/mux/live-mux/modal-overlays.ts +210 -31
- package/src/mux/live-mux/modal-pointer.ts +3 -7
- package/src/mux/live-mux/modal-prompt-handlers.ts +107 -1
- package/src/mux/live-mux/modal-release-notes-handler.ts +111 -0
- package/src/mux/live-mux/modal-task-editor-handler.ts +16 -11
- package/src/mux/live-mux/pointer-routing.ts +5 -2
- package/src/mux/live-mux/project-pane-pointer.ts +8 -0
- package/src/mux/live-mux/rail-layout.ts +33 -30
- package/src/mux/live-mux/release-notes.ts +383 -0
- package/src/mux/live-mux/render-trace-analysis.ts +52 -7
- package/src/mux/live-mux/repository-folding.ts +3 -0
- package/src/mux/live-mux/selection.ts +0 -4
- package/src/mux/live-mux/session-diagnostics-paths.ts +21 -0
- package/src/mux/project-pane-github-review.ts +271 -0
- package/src/mux/render-frame.ts +4 -0
- package/src/mux/runtime-app/codex-live-mux-runtime.ts +5191 -0
- package/src/mux/task-composer.ts +21 -14
- package/src/mux/task-focused-pane.ts +118 -117
- package/src/mux/task-screen-keybindings.ts +19 -82
- package/src/mux/workspace-rail-model.ts +270 -104
- package/src/mux/workspace-rail.ts +45 -22
- package/src/pty/session-broker.ts +1 -1
- package/{scripts → src/recording}/terminal-recording-gif-lib.ts +2 -2
- package/src/services/control-plane.ts +50 -32
- package/src/services/conversation-lifecycle.ts +118 -87
- package/src/services/conversation-startup-hydration.ts +20 -12
- package/src/services/directory-hydration.ts +21 -16
- package/src/services/event-persistence.ts +7 -0
- package/src/services/left-rail-pointer-handler.ts +329 -0
- package/src/services/mux-ui-state-persistence.ts +5 -1
- package/src/services/recording.ts +34 -26
- package/src/services/runtime-command-menu-agent-tools.ts +1 -1
- package/src/services/runtime-control-actions.ts +79 -61
- package/src/services/runtime-control-plane-ops.ts +122 -83
- package/src/services/runtime-conversation-actions.ts +40 -26
- package/src/services/runtime-conversation-activation.ts +82 -30
- package/src/services/runtime-conversation-starter.ts +80 -48
- package/src/services/runtime-conversation-title-edit.ts +91 -80
- package/src/services/runtime-envelope-handler.ts +107 -105
- package/src/services/runtime-git-state.ts +42 -29
- package/src/services/runtime-layout-resize.ts +3 -1
- package/src/services/runtime-left-rail-render.ts +99 -63
- package/src/services/runtime-nim-cli-session.ts +438 -0
- package/src/services/runtime-nim-session.ts +705 -0
- package/src/services/runtime-nim-tool-bridge.ts +141 -0
- package/src/services/runtime-observed-event-projection-pipeline.ts +45 -0
- package/src/services/runtime-process-wiring.ts +29 -36
- package/src/services/runtime-project-pane-github-review-cache.ts +164 -0
- package/src/services/runtime-render-flush.ts +63 -70
- package/src/services/runtime-render-lifecycle.ts +65 -64
- package/src/services/runtime-render-orchestrator.ts +55 -45
- package/src/services/runtime-render-pipeline.ts +106 -103
- package/src/services/runtime-render-state.ts +62 -49
- package/src/services/runtime-repository-actions.ts +97 -70
- package/src/services/runtime-right-pane-render.ts +80 -53
- package/src/services/runtime-shutdown.ts +38 -35
- package/src/services/runtime-stream-subscriptions.ts +35 -27
- package/src/services/runtime-task-composer-persistence.ts +71 -59
- package/src/services/runtime-task-composer-snapshot.ts +14 -0
- package/src/services/runtime-task-editor-actions.ts +46 -29
- package/src/services/runtime-task-pane-actions.ts +220 -134
- package/src/services/runtime-task-pane-shortcuts.ts +323 -123
- package/src/services/runtime-workspace-observed-effect-queue.ts +25 -0
- package/src/services/runtime-workspace-observed-events.ts +33 -184
- package/src/services/runtime-workspace-observed-transition-policy.ts +228 -0
- package/src/services/session-diagnostics-store.ts +217 -0
- package/src/services/startup-background-resume.ts +26 -21
- package/src/services/startup-orchestrator.ts +16 -13
- package/src/services/startup-paint-tracker.ts +29 -21
- package/src/services/startup-persisted-conversation-queue.ts +19 -13
- package/src/services/startup-settled-gate.ts +25 -15
- package/src/services/startup-shutdown.ts +18 -22
- package/src/services/startup-state-hydration.ts +44 -34
- package/src/services/startup-visibility.ts +12 -4
- package/src/services/task-pane-selection-actions.ts +89 -72
- package/src/services/task-planning-hydration.ts +24 -18
- package/src/services/task-planning-observed-events.ts +50 -52
- package/src/services/workspace-observed-events.ts +66 -63
- package/src/storage/storage-lifecycle-core.ts +438 -0
- package/src/store/control-plane-store-normalize.ts +33 -242
- package/src/store/control-plane-store-types.ts +1 -35
- package/src/store/control-plane-store.ts +396 -56
- package/src/store/event-store.ts +397 -3
- package/src/terminal/snapshot-oracle.ts +207 -94
- package/src/ui/mux-theme.ts +112 -8
- package/src/ui/panes/home-gridfire.ts +40 -31
- package/src/ui/panes/home.ts +10 -2
- package/src/ui/panes/nim.ts +315 -0
- package/src/mux/live-mux/actions-task.ts +0 -115
- package/src/mux/live-mux/left-rail-actions.ts +0 -118
- package/src/mux/live-mux/left-rail-conversation-click.ts +0 -82
- package/src/mux/live-mux/left-rail-pointer.ts +0 -74
- package/src/mux/live-mux/task-pane-shortcuts.ts +0 -206
- package/src/services/runtime-directory-actions.ts +0 -164
- package/src/services/runtime-input-pipeline.ts +0 -50
- package/src/services/runtime-input-router.ts +0 -189
- package/src/services/runtime-main-pane-input.ts +0 -230
- package/src/services/runtime-modal-input.ts +0 -119
- package/src/services/runtime-navigation-input.ts +0 -197
- package/src/services/runtime-rail-input.ts +0 -278
- package/src/services/runtime-task-pane.ts +0 -62
- package/src/services/runtime-workspace-actions.ts +0 -158
- package/src/ui/conversation-input-forwarder.ts +0 -114
- package/src/ui/conversation-selection-input.ts +0 -103
- package/src/ui/global-shortcut-input.ts +0 -89
- package/src/ui/input.ts +0 -238
- package/src/ui/kit.ts +0 -509
- package/src/ui/left-nav-input.ts +0 -80
- package/src/ui/left-rail-pointer-input.ts +0 -148
- package/src/ui/repository-fold-input.ts +0 -91
- package/src/ui/surface.ts +0 -224
|
@@ -3,7 +3,6 @@ import type { StreamCommand } from './stream-protocol.ts';
|
|
|
3
3
|
type StreamCommandType = StreamCommand['type'];
|
|
4
4
|
type CommandRecord = Record<string, unknown>;
|
|
5
5
|
type CommandParser = (record: CommandRecord) => StreamCommand | null;
|
|
6
|
-
type ParsedTaskLinearInput = NonNullable<Extract<StreamCommand, { type: 'task.create' }>['linear']>;
|
|
7
6
|
const INVALID_OPTIONAL = Symbol('invalid-optional');
|
|
8
7
|
|
|
9
8
|
function asRecord(value: unknown): CommandRecord | null {
|
|
@@ -95,115 +94,6 @@ function readOptionalNullableString(
|
|
|
95
94
|
return value;
|
|
96
95
|
}
|
|
97
96
|
|
|
98
|
-
function readOptionalNullableNonNegativeInteger(
|
|
99
|
-
record: CommandRecord,
|
|
100
|
-
field: string,
|
|
101
|
-
): number | null | undefined | typeof INVALID_OPTIONAL {
|
|
102
|
-
const value = record[field];
|
|
103
|
-
if (value === undefined) {
|
|
104
|
-
return undefined;
|
|
105
|
-
}
|
|
106
|
-
if (value === null) {
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
if (typeof value !== 'number' || !Number.isInteger(value) || value < 0) {
|
|
110
|
-
return INVALID_OPTIONAL;
|
|
111
|
-
}
|
|
112
|
-
return value;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function parseTaskLinearInput(value: unknown): ParsedTaskLinearInput | null {
|
|
116
|
-
const record = asRecord(value);
|
|
117
|
-
if (record === null) {
|
|
118
|
-
return null;
|
|
119
|
-
}
|
|
120
|
-
const issueId = readOptionalNullableString(record, 'issueId');
|
|
121
|
-
const identifier = readOptionalNullableString(record, 'identifier');
|
|
122
|
-
const url = readOptionalNullableString(record, 'url');
|
|
123
|
-
const teamId = readOptionalNullableString(record, 'teamId');
|
|
124
|
-
const projectId = readOptionalNullableString(record, 'projectId');
|
|
125
|
-
const projectMilestoneId = readOptionalNullableString(record, 'projectMilestoneId');
|
|
126
|
-
const cycleId = readOptionalNullableString(record, 'cycleId');
|
|
127
|
-
const stateId = readOptionalNullableString(record, 'stateId');
|
|
128
|
-
const assigneeId = readOptionalNullableString(record, 'assigneeId');
|
|
129
|
-
const dueDate = readOptionalNullableString(record, 'dueDate');
|
|
130
|
-
const priority = readOptionalNullableNonNegativeInteger(record, 'priority');
|
|
131
|
-
const estimate = readOptionalNullableNonNegativeInteger(record, 'estimate');
|
|
132
|
-
const labelsRaw = record['labelIds'];
|
|
133
|
-
let labelIds: string[] | null | undefined;
|
|
134
|
-
if (labelsRaw !== undefined) {
|
|
135
|
-
if (labelsRaw === null) {
|
|
136
|
-
labelIds = null;
|
|
137
|
-
} else if (Array.isArray(labelsRaw) && labelsRaw.every((entry) => typeof entry === 'string')) {
|
|
138
|
-
labelIds = [...labelsRaw];
|
|
139
|
-
} else {
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (
|
|
145
|
-
issueId === INVALID_OPTIONAL ||
|
|
146
|
-
identifier === INVALID_OPTIONAL ||
|
|
147
|
-
url === INVALID_OPTIONAL ||
|
|
148
|
-
teamId === INVALID_OPTIONAL ||
|
|
149
|
-
projectId === INVALID_OPTIONAL ||
|
|
150
|
-
projectMilestoneId === INVALID_OPTIONAL ||
|
|
151
|
-
cycleId === INVALID_OPTIONAL ||
|
|
152
|
-
stateId === INVALID_OPTIONAL ||
|
|
153
|
-
assigneeId === INVALID_OPTIONAL ||
|
|
154
|
-
dueDate === INVALID_OPTIONAL ||
|
|
155
|
-
priority === INVALID_OPTIONAL ||
|
|
156
|
-
estimate === INVALID_OPTIONAL
|
|
157
|
-
) {
|
|
158
|
-
return null;
|
|
159
|
-
}
|
|
160
|
-
if (priority !== undefined && priority !== null && priority > 4) {
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const out: ParsedTaskLinearInput = {};
|
|
165
|
-
if (issueId !== undefined) {
|
|
166
|
-
out.issueId = issueId;
|
|
167
|
-
}
|
|
168
|
-
if (identifier !== undefined) {
|
|
169
|
-
out.identifier = identifier;
|
|
170
|
-
}
|
|
171
|
-
if (url !== undefined) {
|
|
172
|
-
out.url = url;
|
|
173
|
-
}
|
|
174
|
-
if (teamId !== undefined) {
|
|
175
|
-
out.teamId = teamId;
|
|
176
|
-
}
|
|
177
|
-
if (projectId !== undefined) {
|
|
178
|
-
out.projectId = projectId;
|
|
179
|
-
}
|
|
180
|
-
if (projectMilestoneId !== undefined) {
|
|
181
|
-
out.projectMilestoneId = projectMilestoneId;
|
|
182
|
-
}
|
|
183
|
-
if (cycleId !== undefined) {
|
|
184
|
-
out.cycleId = cycleId;
|
|
185
|
-
}
|
|
186
|
-
if (stateId !== undefined) {
|
|
187
|
-
out.stateId = stateId;
|
|
188
|
-
}
|
|
189
|
-
if (assigneeId !== undefined) {
|
|
190
|
-
out.assigneeId = assigneeId;
|
|
191
|
-
}
|
|
192
|
-
if (priority !== undefined) {
|
|
193
|
-
out.priority = priority as 0 | 1 | 2 | 3 | 4 | null;
|
|
194
|
-
}
|
|
195
|
-
if (estimate !== undefined) {
|
|
196
|
-
out.estimate = estimate;
|
|
197
|
-
}
|
|
198
|
-
if (dueDate !== undefined) {
|
|
199
|
-
out.dueDate = dueDate;
|
|
200
|
-
}
|
|
201
|
-
if (labelIds !== undefined) {
|
|
202
|
-
out.labelIds = labelIds;
|
|
203
|
-
}
|
|
204
|
-
return out;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
97
|
function parseSessionControllerType(value: unknown): 'human' | 'agent' | 'automation' | null {
|
|
208
98
|
if (value === 'human' || value === 'agent' || value === 'automation') {
|
|
209
99
|
return value;
|
|
@@ -586,32 +476,38 @@ function parseRepositoryArchive(record: CommandRecord): StreamCommand | null {
|
|
|
586
476
|
}
|
|
587
477
|
|
|
588
478
|
function parseTaskCreate(record: CommandRecord): StreamCommand | null {
|
|
589
|
-
const
|
|
590
|
-
if (
|
|
479
|
+
const body = readString(record['body']);
|
|
480
|
+
if (body === null) {
|
|
591
481
|
return null;
|
|
592
482
|
}
|
|
483
|
+
const title = readOptionalNullableString(record, 'title');
|
|
593
484
|
const taskId = readOptionalString(record, 'taskId');
|
|
594
485
|
const tenantId = readOptionalString(record, 'tenantId');
|
|
595
486
|
const userId = readOptionalString(record, 'userId');
|
|
596
487
|
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
597
488
|
const repositoryId = readOptionalString(record, 'repositoryId');
|
|
598
489
|
const projectId = readOptionalString(record, 'projectId');
|
|
599
|
-
const description = readOptionalString(record, 'description');
|
|
600
490
|
if (
|
|
491
|
+
title === INVALID_OPTIONAL ||
|
|
601
492
|
taskId === undefined ||
|
|
602
493
|
tenantId === undefined ||
|
|
603
494
|
userId === undefined ||
|
|
604
495
|
workspaceId === undefined ||
|
|
605
496
|
repositoryId === undefined ||
|
|
606
|
-
projectId === undefined
|
|
607
|
-
description === undefined
|
|
497
|
+
projectId === undefined
|
|
608
498
|
) {
|
|
609
499
|
return null;
|
|
610
500
|
}
|
|
501
|
+
if (repositoryId === null && projectId === null) {
|
|
502
|
+
return null;
|
|
503
|
+
}
|
|
611
504
|
const command: StreamCommand = {
|
|
612
505
|
type: 'task.create',
|
|
613
|
-
|
|
506
|
+
body,
|
|
614
507
|
};
|
|
508
|
+
if (title !== undefined) {
|
|
509
|
+
command.title = title;
|
|
510
|
+
}
|
|
615
511
|
if (taskId !== null) {
|
|
616
512
|
command.taskId = taskId;
|
|
617
513
|
}
|
|
@@ -630,16 +526,6 @@ function parseTaskCreate(record: CommandRecord): StreamCommand | null {
|
|
|
630
526
|
if (projectId !== null) {
|
|
631
527
|
command.projectId = projectId;
|
|
632
528
|
}
|
|
633
|
-
if (description !== null) {
|
|
634
|
-
command.description = description;
|
|
635
|
-
}
|
|
636
|
-
if (record['linear'] !== undefined) {
|
|
637
|
-
const linear = parseTaskLinearInput(record['linear']);
|
|
638
|
-
if (linear === null) {
|
|
639
|
-
return null;
|
|
640
|
-
}
|
|
641
|
-
command.linear = linear;
|
|
642
|
-
}
|
|
643
529
|
return command;
|
|
644
530
|
}
|
|
645
531
|
|
|
@@ -728,9 +614,9 @@ function parseTaskUpdate(record: CommandRecord): StreamCommand | null {
|
|
|
728
614
|
if (taskId === null) {
|
|
729
615
|
return null;
|
|
730
616
|
}
|
|
731
|
-
const title =
|
|
732
|
-
const
|
|
733
|
-
if (title ===
|
|
617
|
+
const title = readOptionalNullableString(record, 'title');
|
|
618
|
+
const body = readOptionalString(record, 'body');
|
|
619
|
+
if (title === INVALID_OPTIONAL || body === undefined) {
|
|
734
620
|
return null;
|
|
735
621
|
}
|
|
736
622
|
let repositoryId: string | null | undefined;
|
|
@@ -753,16 +639,19 @@ function parseTaskUpdate(record: CommandRecord): StreamCommand | null {
|
|
|
753
639
|
} else {
|
|
754
640
|
return null;
|
|
755
641
|
}
|
|
642
|
+
if (repositoryId === null && projectId === null) {
|
|
643
|
+
return null;
|
|
644
|
+
}
|
|
756
645
|
|
|
757
646
|
const command: StreamCommand = {
|
|
758
647
|
type: 'task.update',
|
|
759
648
|
taskId,
|
|
760
649
|
};
|
|
761
|
-
if (title !==
|
|
650
|
+
if (title !== undefined) {
|
|
762
651
|
command.title = title;
|
|
763
652
|
}
|
|
764
|
-
if (
|
|
765
|
-
command.
|
|
653
|
+
if (body !== null) {
|
|
654
|
+
command.body = body;
|
|
766
655
|
}
|
|
767
656
|
if (repositoryId !== undefined) {
|
|
768
657
|
command.repositoryId = repositoryId;
|
|
@@ -770,17 +659,6 @@ function parseTaskUpdate(record: CommandRecord): StreamCommand | null {
|
|
|
770
659
|
if (projectId !== undefined) {
|
|
771
660
|
command.projectId = projectId;
|
|
772
661
|
}
|
|
773
|
-
if (record['linear'] !== undefined) {
|
|
774
|
-
if (record['linear'] === null) {
|
|
775
|
-
command.linear = null;
|
|
776
|
-
} else {
|
|
777
|
-
const linear = parseTaskLinearInput(record['linear']);
|
|
778
|
-
if (linear === null) {
|
|
779
|
-
return null;
|
|
780
|
-
}
|
|
781
|
-
command.linear = linear;
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
662
|
return command;
|
|
785
663
|
}
|
|
786
664
|
|
|
@@ -1109,6 +987,25 @@ function parseGitHubProjectPr(record: CommandRecord): StreamCommand | null {
|
|
|
1109
987
|
};
|
|
1110
988
|
}
|
|
1111
989
|
|
|
990
|
+
function parseGitHubProjectReview(record: CommandRecord): StreamCommand | null {
|
|
991
|
+
const directoryId = readString(record['directoryId']);
|
|
992
|
+
const forceRefresh = readOptionalBoolean(record, 'forceRefresh');
|
|
993
|
+
if (directoryId === null) {
|
|
994
|
+
return null;
|
|
995
|
+
}
|
|
996
|
+
if (forceRefresh === undefined) {
|
|
997
|
+
return null;
|
|
998
|
+
}
|
|
999
|
+
const command: StreamCommand = {
|
|
1000
|
+
type: 'github.project-review',
|
|
1001
|
+
directoryId,
|
|
1002
|
+
};
|
|
1003
|
+
if (forceRefresh !== null) {
|
|
1004
|
+
command.forceRefresh = forceRefresh;
|
|
1005
|
+
}
|
|
1006
|
+
return command;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1112
1009
|
function parseGitHubPrList(record: CommandRecord): StreamCommand | null {
|
|
1113
1010
|
const tenantId = readOptionalString(record, 'tenantId');
|
|
1114
1011
|
const userId = readOptionalString(record, 'userId');
|
|
@@ -1256,6 +1153,47 @@ function parseGitHubRepoMyPrsUrl(record: CommandRecord): StreamCommand | null {
|
|
|
1256
1153
|
};
|
|
1257
1154
|
}
|
|
1258
1155
|
|
|
1156
|
+
function parseLinearIssueImport(record: CommandRecord): StreamCommand | null {
|
|
1157
|
+
const url = readString(record['url']);
|
|
1158
|
+
if (url === null) {
|
|
1159
|
+
return null;
|
|
1160
|
+
}
|
|
1161
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
1162
|
+
const userId = readOptionalString(record, 'userId');
|
|
1163
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
1164
|
+
const repositoryId = readOptionalString(record, 'repositoryId');
|
|
1165
|
+
const projectId = readOptionalString(record, 'projectId');
|
|
1166
|
+
if (
|
|
1167
|
+
tenantId === undefined ||
|
|
1168
|
+
userId === undefined ||
|
|
1169
|
+
workspaceId === undefined ||
|
|
1170
|
+
repositoryId === undefined ||
|
|
1171
|
+
projectId === undefined
|
|
1172
|
+
) {
|
|
1173
|
+
return null;
|
|
1174
|
+
}
|
|
1175
|
+
const command: StreamCommand = {
|
|
1176
|
+
type: 'linear.issue.import',
|
|
1177
|
+
url,
|
|
1178
|
+
};
|
|
1179
|
+
if (tenantId !== null) {
|
|
1180
|
+
command.tenantId = tenantId;
|
|
1181
|
+
}
|
|
1182
|
+
if (userId !== null) {
|
|
1183
|
+
command.userId = userId;
|
|
1184
|
+
}
|
|
1185
|
+
if (workspaceId !== null) {
|
|
1186
|
+
command.workspaceId = workspaceId;
|
|
1187
|
+
}
|
|
1188
|
+
if (repositoryId !== null) {
|
|
1189
|
+
command.repositoryId = repositoryId;
|
|
1190
|
+
}
|
|
1191
|
+
if (projectId !== null) {
|
|
1192
|
+
command.projectId = projectId;
|
|
1193
|
+
}
|
|
1194
|
+
return command;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1259
1197
|
function parseStreamSubscribe(record: CommandRecord): StreamCommand | null {
|
|
1260
1198
|
const tenantId = readOptionalString(record, 'tenantId');
|
|
1261
1199
|
const userId = readOptionalString(record, 'userId');
|
|
@@ -1664,10 +1602,12 @@ export const DEFAULT_STREAM_COMMAND_PARSERS: StreamCommandParserRegistry = {
|
|
|
1664
1602
|
'automation.policy-get': parseAutomationPolicyGet,
|
|
1665
1603
|
'automation.policy-set': parseAutomationPolicySet,
|
|
1666
1604
|
'github.project-pr': parseGitHubProjectPr,
|
|
1605
|
+
'github.project-review': parseGitHubProjectReview,
|
|
1667
1606
|
'github.pr-list': parseGitHubPrList,
|
|
1668
1607
|
'github.pr-create': parseGitHubPrCreate,
|
|
1669
1608
|
'github.pr-jobs-list': parseGitHubPrJobsList,
|
|
1670
1609
|
'github.repo-my-prs-url': parseGitHubRepoMyPrsUrl,
|
|
1610
|
+
'linear.issue.import': parseLinearIssueImport,
|
|
1671
1611
|
'stream.subscribe': parseStreamSubscribe,
|
|
1672
1612
|
'stream.unsubscribe': parseStreamUnsubscribe,
|
|
1673
1613
|
'session.list': parseSessionList,
|
|
@@ -10,6 +10,17 @@ export type StreamPromptCaptureSource = 'otlp-log' | 'hook-notify' | 'history';
|
|
|
10
10
|
export type StreamPromptConfidence = 'high' | 'medium' | 'low';
|
|
11
11
|
export type StreamSessionControllerType = 'human' | 'agent' | 'automation';
|
|
12
12
|
export type StreamSessionDisplayPhase = 'needs-action' | 'starting' | 'working' | 'idle' | 'exited';
|
|
13
|
+
export type StreamSessionActivityHint = 'needs-action' | 'working' | 'idle';
|
|
14
|
+
|
|
15
|
+
export function isStreamSessionRuntimeStatus(value: unknown): value is StreamSessionRuntimeStatus {
|
|
16
|
+
return (
|
|
17
|
+
value === 'running' || value === 'needs-input' || value === 'completed' || value === 'exited'
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function parseStreamSessionRuntimeStatus(value: unknown): StreamSessionRuntimeStatus | null {
|
|
22
|
+
return isStreamSessionRuntimeStatus(value) ? value : null;
|
|
23
|
+
}
|
|
13
24
|
|
|
14
25
|
export interface StreamSessionController {
|
|
15
26
|
controllerId: string;
|
|
@@ -35,7 +46,7 @@ export interface StreamSessionStatusModel {
|
|
|
35
46
|
attentionReason: string | null;
|
|
36
47
|
lastKnownWork: string | null;
|
|
37
48
|
lastKnownWorkAt: string | null;
|
|
38
|
-
|
|
49
|
+
activityHint: StreamSessionActivityHint | null;
|
|
39
50
|
observedAt: string;
|
|
40
51
|
}
|
|
41
52
|
|
|
@@ -131,27 +142,10 @@ interface ConversationDeleteCommand {
|
|
|
131
142
|
|
|
132
143
|
type StreamTaskStatus = 'draft' | 'ready' | 'in-progress' | 'completed';
|
|
133
144
|
type StreamTaskScopeKind = 'global' | 'repository' | 'project';
|
|
134
|
-
type StreamTaskLinearPriority = 0 | 1 | 2 | 3 | 4;
|
|
135
145
|
type StreamProjectTaskFocusMode = 'balanced' | 'own-only';
|
|
136
146
|
type StreamProjectThreadSpawnMode = 'new-thread' | 'reuse-thread';
|
|
137
147
|
type StreamAutomationPolicyScope = 'global' | 'repository' | 'project';
|
|
138
148
|
|
|
139
|
-
interface StreamTaskLinearInput {
|
|
140
|
-
issueId?: string | null;
|
|
141
|
-
identifier?: string | null;
|
|
142
|
-
url?: string | null;
|
|
143
|
-
teamId?: string | null;
|
|
144
|
-
projectId?: string | null;
|
|
145
|
-
projectMilestoneId?: string | null;
|
|
146
|
-
cycleId?: string | null;
|
|
147
|
-
stateId?: string | null;
|
|
148
|
-
assigneeId?: string | null;
|
|
149
|
-
priority?: StreamTaskLinearPriority | null;
|
|
150
|
-
estimate?: number | null;
|
|
151
|
-
dueDate?: string | null;
|
|
152
|
-
labelIds?: readonly string[] | null;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
149
|
interface RepositoryUpsertCommand {
|
|
156
150
|
type: 'repository.upsert';
|
|
157
151
|
repositoryId?: string;
|
|
@@ -200,9 +194,8 @@ interface TaskCreateCommand {
|
|
|
200
194
|
workspaceId?: string;
|
|
201
195
|
repositoryId?: string;
|
|
202
196
|
projectId?: string;
|
|
203
|
-
title
|
|
204
|
-
|
|
205
|
-
linear?: StreamTaskLinearInput;
|
|
197
|
+
title?: string | null;
|
|
198
|
+
body: string;
|
|
206
199
|
}
|
|
207
200
|
|
|
208
201
|
interface TaskGetCommand {
|
|
@@ -225,11 +218,10 @@ interface TaskListCommand {
|
|
|
225
218
|
interface TaskUpdateCommand {
|
|
226
219
|
type: 'task.update';
|
|
227
220
|
taskId: string;
|
|
228
|
-
title?: string;
|
|
229
|
-
|
|
221
|
+
title?: string | null;
|
|
222
|
+
body?: string;
|
|
230
223
|
repositoryId?: string | null;
|
|
231
224
|
projectId?: string | null;
|
|
232
|
-
linear?: StreamTaskLinearInput | null;
|
|
233
225
|
}
|
|
234
226
|
|
|
235
227
|
interface TaskDeleteCommand {
|
|
@@ -329,6 +321,12 @@ interface GitHubProjectPrCommand {
|
|
|
329
321
|
directoryId: string;
|
|
330
322
|
}
|
|
331
323
|
|
|
324
|
+
interface GitHubProjectReviewCommand {
|
|
325
|
+
type: 'github.project-review';
|
|
326
|
+
directoryId: string;
|
|
327
|
+
forceRefresh?: boolean;
|
|
328
|
+
}
|
|
329
|
+
|
|
332
330
|
interface GitHubPrListCommand {
|
|
333
331
|
type: 'github.pr-list';
|
|
334
332
|
tenantId?: string;
|
|
@@ -366,6 +364,16 @@ interface GitHubRepoMyPrsUrlCommand {
|
|
|
366
364
|
repositoryId: string;
|
|
367
365
|
}
|
|
368
366
|
|
|
367
|
+
interface LinearIssueImportCommand {
|
|
368
|
+
type: 'linear.issue.import';
|
|
369
|
+
url: string;
|
|
370
|
+
tenantId?: string;
|
|
371
|
+
userId?: string;
|
|
372
|
+
workspaceId?: string;
|
|
373
|
+
repositoryId?: string;
|
|
374
|
+
projectId?: string;
|
|
375
|
+
}
|
|
376
|
+
|
|
369
377
|
interface StreamSubscribeCommand {
|
|
370
378
|
type: 'stream.subscribe';
|
|
371
379
|
tenantId?: string;
|
|
@@ -524,10 +532,12 @@ export type StreamCommand =
|
|
|
524
532
|
| AutomationPolicyGetCommand
|
|
525
533
|
| AutomationPolicySetCommand
|
|
526
534
|
| GitHubProjectPrCommand
|
|
535
|
+
| GitHubProjectReviewCommand
|
|
527
536
|
| GitHubPrListCommand
|
|
528
537
|
| GitHubPrCreateCommand
|
|
529
538
|
| GitHubPrJobsListCommand
|
|
530
539
|
| GitHubRepoMyPrsUrlCommand
|
|
540
|
+
| LinearIssueImportCommand
|
|
531
541
|
| StreamSubscribeCommand
|
|
532
542
|
| StreamUnsubscribeCommand
|
|
533
543
|
| SessionListCommand
|
|
@@ -1097,6 +1107,13 @@ function parsePromptConfidence(value: unknown): StreamPromptConfidence | null {
|
|
|
1097
1107
|
return null;
|
|
1098
1108
|
}
|
|
1099
1109
|
|
|
1110
|
+
function parseSessionActivityHint(value: unknown): StreamSessionActivityHint | undefined {
|
|
1111
|
+
if (value === 'needs-action' || value === 'working' || value === 'idle') {
|
|
1112
|
+
return value;
|
|
1113
|
+
}
|
|
1114
|
+
return undefined;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1100
1117
|
function parseTelemetrySummary(value: unknown): StreamTelemetrySummary | null | undefined {
|
|
1101
1118
|
if (value === undefined) {
|
|
1102
1119
|
return undefined;
|
|
@@ -1131,7 +1148,9 @@ function parseTelemetrySummary(value: unknown): StreamTelemetrySummary | null |
|
|
|
1131
1148
|
};
|
|
1132
1149
|
}
|
|
1133
1150
|
|
|
1134
|
-
function
|
|
1151
|
+
export function parseStreamSessionStatusModel(
|
|
1152
|
+
value: unknown,
|
|
1153
|
+
): StreamSessionStatusModel | null | undefined {
|
|
1135
1154
|
if (value === undefined) {
|
|
1136
1155
|
return undefined;
|
|
1137
1156
|
}
|
|
@@ -1153,14 +1172,15 @@ function parseSessionStatusModel(value: unknown): StreamSessionStatusModel | nul
|
|
|
1153
1172
|
record['lastKnownWork'] === null ? null : readString(record['lastKnownWork']);
|
|
1154
1173
|
const lastKnownWorkAt =
|
|
1155
1174
|
record['lastKnownWorkAt'] === null ? null : readString(record['lastKnownWorkAt']);
|
|
1156
|
-
const
|
|
1175
|
+
const activityHintValue = record['activityHint'];
|
|
1176
|
+
const activityHint =
|
|
1177
|
+
activityHintValue === undefined || activityHintValue === null
|
|
1178
|
+
? null
|
|
1179
|
+
: parseSessionActivityHint(activityHintValue);
|
|
1157
1180
|
const observedAt = readString(record['observedAt']);
|
|
1158
1181
|
if (
|
|
1159
1182
|
runtimeStatus === null ||
|
|
1160
|
-
(runtimeStatus
|
|
1161
|
-
runtimeStatus !== 'needs-input' &&
|
|
1162
|
-
runtimeStatus !== 'completed' &&
|
|
1163
|
-
runtimeStatus !== 'exited') ||
|
|
1183
|
+
!isStreamSessionRuntimeStatus(runtimeStatus) ||
|
|
1164
1184
|
phase === null ||
|
|
1165
1185
|
(phase !== 'needs-action' &&
|
|
1166
1186
|
phase !== 'starting' &&
|
|
@@ -1175,11 +1195,7 @@ function parseSessionStatusModel(value: unknown): StreamSessionStatusModel | nul
|
|
|
1175
1195
|
(attentionReason === null && record['attentionReason'] !== null) ||
|
|
1176
1196
|
(lastKnownWork === null && record['lastKnownWork'] !== null) ||
|
|
1177
1197
|
(lastKnownWorkAt === null && record['lastKnownWorkAt'] !== null) ||
|
|
1178
|
-
|
|
1179
|
-
(phaseHint !== null &&
|
|
1180
|
-
phaseHint !== 'needs-action' &&
|
|
1181
|
-
phaseHint !== 'working' &&
|
|
1182
|
-
phaseHint !== 'idle') ||
|
|
1198
|
+
activityHint === undefined ||
|
|
1183
1199
|
observedAt === null
|
|
1184
1200
|
) {
|
|
1185
1201
|
return undefined;
|
|
@@ -1193,7 +1209,7 @@ function parseSessionStatusModel(value: unknown): StreamSessionStatusModel | nul
|
|
|
1193
1209
|
attentionReason,
|
|
1194
1210
|
lastKnownWork,
|
|
1195
1211
|
lastKnownWorkAt,
|
|
1196
|
-
|
|
1212
|
+
activityHint,
|
|
1197
1213
|
observedAt,
|
|
1198
1214
|
};
|
|
1199
1215
|
}
|
|
@@ -1599,7 +1615,7 @@ function parseStreamObservedEvent(value: unknown): StreamObservedEvent | null {
|
|
|
1599
1615
|
const sessionId = readString(record['sessionId']);
|
|
1600
1616
|
const status = readString(record['status']);
|
|
1601
1617
|
const attentionReason = readString(record['attentionReason']);
|
|
1602
|
-
const statusModel =
|
|
1618
|
+
const statusModel = parseStreamSessionStatusModel(record['statusModel']);
|
|
1603
1619
|
const live = readBoolean(record['live']);
|
|
1604
1620
|
const ts = readString(record['ts']);
|
|
1605
1621
|
const directoryId = readString(record['directoryId']);
|
|
@@ -13,6 +13,16 @@ const HISTORY_POLL_JITTER_RATIO = 0.35;
|
|
|
13
13
|
const HISTORY_POLL_MAX_DELAY_MS = 60_000;
|
|
14
14
|
const LINE_FEED_BYTE = '\n'.charCodeAt(0);
|
|
15
15
|
|
|
16
|
+
function isClosedDatabaseError(error: unknown): boolean {
|
|
17
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
18
|
+
const normalized = message.trim().toLowerCase();
|
|
19
|
+
return (
|
|
20
|
+
normalized.includes('database has closed') ||
|
|
21
|
+
normalized.includes('database is closed') ||
|
|
22
|
+
normalized.includes('cannot use a closed database')
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
16
26
|
interface GitStatusSummary {
|
|
17
27
|
branch: string | null;
|
|
18
28
|
changedFiles: number;
|
|
@@ -215,7 +225,10 @@ export async function pollHistoryFile(ctx: BackgroundContext): Promise<void> {
|
|
|
215
225
|
);
|
|
216
226
|
ctx.historyNextAllowedPollAtMs = Date.now() + jitterDelayMs(backoffMs);
|
|
217
227
|
}
|
|
218
|
-
} catch {
|
|
228
|
+
} catch (error: unknown) {
|
|
229
|
+
if (isClosedDatabaseError(error)) {
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
219
232
|
ctx.historyIdleStreak = Math.min(ctx.historyIdleStreak + 1, 4);
|
|
220
233
|
const backoffMs = Math.min(
|
|
221
234
|
HISTORY_POLL_MAX_DELAY_MS,
|
|
@@ -467,7 +480,10 @@ export async function refreshGitStatusForDirectory(
|
|
|
467
480
|
forcePublished: options.forcePublish ? 1 : 0,
|
|
468
481
|
repositoryLinked: repositoryId === null ? 0 : 1,
|
|
469
482
|
});
|
|
470
|
-
} catch {
|
|
483
|
+
} catch (error: unknown) {
|
|
484
|
+
if (isClosedDatabaseError(error)) {
|
|
485
|
+
throw error;
|
|
486
|
+
}
|
|
471
487
|
if (previous !== null) {
|
|
472
488
|
ctx.gitStatusByDirectoryId.set(directory.directoryId, {
|
|
473
489
|
...previous,
|