@jmoyers/harness 0.1.0
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/LICENSE +21 -0
- package/README.md +145 -0
- package/native/ptyd/Cargo.lock +16 -0
- package/native/ptyd/Cargo.toml +7 -0
- package/native/ptyd/src/main.rs +257 -0
- package/package.json +90 -0
- package/scripts/build-ptyd.sh +73 -0
- package/scripts/control-plane-daemon.ts +277 -0
- package/scripts/cursor-hook-relay.ts +82 -0
- package/scripts/harness-animate.ts +469 -0
- package/scripts/harness-bin.js +77 -0
- package/scripts/harness-core.ts +1 -0
- package/scripts/harness-inspector.ts +439 -0
- package/scripts/harness.ts +2493 -0
- package/src/adapters/agent-session-state.ts +390 -0
- package/src/cli/gateway-record.ts +173 -0
- package/src/codex/live-session.ts +872 -0
- package/src/config/config-core.ts +1359 -0
- package/src/config/secrets-core.ts +170 -0
- package/src/control-plane/agent-realtime-api.ts +2441 -0
- package/src/control-plane/codex-session-stream.ts +392 -0
- package/src/control-plane/codex-telemetry.ts +1325 -0
- package/src/control-plane/lifecycle-hooks.ts +706 -0
- package/src/control-plane/session-summary.ts +380 -0
- package/src/control-plane/status/agent-status-reducer.ts +21 -0
- package/src/control-plane/status/reducer-base.ts +170 -0
- package/src/control-plane/status/reducers/claude-status-reducer.ts +37 -0
- package/src/control-plane/status/reducers/codex-status-reducer.ts +48 -0
- package/src/control-plane/status/reducers/critique-status-reducer.ts +15 -0
- package/src/control-plane/status/reducers/cursor-status-reducer.ts +37 -0
- package/src/control-plane/status/reducers/terminal-status-reducer.ts +15 -0
- package/src/control-plane/status/session-status-engine.ts +76 -0
- package/src/control-plane/stream-client.ts +396 -0
- package/src/control-plane/stream-command-parser.ts +1673 -0
- package/src/control-plane/stream-protocol.ts +1808 -0
- package/src/control-plane/stream-server-background.ts +486 -0
- package/src/control-plane/stream-server-command.ts +2557 -0
- package/src/control-plane/stream-server-connection.ts +234 -0
- package/src/control-plane/stream-server-observed-filter.ts +112 -0
- package/src/control-plane/stream-server-session-runtime.ts +566 -0
- package/src/control-plane/stream-server-state-store.ts +15 -0
- package/src/control-plane/stream-server.ts +3192 -0
- package/src/cursor/managed-hooks.ts +282 -0
- package/src/domain/conversations.ts +414 -0
- package/src/domain/directories.ts +78 -0
- package/src/domain/repositories.ts +123 -0
- package/src/domain/tasks.ts +148 -0
- package/src/domain/workspace.ts +156 -0
- package/src/events/normalized-events.ts +124 -0
- package/src/mux/ansi-integrity.ts +103 -0
- package/src/mux/control-plane-op-queue.ts +212 -0
- package/src/mux/conversation-rail.ts +339 -0
- package/src/mux/double-click.ts +78 -0
- package/src/mux/dual-pane-core.ts +435 -0
- package/src/mux/harness-core-ui.ts +817 -0
- package/src/mux/input-shortcuts.ts +667 -0
- package/src/mux/live-mux/actions-conversation.ts +344 -0
- package/src/mux/live-mux/actions-repository.ts +246 -0
- package/src/mux/live-mux/actions-task.ts +115 -0
- package/src/mux/live-mux/args.ts +142 -0
- package/src/mux/live-mux/command-menu.ts +298 -0
- package/src/mux/live-mux/control-plane-records.ts +546 -0
- package/src/mux/live-mux/conversation-state.ts +188 -0
- package/src/mux/live-mux/directory-resolution.ts +34 -0
- package/src/mux/live-mux/event-mapping.ts +96 -0
- package/src/mux/live-mux/gateway-profiler.ts +152 -0
- package/src/mux/live-mux/gateway-render-trace.ts +177 -0
- package/src/mux/live-mux/gateway-status-timeline.ts +166 -0
- package/src/mux/live-mux/git-parsing.ts +131 -0
- package/src/mux/live-mux/git-snapshot.ts +263 -0
- package/src/mux/live-mux/git-state.ts +136 -0
- package/src/mux/live-mux/global-shortcut-handlers.ts +143 -0
- package/src/mux/live-mux/home-pane-actions.ts +58 -0
- package/src/mux/live-mux/home-pane-drop.ts +44 -0
- package/src/mux/live-mux/home-pane-entity-click.ts +96 -0
- package/src/mux/live-mux/home-pane-pointer.ts +96 -0
- package/src/mux/live-mux/input-forwarding.ts +112 -0
- package/src/mux/live-mux/layout.ts +30 -0
- package/src/mux/live-mux/left-nav-activation.ts +103 -0
- package/src/mux/live-mux/left-nav.ts +85 -0
- package/src/mux/live-mux/left-rail-actions.ts +118 -0
- package/src/mux/live-mux/left-rail-conversation-click.ts +82 -0
- package/src/mux/live-mux/left-rail-pointer.ts +74 -0
- package/src/mux/live-mux/modal-command-menu-handler.ts +101 -0
- package/src/mux/live-mux/modal-conversation-handlers.ts +217 -0
- package/src/mux/live-mux/modal-input-reducers.ts +94 -0
- package/src/mux/live-mux/modal-overlays.ts +287 -0
- package/src/mux/live-mux/modal-pointer.ts +70 -0
- package/src/mux/live-mux/modal-prompt-handlers.ts +187 -0
- package/src/mux/live-mux/modal-task-editor-handler.ts +156 -0
- package/src/mux/live-mux/observed-stream.ts +87 -0
- package/src/mux/live-mux/palette-parsing.ts +128 -0
- package/src/mux/live-mux/pointer-routing.ts +108 -0
- package/src/mux/live-mux/process-usage.ts +53 -0
- package/src/mux/live-mux/project-pane-pointer.ts +44 -0
- package/src/mux/live-mux/rail-layout.ts +244 -0
- package/src/mux/live-mux/render-trace-analysis.ts +213 -0
- package/src/mux/live-mux/render-trace-state.ts +84 -0
- package/src/mux/live-mux/repository-folding.ts +207 -0
- package/src/mux/live-mux/runtime-shutdown.ts +51 -0
- package/src/mux/live-mux/selection.ts +411 -0
- package/src/mux/live-mux/startup-utils.ts +187 -0
- package/src/mux/live-mux/status-timeline-state.ts +82 -0
- package/src/mux/live-mux/task-pane-shortcuts.ts +206 -0
- package/src/mux/live-mux/terminal-palette.ts +79 -0
- package/src/mux/new-thread-prompt.ts +165 -0
- package/src/mux/project-tree.ts +295 -0
- package/src/mux/render-frame.ts +113 -0
- package/src/mux/runtime-wiring.ts +185 -0
- package/src/mux/selector-index.ts +160 -0
- package/src/mux/startup-sequencer.ts +238 -0
- package/src/mux/task-composer.ts +289 -0
- package/src/mux/task-focused-pane.ts +417 -0
- package/src/mux/task-screen-keybindings.ts +539 -0
- package/src/mux/terminal-input-modes.ts +35 -0
- package/src/mux/workspace-path.ts +55 -0
- package/src/mux/workspace-rail-model.ts +701 -0
- package/src/mux/workspace-rail.ts +247 -0
- package/src/perf/perf-core.ts +307 -0
- package/src/pty/pty_host.ts +217 -0
- package/src/pty/session-broker.ts +158 -0
- package/src/recording/terminal-recording.ts +383 -0
- package/src/services/control-plane.ts +567 -0
- package/src/services/conversation-lifecycle.ts +176 -0
- package/src/services/conversation-startup-hydration.ts +47 -0
- package/src/services/directory-hydration.ts +49 -0
- package/src/services/event-persistence.ts +104 -0
- package/src/services/mux-ui-state-persistence.ts +82 -0
- package/src/services/output-load-sampler.ts +231 -0
- package/src/services/process-usage-refresh.ts +88 -0
- package/src/services/recording.ts +75 -0
- package/src/services/render-trace-recorder.ts +177 -0
- package/src/services/runtime-control-actions.ts +123 -0
- package/src/services/runtime-control-plane-ops.ts +131 -0
- package/src/services/runtime-conversation-actions.ts +113 -0
- package/src/services/runtime-conversation-activation.ts +78 -0
- package/src/services/runtime-conversation-starter.ts +171 -0
- package/src/services/runtime-conversation-title-edit.ts +149 -0
- package/src/services/runtime-directory-actions.ts +164 -0
- package/src/services/runtime-envelope-handler.ts +198 -0
- package/src/services/runtime-git-state.ts +92 -0
- package/src/services/runtime-input-pipeline.ts +50 -0
- package/src/services/runtime-input-router.ts +202 -0
- package/src/services/runtime-layout-resize.ts +236 -0
- package/src/services/runtime-left-rail-render.ts +159 -0
- package/src/services/runtime-main-pane-input.ts +230 -0
- package/src/services/runtime-modal-input.ts +119 -0
- package/src/services/runtime-navigation-input.ts +207 -0
- package/src/services/runtime-process-wiring.ts +68 -0
- package/src/services/runtime-rail-input.ts +287 -0
- package/src/services/runtime-render-flush.ts +146 -0
- package/src/services/runtime-render-lifecycle.ts +104 -0
- package/src/services/runtime-render-orchestrator.ts +108 -0
- package/src/services/runtime-render-pipeline.ts +167 -0
- package/src/services/runtime-render-state.ts +72 -0
- package/src/services/runtime-repository-actions.ts +197 -0
- package/src/services/runtime-right-pane-render.ts +132 -0
- package/src/services/runtime-shutdown.ts +79 -0
- package/src/services/runtime-stream-subscriptions.ts +56 -0
- package/src/services/runtime-task-composer-persistence.ts +139 -0
- package/src/services/runtime-task-editor-actions.ts +83 -0
- package/src/services/runtime-task-pane-actions.ts +198 -0
- package/src/services/runtime-task-pane-shortcuts.ts +189 -0
- package/src/services/runtime-task-pane.ts +62 -0
- package/src/services/runtime-workspace-actions.ts +153 -0
- package/src/services/runtime-workspace-observed-events.ts +190 -0
- package/src/services/session-projection-instrumentation.ts +190 -0
- package/src/services/startup-background-probe.ts +91 -0
- package/src/services/startup-background-resume.ts +65 -0
- package/src/services/startup-orchestrator.ts +166 -0
- package/src/services/startup-output-tracker.ts +54 -0
- package/src/services/startup-paint-tracker.ts +115 -0
- package/src/services/startup-persisted-conversation-queue.ts +45 -0
- package/src/services/startup-settled-gate.ts +67 -0
- package/src/services/startup-shutdown.ts +53 -0
- package/src/services/startup-span-tracker.ts +77 -0
- package/src/services/startup-state-hydration.ts +94 -0
- package/src/services/startup-visibility.ts +35 -0
- package/src/services/status-timeline-recorder.ts +144 -0
- package/src/services/task-pane-selection-actions.ts +153 -0
- package/src/services/task-planning-hydration.ts +58 -0
- package/src/services/task-planning-observed-events.ts +89 -0
- package/src/services/workspace-observed-events.ts +113 -0
- package/src/store/control-plane-store-normalize.ts +760 -0
- package/src/store/control-plane-store-types.ts +224 -0
- package/src/store/control-plane-store.ts +2951 -0
- package/src/store/event-store.ts +253 -0
- package/src/store/sqlite.ts +81 -0
- package/src/terminal/compat-matrix.ts +345 -0
- package/src/terminal/differential-checkpoints.ts +132 -0
- package/src/terminal/parity-suite.ts +441 -0
- package/src/terminal/snapshot-oracle.ts +1840 -0
- package/src/ui/conversation-input-forwarder.ts +114 -0
- package/src/ui/conversation-selection-input.ts +103 -0
- package/src/ui/debug-footer-notice.ts +39 -0
- package/src/ui/global-shortcut-input.ts +126 -0
- package/src/ui/input-preflight.ts +68 -0
- package/src/ui/input-token-router.ts +312 -0
- package/src/ui/input.ts +238 -0
- package/src/ui/kit.ts +509 -0
- package/src/ui/left-nav-input.ts +80 -0
- package/src/ui/left-rail-pointer-input.ts +148 -0
- package/src/ui/main-pane-pointer-input.ts +150 -0
- package/src/ui/modals/manager.ts +192 -0
- package/src/ui/mux-theme.ts +529 -0
- package/src/ui/panes/conversation.ts +19 -0
- package/src/ui/panes/home-gridfire.ts +302 -0
- package/src/ui/panes/home.ts +109 -0
- package/src/ui/panes/left-rail.ts +12 -0
- package/src/ui/panes/project.ts +44 -0
- package/src/ui/pointer-routing-input.ts +158 -0
- package/src/ui/repository-fold-input.ts +91 -0
- package/src/ui/screen.ts +210 -0
- package/src/ui/surface.ts +224 -0
|
@@ -0,0 +1,1673 @@
|
|
|
1
|
+
import type { StreamCommand } from './stream-protocol.ts';
|
|
2
|
+
|
|
3
|
+
type StreamCommandType = StreamCommand['type'];
|
|
4
|
+
type CommandRecord = Record<string, unknown>;
|
|
5
|
+
type CommandParser = (record: CommandRecord) => StreamCommand | null;
|
|
6
|
+
type ParsedTaskLinearInput = NonNullable<Extract<StreamCommand, { type: 'task.create' }>['linear']>;
|
|
7
|
+
const INVALID_OPTIONAL = Symbol('invalid-optional');
|
|
8
|
+
|
|
9
|
+
function asRecord(value: unknown): CommandRecord | null {
|
|
10
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
return value as CommandRecord;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function readString(value: unknown): string | null {
|
|
17
|
+
return typeof value === 'string' ? value : null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function readNumber(value: unknown): number | null {
|
|
21
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function readBoolean(value: unknown): boolean | null {
|
|
25
|
+
return typeof value === 'boolean' ? value : null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function readStringRecord(value: unknown): Record<string, string> | null {
|
|
29
|
+
const record = asRecord(value);
|
|
30
|
+
if (record === null) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const normalized: Record<string, string> = {};
|
|
34
|
+
for (const [key, entryValue] of Object.entries(record)) {
|
|
35
|
+
if (typeof entryValue !== 'string') {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
normalized[key] = entryValue;
|
|
39
|
+
}
|
|
40
|
+
return normalized;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isStringArray(value: unknown): value is string[] {
|
|
44
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === 'string');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function readOptionalString(record: CommandRecord, field: string): string | null | undefined {
|
|
48
|
+
const value = readString(record[field]);
|
|
49
|
+
if (record[field] !== undefined && value === null) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function readOptionalBoolean(record: CommandRecord, field: string): boolean | null | undefined {
|
|
56
|
+
const value = readBoolean(record[field]);
|
|
57
|
+
if (record[field] !== undefined && value === null) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function readOptionalInteger(
|
|
64
|
+
record: CommandRecord,
|
|
65
|
+
field: string,
|
|
66
|
+
minInclusive: number,
|
|
67
|
+
): number | null | undefined {
|
|
68
|
+
const value = readNumber(record[field]);
|
|
69
|
+
if (record[field] !== undefined && value === null) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
if (value === null) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
if (!Number.isInteger(value) || value < minInclusive) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
return value;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function readOptionalNullableString(
|
|
82
|
+
record: CommandRecord,
|
|
83
|
+
field: string,
|
|
84
|
+
): string | null | undefined | typeof INVALID_OPTIONAL {
|
|
85
|
+
const value = record[field];
|
|
86
|
+
if (value === undefined) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
if (value === null) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
if (typeof value !== 'string') {
|
|
93
|
+
return INVALID_OPTIONAL;
|
|
94
|
+
}
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
|
|
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
|
+
function parseSessionControllerType(value: unknown): 'human' | 'agent' | 'automation' | null {
|
|
208
|
+
if (value === 'human' || value === 'agent' || value === 'automation') {
|
|
209
|
+
return value;
|
|
210
|
+
}
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function parseDirectoryUpsert(record: CommandRecord): StreamCommand | null {
|
|
215
|
+
const path = readString(record['path']);
|
|
216
|
+
if (path === null) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
const directoryId = readOptionalString(record, 'directoryId');
|
|
220
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
221
|
+
const userId = readOptionalString(record, 'userId');
|
|
222
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
223
|
+
if (
|
|
224
|
+
directoryId === undefined ||
|
|
225
|
+
tenantId === undefined ||
|
|
226
|
+
userId === undefined ||
|
|
227
|
+
workspaceId === undefined
|
|
228
|
+
) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
const command: StreamCommand = {
|
|
232
|
+
type: 'directory.upsert',
|
|
233
|
+
path,
|
|
234
|
+
};
|
|
235
|
+
if (directoryId !== null) {
|
|
236
|
+
command.directoryId = directoryId;
|
|
237
|
+
}
|
|
238
|
+
if (tenantId !== null) {
|
|
239
|
+
command.tenantId = tenantId;
|
|
240
|
+
}
|
|
241
|
+
if (userId !== null) {
|
|
242
|
+
command.userId = userId;
|
|
243
|
+
}
|
|
244
|
+
if (workspaceId !== null) {
|
|
245
|
+
command.workspaceId = workspaceId;
|
|
246
|
+
}
|
|
247
|
+
return command;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function parseDirectoryList(record: CommandRecord): StreamCommand | null {
|
|
251
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
252
|
+
const userId = readOptionalString(record, 'userId');
|
|
253
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
254
|
+
const includeArchived = readOptionalBoolean(record, 'includeArchived');
|
|
255
|
+
const limit = readOptionalInteger(record, 'limit', 1);
|
|
256
|
+
if (
|
|
257
|
+
tenantId === undefined ||
|
|
258
|
+
userId === undefined ||
|
|
259
|
+
workspaceId === undefined ||
|
|
260
|
+
includeArchived === undefined ||
|
|
261
|
+
limit === undefined
|
|
262
|
+
) {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
const command: StreamCommand = {
|
|
266
|
+
type: 'directory.list',
|
|
267
|
+
};
|
|
268
|
+
if (tenantId !== null) {
|
|
269
|
+
command.tenantId = tenantId;
|
|
270
|
+
}
|
|
271
|
+
if (userId !== null) {
|
|
272
|
+
command.userId = userId;
|
|
273
|
+
}
|
|
274
|
+
if (workspaceId !== null) {
|
|
275
|
+
command.workspaceId = workspaceId;
|
|
276
|
+
}
|
|
277
|
+
if (includeArchived !== null) {
|
|
278
|
+
command.includeArchived = includeArchived;
|
|
279
|
+
}
|
|
280
|
+
if (limit !== null) {
|
|
281
|
+
command.limit = limit;
|
|
282
|
+
}
|
|
283
|
+
return command;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function parseDirectoryArchive(record: CommandRecord): StreamCommand | null {
|
|
287
|
+
const directoryId = readString(record['directoryId']);
|
|
288
|
+
if (directoryId === null) {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
type: 'directory.archive',
|
|
293
|
+
directoryId,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function parseDirectoryGitStatusList(record: CommandRecord): StreamCommand | null {
|
|
298
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
299
|
+
const userId = readOptionalString(record, 'userId');
|
|
300
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
301
|
+
const directoryId = readOptionalString(record, 'directoryId');
|
|
302
|
+
if (
|
|
303
|
+
tenantId === undefined ||
|
|
304
|
+
userId === undefined ||
|
|
305
|
+
workspaceId === undefined ||
|
|
306
|
+
directoryId === undefined
|
|
307
|
+
) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
const command: StreamCommand = {
|
|
311
|
+
type: 'directory.git-status',
|
|
312
|
+
};
|
|
313
|
+
if (tenantId !== null) {
|
|
314
|
+
command.tenantId = tenantId;
|
|
315
|
+
}
|
|
316
|
+
if (userId !== null) {
|
|
317
|
+
command.userId = userId;
|
|
318
|
+
}
|
|
319
|
+
if (workspaceId !== null) {
|
|
320
|
+
command.workspaceId = workspaceId;
|
|
321
|
+
}
|
|
322
|
+
if (directoryId !== null) {
|
|
323
|
+
command.directoryId = directoryId;
|
|
324
|
+
}
|
|
325
|
+
return command;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function parseConversationCreate(record: CommandRecord): StreamCommand | null {
|
|
329
|
+
const directoryId = readString(record['directoryId']);
|
|
330
|
+
const title = readString(record['title']);
|
|
331
|
+
const agentType = readString(record['agentType']);
|
|
332
|
+
if (directoryId === null || title === null || agentType === null) {
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
const conversationId = readOptionalString(record, 'conversationId');
|
|
336
|
+
if (conversationId === undefined) {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
const command: StreamCommand = {
|
|
340
|
+
type: 'conversation.create',
|
|
341
|
+
directoryId,
|
|
342
|
+
title,
|
|
343
|
+
agentType,
|
|
344
|
+
};
|
|
345
|
+
const adapterState = record['adapterState'];
|
|
346
|
+
if (adapterState !== undefined) {
|
|
347
|
+
const parsedAdapterState = asRecord(adapterState);
|
|
348
|
+
if (parsedAdapterState === null) {
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
command.adapterState = parsedAdapterState;
|
|
352
|
+
}
|
|
353
|
+
if (conversationId !== null) {
|
|
354
|
+
command.conversationId = conversationId;
|
|
355
|
+
}
|
|
356
|
+
return command;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function parseConversationList(record: CommandRecord): StreamCommand | null {
|
|
360
|
+
const directoryId = readOptionalString(record, 'directoryId');
|
|
361
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
362
|
+
const userId = readOptionalString(record, 'userId');
|
|
363
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
364
|
+
const includeArchived = readOptionalBoolean(record, 'includeArchived');
|
|
365
|
+
const limit = readOptionalInteger(record, 'limit', 1);
|
|
366
|
+
if (
|
|
367
|
+
directoryId === undefined ||
|
|
368
|
+
tenantId === undefined ||
|
|
369
|
+
userId === undefined ||
|
|
370
|
+
workspaceId === undefined ||
|
|
371
|
+
includeArchived === undefined ||
|
|
372
|
+
limit === undefined
|
|
373
|
+
) {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
const command: StreamCommand = {
|
|
377
|
+
type: 'conversation.list',
|
|
378
|
+
};
|
|
379
|
+
if (directoryId !== null) {
|
|
380
|
+
command.directoryId = directoryId;
|
|
381
|
+
}
|
|
382
|
+
if (tenantId !== null) {
|
|
383
|
+
command.tenantId = tenantId;
|
|
384
|
+
}
|
|
385
|
+
if (userId !== null) {
|
|
386
|
+
command.userId = userId;
|
|
387
|
+
}
|
|
388
|
+
if (workspaceId !== null) {
|
|
389
|
+
command.workspaceId = workspaceId;
|
|
390
|
+
}
|
|
391
|
+
if (includeArchived !== null) {
|
|
392
|
+
command.includeArchived = includeArchived;
|
|
393
|
+
}
|
|
394
|
+
if (limit !== null) {
|
|
395
|
+
command.limit = limit;
|
|
396
|
+
}
|
|
397
|
+
return command;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function parseConversationArchive(record: CommandRecord): StreamCommand | null {
|
|
401
|
+
const conversationId = readString(record['conversationId']);
|
|
402
|
+
if (conversationId === null) {
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
return {
|
|
406
|
+
type: 'conversation.archive',
|
|
407
|
+
conversationId,
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function parseConversationUpdate(record: CommandRecord): StreamCommand | null {
|
|
412
|
+
const conversationId = readString(record['conversationId']);
|
|
413
|
+
const title = readString(record['title']);
|
|
414
|
+
if (conversationId === null || title === null) {
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
return {
|
|
418
|
+
type: 'conversation.update',
|
|
419
|
+
conversationId,
|
|
420
|
+
title,
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function parseConversationDelete(record: CommandRecord): StreamCommand | null {
|
|
425
|
+
const conversationId = readString(record['conversationId']);
|
|
426
|
+
if (conversationId === null) {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
return {
|
|
430
|
+
type: 'conversation.delete',
|
|
431
|
+
conversationId,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function parseRepositoryUpsert(record: CommandRecord): StreamCommand | null {
|
|
436
|
+
const name = readString(record['name']);
|
|
437
|
+
const remoteUrl = readString(record['remoteUrl']);
|
|
438
|
+
if (name === null || remoteUrl === null) {
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
const repositoryId = readOptionalString(record, 'repositoryId');
|
|
442
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
443
|
+
const userId = readOptionalString(record, 'userId');
|
|
444
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
445
|
+
const defaultBranch = readOptionalString(record, 'defaultBranch');
|
|
446
|
+
if (
|
|
447
|
+
repositoryId === undefined ||
|
|
448
|
+
tenantId === undefined ||
|
|
449
|
+
userId === undefined ||
|
|
450
|
+
workspaceId === undefined ||
|
|
451
|
+
defaultBranch === undefined
|
|
452
|
+
) {
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
const command: StreamCommand = {
|
|
456
|
+
type: 'repository.upsert',
|
|
457
|
+
name,
|
|
458
|
+
remoteUrl,
|
|
459
|
+
};
|
|
460
|
+
if (repositoryId !== null) {
|
|
461
|
+
command.repositoryId = repositoryId;
|
|
462
|
+
}
|
|
463
|
+
if (tenantId !== null) {
|
|
464
|
+
command.tenantId = tenantId;
|
|
465
|
+
}
|
|
466
|
+
if (userId !== null) {
|
|
467
|
+
command.userId = userId;
|
|
468
|
+
}
|
|
469
|
+
if (workspaceId !== null) {
|
|
470
|
+
command.workspaceId = workspaceId;
|
|
471
|
+
}
|
|
472
|
+
if (defaultBranch !== null) {
|
|
473
|
+
command.defaultBranch = defaultBranch;
|
|
474
|
+
}
|
|
475
|
+
if (record['metadata'] !== undefined) {
|
|
476
|
+
const metadata = asRecord(record['metadata']);
|
|
477
|
+
if (metadata === null) {
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
command.metadata = metadata;
|
|
481
|
+
}
|
|
482
|
+
return command;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function parseRepositoryGet(record: CommandRecord): StreamCommand | null {
|
|
486
|
+
const repositoryId = readString(record['repositoryId']);
|
|
487
|
+
if (repositoryId === null) {
|
|
488
|
+
return null;
|
|
489
|
+
}
|
|
490
|
+
return {
|
|
491
|
+
type: 'repository.get',
|
|
492
|
+
repositoryId,
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function parseRepositoryList(record: CommandRecord): StreamCommand | null {
|
|
497
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
498
|
+
const userId = readOptionalString(record, 'userId');
|
|
499
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
500
|
+
const includeArchived = readOptionalBoolean(record, 'includeArchived');
|
|
501
|
+
const limit = readOptionalInteger(record, 'limit', 1);
|
|
502
|
+
if (
|
|
503
|
+
tenantId === undefined ||
|
|
504
|
+
userId === undefined ||
|
|
505
|
+
workspaceId === undefined ||
|
|
506
|
+
includeArchived === undefined ||
|
|
507
|
+
limit === undefined
|
|
508
|
+
) {
|
|
509
|
+
return null;
|
|
510
|
+
}
|
|
511
|
+
const command: StreamCommand = {
|
|
512
|
+
type: 'repository.list',
|
|
513
|
+
};
|
|
514
|
+
if (tenantId !== null) {
|
|
515
|
+
command.tenantId = tenantId;
|
|
516
|
+
}
|
|
517
|
+
if (userId !== null) {
|
|
518
|
+
command.userId = userId;
|
|
519
|
+
}
|
|
520
|
+
if (workspaceId !== null) {
|
|
521
|
+
command.workspaceId = workspaceId;
|
|
522
|
+
}
|
|
523
|
+
if (includeArchived !== null) {
|
|
524
|
+
command.includeArchived = includeArchived;
|
|
525
|
+
}
|
|
526
|
+
if (limit !== null) {
|
|
527
|
+
command.limit = limit;
|
|
528
|
+
}
|
|
529
|
+
return command;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function parseRepositoryUpdate(record: CommandRecord): StreamCommand | null {
|
|
533
|
+
const repositoryId = readString(record['repositoryId']);
|
|
534
|
+
if (repositoryId === null) {
|
|
535
|
+
return null;
|
|
536
|
+
}
|
|
537
|
+
const name = readOptionalString(record, 'name');
|
|
538
|
+
const remoteUrl = readOptionalString(record, 'remoteUrl');
|
|
539
|
+
const defaultBranch = readOptionalString(record, 'defaultBranch');
|
|
540
|
+
if (name === undefined || remoteUrl === undefined || defaultBranch === undefined) {
|
|
541
|
+
return null;
|
|
542
|
+
}
|
|
543
|
+
const command: StreamCommand = {
|
|
544
|
+
type: 'repository.update',
|
|
545
|
+
repositoryId,
|
|
546
|
+
};
|
|
547
|
+
if (name !== null) {
|
|
548
|
+
command.name = name;
|
|
549
|
+
}
|
|
550
|
+
if (remoteUrl !== null) {
|
|
551
|
+
command.remoteUrl = remoteUrl;
|
|
552
|
+
}
|
|
553
|
+
if (defaultBranch !== null) {
|
|
554
|
+
command.defaultBranch = defaultBranch;
|
|
555
|
+
}
|
|
556
|
+
if (record['metadata'] !== undefined) {
|
|
557
|
+
const metadata = asRecord(record['metadata']);
|
|
558
|
+
if (metadata === null) {
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
561
|
+
command.metadata = metadata;
|
|
562
|
+
}
|
|
563
|
+
return command;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
function parseRepositoryArchive(record: CommandRecord): StreamCommand | null {
|
|
567
|
+
const repositoryId = readString(record['repositoryId']);
|
|
568
|
+
if (repositoryId === null) {
|
|
569
|
+
return null;
|
|
570
|
+
}
|
|
571
|
+
return {
|
|
572
|
+
type: 'repository.archive',
|
|
573
|
+
repositoryId,
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
function parseTaskCreate(record: CommandRecord): StreamCommand | null {
|
|
578
|
+
const title = readString(record['title']);
|
|
579
|
+
if (title === null) {
|
|
580
|
+
return null;
|
|
581
|
+
}
|
|
582
|
+
const taskId = readOptionalString(record, 'taskId');
|
|
583
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
584
|
+
const userId = readOptionalString(record, 'userId');
|
|
585
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
586
|
+
const repositoryId = readOptionalString(record, 'repositoryId');
|
|
587
|
+
const projectId = readOptionalString(record, 'projectId');
|
|
588
|
+
const description = readOptionalString(record, 'description');
|
|
589
|
+
if (
|
|
590
|
+
taskId === undefined ||
|
|
591
|
+
tenantId === undefined ||
|
|
592
|
+
userId === undefined ||
|
|
593
|
+
workspaceId === undefined ||
|
|
594
|
+
repositoryId === undefined ||
|
|
595
|
+
projectId === undefined ||
|
|
596
|
+
description === undefined
|
|
597
|
+
) {
|
|
598
|
+
return null;
|
|
599
|
+
}
|
|
600
|
+
const command: StreamCommand = {
|
|
601
|
+
type: 'task.create',
|
|
602
|
+
title,
|
|
603
|
+
};
|
|
604
|
+
if (taskId !== null) {
|
|
605
|
+
command.taskId = taskId;
|
|
606
|
+
}
|
|
607
|
+
if (tenantId !== null) {
|
|
608
|
+
command.tenantId = tenantId;
|
|
609
|
+
}
|
|
610
|
+
if (userId !== null) {
|
|
611
|
+
command.userId = userId;
|
|
612
|
+
}
|
|
613
|
+
if (workspaceId !== null) {
|
|
614
|
+
command.workspaceId = workspaceId;
|
|
615
|
+
}
|
|
616
|
+
if (repositoryId !== null) {
|
|
617
|
+
command.repositoryId = repositoryId;
|
|
618
|
+
}
|
|
619
|
+
if (projectId !== null) {
|
|
620
|
+
command.projectId = projectId;
|
|
621
|
+
}
|
|
622
|
+
if (description !== null) {
|
|
623
|
+
command.description = description;
|
|
624
|
+
}
|
|
625
|
+
if (record['linear'] !== undefined) {
|
|
626
|
+
const linear = parseTaskLinearInput(record['linear']);
|
|
627
|
+
if (linear === null) {
|
|
628
|
+
return null;
|
|
629
|
+
}
|
|
630
|
+
command.linear = linear;
|
|
631
|
+
}
|
|
632
|
+
return command;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
function parseTaskGet(record: CommandRecord): StreamCommand | null {
|
|
636
|
+
const taskId = readString(record['taskId']);
|
|
637
|
+
if (taskId === null) {
|
|
638
|
+
return null;
|
|
639
|
+
}
|
|
640
|
+
return {
|
|
641
|
+
type: 'task.get',
|
|
642
|
+
taskId,
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
function parseTaskList(record: CommandRecord): StreamCommand | null {
|
|
647
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
648
|
+
const userId = readOptionalString(record, 'userId');
|
|
649
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
650
|
+
const repositoryId = readOptionalString(record, 'repositoryId');
|
|
651
|
+
const projectId = readOptionalString(record, 'projectId');
|
|
652
|
+
const scopeKind = readOptionalString(record, 'scopeKind');
|
|
653
|
+
const status = readOptionalString(record, 'status');
|
|
654
|
+
const limit = readOptionalInteger(record, 'limit', 1);
|
|
655
|
+
if (
|
|
656
|
+
tenantId === undefined ||
|
|
657
|
+
userId === undefined ||
|
|
658
|
+
workspaceId === undefined ||
|
|
659
|
+
repositoryId === undefined ||
|
|
660
|
+
projectId === undefined ||
|
|
661
|
+
scopeKind === undefined ||
|
|
662
|
+
status === undefined ||
|
|
663
|
+
limit === undefined
|
|
664
|
+
) {
|
|
665
|
+
return null;
|
|
666
|
+
}
|
|
667
|
+
if (
|
|
668
|
+
scopeKind !== null &&
|
|
669
|
+
scopeKind !== 'global' &&
|
|
670
|
+
scopeKind !== 'repository' &&
|
|
671
|
+
scopeKind !== 'project'
|
|
672
|
+
) {
|
|
673
|
+
return null;
|
|
674
|
+
}
|
|
675
|
+
if (
|
|
676
|
+
status !== null &&
|
|
677
|
+
status !== 'draft' &&
|
|
678
|
+
status !== 'ready' &&
|
|
679
|
+
status !== 'queued' &&
|
|
680
|
+
status !== 'in-progress' &&
|
|
681
|
+
status !== 'completed'
|
|
682
|
+
) {
|
|
683
|
+
return null;
|
|
684
|
+
}
|
|
685
|
+
const command: StreamCommand = {
|
|
686
|
+
type: 'task.list',
|
|
687
|
+
};
|
|
688
|
+
if (tenantId !== null) {
|
|
689
|
+
command.tenantId = tenantId;
|
|
690
|
+
}
|
|
691
|
+
if (userId !== null) {
|
|
692
|
+
command.userId = userId;
|
|
693
|
+
}
|
|
694
|
+
if (workspaceId !== null) {
|
|
695
|
+
command.workspaceId = workspaceId;
|
|
696
|
+
}
|
|
697
|
+
if (repositoryId !== null) {
|
|
698
|
+
command.repositoryId = repositoryId;
|
|
699
|
+
}
|
|
700
|
+
if (projectId !== null) {
|
|
701
|
+
command.projectId = projectId;
|
|
702
|
+
}
|
|
703
|
+
if (scopeKind !== null) {
|
|
704
|
+
command.scopeKind = scopeKind;
|
|
705
|
+
}
|
|
706
|
+
if (status !== null) {
|
|
707
|
+
command.status = status === 'queued' ? 'ready' : status;
|
|
708
|
+
}
|
|
709
|
+
if (limit !== null) {
|
|
710
|
+
command.limit = limit;
|
|
711
|
+
}
|
|
712
|
+
return command;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
function parseTaskUpdate(record: CommandRecord): StreamCommand | null {
|
|
716
|
+
const taskId = readString(record['taskId']);
|
|
717
|
+
if (taskId === null) {
|
|
718
|
+
return null;
|
|
719
|
+
}
|
|
720
|
+
const title = readOptionalString(record, 'title');
|
|
721
|
+
const description = readOptionalString(record, 'description');
|
|
722
|
+
if (title === undefined || description === undefined) {
|
|
723
|
+
return null;
|
|
724
|
+
}
|
|
725
|
+
let repositoryId: string | null | undefined;
|
|
726
|
+
let projectId: string | null | undefined;
|
|
727
|
+
if (record['repositoryId'] === undefined) {
|
|
728
|
+
repositoryId = undefined;
|
|
729
|
+
} else if (record['repositoryId'] === null) {
|
|
730
|
+
repositoryId = null;
|
|
731
|
+
} else if (typeof record['repositoryId'] === 'string') {
|
|
732
|
+
repositoryId = record['repositoryId'];
|
|
733
|
+
} else {
|
|
734
|
+
return null;
|
|
735
|
+
}
|
|
736
|
+
if (record['projectId'] === undefined) {
|
|
737
|
+
projectId = undefined;
|
|
738
|
+
} else if (record['projectId'] === null) {
|
|
739
|
+
projectId = null;
|
|
740
|
+
} else if (typeof record['projectId'] === 'string') {
|
|
741
|
+
projectId = record['projectId'];
|
|
742
|
+
} else {
|
|
743
|
+
return null;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
const command: StreamCommand = {
|
|
747
|
+
type: 'task.update',
|
|
748
|
+
taskId,
|
|
749
|
+
};
|
|
750
|
+
if (title !== null) {
|
|
751
|
+
command.title = title;
|
|
752
|
+
}
|
|
753
|
+
if (description !== null) {
|
|
754
|
+
command.description = description;
|
|
755
|
+
}
|
|
756
|
+
if (repositoryId !== undefined) {
|
|
757
|
+
command.repositoryId = repositoryId;
|
|
758
|
+
}
|
|
759
|
+
if (projectId !== undefined) {
|
|
760
|
+
command.projectId = projectId;
|
|
761
|
+
}
|
|
762
|
+
if (record['linear'] !== undefined) {
|
|
763
|
+
if (record['linear'] === null) {
|
|
764
|
+
command.linear = null;
|
|
765
|
+
} else {
|
|
766
|
+
const linear = parseTaskLinearInput(record['linear']);
|
|
767
|
+
if (linear === null) {
|
|
768
|
+
return null;
|
|
769
|
+
}
|
|
770
|
+
command.linear = linear;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
return command;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
function parseTaskDelete(record: CommandRecord): StreamCommand | null {
|
|
777
|
+
const taskId = readString(record['taskId']);
|
|
778
|
+
if (taskId === null) {
|
|
779
|
+
return null;
|
|
780
|
+
}
|
|
781
|
+
return {
|
|
782
|
+
type: 'task.delete',
|
|
783
|
+
taskId,
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
function parseTaskClaim(record: CommandRecord): StreamCommand | null {
|
|
788
|
+
const taskId = readString(record['taskId']);
|
|
789
|
+
const controllerId = readString(record['controllerId']);
|
|
790
|
+
if (taskId === null || controllerId === null) {
|
|
791
|
+
return null;
|
|
792
|
+
}
|
|
793
|
+
const directoryId = readOptionalString(record, 'directoryId');
|
|
794
|
+
const branchName = readOptionalString(record, 'branchName');
|
|
795
|
+
const baseBranch = readOptionalString(record, 'baseBranch');
|
|
796
|
+
if (directoryId === undefined || branchName === undefined || baseBranch === undefined) {
|
|
797
|
+
return null;
|
|
798
|
+
}
|
|
799
|
+
const command: StreamCommand = {
|
|
800
|
+
type: 'task.claim',
|
|
801
|
+
taskId,
|
|
802
|
+
controllerId,
|
|
803
|
+
};
|
|
804
|
+
if (directoryId !== null) {
|
|
805
|
+
command.directoryId = directoryId;
|
|
806
|
+
}
|
|
807
|
+
if (branchName !== null) {
|
|
808
|
+
command.branchName = branchName;
|
|
809
|
+
}
|
|
810
|
+
if (baseBranch !== null) {
|
|
811
|
+
command.baseBranch = baseBranch;
|
|
812
|
+
}
|
|
813
|
+
return command;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
function parseTaskPull(record: CommandRecord): StreamCommand | null {
|
|
817
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
818
|
+
const userId = readOptionalString(record, 'userId');
|
|
819
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
820
|
+
const controllerId = readString(record['controllerId']);
|
|
821
|
+
const directoryId = readOptionalString(record, 'directoryId');
|
|
822
|
+
const repositoryId = readOptionalString(record, 'repositoryId');
|
|
823
|
+
const branchName = readOptionalString(record, 'branchName');
|
|
824
|
+
const baseBranch = readOptionalString(record, 'baseBranch');
|
|
825
|
+
if (
|
|
826
|
+
tenantId === undefined ||
|
|
827
|
+
userId === undefined ||
|
|
828
|
+
workspaceId === undefined ||
|
|
829
|
+
controllerId === null ||
|
|
830
|
+
directoryId === undefined ||
|
|
831
|
+
repositoryId === undefined ||
|
|
832
|
+
branchName === undefined ||
|
|
833
|
+
baseBranch === undefined
|
|
834
|
+
) {
|
|
835
|
+
return null;
|
|
836
|
+
}
|
|
837
|
+
const command: StreamCommand = {
|
|
838
|
+
type: 'task.pull',
|
|
839
|
+
controllerId,
|
|
840
|
+
};
|
|
841
|
+
if (tenantId !== null) {
|
|
842
|
+
command.tenantId = tenantId;
|
|
843
|
+
}
|
|
844
|
+
if (userId !== null) {
|
|
845
|
+
command.userId = userId;
|
|
846
|
+
}
|
|
847
|
+
if (workspaceId !== null) {
|
|
848
|
+
command.workspaceId = workspaceId;
|
|
849
|
+
}
|
|
850
|
+
if (directoryId !== null) {
|
|
851
|
+
command.directoryId = directoryId;
|
|
852
|
+
}
|
|
853
|
+
if (repositoryId !== null) {
|
|
854
|
+
command.repositoryId = repositoryId;
|
|
855
|
+
}
|
|
856
|
+
if (branchName !== null) {
|
|
857
|
+
command.branchName = branchName;
|
|
858
|
+
}
|
|
859
|
+
if (baseBranch !== null) {
|
|
860
|
+
command.baseBranch = baseBranch;
|
|
861
|
+
}
|
|
862
|
+
return command;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
function parseTaskComplete(record: CommandRecord): StreamCommand | null {
|
|
866
|
+
const taskId = readString(record['taskId']);
|
|
867
|
+
if (taskId === null) {
|
|
868
|
+
return null;
|
|
869
|
+
}
|
|
870
|
+
return {
|
|
871
|
+
type: 'task.complete',
|
|
872
|
+
taskId,
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
function parseTaskQueue(record: CommandRecord): StreamCommand | null {
|
|
877
|
+
const taskId = readString(record['taskId']);
|
|
878
|
+
if (taskId === null) {
|
|
879
|
+
return null;
|
|
880
|
+
}
|
|
881
|
+
return {
|
|
882
|
+
type: 'task.queue',
|
|
883
|
+
taskId,
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
function parseTaskReady(record: CommandRecord): StreamCommand | null {
|
|
888
|
+
const taskId = readString(record['taskId']);
|
|
889
|
+
if (taskId === null) {
|
|
890
|
+
return null;
|
|
891
|
+
}
|
|
892
|
+
return {
|
|
893
|
+
type: 'task.ready',
|
|
894
|
+
taskId,
|
|
895
|
+
};
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
function parseTaskDraft(record: CommandRecord): StreamCommand | null {
|
|
899
|
+
const taskId = readString(record['taskId']);
|
|
900
|
+
if (taskId === null) {
|
|
901
|
+
return null;
|
|
902
|
+
}
|
|
903
|
+
return {
|
|
904
|
+
type: 'task.draft',
|
|
905
|
+
taskId,
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
function parseTaskReorder(record: CommandRecord): StreamCommand | null {
|
|
910
|
+
const tenantId = readString(record['tenantId']);
|
|
911
|
+
const userId = readString(record['userId']);
|
|
912
|
+
const workspaceId = readString(record['workspaceId']);
|
|
913
|
+
const orderedTaskIds = record['orderedTaskIds'];
|
|
914
|
+
if (
|
|
915
|
+
tenantId === null ||
|
|
916
|
+
userId === null ||
|
|
917
|
+
workspaceId === null ||
|
|
918
|
+
!isStringArray(orderedTaskIds)
|
|
919
|
+
) {
|
|
920
|
+
return null;
|
|
921
|
+
}
|
|
922
|
+
return {
|
|
923
|
+
type: 'task.reorder',
|
|
924
|
+
tenantId,
|
|
925
|
+
userId,
|
|
926
|
+
workspaceId,
|
|
927
|
+
orderedTaskIds,
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
function parseProjectSettingsGet(record: CommandRecord): StreamCommand | null {
|
|
932
|
+
const directoryId = readString(record['directoryId']);
|
|
933
|
+
if (directoryId === null) {
|
|
934
|
+
return null;
|
|
935
|
+
}
|
|
936
|
+
return {
|
|
937
|
+
type: 'project.settings-get',
|
|
938
|
+
directoryId,
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
function parseProjectSettingsUpdate(record: CommandRecord): StreamCommand | null {
|
|
943
|
+
const directoryId = readString(record['directoryId']);
|
|
944
|
+
if (directoryId === null) {
|
|
945
|
+
return null;
|
|
946
|
+
}
|
|
947
|
+
const pinnedBranch = readOptionalNullableString(record, 'pinnedBranch');
|
|
948
|
+
const taskFocusMode = readOptionalString(record, 'taskFocusMode');
|
|
949
|
+
const threadSpawnMode = readOptionalString(record, 'threadSpawnMode');
|
|
950
|
+
if (
|
|
951
|
+
pinnedBranch === INVALID_OPTIONAL ||
|
|
952
|
+
taskFocusMode === undefined ||
|
|
953
|
+
threadSpawnMode === undefined
|
|
954
|
+
) {
|
|
955
|
+
return null;
|
|
956
|
+
}
|
|
957
|
+
if (taskFocusMode !== null && taskFocusMode !== 'balanced' && taskFocusMode !== 'own-only') {
|
|
958
|
+
return null;
|
|
959
|
+
}
|
|
960
|
+
if (
|
|
961
|
+
threadSpawnMode !== null &&
|
|
962
|
+
threadSpawnMode !== 'new-thread' &&
|
|
963
|
+
threadSpawnMode !== 'reuse-thread'
|
|
964
|
+
) {
|
|
965
|
+
return null;
|
|
966
|
+
}
|
|
967
|
+
const command: StreamCommand = {
|
|
968
|
+
type: 'project.settings-update',
|
|
969
|
+
directoryId,
|
|
970
|
+
};
|
|
971
|
+
if (pinnedBranch !== undefined) {
|
|
972
|
+
command.pinnedBranch = pinnedBranch;
|
|
973
|
+
}
|
|
974
|
+
if (taskFocusMode !== null) {
|
|
975
|
+
command.taskFocusMode = taskFocusMode;
|
|
976
|
+
}
|
|
977
|
+
if (threadSpawnMode !== null) {
|
|
978
|
+
command.threadSpawnMode = threadSpawnMode;
|
|
979
|
+
}
|
|
980
|
+
return command;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
function parseProjectStatus(record: CommandRecord): StreamCommand | null {
|
|
984
|
+
const directoryId = readString(record['directoryId']);
|
|
985
|
+
if (directoryId === null) {
|
|
986
|
+
return null;
|
|
987
|
+
}
|
|
988
|
+
return {
|
|
989
|
+
type: 'project.status',
|
|
990
|
+
directoryId,
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
function parseAutomationPolicyGet(record: CommandRecord): StreamCommand | null {
|
|
995
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
996
|
+
const userId = readOptionalString(record, 'userId');
|
|
997
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
998
|
+
const scope = readString(record['scope']);
|
|
999
|
+
const scopeId = readOptionalString(record, 'scopeId');
|
|
1000
|
+
if (
|
|
1001
|
+
tenantId === undefined ||
|
|
1002
|
+
userId === undefined ||
|
|
1003
|
+
workspaceId === undefined ||
|
|
1004
|
+
scope === null ||
|
|
1005
|
+
scopeId === undefined
|
|
1006
|
+
) {
|
|
1007
|
+
return null;
|
|
1008
|
+
}
|
|
1009
|
+
if (scope !== 'global' && scope !== 'repository' && scope !== 'project') {
|
|
1010
|
+
return null;
|
|
1011
|
+
}
|
|
1012
|
+
if (scope === 'global' && scopeId !== null) {
|
|
1013
|
+
return null;
|
|
1014
|
+
}
|
|
1015
|
+
if (scope !== 'global' && scopeId === null) {
|
|
1016
|
+
return null;
|
|
1017
|
+
}
|
|
1018
|
+
const command: StreamCommand = {
|
|
1019
|
+
type: 'automation.policy-get',
|
|
1020
|
+
scope,
|
|
1021
|
+
};
|
|
1022
|
+
if (tenantId !== null) {
|
|
1023
|
+
command.tenantId = tenantId;
|
|
1024
|
+
}
|
|
1025
|
+
if (userId !== null) {
|
|
1026
|
+
command.userId = userId;
|
|
1027
|
+
}
|
|
1028
|
+
if (workspaceId !== null) {
|
|
1029
|
+
command.workspaceId = workspaceId;
|
|
1030
|
+
}
|
|
1031
|
+
if (scopeId !== null) {
|
|
1032
|
+
command.scopeId = scopeId;
|
|
1033
|
+
}
|
|
1034
|
+
return command;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
function parseAutomationPolicySet(record: CommandRecord): StreamCommand | null {
|
|
1038
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
1039
|
+
const userId = readOptionalString(record, 'userId');
|
|
1040
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
1041
|
+
const scope = readString(record['scope']);
|
|
1042
|
+
const scopeId = readOptionalString(record, 'scopeId');
|
|
1043
|
+
const automationEnabled = readOptionalBoolean(record, 'automationEnabled');
|
|
1044
|
+
const frozen = readOptionalBoolean(record, 'frozen');
|
|
1045
|
+
if (
|
|
1046
|
+
tenantId === undefined ||
|
|
1047
|
+
userId === undefined ||
|
|
1048
|
+
workspaceId === undefined ||
|
|
1049
|
+
scope === null ||
|
|
1050
|
+
scopeId === undefined ||
|
|
1051
|
+
automationEnabled === undefined ||
|
|
1052
|
+
frozen === undefined
|
|
1053
|
+
) {
|
|
1054
|
+
return null;
|
|
1055
|
+
}
|
|
1056
|
+
if (scope !== 'global' && scope !== 'repository' && scope !== 'project') {
|
|
1057
|
+
return null;
|
|
1058
|
+
}
|
|
1059
|
+
if (scope === 'global' && scopeId !== null) {
|
|
1060
|
+
return null;
|
|
1061
|
+
}
|
|
1062
|
+
if (scope !== 'global' && scopeId === null) {
|
|
1063
|
+
return null;
|
|
1064
|
+
}
|
|
1065
|
+
const command: StreamCommand = {
|
|
1066
|
+
type: 'automation.policy-set',
|
|
1067
|
+
scope,
|
|
1068
|
+
};
|
|
1069
|
+
if (tenantId !== null) {
|
|
1070
|
+
command.tenantId = tenantId;
|
|
1071
|
+
}
|
|
1072
|
+
if (userId !== null) {
|
|
1073
|
+
command.userId = userId;
|
|
1074
|
+
}
|
|
1075
|
+
if (workspaceId !== null) {
|
|
1076
|
+
command.workspaceId = workspaceId;
|
|
1077
|
+
}
|
|
1078
|
+
if (scopeId !== null) {
|
|
1079
|
+
command.scopeId = scopeId;
|
|
1080
|
+
}
|
|
1081
|
+
if (automationEnabled !== null) {
|
|
1082
|
+
command.automationEnabled = automationEnabled;
|
|
1083
|
+
}
|
|
1084
|
+
if (frozen !== null) {
|
|
1085
|
+
command.frozen = frozen;
|
|
1086
|
+
}
|
|
1087
|
+
return command;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
function parseGitHubProjectPr(record: CommandRecord): StreamCommand | null {
|
|
1091
|
+
const directoryId = readString(record['directoryId']);
|
|
1092
|
+
if (directoryId === null) {
|
|
1093
|
+
return null;
|
|
1094
|
+
}
|
|
1095
|
+
return {
|
|
1096
|
+
type: 'github.project-pr',
|
|
1097
|
+
directoryId,
|
|
1098
|
+
};
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
function parseGitHubPrList(record: CommandRecord): StreamCommand | null {
|
|
1102
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
1103
|
+
const userId = readOptionalString(record, 'userId');
|
|
1104
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
1105
|
+
const repositoryId = readOptionalString(record, 'repositoryId');
|
|
1106
|
+
const directoryId = readOptionalString(record, 'directoryId');
|
|
1107
|
+
const headBranch = readOptionalString(record, 'headBranch');
|
|
1108
|
+
const state = readOptionalString(record, 'state');
|
|
1109
|
+
const limit = readOptionalInteger(record, 'limit', 1);
|
|
1110
|
+
if (
|
|
1111
|
+
tenantId === undefined ||
|
|
1112
|
+
userId === undefined ||
|
|
1113
|
+
workspaceId === undefined ||
|
|
1114
|
+
repositoryId === undefined ||
|
|
1115
|
+
directoryId === undefined ||
|
|
1116
|
+
headBranch === undefined ||
|
|
1117
|
+
state === undefined ||
|
|
1118
|
+
limit === undefined
|
|
1119
|
+
) {
|
|
1120
|
+
return null;
|
|
1121
|
+
}
|
|
1122
|
+
if (state !== null && state !== 'open' && state !== 'closed') {
|
|
1123
|
+
return null;
|
|
1124
|
+
}
|
|
1125
|
+
const command: StreamCommand = {
|
|
1126
|
+
type: 'github.pr-list',
|
|
1127
|
+
};
|
|
1128
|
+
if (tenantId !== null) {
|
|
1129
|
+
command.tenantId = tenantId;
|
|
1130
|
+
}
|
|
1131
|
+
if (userId !== null) {
|
|
1132
|
+
command.userId = userId;
|
|
1133
|
+
}
|
|
1134
|
+
if (workspaceId !== null) {
|
|
1135
|
+
command.workspaceId = workspaceId;
|
|
1136
|
+
}
|
|
1137
|
+
if (repositoryId !== null) {
|
|
1138
|
+
command.repositoryId = repositoryId;
|
|
1139
|
+
}
|
|
1140
|
+
if (directoryId !== null) {
|
|
1141
|
+
command.directoryId = directoryId;
|
|
1142
|
+
}
|
|
1143
|
+
if (headBranch !== null) {
|
|
1144
|
+
command.headBranch = headBranch;
|
|
1145
|
+
}
|
|
1146
|
+
if (state !== null) {
|
|
1147
|
+
command.state = state;
|
|
1148
|
+
}
|
|
1149
|
+
if (limit !== null) {
|
|
1150
|
+
command.limit = limit;
|
|
1151
|
+
}
|
|
1152
|
+
return command;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
function parseGitHubPrCreate(record: CommandRecord): StreamCommand | null {
|
|
1156
|
+
const directoryId = readString(record['directoryId']);
|
|
1157
|
+
if (directoryId === null) {
|
|
1158
|
+
return null;
|
|
1159
|
+
}
|
|
1160
|
+
const title = readOptionalString(record, 'title');
|
|
1161
|
+
const body = readOptionalString(record, 'body');
|
|
1162
|
+
const baseBranch = readOptionalString(record, 'baseBranch');
|
|
1163
|
+
const headBranch = readOptionalString(record, 'headBranch');
|
|
1164
|
+
const draft = readOptionalBoolean(record, 'draft');
|
|
1165
|
+
if (
|
|
1166
|
+
title === undefined ||
|
|
1167
|
+
body === undefined ||
|
|
1168
|
+
baseBranch === undefined ||
|
|
1169
|
+
headBranch === undefined ||
|
|
1170
|
+
draft === undefined
|
|
1171
|
+
) {
|
|
1172
|
+
return null;
|
|
1173
|
+
}
|
|
1174
|
+
const command: StreamCommand = {
|
|
1175
|
+
type: 'github.pr-create',
|
|
1176
|
+
directoryId,
|
|
1177
|
+
};
|
|
1178
|
+
if (title !== null) {
|
|
1179
|
+
command.title = title;
|
|
1180
|
+
}
|
|
1181
|
+
if (body !== null) {
|
|
1182
|
+
command.body = body;
|
|
1183
|
+
}
|
|
1184
|
+
if (baseBranch !== null) {
|
|
1185
|
+
command.baseBranch = baseBranch;
|
|
1186
|
+
}
|
|
1187
|
+
if (headBranch !== null) {
|
|
1188
|
+
command.headBranch = headBranch;
|
|
1189
|
+
}
|
|
1190
|
+
if (draft !== null) {
|
|
1191
|
+
command.draft = draft;
|
|
1192
|
+
}
|
|
1193
|
+
return command;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
function parseGitHubPrJobsList(record: CommandRecord): StreamCommand | null {
|
|
1197
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
1198
|
+
const userId = readOptionalString(record, 'userId');
|
|
1199
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
1200
|
+
const repositoryId = readOptionalString(record, 'repositoryId');
|
|
1201
|
+
const prRecordId = readOptionalString(record, 'prRecordId');
|
|
1202
|
+
const limit = readOptionalInteger(record, 'limit', 1);
|
|
1203
|
+
if (
|
|
1204
|
+
tenantId === undefined ||
|
|
1205
|
+
userId === undefined ||
|
|
1206
|
+
workspaceId === undefined ||
|
|
1207
|
+
repositoryId === undefined ||
|
|
1208
|
+
prRecordId === undefined ||
|
|
1209
|
+
limit === undefined
|
|
1210
|
+
) {
|
|
1211
|
+
return null;
|
|
1212
|
+
}
|
|
1213
|
+
const command: StreamCommand = {
|
|
1214
|
+
type: 'github.pr-jobs-list',
|
|
1215
|
+
};
|
|
1216
|
+
if (tenantId !== null) {
|
|
1217
|
+
command.tenantId = tenantId;
|
|
1218
|
+
}
|
|
1219
|
+
if (userId !== null) {
|
|
1220
|
+
command.userId = userId;
|
|
1221
|
+
}
|
|
1222
|
+
if (workspaceId !== null) {
|
|
1223
|
+
command.workspaceId = workspaceId;
|
|
1224
|
+
}
|
|
1225
|
+
if (repositoryId !== null) {
|
|
1226
|
+
command.repositoryId = repositoryId;
|
|
1227
|
+
}
|
|
1228
|
+
if (prRecordId !== null) {
|
|
1229
|
+
command.prRecordId = prRecordId;
|
|
1230
|
+
}
|
|
1231
|
+
if (limit !== null) {
|
|
1232
|
+
command.limit = limit;
|
|
1233
|
+
}
|
|
1234
|
+
return command;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
function parseGitHubRepoMyPrsUrl(record: CommandRecord): StreamCommand | null {
|
|
1238
|
+
const repositoryId = readString(record['repositoryId']);
|
|
1239
|
+
if (repositoryId === null) {
|
|
1240
|
+
return null;
|
|
1241
|
+
}
|
|
1242
|
+
return {
|
|
1243
|
+
type: 'github.repo-my-prs-url',
|
|
1244
|
+
repositoryId,
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
function parseStreamSubscribe(record: CommandRecord): StreamCommand | null {
|
|
1249
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
1250
|
+
const userId = readOptionalString(record, 'userId');
|
|
1251
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
1252
|
+
const repositoryId = readOptionalString(record, 'repositoryId');
|
|
1253
|
+
const taskId = readOptionalString(record, 'taskId');
|
|
1254
|
+
const directoryId = readOptionalString(record, 'directoryId');
|
|
1255
|
+
const conversationId = readOptionalString(record, 'conversationId');
|
|
1256
|
+
const includeOutput = readOptionalBoolean(record, 'includeOutput');
|
|
1257
|
+
const afterCursor = readOptionalInteger(record, 'afterCursor', 0);
|
|
1258
|
+
if (
|
|
1259
|
+
tenantId === undefined ||
|
|
1260
|
+
userId === undefined ||
|
|
1261
|
+
workspaceId === undefined ||
|
|
1262
|
+
repositoryId === undefined ||
|
|
1263
|
+
taskId === undefined ||
|
|
1264
|
+
directoryId === undefined ||
|
|
1265
|
+
conversationId === undefined ||
|
|
1266
|
+
includeOutput === undefined ||
|
|
1267
|
+
afterCursor === undefined
|
|
1268
|
+
) {
|
|
1269
|
+
return null;
|
|
1270
|
+
}
|
|
1271
|
+
const command: StreamCommand = {
|
|
1272
|
+
type: 'stream.subscribe',
|
|
1273
|
+
};
|
|
1274
|
+
if (tenantId !== null) {
|
|
1275
|
+
command.tenantId = tenantId;
|
|
1276
|
+
}
|
|
1277
|
+
if (userId !== null) {
|
|
1278
|
+
command.userId = userId;
|
|
1279
|
+
}
|
|
1280
|
+
if (workspaceId !== null) {
|
|
1281
|
+
command.workspaceId = workspaceId;
|
|
1282
|
+
}
|
|
1283
|
+
if (repositoryId !== null) {
|
|
1284
|
+
command.repositoryId = repositoryId;
|
|
1285
|
+
}
|
|
1286
|
+
if (taskId !== null) {
|
|
1287
|
+
command.taskId = taskId;
|
|
1288
|
+
}
|
|
1289
|
+
if (directoryId !== null) {
|
|
1290
|
+
command.directoryId = directoryId;
|
|
1291
|
+
}
|
|
1292
|
+
if (conversationId !== null) {
|
|
1293
|
+
command.conversationId = conversationId;
|
|
1294
|
+
}
|
|
1295
|
+
if (includeOutput !== null) {
|
|
1296
|
+
command.includeOutput = includeOutput;
|
|
1297
|
+
}
|
|
1298
|
+
if (afterCursor !== null) {
|
|
1299
|
+
command.afterCursor = afterCursor;
|
|
1300
|
+
}
|
|
1301
|
+
return command;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
function parseStreamUnsubscribe(record: CommandRecord): StreamCommand | null {
|
|
1305
|
+
const subscriptionId = readString(record['subscriptionId']);
|
|
1306
|
+
if (subscriptionId === null) {
|
|
1307
|
+
return null;
|
|
1308
|
+
}
|
|
1309
|
+
return {
|
|
1310
|
+
type: 'stream.unsubscribe',
|
|
1311
|
+
subscriptionId,
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
function parseSessionList(record: CommandRecord): StreamCommand | null {
|
|
1316
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
1317
|
+
const userId = readOptionalString(record, 'userId');
|
|
1318
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
1319
|
+
const worktreeId = readOptionalString(record, 'worktreeId');
|
|
1320
|
+
const status = readOptionalString(record, 'status');
|
|
1321
|
+
const live = readOptionalBoolean(record, 'live');
|
|
1322
|
+
const sort = readOptionalString(record, 'sort');
|
|
1323
|
+
const limit = readOptionalInteger(record, 'limit', 1);
|
|
1324
|
+
if (
|
|
1325
|
+
tenantId === undefined ||
|
|
1326
|
+
userId === undefined ||
|
|
1327
|
+
workspaceId === undefined ||
|
|
1328
|
+
worktreeId === undefined ||
|
|
1329
|
+
status === undefined ||
|
|
1330
|
+
live === undefined ||
|
|
1331
|
+
sort === undefined ||
|
|
1332
|
+
limit === undefined
|
|
1333
|
+
) {
|
|
1334
|
+
return null;
|
|
1335
|
+
}
|
|
1336
|
+
if (
|
|
1337
|
+
status !== null &&
|
|
1338
|
+
status !== 'running' &&
|
|
1339
|
+
status !== 'needs-input' &&
|
|
1340
|
+
status !== 'completed' &&
|
|
1341
|
+
status !== 'exited'
|
|
1342
|
+
) {
|
|
1343
|
+
return null;
|
|
1344
|
+
}
|
|
1345
|
+
if (
|
|
1346
|
+
sort !== null &&
|
|
1347
|
+
sort !== 'attention-first' &&
|
|
1348
|
+
sort !== 'started-desc' &&
|
|
1349
|
+
sort !== 'started-asc'
|
|
1350
|
+
) {
|
|
1351
|
+
return null;
|
|
1352
|
+
}
|
|
1353
|
+
const command: StreamCommand = {
|
|
1354
|
+
type: 'session.list',
|
|
1355
|
+
};
|
|
1356
|
+
if (tenantId !== null) {
|
|
1357
|
+
command.tenantId = tenantId;
|
|
1358
|
+
}
|
|
1359
|
+
if (userId !== null) {
|
|
1360
|
+
command.userId = userId;
|
|
1361
|
+
}
|
|
1362
|
+
if (workspaceId !== null) {
|
|
1363
|
+
command.workspaceId = workspaceId;
|
|
1364
|
+
}
|
|
1365
|
+
if (worktreeId !== null) {
|
|
1366
|
+
command.worktreeId = worktreeId;
|
|
1367
|
+
}
|
|
1368
|
+
if (status !== null) {
|
|
1369
|
+
command.status = status;
|
|
1370
|
+
}
|
|
1371
|
+
if (live !== null) {
|
|
1372
|
+
command.live = live;
|
|
1373
|
+
}
|
|
1374
|
+
if (sort !== null) {
|
|
1375
|
+
command.sort = sort;
|
|
1376
|
+
}
|
|
1377
|
+
if (limit !== null) {
|
|
1378
|
+
command.limit = limit;
|
|
1379
|
+
}
|
|
1380
|
+
return command;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
function parseAttentionList(): StreamCommand {
|
|
1384
|
+
return {
|
|
1385
|
+
type: 'attention.list',
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
function parseSessionIdCommand(type: 'session.status' | 'session.interrupt' | 'session.remove') {
|
|
1390
|
+
return (record: CommandRecord): StreamCommand | null => {
|
|
1391
|
+
const sessionId = readString(record['sessionId']);
|
|
1392
|
+
if (sessionId === null) {
|
|
1393
|
+
return null;
|
|
1394
|
+
}
|
|
1395
|
+
return {
|
|
1396
|
+
type,
|
|
1397
|
+
sessionId,
|
|
1398
|
+
};
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
function parseSessionSnapshot(record: CommandRecord): StreamCommand | null {
|
|
1403
|
+
const sessionId = readString(record['sessionId']);
|
|
1404
|
+
const tailLines = readOptionalInteger(record, 'tailLines', 1);
|
|
1405
|
+
if (sessionId === null || tailLines === undefined) {
|
|
1406
|
+
return null;
|
|
1407
|
+
}
|
|
1408
|
+
const command: Extract<StreamCommand, { type: 'session.snapshot' }> = {
|
|
1409
|
+
type: 'session.snapshot',
|
|
1410
|
+
sessionId,
|
|
1411
|
+
};
|
|
1412
|
+
if (tailLines !== null) {
|
|
1413
|
+
command.tailLines = tailLines;
|
|
1414
|
+
}
|
|
1415
|
+
return command;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
function parseSessionRespond(record: CommandRecord): StreamCommand | null {
|
|
1419
|
+
const sessionId = readString(record['sessionId']);
|
|
1420
|
+
const text = readString(record['text']);
|
|
1421
|
+
if (sessionId === null || text === null) {
|
|
1422
|
+
return null;
|
|
1423
|
+
}
|
|
1424
|
+
return {
|
|
1425
|
+
type: 'session.respond',
|
|
1426
|
+
sessionId,
|
|
1427
|
+
text,
|
|
1428
|
+
};
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
function parseSessionClaim(record: CommandRecord): StreamCommand | null {
|
|
1432
|
+
const sessionId = readString(record['sessionId']);
|
|
1433
|
+
const controllerId = readString(record['controllerId']);
|
|
1434
|
+
const controllerType = parseSessionControllerType(record['controllerType']);
|
|
1435
|
+
if (sessionId === null || controllerId === null || controllerType === null) {
|
|
1436
|
+
return null;
|
|
1437
|
+
}
|
|
1438
|
+
const controllerLabel = readOptionalString(record, 'controllerLabel');
|
|
1439
|
+
const reason = readOptionalString(record, 'reason');
|
|
1440
|
+
const takeover = readOptionalBoolean(record, 'takeover');
|
|
1441
|
+
if (controllerLabel === undefined || reason === undefined || takeover === undefined) {
|
|
1442
|
+
return null;
|
|
1443
|
+
}
|
|
1444
|
+
const command: StreamCommand = {
|
|
1445
|
+
type: 'session.claim',
|
|
1446
|
+
sessionId,
|
|
1447
|
+
controllerId,
|
|
1448
|
+
controllerType,
|
|
1449
|
+
};
|
|
1450
|
+
if (controllerLabel !== null) {
|
|
1451
|
+
command.controllerLabel = controllerLabel;
|
|
1452
|
+
}
|
|
1453
|
+
if (reason !== null) {
|
|
1454
|
+
command.reason = reason;
|
|
1455
|
+
}
|
|
1456
|
+
if (takeover !== null) {
|
|
1457
|
+
command.takeover = takeover;
|
|
1458
|
+
}
|
|
1459
|
+
return command;
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
function parseSessionRelease(record: CommandRecord): StreamCommand | null {
|
|
1463
|
+
const sessionId = readString(record['sessionId']);
|
|
1464
|
+
if (sessionId === null) {
|
|
1465
|
+
return null;
|
|
1466
|
+
}
|
|
1467
|
+
const reason = readOptionalString(record, 'reason');
|
|
1468
|
+
if (reason === undefined) {
|
|
1469
|
+
return null;
|
|
1470
|
+
}
|
|
1471
|
+
const command: StreamCommand = {
|
|
1472
|
+
type: 'session.release',
|
|
1473
|
+
sessionId,
|
|
1474
|
+
};
|
|
1475
|
+
if (reason !== null) {
|
|
1476
|
+
command.reason = reason;
|
|
1477
|
+
}
|
|
1478
|
+
return command;
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
function parsePtyStart(record: CommandRecord): StreamCommand | null {
|
|
1482
|
+
const sessionId = readString(record['sessionId']);
|
|
1483
|
+
if (sessionId === null) {
|
|
1484
|
+
return null;
|
|
1485
|
+
}
|
|
1486
|
+
const argsValue = record['args'];
|
|
1487
|
+
if (!isStringArray(argsValue)) {
|
|
1488
|
+
return null;
|
|
1489
|
+
}
|
|
1490
|
+
const initialCols = readNumber(record['initialCols']);
|
|
1491
|
+
const initialRows = readNumber(record['initialRows']);
|
|
1492
|
+
if (initialCols === null || initialRows === null) {
|
|
1493
|
+
return null;
|
|
1494
|
+
}
|
|
1495
|
+
const envValue = record['env'];
|
|
1496
|
+
let env: Record<string, string> | undefined;
|
|
1497
|
+
if (envValue !== undefined) {
|
|
1498
|
+
const parsedEnv = readStringRecord(envValue);
|
|
1499
|
+
if (parsedEnv === null) {
|
|
1500
|
+
return null;
|
|
1501
|
+
}
|
|
1502
|
+
env = parsedEnv;
|
|
1503
|
+
}
|
|
1504
|
+
const cwd = readOptionalString(record, 'cwd');
|
|
1505
|
+
if (cwd === undefined) {
|
|
1506
|
+
return null;
|
|
1507
|
+
}
|
|
1508
|
+
const tenantId = readOptionalString(record, 'tenantId');
|
|
1509
|
+
const userId = readOptionalString(record, 'userId');
|
|
1510
|
+
const workspaceId = readOptionalString(record, 'workspaceId');
|
|
1511
|
+
const worktreeId = readOptionalString(record, 'worktreeId');
|
|
1512
|
+
if (
|
|
1513
|
+
tenantId === undefined ||
|
|
1514
|
+
userId === undefined ||
|
|
1515
|
+
workspaceId === undefined ||
|
|
1516
|
+
worktreeId === undefined
|
|
1517
|
+
) {
|
|
1518
|
+
return null;
|
|
1519
|
+
}
|
|
1520
|
+
const terminalForegroundHex = record['terminalForegroundHex'];
|
|
1521
|
+
if (terminalForegroundHex !== undefined && typeof terminalForegroundHex !== 'string') {
|
|
1522
|
+
return null;
|
|
1523
|
+
}
|
|
1524
|
+
const terminalBackgroundHex = record['terminalBackgroundHex'];
|
|
1525
|
+
if (terminalBackgroundHex !== undefined && typeof terminalBackgroundHex !== 'string') {
|
|
1526
|
+
return null;
|
|
1527
|
+
}
|
|
1528
|
+
const command: StreamCommand = {
|
|
1529
|
+
type: 'pty.start',
|
|
1530
|
+
sessionId,
|
|
1531
|
+
args: argsValue,
|
|
1532
|
+
initialCols,
|
|
1533
|
+
initialRows,
|
|
1534
|
+
};
|
|
1535
|
+
if (env !== undefined) {
|
|
1536
|
+
command.env = env;
|
|
1537
|
+
}
|
|
1538
|
+
if (cwd !== null) {
|
|
1539
|
+
command.cwd = cwd;
|
|
1540
|
+
}
|
|
1541
|
+
if (terminalForegroundHex !== undefined) {
|
|
1542
|
+
command.terminalForegroundHex = terminalForegroundHex;
|
|
1543
|
+
}
|
|
1544
|
+
if (terminalBackgroundHex !== undefined) {
|
|
1545
|
+
command.terminalBackgroundHex = terminalBackgroundHex;
|
|
1546
|
+
}
|
|
1547
|
+
if (tenantId !== null) {
|
|
1548
|
+
command.tenantId = tenantId;
|
|
1549
|
+
}
|
|
1550
|
+
if (userId !== null) {
|
|
1551
|
+
command.userId = userId;
|
|
1552
|
+
}
|
|
1553
|
+
if (workspaceId !== null) {
|
|
1554
|
+
command.workspaceId = workspaceId;
|
|
1555
|
+
}
|
|
1556
|
+
if (worktreeId !== null) {
|
|
1557
|
+
command.worktreeId = worktreeId;
|
|
1558
|
+
}
|
|
1559
|
+
return command;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
function parsePtyAttach(record: CommandRecord): StreamCommand | null {
|
|
1563
|
+
const sessionId = readString(record['sessionId']);
|
|
1564
|
+
if (sessionId === null) {
|
|
1565
|
+
return null;
|
|
1566
|
+
}
|
|
1567
|
+
const sinceCursor = readNumber(record['sinceCursor']);
|
|
1568
|
+
if (record['sinceCursor'] !== undefined && sinceCursor === null) {
|
|
1569
|
+
return null;
|
|
1570
|
+
}
|
|
1571
|
+
const command: StreamCommand = {
|
|
1572
|
+
type: 'pty.attach',
|
|
1573
|
+
sessionId,
|
|
1574
|
+
};
|
|
1575
|
+
if (sinceCursor !== null) {
|
|
1576
|
+
command.sinceCursor = sinceCursor;
|
|
1577
|
+
}
|
|
1578
|
+
return command;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
function parsePtySimple(
|
|
1582
|
+
type: 'pty.detach' | 'pty.subscribe-events' | 'pty.unsubscribe-events' | 'pty.close',
|
|
1583
|
+
) {
|
|
1584
|
+
return (record: CommandRecord): StreamCommand | null => {
|
|
1585
|
+
const sessionId = readString(record['sessionId']);
|
|
1586
|
+
if (sessionId === null) {
|
|
1587
|
+
return null;
|
|
1588
|
+
}
|
|
1589
|
+
return {
|
|
1590
|
+
type,
|
|
1591
|
+
sessionId,
|
|
1592
|
+
};
|
|
1593
|
+
};
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
export interface StreamCommandParserRegistry {
|
|
1597
|
+
readonly [type: string]: CommandParser;
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
export const DEFAULT_STREAM_COMMAND_PARSERS: StreamCommandParserRegistry = {
|
|
1601
|
+
'directory.upsert': parseDirectoryUpsert,
|
|
1602
|
+
'directory.list': parseDirectoryList,
|
|
1603
|
+
'directory.archive': parseDirectoryArchive,
|
|
1604
|
+
'directory.git-status': parseDirectoryGitStatusList,
|
|
1605
|
+
'conversation.create': parseConversationCreate,
|
|
1606
|
+
'conversation.list': parseConversationList,
|
|
1607
|
+
'conversation.archive': parseConversationArchive,
|
|
1608
|
+
'conversation.update': parseConversationUpdate,
|
|
1609
|
+
'conversation.delete': parseConversationDelete,
|
|
1610
|
+
'repository.upsert': parseRepositoryUpsert,
|
|
1611
|
+
'repository.get': parseRepositoryGet,
|
|
1612
|
+
'repository.list': parseRepositoryList,
|
|
1613
|
+
'repository.update': parseRepositoryUpdate,
|
|
1614
|
+
'repository.archive': parseRepositoryArchive,
|
|
1615
|
+
'task.create': parseTaskCreate,
|
|
1616
|
+
'task.get': parseTaskGet,
|
|
1617
|
+
'task.list': parseTaskList,
|
|
1618
|
+
'task.update': parseTaskUpdate,
|
|
1619
|
+
'task.delete': parseTaskDelete,
|
|
1620
|
+
'task.claim': parseTaskClaim,
|
|
1621
|
+
'task.pull': parseTaskPull,
|
|
1622
|
+
'task.complete': parseTaskComplete,
|
|
1623
|
+
'task.queue': parseTaskQueue,
|
|
1624
|
+
'task.ready': parseTaskReady,
|
|
1625
|
+
'task.draft': parseTaskDraft,
|
|
1626
|
+
'task.reorder': parseTaskReorder,
|
|
1627
|
+
'project.settings-get': parseProjectSettingsGet,
|
|
1628
|
+
'project.settings-update': parseProjectSettingsUpdate,
|
|
1629
|
+
'project.status': parseProjectStatus,
|
|
1630
|
+
'automation.policy-get': parseAutomationPolicyGet,
|
|
1631
|
+
'automation.policy-set': parseAutomationPolicySet,
|
|
1632
|
+
'github.project-pr': parseGitHubProjectPr,
|
|
1633
|
+
'github.pr-list': parseGitHubPrList,
|
|
1634
|
+
'github.pr-create': parseGitHubPrCreate,
|
|
1635
|
+
'github.pr-jobs-list': parseGitHubPrJobsList,
|
|
1636
|
+
'github.repo-my-prs-url': parseGitHubRepoMyPrsUrl,
|
|
1637
|
+
'stream.subscribe': parseStreamSubscribe,
|
|
1638
|
+
'stream.unsubscribe': parseStreamUnsubscribe,
|
|
1639
|
+
'session.list': parseSessionList,
|
|
1640
|
+
'attention.list': () => parseAttentionList(),
|
|
1641
|
+
'session.status': parseSessionIdCommand('session.status'),
|
|
1642
|
+
'session.snapshot': parseSessionSnapshot,
|
|
1643
|
+
'session.respond': parseSessionRespond,
|
|
1644
|
+
'session.claim': parseSessionClaim,
|
|
1645
|
+
'session.release': parseSessionRelease,
|
|
1646
|
+
'session.interrupt': parseSessionIdCommand('session.interrupt'),
|
|
1647
|
+
'session.remove': parseSessionIdCommand('session.remove'),
|
|
1648
|
+
'pty.start': parsePtyStart,
|
|
1649
|
+
'pty.attach': parsePtyAttach,
|
|
1650
|
+
'pty.detach': parsePtySimple('pty.detach'),
|
|
1651
|
+
'pty.subscribe-events': parsePtySimple('pty.subscribe-events'),
|
|
1652
|
+
'pty.unsubscribe-events': parsePtySimple('pty.unsubscribe-events'),
|
|
1653
|
+
'pty.close': parsePtySimple('pty.close'),
|
|
1654
|
+
};
|
|
1655
|
+
|
|
1656
|
+
export function parseStreamCommand(
|
|
1657
|
+
value: unknown,
|
|
1658
|
+
parsers: StreamCommandParserRegistry = DEFAULT_STREAM_COMMAND_PARSERS,
|
|
1659
|
+
): StreamCommand | null {
|
|
1660
|
+
const record = asRecord(value);
|
|
1661
|
+
if (record === null) {
|
|
1662
|
+
return null;
|
|
1663
|
+
}
|
|
1664
|
+
const type = readString(record['type']);
|
|
1665
|
+
if (type === null) {
|
|
1666
|
+
return null;
|
|
1667
|
+
}
|
|
1668
|
+
const parser = parsers[type as StreamCommandType];
|
|
1669
|
+
if (parser === undefined) {
|
|
1670
|
+
return null;
|
|
1671
|
+
}
|
|
1672
|
+
return parser(record);
|
|
1673
|
+
}
|