@rzx/ohs 1.1.16 → 1.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/frontend/index.js +1968 -1297
- package/dist/frontend/index.js.map +45 -19
- package/dist/index.js +40420 -33343
- package/dist/index.js.map +194 -132
- package/dist/migrations/0000_current_schema.sql +436 -0
- package/dist/migrations/meta/0000_snapshot.json +3442 -0
- package/dist/migrations/meta/_journal.json +3 -136
- package/package.json +12 -12
- package/dist/migrations/0000_session_runtime.sql +0 -68
- package/dist/migrations/0001_event_sequence.sql +0 -8
- package/dist/migrations/0002_cron.sql +0 -33
- package/dist/migrations/0003_projects.sql +0 -30
- package/dist/migrations/0004_project_default_shell.sql +0 -1
- package/dist/migrations/0005_scheduled_tasks.sql +0 -57
- package/dist/migrations/0006_event_schema_version.sql +0 -1
- package/dist/migrations/0007_projection_settlement.sql +0 -19
- package/dist/migrations/0008_run_attempt.sql +0 -23
- package/dist/migrations/0009_external_channels.sql +0 -45
- package/dist/migrations/0010_workflow_and_owner.sql +0 -68
- package/dist/migrations/0011_storage_format.sql +0 -6
- package/dist/migrations/0012_job_admission.sql +0 -6
- package/dist/migrations/0013_attachments.sql +0 -20
- package/dist/migrations/0014_session_input_attachments.sql +0 -45
- package/dist/migrations/0015_attachment_representations.sql +0 -22
- package/dist/migrations/0016_attachment_lifecycle.sql +0 -16
- package/dist/migrations/0017_structured_input_items.sql +0 -1
- package/dist/migrations/0018_session_goals.sql +0 -17
- package/dist/migrations/0019_session_goal_progress.sql +0 -3
package/dist/frontend/index.js
CHANGED
|
@@ -128,91 +128,6 @@ var init_session = __esm(() => {
|
|
|
128
128
|
};
|
|
129
129
|
});
|
|
130
130
|
|
|
131
|
-
// ../../packages/protocol/src/runtime-config.ts
|
|
132
|
-
function isRecord(value) {
|
|
133
|
-
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
134
|
-
}
|
|
135
|
-
function stringValue(value) {
|
|
136
|
-
return typeof value === "string" && value.trim() ? value : undefined;
|
|
137
|
-
}
|
|
138
|
-
function numberValue(value) {
|
|
139
|
-
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
140
|
-
}
|
|
141
|
-
function stringArrayValue(value) {
|
|
142
|
-
if (!Array.isArray(value))
|
|
143
|
-
return;
|
|
144
|
-
const items = value.filter((item) => typeof item === "string" && item.trim().length > 0);
|
|
145
|
-
return items.length > 0 ? items : undefined;
|
|
146
|
-
}
|
|
147
|
-
function permissionModeValue(value) {
|
|
148
|
-
return value === "default" || value === "plan" || value === "full_auto" ? value : undefined;
|
|
149
|
-
}
|
|
150
|
-
function effortValue(value) {
|
|
151
|
-
return value === "low" || value === "medium" || value === "high" ? value : undefined;
|
|
152
|
-
}
|
|
153
|
-
function sessionModeValue(value) {
|
|
154
|
-
return value === "coordinator" ? "coordinator" : value === "direct" ? "direct" : undefined;
|
|
155
|
-
}
|
|
156
|
-
function apiFormatValue(value) {
|
|
157
|
-
return value === "anthropic" || value === "openai" ? value : undefined;
|
|
158
|
-
}
|
|
159
|
-
function booleanValue(value) {
|
|
160
|
-
return typeof value === "boolean" ? value : undefined;
|
|
161
|
-
}
|
|
162
|
-
function readRuntimeMetadata(metadata) {
|
|
163
|
-
return isRecord(metadata?.runtime) ? metadata.runtime : {};
|
|
164
|
-
}
|
|
165
|
-
function readSessionRuntimeConfig(session, defaults) {
|
|
166
|
-
const runtime = readRuntimeMetadata(session.metadata);
|
|
167
|
-
const model = stringValue(runtime.model);
|
|
168
|
-
if (!model) {
|
|
169
|
-
throw new Error(`Session runtime config is missing metadata.runtime.model: ${session.id}`);
|
|
170
|
-
}
|
|
171
|
-
return {
|
|
172
|
-
model,
|
|
173
|
-
...stringValue(runtime.provider) ?? defaults?.provider ? { provider: stringValue(runtime.provider) ?? defaults?.provider } : {},
|
|
174
|
-
...stringValue(runtime.baseUrl) ?? defaults?.baseUrl ? { baseUrl: stringValue(runtime.baseUrl) ?? defaults?.baseUrl } : {},
|
|
175
|
-
...apiFormatValue(runtime.apiFormat) ?? defaults?.apiFormat ? { apiFormat: apiFormatValue(runtime.apiFormat) ?? defaults?.apiFormat } : {},
|
|
176
|
-
...permissionModeValue(runtime.permissionMode) ?? defaults?.permissionMode ? { permissionMode: permissionModeValue(runtime.permissionMode) ?? defaults?.permissionMode } : {},
|
|
177
|
-
...numberValue(runtime.maxTurns) ?? defaults?.maxTurns ? { maxTurns: numberValue(runtime.maxTurns) ?? defaults?.maxTurns } : {},
|
|
178
|
-
...effortValue(runtime.effort) ?? defaults?.effort ? { effort: effortValue(runtime.effort) ?? defaults?.effort } : {},
|
|
179
|
-
...sessionModeValue(runtime.sessionMode) ?? defaults?.sessionMode ? { sessionMode: sessionModeValue(runtime.sessionMode) ?? defaults?.sessionMode } : {},
|
|
180
|
-
...stringValue(runtime.systemPrompt) ?? defaults?.systemPrompt ? { systemPrompt: stringValue(runtime.systemPrompt) ?? defaults?.systemPrompt } : {},
|
|
181
|
-
...stringArrayValue(runtime.allowedTools) ?? defaults?.allowedTools ? { allowedTools: stringArrayValue(runtime.allowedTools) ?? defaults?.allowedTools } : {},
|
|
182
|
-
...stringArrayValue(runtime.disallowedTools) ?? defaults?.disallowedTools ? { disallowedTools: stringArrayValue(runtime.disallowedTools) ?? defaults?.disallowedTools } : {},
|
|
183
|
-
...(booleanValue(runtime.pluginsEnabled) ?? defaults?.pluginsEnabled) !== undefined ? { pluginsEnabled: booleanValue(runtime.pluginsEnabled) ?? defaults?.pluginsEnabled } : {}
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
function patchSessionRuntimeMetadata(metadata, patch) {
|
|
187
|
-
const runtime = {
|
|
188
|
-
...readRuntimeMetadata(metadata),
|
|
189
|
-
...stripUndefined(patch)
|
|
190
|
-
};
|
|
191
|
-
return {
|
|
192
|
-
...metadata,
|
|
193
|
-
runtime
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
function stripUndefined(input) {
|
|
197
|
-
return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== undefined));
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// ../../packages/protocol/src/session-input-items.ts
|
|
201
|
-
var SESSION_INPUT_LIMITS;
|
|
202
|
-
var init_session_input_items = __esm(() => {
|
|
203
|
-
SESSION_INPUT_LIMITS = {
|
|
204
|
-
maxItems: 256,
|
|
205
|
-
maxSkills: 32,
|
|
206
|
-
maxTextBytes: 1024 * 1024,
|
|
207
|
-
maxNameChars: 128,
|
|
208
|
-
maxDisplayNameChars: 256
|
|
209
|
-
};
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
// ../../packages/protocol/src/requests.ts
|
|
213
|
-
var init_requests = __esm(() => {
|
|
214
|
-
init_session_input_items();
|
|
215
|
-
});
|
|
216
131
|
// ../../packages/protocol/src/serialization.ts
|
|
217
132
|
function object(value, path) {
|
|
218
133
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -603,6 +518,138 @@ var init_serialization = __esm(() => {
|
|
|
603
518
|
}
|
|
604
519
|
};
|
|
605
520
|
});
|
|
521
|
+
|
|
522
|
+
// ../../packages/protocol/src/runtime-config.ts
|
|
523
|
+
function isRecord(value) {
|
|
524
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
525
|
+
}
|
|
526
|
+
function stringValue(value) {
|
|
527
|
+
return typeof value === "string" && value.trim() ? value : undefined;
|
|
528
|
+
}
|
|
529
|
+
function numberValue(value) {
|
|
530
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
531
|
+
}
|
|
532
|
+
function stringArrayValue(value) {
|
|
533
|
+
if (!Array.isArray(value))
|
|
534
|
+
return;
|
|
535
|
+
const items = value.filter((item) => typeof item === "string" && item.trim().length > 0);
|
|
536
|
+
return items.length > 0 ? items : undefined;
|
|
537
|
+
}
|
|
538
|
+
function permissionModeValue(value) {
|
|
539
|
+
return value === "default" || value === "plan" || value === "full_auto" ? value : undefined;
|
|
540
|
+
}
|
|
541
|
+
function effortValue(value) {
|
|
542
|
+
return value === "low" || value === "medium" || value === "high" ? value : undefined;
|
|
543
|
+
}
|
|
544
|
+
function sessionModeValue(value) {
|
|
545
|
+
return value === "coordinator" ? "coordinator" : value === "direct" ? "direct" : undefined;
|
|
546
|
+
}
|
|
547
|
+
function apiFormatValue(value) {
|
|
548
|
+
return value === "anthropic" || value === "openai" ? value : undefined;
|
|
549
|
+
}
|
|
550
|
+
function booleanValue(value) {
|
|
551
|
+
return typeof value === "boolean" ? value : undefined;
|
|
552
|
+
}
|
|
553
|
+
function readRuntimeMetadata(metadata) {
|
|
554
|
+
const runtime = metadata?.runtime;
|
|
555
|
+
if (runtime === undefined)
|
|
556
|
+
return {};
|
|
557
|
+
if (!isRecord(runtime))
|
|
558
|
+
throw new ProtocolDataError("metadata.runtime must be an object", "metadata.runtime");
|
|
559
|
+
for (const [field, value] of Object.entries(runtime)) {
|
|
560
|
+
let valid = false;
|
|
561
|
+
switch (field) {
|
|
562
|
+
case "model":
|
|
563
|
+
case "provider":
|
|
564
|
+
case "baseUrl":
|
|
565
|
+
case "systemPrompt":
|
|
566
|
+
valid = typeof value === "string";
|
|
567
|
+
break;
|
|
568
|
+
case "apiFormat":
|
|
569
|
+
valid = apiFormatValue(value) !== undefined;
|
|
570
|
+
break;
|
|
571
|
+
case "permissionMode":
|
|
572
|
+
valid = permissionModeValue(value) !== undefined;
|
|
573
|
+
break;
|
|
574
|
+
case "effort":
|
|
575
|
+
valid = effortValue(value) !== undefined;
|
|
576
|
+
break;
|
|
577
|
+
case "sessionMode":
|
|
578
|
+
valid = sessionModeValue(value) !== undefined;
|
|
579
|
+
break;
|
|
580
|
+
case "maxTurns":
|
|
581
|
+
valid = numberValue(value) !== undefined;
|
|
582
|
+
break;
|
|
583
|
+
case "pluginsEnabled":
|
|
584
|
+
valid = booleanValue(value) !== undefined;
|
|
585
|
+
break;
|
|
586
|
+
case "allowedTools":
|
|
587
|
+
case "disallowedTools":
|
|
588
|
+
valid = Array.isArray(value) && value.every((item) => typeof item === "string" && item.trim().length > 0);
|
|
589
|
+
break;
|
|
590
|
+
}
|
|
591
|
+
if (!valid) {
|
|
592
|
+
throw new ProtocolDataError(`Invalid runtime config field metadata.runtime.${field}`, `metadata.runtime.${field}`);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
return runtime;
|
|
596
|
+
}
|
|
597
|
+
function readSessionRuntimeConfig(session, defaults) {
|
|
598
|
+
const runtime = readRuntimeMetadata(session.metadata);
|
|
599
|
+
const model = stringValue(runtime.model);
|
|
600
|
+
if (!model) {
|
|
601
|
+
throw new Error(`Session runtime config is missing metadata.runtime.model: ${session.id}`);
|
|
602
|
+
}
|
|
603
|
+
return {
|
|
604
|
+
model,
|
|
605
|
+
...stringValue(runtime.provider) ?? defaults?.provider ? { provider: stringValue(runtime.provider) ?? defaults?.provider } : {},
|
|
606
|
+
...stringValue(runtime.baseUrl) ?? defaults?.baseUrl ? { baseUrl: stringValue(runtime.baseUrl) ?? defaults?.baseUrl } : {},
|
|
607
|
+
...apiFormatValue(runtime.apiFormat) ?? defaults?.apiFormat ? { apiFormat: apiFormatValue(runtime.apiFormat) ?? defaults?.apiFormat } : {},
|
|
608
|
+
...permissionModeValue(runtime.permissionMode) ?? defaults?.permissionMode ? { permissionMode: permissionModeValue(runtime.permissionMode) ?? defaults?.permissionMode } : {},
|
|
609
|
+
...numberValue(runtime.maxTurns) ?? defaults?.maxTurns ? { maxTurns: numberValue(runtime.maxTurns) ?? defaults?.maxTurns } : {},
|
|
610
|
+
...effortValue(runtime.effort) ?? defaults?.effort ? { effort: effortValue(runtime.effort) ?? defaults?.effort } : {},
|
|
611
|
+
...sessionModeValue(runtime.sessionMode) ?? defaults?.sessionMode ? { sessionMode: sessionModeValue(runtime.sessionMode) ?? defaults?.sessionMode } : {},
|
|
612
|
+
...stringValue(runtime.systemPrompt) ?? defaults?.systemPrompt ? { systemPrompt: stringValue(runtime.systemPrompt) ?? defaults?.systemPrompt } : {},
|
|
613
|
+
...stringArrayValue(runtime.allowedTools) ?? defaults?.allowedTools ? { allowedTools: stringArrayValue(runtime.allowedTools) ?? defaults?.allowedTools } : {},
|
|
614
|
+
...stringArrayValue(runtime.disallowedTools) ?? defaults?.disallowedTools ? { disallowedTools: stringArrayValue(runtime.disallowedTools) ?? defaults?.disallowedTools } : {},
|
|
615
|
+
...(booleanValue(runtime.pluginsEnabled) ?? defaults?.pluginsEnabled) !== undefined ? { pluginsEnabled: booleanValue(runtime.pluginsEnabled) ?? defaults?.pluginsEnabled } : {}
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
function patchSessionRuntimeMetadata(metadata, patch) {
|
|
619
|
+
const runtime = {
|
|
620
|
+
...readRuntimeMetadata(metadata),
|
|
621
|
+
...stripUndefined(patch)
|
|
622
|
+
};
|
|
623
|
+
readRuntimeMetadata({ runtime });
|
|
624
|
+
return {
|
|
625
|
+
...metadata,
|
|
626
|
+
runtime
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
function stripUndefined(input) {
|
|
630
|
+
return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== undefined));
|
|
631
|
+
}
|
|
632
|
+
var init_runtime_config = __esm(() => {
|
|
633
|
+
init_serialization();
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
// ../../packages/protocol/src/session-input-items.ts
|
|
637
|
+
var SESSION_INPUT_LIMITS;
|
|
638
|
+
var init_session_input_items = __esm(() => {
|
|
639
|
+
SESSION_INPUT_LIMITS = {
|
|
640
|
+
maxItems: 256,
|
|
641
|
+
maxSkills: 32,
|
|
642
|
+
maxTextBytes: 1024 * 1024,
|
|
643
|
+
maxNameChars: 128,
|
|
644
|
+
maxDisplayNameChars: 256
|
|
645
|
+
};
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
// ../../packages/protocol/src/requests.ts
|
|
649
|
+
var init_requests = __esm(() => {
|
|
650
|
+
init_runtime_config();
|
|
651
|
+
init_session_input_items();
|
|
652
|
+
});
|
|
606
653
|
// ../../packages/protocol/src/attachment.ts
|
|
607
654
|
function parseAttachmentLimits(value) {
|
|
608
655
|
const record = recordValue(value, "attachment limits");
|
|
@@ -794,6 +841,7 @@ function parseAttachmentTransferCapabilities(value) {
|
|
|
794
841
|
uploadModes
|
|
795
842
|
};
|
|
796
843
|
}
|
|
844
|
+
var CURRENT_PROTOCOL_VERSION = 4, PROTOCOL_VERSION_HEADER = "x-openharness-protocol-version";
|
|
797
845
|
var init_capabilities = __esm(() => {
|
|
798
846
|
init_attachment();
|
|
799
847
|
});
|
|
@@ -806,6 +854,7 @@ var init_session_goals = __esm(() => {
|
|
|
806
854
|
// ../../packages/protocol/src/index.ts
|
|
807
855
|
var init_src = __esm(() => {
|
|
808
856
|
init_session();
|
|
857
|
+
init_runtime_config();
|
|
809
858
|
init_requests();
|
|
810
859
|
init_serialization();
|
|
811
860
|
init_capabilities();
|
|
@@ -814,7 +863,45 @@ var init_src = __esm(() => {
|
|
|
814
863
|
init_session_goals();
|
|
815
864
|
});
|
|
816
865
|
|
|
817
|
-
// ../../packages/client/src/
|
|
866
|
+
// ../../packages/client/src/protocol/protocol-client.ts
|
|
867
|
+
class ProtocolClient {
|
|
868
|
+
transport;
|
|
869
|
+
constructor(transport) {
|
|
870
|
+
this.transport = transport;
|
|
871
|
+
}
|
|
872
|
+
async health(options = {}) {
|
|
873
|
+
return this.transport.request("/health", {
|
|
874
|
+
auth: false,
|
|
875
|
+
signal: options.signal
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
async capabilities(options = {}) {
|
|
879
|
+
const value = await this.transport.request("/capabilities", {
|
|
880
|
+
auth: false,
|
|
881
|
+
signal: options.signal
|
|
882
|
+
});
|
|
883
|
+
const capabilities = parseServerCapabilities(value);
|
|
884
|
+
const compatibility = checkProtocolCompatibility(capabilities, options.support ?? { version: CURRENT_PROTOCOL_VERSION });
|
|
885
|
+
if (!compatibility.compatible) {
|
|
886
|
+
throw new IncompatibleProtocolError(capabilities, compatibility.reason ?? "Client and server protocol versions are incompatible");
|
|
887
|
+
}
|
|
888
|
+
return capabilities;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
var IncompatibleProtocolError;
|
|
892
|
+
var init_protocol_client = __esm(() => {
|
|
893
|
+
init_src();
|
|
894
|
+
IncompatibleProtocolError = class IncompatibleProtocolError extends Error {
|
|
895
|
+
capabilities;
|
|
896
|
+
constructor(capabilities, message) {
|
|
897
|
+
super(message);
|
|
898
|
+
this.capabilities = capabilities;
|
|
899
|
+
this.name = "IncompatibleProtocolError";
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
});
|
|
903
|
+
|
|
904
|
+
// ../../packages/client/src/transport/http-transport.ts
|
|
818
905
|
function responseField(value, field) {
|
|
819
906
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
820
907
|
throw new ProtocolDataError("Response body must be an object");
|
|
@@ -853,14 +940,56 @@ function normalizeDaemonBaseUrl(value) {
|
|
|
853
940
|
const pathname = url.pathname.replace(/\/+$/, "");
|
|
854
941
|
return `${url.origin}${pathname === "/" ? "" : pathname}`;
|
|
855
942
|
}
|
|
856
|
-
function
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
943
|
+
function isReadableStream(value) {
|
|
944
|
+
return typeof ReadableStream !== "undefined" && value instanceof ReadableStream;
|
|
945
|
+
}
|
|
946
|
+
function attachmentRangeHeader(range) {
|
|
947
|
+
if (!range)
|
|
948
|
+
return;
|
|
949
|
+
const { start, end, suffixBytes } = range;
|
|
950
|
+
if (suffixBytes !== undefined) {
|
|
951
|
+
if (start !== undefined || end !== undefined) {
|
|
952
|
+
throw new Error("suffixBytes cannot be combined with start or end");
|
|
953
|
+
}
|
|
954
|
+
assertPositiveSafeInteger(suffixBytes, "suffixBytes");
|
|
955
|
+
return `bytes=-${suffixBytes}`;
|
|
956
|
+
}
|
|
957
|
+
if (start === undefined && end === undefined)
|
|
958
|
+
return;
|
|
959
|
+
if (start === undefined) {
|
|
960
|
+
throw new Error("range start is required when end is provided");
|
|
961
|
+
}
|
|
962
|
+
assertNonNegativeSafeInteger(start, "start");
|
|
963
|
+
if (end === undefined)
|
|
964
|
+
return `bytes=${start}-`;
|
|
965
|
+
assertNonNegativeSafeInteger(end, "end");
|
|
966
|
+
if (end < start)
|
|
967
|
+
throw new Error("range end must not be less than start");
|
|
968
|
+
return `bytes=${start}-${end}`;
|
|
969
|
+
}
|
|
970
|
+
function assertNonNegativeSafeInteger(value, field) {
|
|
971
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
972
|
+
throw new Error(`${field} must be a non-negative safe integer`);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
function assertPositiveSafeInteger(value, field) {
|
|
976
|
+
if (!Number.isSafeInteger(value) || value < 1) {
|
|
977
|
+
throw new Error(`${field} must be a positive safe integer`);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
async function throwResponseError(response) {
|
|
981
|
+
let body;
|
|
982
|
+
try {
|
|
983
|
+
body = await response.json();
|
|
984
|
+
} catch {
|
|
985
|
+
body = await response.text().catch(() => "");
|
|
986
|
+
}
|
|
987
|
+
const message = body && typeof body === "object" && "error" in body && typeof body.error === "string" ? body.error : body && typeof body === "object" && ("message" in body) && typeof body.message === "string" ? body.message : `OpenHarness API request failed with ${response.status}`;
|
|
988
|
+
throw new OpenHarnessApiError(message, response.status, body);
|
|
861
989
|
}
|
|
862
990
|
|
|
863
|
-
class
|
|
991
|
+
class HttpTransport {
|
|
992
|
+
protocolHandshake;
|
|
864
993
|
baseUrl;
|
|
865
994
|
token;
|
|
866
995
|
fetchImpl;
|
|
@@ -869,162 +998,347 @@ class OpenHarnessClient {
|
|
|
869
998
|
this.token = options.token;
|
|
870
999
|
this.fetchImpl = options.fetch ?? fetch;
|
|
871
1000
|
}
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
1001
|
+
isHandshakeExempt(pathname) {
|
|
1002
|
+
const path = pathname.split("?")[0];
|
|
1003
|
+
return path === "/health" || path === "/capabilities";
|
|
1004
|
+
}
|
|
1005
|
+
ensureProtocol(signal) {
|
|
1006
|
+
signal?.throwIfAborted();
|
|
1007
|
+
this.protocolHandshake ??= this.requestUnknown("/capabilities", { auth: false }).then((value) => {
|
|
1008
|
+
const capabilities = parseServerCapabilities(value);
|
|
1009
|
+
const result = checkProtocolCompatibility(capabilities, { version: CURRENT_PROTOCOL_VERSION });
|
|
1010
|
+
if (!result.compatible) {
|
|
1011
|
+
throw new IncompatibleProtocolError(capabilities, result.reason);
|
|
1012
|
+
}
|
|
1013
|
+
return capabilities;
|
|
1014
|
+
}).catch((error) => {
|
|
1015
|
+
this.protocolHandshake = undefined;
|
|
1016
|
+
throw error;
|
|
1017
|
+
});
|
|
1018
|
+
if (!signal)
|
|
1019
|
+
return this.protocolHandshake;
|
|
1020
|
+
return new Promise((resolve, reject) => {
|
|
1021
|
+
const onAbort = () => reject(signal.reason);
|
|
1022
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1023
|
+
this.protocolHandshake.then(resolve, reject).finally(() => {
|
|
1024
|
+
signal.removeEventListener("abort", onAbort);
|
|
1025
|
+
});
|
|
876
1026
|
});
|
|
877
1027
|
}
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
1028
|
+
headers(jsonOrOptions = false, auth = true) {
|
|
1029
|
+
let json = false;
|
|
1030
|
+
let authHeader = auth;
|
|
1031
|
+
let extra;
|
|
1032
|
+
if (typeof jsonOrOptions === "object" && jsonOrOptions !== null) {
|
|
1033
|
+
json = jsonOrOptions.json ?? false;
|
|
1034
|
+
authHeader = jsonOrOptions.auth ?? true;
|
|
1035
|
+
extra = jsonOrOptions.extra;
|
|
1036
|
+
} else {
|
|
1037
|
+
json = Boolean(jsonOrOptions);
|
|
1038
|
+
authHeader = auth;
|
|
1039
|
+
}
|
|
1040
|
+
return {
|
|
1041
|
+
...authHeader && this.token ? { authorization: `Bearer ${this.token}` } : {},
|
|
1042
|
+
...json ? { "content-type": "application/json" } : {},
|
|
1043
|
+
...extra ?? {}
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
path(pathname, query = {}) {
|
|
1047
|
+
const params = new URLSearchParams;
|
|
1048
|
+
for (const [key, value] of Object.entries(query)) {
|
|
1049
|
+
if (value === undefined || value === null || value === false)
|
|
1050
|
+
continue;
|
|
1051
|
+
params.set(key, String(value));
|
|
1052
|
+
}
|
|
1053
|
+
const qs = params.toString();
|
|
1054
|
+
return qs ? `${pathname}?${qs}` : pathname;
|
|
1055
|
+
}
|
|
1056
|
+
resolveUrl(pathname, query) {
|
|
1057
|
+
const resolvedPath = query ? this.path(pathname, query) : pathname;
|
|
1058
|
+
return `${this.baseUrl}${resolvedPath}`;
|
|
1059
|
+
}
|
|
1060
|
+
async request(path, options = {}) {
|
|
1061
|
+
const business = !this.isHandshakeExempt(path);
|
|
1062
|
+
if (business)
|
|
1063
|
+
await this.ensureProtocol(options.signal);
|
|
1064
|
+
options.signal?.throwIfAborted();
|
|
1065
|
+
const url = this.resolveUrl(path, options.query);
|
|
1066
|
+
const hasJsonBody = options.body !== undefined;
|
|
1067
|
+
const headers = mergeHeaders(this.headers(hasJsonBody, options.auth ?? true), options.headers);
|
|
1068
|
+
if (business)
|
|
1069
|
+
headers[PROTOCOL_VERSION_HEADER] = String(CURRENT_PROTOCOL_VERSION);
|
|
1070
|
+
const response = await this.fetchImpl(url, {
|
|
1071
|
+
method: options.method ?? "GET",
|
|
1072
|
+
headers,
|
|
1073
|
+
body: hasJsonBody ? JSON.stringify(options.body) : undefined,
|
|
881
1074
|
signal: options.signal
|
|
882
1075
|
});
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
if (!compatibility.compatible) {
|
|
886
|
-
throw new IncompatibleProtocolError(capabilities, compatibility.reason ?? "Client and server protocol versions are incompatible");
|
|
1076
|
+
if (!response.ok) {
|
|
1077
|
+
await throwResponseError(response);
|
|
887
1078
|
}
|
|
888
|
-
return
|
|
1079
|
+
return await response.json();
|
|
889
1080
|
}
|
|
890
|
-
async
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
1081
|
+
async requestUnknown(path, options = {}) {
|
|
1082
|
+
return this.request(path, options);
|
|
1083
|
+
}
|
|
1084
|
+
async requestResponse(path, options = {}) {
|
|
1085
|
+
const business = !this.isHandshakeExempt(path);
|
|
1086
|
+
if (business)
|
|
1087
|
+
await this.ensureProtocol(options.signal ?? undefined);
|
|
1088
|
+
options.signal?.throwIfAborted();
|
|
1089
|
+
const url = this.resolveUrl(path, options.query);
|
|
1090
|
+
const auth = options.auth ?? true;
|
|
1091
|
+
const headers = mergeHeaders(this.headers(false, auth), options.headers);
|
|
1092
|
+
if (business)
|
|
1093
|
+
headers[PROTOCOL_VERSION_HEADER] = String(CURRENT_PROTOCOL_VERSION);
|
|
895
1094
|
const init = {
|
|
896
|
-
|
|
897
|
-
headers
|
|
898
|
-
body: input.body,
|
|
899
|
-
signal: input.signal
|
|
1095
|
+
...options,
|
|
1096
|
+
headers
|
|
900
1097
|
};
|
|
901
|
-
if (isReadableStream(
|
|
1098
|
+
if (isReadableStream(init.body) && !init.duplex) {
|
|
902
1099
|
init.duplex = "half";
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
async getAttachment(id, options = {}) {
|
|
909
|
-
const value = await this.request(`/attachments/${encodeURIComponent(id)}`, { signal: options.signal });
|
|
910
|
-
return parseAttachmentAssetRecord(value);
|
|
911
|
-
}
|
|
912
|
-
async downloadAttachment(id, options = {}) {
|
|
913
|
-
const range = attachmentRangeHeader(options.range);
|
|
914
|
-
const headers = this.headers();
|
|
915
|
-
if (range)
|
|
916
|
-
headers.range = range;
|
|
917
|
-
const response = await this.fetchImpl(`${this.baseUrl}/attachments/${encodeURIComponent(id)}/content`, { method: "GET", headers, signal: options.signal });
|
|
918
|
-
if (!response.ok)
|
|
919
|
-
await this.throwResponseError(response);
|
|
1100
|
+
}
|
|
1101
|
+
const response = await this.fetchImpl(url, init);
|
|
1102
|
+
if (!response.ok) {
|
|
1103
|
+
await throwResponseError(response);
|
|
1104
|
+
}
|
|
920
1105
|
return response;
|
|
921
1106
|
}
|
|
922
|
-
async
|
|
923
|
-
|
|
924
|
-
return parseAttachmentAssetRecord(value);
|
|
1107
|
+
async throwResponseError(response) {
|
|
1108
|
+
return throwResponseError(response);
|
|
925
1109
|
}
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1110
|
+
}
|
|
1111
|
+
function mergeHeaders(defaults, overrides) {
|
|
1112
|
+
const headers = new Headers(defaults);
|
|
1113
|
+
if (overrides) {
|
|
1114
|
+
new Headers(overrides).forEach((value, key) => headers.set(key, value));
|
|
930
1115
|
}
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1116
|
+
return Object.fromEntries(headers.entries());
|
|
1117
|
+
}
|
|
1118
|
+
var OpenHarnessApiError;
|
|
1119
|
+
var init_http_transport = __esm(() => {
|
|
1120
|
+
init_src();
|
|
1121
|
+
init_protocol_client();
|
|
1122
|
+
OpenHarnessApiError = class OpenHarnessApiError extends Error {
|
|
1123
|
+
status;
|
|
1124
|
+
body;
|
|
1125
|
+
constructor(message, status, body) {
|
|
1126
|
+
super(message);
|
|
1127
|
+
this.status = status;
|
|
1128
|
+
this.body = body;
|
|
1129
|
+
this.name = "OpenHarnessApiError";
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
1132
|
+
});
|
|
1133
|
+
|
|
1134
|
+
// ../../packages/client/src/transport/sse-transport.ts
|
|
1135
|
+
function parseRawSseFrame(frame) {
|
|
1136
|
+
let id;
|
|
1137
|
+
let event;
|
|
1138
|
+
let retry;
|
|
1139
|
+
const dataLines = [];
|
|
1140
|
+
for (const line of frame.split(/\r?\n/)) {
|
|
1141
|
+
if (!line || line.startsWith(":"))
|
|
1142
|
+
continue;
|
|
1143
|
+
if (line.startsWith("data:")) {
|
|
1144
|
+
dataLines.push(line.startsWith("data: ") ? line.slice(6) : line.slice(5));
|
|
1145
|
+
} else if (line.startsWith("event:")) {
|
|
1146
|
+
event = (line.startsWith("event: ") ? line.slice(7) : line.slice(6)).trim();
|
|
1147
|
+
} else if (line.startsWith("id:")) {
|
|
1148
|
+
id = (line.startsWith("id: ") ? line.slice(4) : line.slice(3)).trim();
|
|
1149
|
+
} else if (line.startsWith("retry:")) {
|
|
1150
|
+
const value = (line.startsWith("retry: ") ? line.slice(7) : line.slice(6)).trim();
|
|
1151
|
+
const parsed = parseInt(value, 10);
|
|
1152
|
+
if (!Number.isNaN(parsed)) {
|
|
1153
|
+
retry = parsed;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
937
1156
|
}
|
|
938
|
-
|
|
939
|
-
return
|
|
940
|
-
method: "POST",
|
|
941
|
-
body: { action: "gc" },
|
|
942
|
-
signal: options.signal
|
|
943
|
-
});
|
|
1157
|
+
if (dataLines.length === 0 && !id && !event && retry === undefined) {
|
|
1158
|
+
return;
|
|
944
1159
|
}
|
|
945
|
-
|
|
946
|
-
|
|
1160
|
+
return {
|
|
1161
|
+
id,
|
|
1162
|
+
event,
|
|
1163
|
+
retry,
|
|
1164
|
+
data: dataLines.length > 0 ? dataLines.join(`
|
|
1165
|
+
`) : undefined
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
function parseSseFrame(frame) {
|
|
1169
|
+
let data = "";
|
|
1170
|
+
for (const line of frame.split(/\r?\n/)) {
|
|
1171
|
+
if (!line || line.startsWith(":"))
|
|
1172
|
+
continue;
|
|
1173
|
+
if (line.startsWith("data:")) {
|
|
1174
|
+
const slice = line.slice(5).trimStart();
|
|
1175
|
+
data = data ? `${data}
|
|
1176
|
+
${slice}` : slice;
|
|
1177
|
+
}
|
|
947
1178
|
}
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
1179
|
+
if (!data)
|
|
1180
|
+
return;
|
|
1181
|
+
return JSON.parse(data);
|
|
1182
|
+
}
|
|
1183
|
+
async function* streamServerSentEvents(open, decode = (value) => value) {
|
|
1184
|
+
const reader = (await open()).getReader();
|
|
1185
|
+
const decoder = new TextDecoder;
|
|
1186
|
+
let buffer = "";
|
|
1187
|
+
try {
|
|
1188
|
+
while (true) {
|
|
1189
|
+
const chunk = await reader.read();
|
|
1190
|
+
if (chunk.done)
|
|
1191
|
+
break;
|
|
1192
|
+
buffer += decoder.decode(chunk.value, { stream: true });
|
|
1193
|
+
const frames = buffer.split(/\r?\n\r?\n/);
|
|
1194
|
+
buffer = frames.pop() ?? "";
|
|
1195
|
+
for (const frame of frames) {
|
|
1196
|
+
const event = parseSseFrame(frame);
|
|
1197
|
+
if (event !== undefined)
|
|
1198
|
+
yield decode(event);
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
buffer += decoder.decode();
|
|
1202
|
+
const event = parseSseFrame(buffer);
|
|
1203
|
+
if (event !== undefined)
|
|
1204
|
+
yield decode(event);
|
|
1205
|
+
} finally {
|
|
1206
|
+
reader.releaseLock();
|
|
951
1207
|
}
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
class SseTransport {
|
|
1211
|
+
transport;
|
|
1212
|
+
constructor(transport) {
|
|
1213
|
+
this.transport = transport;
|
|
1214
|
+
}
|
|
1215
|
+
streamFromReader(open, decode = (val) => val) {
|
|
1216
|
+
return streamServerSentEvents(open, decode);
|
|
1217
|
+
}
|
|
1218
|
+
async* stream(url, options = {}) {
|
|
1219
|
+
let lastEventId = options.lastEventId;
|
|
1220
|
+
let reconnectDelayMs = options.reconnectDelayMs ?? 250;
|
|
1221
|
+
let connected = false;
|
|
1222
|
+
while (!options.signal?.aborted) {
|
|
1223
|
+
const headers = new Headers(options.headers);
|
|
1224
|
+
if (lastEventId)
|
|
1225
|
+
headers.set("Last-Event-ID", lastEventId);
|
|
1226
|
+
const requestUrl = connected && lastEventId ? withoutCursor(url) : url;
|
|
1227
|
+
const response = await this.transport.requestResponse(requestUrl.slice(this.transport.baseUrl.length), { headers, signal: options.signal });
|
|
1228
|
+
connected = true;
|
|
1229
|
+
if (!response.body) {
|
|
1230
|
+
throw new Error(options.noBodyMessage ?? "Event stream response has no body");
|
|
1231
|
+
}
|
|
1232
|
+
for await (const frame of readRawSseFrames(response.body)) {
|
|
1233
|
+
if (frame.id !== undefined)
|
|
1234
|
+
lastEventId = frame.id;
|
|
1235
|
+
if (frame.retry !== undefined)
|
|
1236
|
+
reconnectDelayMs = frame.retry;
|
|
1237
|
+
if (frame.data !== undefined) {
|
|
1238
|
+
yield (options.decode ?? ((value) => value))(JSON.parse(frame.data));
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
if (!options.reconnect || options.signal?.aborted)
|
|
1242
|
+
return;
|
|
1243
|
+
await waitForReconnect(reconnectDelayMs, options.signal);
|
|
1244
|
+
}
|
|
955
1245
|
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1246
|
+
}
|
|
1247
|
+
async function* readRawSseFrames(stream) {
|
|
1248
|
+
const reader = stream.getReader();
|
|
1249
|
+
const decoder = new TextDecoder;
|
|
1250
|
+
let buffer = "";
|
|
1251
|
+
try {
|
|
1252
|
+
while (true) {
|
|
1253
|
+
const chunk = await reader.read();
|
|
1254
|
+
if (chunk.done)
|
|
1255
|
+
break;
|
|
1256
|
+
buffer += decoder.decode(chunk.value, { stream: true });
|
|
1257
|
+
const frames = buffer.split(/\r?\n\r?\n/);
|
|
1258
|
+
buffer = frames.pop() ?? "";
|
|
1259
|
+
for (const value of frames) {
|
|
1260
|
+
const frame = parseRawSseFrame(value);
|
|
1261
|
+
if (frame)
|
|
1262
|
+
yield frame;
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
buffer += decoder.decode();
|
|
1266
|
+
const frame = parseRawSseFrame(buffer);
|
|
1267
|
+
if (frame)
|
|
1268
|
+
yield frame;
|
|
1269
|
+
} finally {
|
|
1270
|
+
reader.releaseLock();
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
function waitForReconnect(ms, signal) {
|
|
1274
|
+
if (signal?.aborted)
|
|
1275
|
+
return Promise.reject(abortError(signal));
|
|
1276
|
+
return new Promise((resolve, reject) => {
|
|
1277
|
+
const timer = setTimeout(() => {
|
|
1278
|
+
signal?.removeEventListener("abort", onAbort);
|
|
1279
|
+
resolve();
|
|
1280
|
+
}, Math.max(0, ms));
|
|
1281
|
+
const onAbort = () => {
|
|
1282
|
+
clearTimeout(timer);
|
|
1283
|
+
reject(abortError(signal));
|
|
1284
|
+
};
|
|
1285
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1288
|
+
function abortError(signal) {
|
|
1289
|
+
if (signal.reason instanceof Error)
|
|
1290
|
+
return signal.reason;
|
|
1291
|
+
return new DOMException("Aborted", "AbortError");
|
|
1292
|
+
}
|
|
1293
|
+
function withoutCursor(url) {
|
|
1294
|
+
const parsed = new URL(url);
|
|
1295
|
+
parsed.searchParams.delete("cursor");
|
|
1296
|
+
return parsed.toString();
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
// ../../packages/client/src/protocol/index.ts
|
|
1300
|
+
var init_protocol = __esm(() => {
|
|
1301
|
+
init_protocol_client();
|
|
1302
|
+
});
|
|
1303
|
+
|
|
1304
|
+
// ../../packages/client/src/resources/system-resource.ts
|
|
1305
|
+
class SystemResource {
|
|
1306
|
+
transport;
|
|
1307
|
+
constructor(transport) {
|
|
1308
|
+
this.transport = transport;
|
|
960
1309
|
}
|
|
961
1310
|
async listCommands(options) {
|
|
962
1311
|
const { signal, ...query } = options;
|
|
963
|
-
const response = await this.request(this.path("/commands", query), { signal });
|
|
1312
|
+
const response = await this.transport.request(this.transport.path("/commands", query), { signal });
|
|
964
1313
|
return response.commands;
|
|
965
1314
|
}
|
|
966
1315
|
async getSettings(options = {}) {
|
|
967
|
-
const response = await this.request("/settings", { signal: options.signal });
|
|
1316
|
+
const response = await this.transport.request("/settings", { signal: options.signal });
|
|
968
1317
|
return response.settings;
|
|
969
1318
|
}
|
|
970
1319
|
async patchSettings(patch, options = {}) {
|
|
971
|
-
const response = await this.request("/settings", {
|
|
1320
|
+
const response = await this.transport.request("/settings", {
|
|
972
1321
|
method: "PATCH",
|
|
973
1322
|
body: patch,
|
|
974
1323
|
signal: options.signal
|
|
975
1324
|
});
|
|
976
1325
|
return response.settings;
|
|
977
1326
|
}
|
|
978
|
-
async listProviders(options = {}) {
|
|
979
|
-
const response = await this.request("/providers", { signal: options.signal });
|
|
980
|
-
return response.providers;
|
|
981
|
-
}
|
|
982
|
-
async createCustomProvider(input, options = {}) {
|
|
983
|
-
const response = await this.request("/providers/custom", {
|
|
984
|
-
method: "POST",
|
|
985
|
-
body: input,
|
|
986
|
-
signal: options.signal
|
|
987
|
-
});
|
|
988
|
-
return response.provider;
|
|
989
|
-
}
|
|
990
|
-
async connectCatalogProvider(id, apiKey, options = {}) {
|
|
991
|
-
const response = await this.request(`/providers/catalog/${encodeURIComponent(id)}/connect`, { method: "POST", body: { apiKey }, signal: options.signal });
|
|
992
|
-
return response.provider;
|
|
993
|
-
}
|
|
994
|
-
async disconnectCatalogProvider(id, options = {}) {
|
|
995
|
-
await this.request(`/providers/catalog/${encodeURIComponent(id)}/connect`, { method: "DELETE", signal: options.signal });
|
|
996
|
-
}
|
|
997
|
-
async updateCustomProvider(id, input, options = {}) {
|
|
998
|
-
const response = await this.request(`/providers/custom/${encodeURIComponent(id)}`, { method: "PATCH", body: input, signal: options.signal });
|
|
999
|
-
return response.provider;
|
|
1000
|
-
}
|
|
1001
|
-
async removeCustomProvider(id, options = {}) {
|
|
1002
|
-
await this.request(`/providers/custom/${encodeURIComponent(id)}`, {
|
|
1003
|
-
method: "DELETE",
|
|
1004
|
-
signal: options.signal
|
|
1005
|
-
});
|
|
1006
|
-
}
|
|
1007
|
-
async listModels(options = {}) {
|
|
1008
|
-
const response = await this.request("/models", { signal: options.signal });
|
|
1009
|
-
return response.providers;
|
|
1010
|
-
}
|
|
1011
1327
|
async getSessionMcp(sessionId, options = {}) {
|
|
1012
|
-
const response = await this.request(`/sessions/${encodeURIComponent(sessionId)}/mcp`, { signal: options.signal });
|
|
1328
|
+
const response = await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/mcp`, { signal: options.signal });
|
|
1013
1329
|
return response.servers;
|
|
1014
1330
|
}
|
|
1015
1331
|
async listMemory(options) {
|
|
1016
1332
|
const { signal, ...query } = options;
|
|
1017
|
-
return await this.request(this.path("/memory", query), {
|
|
1018
|
-
signal
|
|
1019
|
-
});
|
|
1333
|
+
return await this.transport.request(this.transport.path("/memory", query), { signal });
|
|
1020
1334
|
}
|
|
1021
1335
|
async getMemory(entryId, options) {
|
|
1022
1336
|
const { signal, cwd } = options;
|
|
1023
|
-
const response = await this.request(this.path(`/memory/${encodeURIComponent(entryId)}`, { cwd }), { signal });
|
|
1337
|
+
const response = await this.transport.request(this.transport.path(`/memory/${encodeURIComponent(entryId)}`, { cwd }), { signal });
|
|
1024
1338
|
return response.entry;
|
|
1025
1339
|
}
|
|
1026
1340
|
async addMemory(input, options = {}) {
|
|
1027
|
-
const response = await this.request("/memory", {
|
|
1341
|
+
const response = await this.transport.request("/memory", {
|
|
1028
1342
|
method: "POST",
|
|
1029
1343
|
body: input,
|
|
1030
1344
|
signal: options.signal
|
|
@@ -1033,36 +1347,21 @@ class OpenHarnessClient {
|
|
|
1033
1347
|
}
|
|
1034
1348
|
async removeMemory(entryId, options) {
|
|
1035
1349
|
const { signal, cwd } = options;
|
|
1036
|
-
await this.request(this.path(`/memory/${encodeURIComponent(entryId)}`, { cwd }), { method: "DELETE", signal });
|
|
1037
|
-
}
|
|
1038
|
-
async getAuthStatus(options = {}) {
|
|
1039
|
-
const response = await this.request("/auth", {
|
|
1040
|
-
signal: options.signal
|
|
1041
|
-
});
|
|
1042
|
-
return response.auth;
|
|
1043
|
-
}
|
|
1044
|
-
async authLogin(input, options = {}) {
|
|
1045
|
-
return await this.request("/auth/login", {
|
|
1046
|
-
method: "POST",
|
|
1047
|
-
body: input,
|
|
1048
|
-
signal: options.signal
|
|
1049
|
-
});
|
|
1350
|
+
await this.transport.request(this.transport.path(`/memory/${encodeURIComponent(entryId)}`, { cwd }), { method: "DELETE", signal });
|
|
1050
1351
|
}
|
|
1051
|
-
async
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
signal: options.signal
|
|
1056
|
-
});
|
|
1352
|
+
async listContextPlugins(options) {
|
|
1353
|
+
const { signal, ...query } = options;
|
|
1354
|
+
const response = await this.transport.request(this.transport.path("/context/plugins", query), { signal });
|
|
1355
|
+
return response.plugins;
|
|
1057
1356
|
}
|
|
1058
1357
|
async getContextPreview(options) {
|
|
1059
1358
|
const { signal, ...query } = options;
|
|
1060
|
-
const response = await this.request(this.path("/context", query), { signal });
|
|
1359
|
+
const response = await this.transport.request(this.transport.path("/context", query), { signal });
|
|
1061
1360
|
return response.report;
|
|
1062
1361
|
}
|
|
1063
1362
|
async getContextStatus(options) {
|
|
1064
1363
|
const { signal, ...query } = options;
|
|
1065
|
-
const response = await this.request(this.path("/context/status", query), { signal });
|
|
1364
|
+
const response = await this.transport.request(this.transport.path("/context/status", query), { signal });
|
|
1066
1365
|
return response.report;
|
|
1067
1366
|
}
|
|
1068
1367
|
async getContextUsage(options) {
|
|
@@ -1072,357 +1371,559 @@ class OpenHarnessClient {
|
|
|
1072
1371
|
...refresh !== undefined ? { refresh: refresh ? "true" : "false" } : {},
|
|
1073
1372
|
...previousContextWindow !== undefined ? { previousContextWindow: String(previousContextWindow) } : {}
|
|
1074
1373
|
};
|
|
1075
|
-
return await this.request(this.path("/context/usage", query), { signal });
|
|
1076
|
-
}
|
|
1077
|
-
async compactSession(sessionId, options = {}) {
|
|
1078
|
-
return await this.request(`/sessions/${encodeURIComponent(sessionId)}/compact`, { method: "POST", signal: options.signal });
|
|
1079
|
-
}
|
|
1080
|
-
async getSessionGoal(sessionId) {
|
|
1081
|
-
const response = await this.request(`/sessions/${encodeURIComponent(sessionId)}/goal`);
|
|
1082
|
-
return response.goal;
|
|
1083
|
-
}
|
|
1084
|
-
async createSessionGoal(sessionId, input) {
|
|
1085
|
-
const response = await this.request(`/sessions/${encodeURIComponent(sessionId)}/goals`, { method: "POST", body: input });
|
|
1086
|
-
return response.goal;
|
|
1087
|
-
}
|
|
1088
|
-
async updateSessionGoal(sessionId, goalId, input) {
|
|
1089
|
-
const response = await this.request(`/sessions/${encodeURIComponent(sessionId)}/goals/${encodeURIComponent(goalId)}`, { method: "PATCH", body: input });
|
|
1090
|
-
return response.goal;
|
|
1091
|
-
}
|
|
1092
|
-
async applySessionGoalAction(sessionId, goalId, input) {
|
|
1093
|
-
const response = await this.request(`/sessions/${encodeURIComponent(sessionId)}/goals/${encodeURIComponent(goalId)}/actions`, { method: "POST", body: input });
|
|
1094
|
-
return response.goal;
|
|
1095
|
-
}
|
|
1096
|
-
async rewindSession(sessionId, input = {}, options = {}) {
|
|
1097
|
-
return await this.request(`/sessions/${encodeURIComponent(sessionId)}/rewind`, { method: "POST", body: input, signal: options.signal });
|
|
1098
|
-
}
|
|
1099
|
-
async rememberSession(sessionId, options = {}) {
|
|
1100
|
-
return await this.request(`/sessions/${encodeURIComponent(sessionId)}/remember`, { method: "POST", signal: options.signal });
|
|
1374
|
+
return await this.transport.request(this.transport.path("/context/usage", query), { signal });
|
|
1101
1375
|
}
|
|
1102
1376
|
async startDream(input, options = {}) {
|
|
1103
|
-
return await this.request("/dream", {
|
|
1377
|
+
return await this.transport.request("/dream", {
|
|
1104
1378
|
method: "POST",
|
|
1105
1379
|
body: input,
|
|
1106
1380
|
signal: options.signal
|
|
1107
1381
|
});
|
|
1108
1382
|
}
|
|
1109
1383
|
async getProfileStatus(options = {}) {
|
|
1110
|
-
const response = await this.request("/profile", {
|
|
1384
|
+
const response = await this.transport.request("/profile", {
|
|
1111
1385
|
signal: options.signal
|
|
1112
1386
|
});
|
|
1113
1387
|
return response.report;
|
|
1114
1388
|
}
|
|
1115
1389
|
async initProfile(options = {}) {
|
|
1116
|
-
const response = await this.request("/profile/init", {
|
|
1390
|
+
const response = await this.transport.request("/profile/init", {
|
|
1117
1391
|
method: "POST",
|
|
1118
1392
|
signal: options.signal
|
|
1119
1393
|
});
|
|
1120
1394
|
return response.report;
|
|
1121
1395
|
}
|
|
1122
1396
|
async listOutputStyles(options = {}) {
|
|
1123
|
-
const response = await this.request("/output-styles", {
|
|
1397
|
+
const response = await this.transport.request("/output-styles", {
|
|
1124
1398
|
signal: options.signal
|
|
1125
1399
|
});
|
|
1126
1400
|
return response.styles;
|
|
1127
1401
|
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
// ../../packages/client/src/resources/provider-resource.ts
|
|
1405
|
+
class ProviderResource {
|
|
1406
|
+
transport;
|
|
1407
|
+
constructor(transport) {
|
|
1408
|
+
this.transport = transport;
|
|
1409
|
+
}
|
|
1410
|
+
async listProviders(options = {}) {
|
|
1411
|
+
const response = await this.transport.request("/providers", { signal: options.signal });
|
|
1412
|
+
return response.providers;
|
|
1413
|
+
}
|
|
1414
|
+
async createCustomProvider(input, options = {}) {
|
|
1415
|
+
const response = await this.transport.request("/providers/custom", {
|
|
1416
|
+
method: "POST",
|
|
1417
|
+
body: input,
|
|
1418
|
+
signal: options.signal
|
|
1419
|
+
});
|
|
1420
|
+
return response.provider;
|
|
1421
|
+
}
|
|
1422
|
+
async connectCatalogProvider(id, apiKeyOrInput, options = {}) {
|
|
1423
|
+
const body = typeof apiKeyOrInput === "string" ? { apiKey: apiKeyOrInput } : apiKeyOrInput;
|
|
1424
|
+
const response = await this.transport.request(`/providers/catalog/${encodeURIComponent(id)}/connect`, { method: "POST", body, signal: options.signal });
|
|
1425
|
+
return response.provider;
|
|
1426
|
+
}
|
|
1427
|
+
async updateCatalogProviderHeaders(id, headers, options = {}) {
|
|
1428
|
+
const response = await this.transport.request(`/providers/catalog/${encodeURIComponent(id)}`, {
|
|
1429
|
+
method: "PATCH",
|
|
1430
|
+
body: { headers },
|
|
1431
|
+
signal: options.signal
|
|
1432
|
+
});
|
|
1433
|
+
return response.provider;
|
|
1434
|
+
}
|
|
1435
|
+
async disconnectCatalogProvider(id, options = {}) {
|
|
1436
|
+
await this.transport.request(`/providers/catalog/${encodeURIComponent(id)}/connect`, { method: "DELETE", signal: options.signal });
|
|
1437
|
+
}
|
|
1438
|
+
async updateCustomProvider(id, input, options = {}) {
|
|
1439
|
+
const response = await this.transport.request(`/providers/custom/${encodeURIComponent(id)}`, { method: "PATCH", body: input, signal: options.signal });
|
|
1440
|
+
return response.provider;
|
|
1441
|
+
}
|
|
1442
|
+
async removeCustomProvider(id, options = {}) {
|
|
1443
|
+
await this.transport.request(`/providers/custom/${encodeURIComponent(id)}`, {
|
|
1444
|
+
method: "DELETE",
|
|
1445
|
+
signal: options.signal
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
async listModels(options = {}) {
|
|
1449
|
+
const response = await this.transport.request("/models", { signal: options.signal });
|
|
1450
|
+
return response.providers;
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
// ../../packages/client/src/resources/auth-resource.ts
|
|
1455
|
+
class AuthResource {
|
|
1456
|
+
transport;
|
|
1457
|
+
constructor(transport) {
|
|
1458
|
+
this.transport = transport;
|
|
1459
|
+
}
|
|
1460
|
+
async getStatus(options = {}) {
|
|
1461
|
+
const response = await this.transport.request("/auth", {
|
|
1462
|
+
signal: options.signal
|
|
1463
|
+
});
|
|
1464
|
+
return response.auth;
|
|
1465
|
+
}
|
|
1466
|
+
async login(input, options = {}) {
|
|
1467
|
+
return await this.transport.request("/auth/login", {
|
|
1468
|
+
method: "POST",
|
|
1469
|
+
body: input,
|
|
1470
|
+
signal: options.signal
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1473
|
+
async logout(input, options = {}) {
|
|
1474
|
+
return await this.transport.request("/auth/logout", {
|
|
1475
|
+
method: "POST",
|
|
1476
|
+
body: input,
|
|
1477
|
+
signal: options.signal
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
// ../../packages/client/src/resources/project-resource.ts
|
|
1483
|
+
class ProjectResource {
|
|
1484
|
+
transport;
|
|
1485
|
+
constructor(transport) {
|
|
1486
|
+
this.transport = transport;
|
|
1487
|
+
}
|
|
1488
|
+
async list(options = {}) {
|
|
1489
|
+
const { signal, ...query } = options;
|
|
1490
|
+
const response = await this.transport.request(this.transport.path("/projects", query), { signal });
|
|
1491
|
+
return response.projects;
|
|
1492
|
+
}
|
|
1493
|
+
async inspect(path) {
|
|
1494
|
+
return (await this.transport.request("/projects/inspect", {
|
|
1495
|
+
method: "POST",
|
|
1496
|
+
body: { path }
|
|
1497
|
+
})).project;
|
|
1498
|
+
}
|
|
1499
|
+
async rename(projectId, name) {
|
|
1500
|
+
return (await this.transport.request(`/projects/${encodeURIComponent(projectId)}`, { method: "PATCH", body: { name } })).project;
|
|
1501
|
+
}
|
|
1502
|
+
async setPinned(projectId, pinned) {
|
|
1503
|
+
return (await this.transport.request(`/projects/${encodeURIComponent(projectId)}`, { method: "PATCH", body: { pinned } })).project;
|
|
1504
|
+
}
|
|
1505
|
+
async setDefaultShell(projectId, defaultShell) {
|
|
1506
|
+
return (await this.transport.request(`/projects/${encodeURIComponent(projectId)}`, { method: "PATCH", body: { defaultShell } })).project;
|
|
1507
|
+
}
|
|
1508
|
+
async rebind(projectId, path) {
|
|
1509
|
+
return (await this.transport.request(`/projects/${encodeURIComponent(projectId)}/rebind`, { method: "POST", body: { path } })).project;
|
|
1510
|
+
}
|
|
1511
|
+
async archive(projectId) {
|
|
1512
|
+
return (await this.transport.request(`/projects/${encodeURIComponent(projectId)}`, { method: "DELETE" })).project;
|
|
1513
|
+
}
|
|
1514
|
+
async init(input, options = {}) {
|
|
1515
|
+
const response = await this.transport.request("/project/init", {
|
|
1130
1516
|
method: "POST",
|
|
1131
1517
|
body: input,
|
|
1132
1518
|
signal: options.signal
|
|
1133
1519
|
});
|
|
1134
1520
|
return response.report;
|
|
1135
1521
|
}
|
|
1136
|
-
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
// ../../packages/client/src/resources/plugin-resource.ts
|
|
1525
|
+
class PluginResource {
|
|
1526
|
+
transport;
|
|
1527
|
+
constructor(transport) {
|
|
1528
|
+
this.transport = transport;
|
|
1529
|
+
}
|
|
1530
|
+
async list(options) {
|
|
1137
1531
|
const { signal, ...query } = options;
|
|
1138
|
-
return await this.request(this.path("/plugins", query), { signal });
|
|
1532
|
+
return await this.transport.request(this.transport.path("/plugins", query), { signal });
|
|
1533
|
+
}
|
|
1534
|
+
async enable(id, input, options = {}) {
|
|
1535
|
+
return await this.transport.request(`/plugins/${encodeURIComponent(id)}/enable`, { method: "POST", body: input, signal: options.signal });
|
|
1536
|
+
}
|
|
1537
|
+
async disable(id, input, options = {}) {
|
|
1538
|
+
return await this.transport.request(`/plugins/${encodeURIComponent(id)}/disable`, { method: "POST", body: input, signal: options.signal });
|
|
1139
1539
|
}
|
|
1140
|
-
async
|
|
1141
|
-
return await this.request(
|
|
1540
|
+
async installLocal(input) {
|
|
1541
|
+
return await this.transport.request(input.link ? "/plugins/link-local" : "/plugins/install-local", { method: "POST", body: input });
|
|
1142
1542
|
}
|
|
1143
|
-
async
|
|
1144
|
-
return await this.request(
|
|
1543
|
+
async previewArchive(input, options = {}) {
|
|
1544
|
+
return await this.transport.request("/plugins/archive/preview", {
|
|
1545
|
+
method: "POST",
|
|
1546
|
+
body: input,
|
|
1547
|
+
signal: options.signal
|
|
1548
|
+
});
|
|
1145
1549
|
}
|
|
1146
|
-
async
|
|
1147
|
-
return await this.request(
|
|
1550
|
+
async installArchive(input, options = {}) {
|
|
1551
|
+
return await this.transport.request("/plugins/archive/install", {
|
|
1552
|
+
method: "POST",
|
|
1553
|
+
body: input,
|
|
1554
|
+
signal: options.signal
|
|
1555
|
+
});
|
|
1148
1556
|
}
|
|
1149
|
-
async
|
|
1150
|
-
return await this.request("/plugins/
|
|
1557
|
+
async previewGit(input, options = {}) {
|
|
1558
|
+
return await this.transport.request("/plugins/git/preview", {
|
|
1151
1559
|
method: "POST",
|
|
1152
1560
|
body: input,
|
|
1153
1561
|
signal: options.signal
|
|
1154
1562
|
});
|
|
1155
1563
|
}
|
|
1156
|
-
async
|
|
1157
|
-
return await this.request("/plugins/
|
|
1564
|
+
async installGit(input, options = {}) {
|
|
1565
|
+
return await this.transport.request("/plugins/git/install", {
|
|
1158
1566
|
method: "POST",
|
|
1159
1567
|
body: input,
|
|
1160
1568
|
signal: options.signal
|
|
1161
1569
|
});
|
|
1162
1570
|
}
|
|
1163
|
-
async
|
|
1164
|
-
return await this.request(`/plugins/${encodeURIComponent(id)}`, { method: "DELETE", body: input });
|
|
1571
|
+
async uninstall(id, input) {
|
|
1572
|
+
return await this.transport.request(`/plugins/${encodeURIComponent(id)}`, { method: "DELETE", body: input });
|
|
1165
1573
|
}
|
|
1166
|
-
async
|
|
1167
|
-
return await this.request("/plugins/reload", {
|
|
1574
|
+
async reload(input, options = {}) {
|
|
1575
|
+
return await this.transport.request("/plugins/reload", {
|
|
1168
1576
|
method: "POST",
|
|
1169
1577
|
body: input,
|
|
1170
1578
|
signal: options.signal
|
|
1171
1579
|
});
|
|
1172
1580
|
}
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
// ../../packages/client/src/resources/development-resource.ts
|
|
1584
|
+
class DevelopmentResource {
|
|
1585
|
+
transport;
|
|
1586
|
+
constructor(transport) {
|
|
1587
|
+
this.transport = transport;
|
|
1588
|
+
}
|
|
1173
1589
|
async listSkills(options = {}) {
|
|
1174
|
-
return await this.request("/skills", {
|
|
1590
|
+
return await this.transport.request("/skills", {
|
|
1175
1591
|
signal: options.signal
|
|
1176
1592
|
});
|
|
1177
1593
|
}
|
|
1178
1594
|
async removeSkill(id, input, options = {}) {
|
|
1179
|
-
return await this.request(`/skills/${encodeURIComponent(id)}`, {
|
|
1595
|
+
return await this.transport.request(`/skills/${encodeURIComponent(id)}`, {
|
|
1180
1596
|
method: "DELETE",
|
|
1181
1597
|
body: input,
|
|
1182
1598
|
signal: options.signal
|
|
1183
1599
|
});
|
|
1184
1600
|
}
|
|
1185
1601
|
async listAgentPersonas(options = {}) {
|
|
1186
|
-
const response = await this.request("/agent-personas", {
|
|
1602
|
+
const response = await this.transport.request("/agent-personas", {
|
|
1187
1603
|
signal: options.signal
|
|
1188
1604
|
});
|
|
1189
1605
|
return response.agents;
|
|
1190
1606
|
}
|
|
1191
1607
|
async listHooks(options) {
|
|
1192
1608
|
const { signal, ...query } = options;
|
|
1193
|
-
const response = await this.request(this.path("/hooks", query), { signal });
|
|
1609
|
+
const response = await this.transport.request(this.transport.path("/hooks", query), { signal });
|
|
1194
1610
|
return response.hooks;
|
|
1195
1611
|
}
|
|
1196
1612
|
async getGitDiff(options) {
|
|
1197
1613
|
const { signal, cwd, full } = options;
|
|
1198
|
-
const response = await this.request(this.path("/git/diff", { cwd, ...full ? { full: "true" } : {} }), { signal });
|
|
1614
|
+
const response = await this.transport.request(this.transport.path("/git/diff", { cwd, ...full ? { full: "true" } : {} }), { signal });
|
|
1199
1615
|
return response.output;
|
|
1200
1616
|
}
|
|
1201
1617
|
async getGitBranch(options) {
|
|
1202
1618
|
const { signal, cwd, list } = options;
|
|
1203
|
-
const response = await this.request(this.path("/git/branch", { cwd, ...list ? { list: "true" } : {} }), { signal });
|
|
1619
|
+
const response = await this.transport.request(this.transport.path("/git/branch", { cwd, ...list ? { list: "true" } : {} }), { signal });
|
|
1204
1620
|
return response.output;
|
|
1205
1621
|
}
|
|
1206
1622
|
async getGitStatus(options) {
|
|
1207
1623
|
const { signal, cwd } = options;
|
|
1208
|
-
const response = await this.request(this.path("/git/status", { cwd }), { signal });
|
|
1624
|
+
const response = await this.transport.request(this.transport.path("/git/status", { cwd }), { signal });
|
|
1209
1625
|
return response.output;
|
|
1210
1626
|
}
|
|
1211
1627
|
async gitCommit(input, options = {}) {
|
|
1212
|
-
const response = await this.request("/git/commit", {
|
|
1628
|
+
const response = await this.transport.request("/git/commit", {
|
|
1213
1629
|
method: "POST",
|
|
1214
1630
|
body: input,
|
|
1215
1631
|
signal: options.signal
|
|
1216
1632
|
});
|
|
1217
1633
|
return response.output;
|
|
1218
1634
|
}
|
|
1219
|
-
|
|
1220
|
-
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
// ../../packages/client/src/resources/session-resource.ts
|
|
1638
|
+
function createPromptRequestId() {
|
|
1639
|
+
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
1640
|
+
return globalThis.crypto.randomUUID();
|
|
1221
1641
|
}
|
|
1222
|
-
|
|
1223
|
-
|
|
1642
|
+
promptRequestCounter += 1;
|
|
1643
|
+
return `prompt-${Date.now().toString(36)}-${promptRequestCounter.toString(36)}`;
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
class SessionResource {
|
|
1647
|
+
transport;
|
|
1648
|
+
constructor(transport) {
|
|
1649
|
+
this.transport = transport;
|
|
1224
1650
|
}
|
|
1225
|
-
async
|
|
1651
|
+
async list(options = {}) {
|
|
1226
1652
|
const { signal, ...query } = options;
|
|
1227
|
-
const response = await this.request(this.path("/sessions", query), { signal });
|
|
1653
|
+
const response = await this.transport.request(this.transport.path("/sessions", query), { signal });
|
|
1228
1654
|
return response.sessions;
|
|
1229
1655
|
}
|
|
1230
|
-
async
|
|
1231
|
-
const
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
async inspectProject(path) {
|
|
1236
|
-
return (await this.request("/projects/inspect", {
|
|
1237
|
-
method: "POST",
|
|
1238
|
-
body: { path }
|
|
1239
|
-
})).project;
|
|
1240
|
-
}
|
|
1241
|
-
async renameProject(projectId, name) {
|
|
1242
|
-
return (await this.request(`/projects/${encodeURIComponent(projectId)}`, { method: "PATCH", body: { name } })).project;
|
|
1243
|
-
}
|
|
1244
|
-
async setProjectPinned(projectId, pinned) {
|
|
1245
|
-
return (await this.request(`/projects/${encodeURIComponent(projectId)}`, { method: "PATCH", body: { pinned } })).project;
|
|
1246
|
-
}
|
|
1247
|
-
async setProjectDefaultShell(projectId, defaultShell) {
|
|
1248
|
-
return (await this.request(`/projects/${encodeURIComponent(projectId)}`, { method: "PATCH", body: { defaultShell } })).project;
|
|
1249
|
-
}
|
|
1250
|
-
async rebindProject(projectId, path) {
|
|
1251
|
-
return (await this.request(`/projects/${encodeURIComponent(projectId)}/rebind`, { method: "POST", body: { path } })).project;
|
|
1252
|
-
}
|
|
1253
|
-
async archiveProject(projectId) {
|
|
1254
|
-
return (await this.request(`/projects/${encodeURIComponent(projectId)}`, { method: "DELETE" })).project;
|
|
1656
|
+
async get(sessionId, options = {}) {
|
|
1657
|
+
const response = await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}`, {
|
|
1658
|
+
signal: options.signal
|
|
1659
|
+
});
|
|
1660
|
+
return response.session;
|
|
1255
1661
|
}
|
|
1256
|
-
async
|
|
1257
|
-
const response = await this.request("/sessions", {
|
|
1662
|
+
async create(input, options = {}) {
|
|
1663
|
+
const response = await this.transport.request("/sessions", {
|
|
1258
1664
|
method: "POST",
|
|
1259
1665
|
body: input,
|
|
1260
1666
|
signal: options.signal
|
|
1261
1667
|
});
|
|
1262
1668
|
return response.session;
|
|
1263
1669
|
}
|
|
1264
|
-
async
|
|
1265
|
-
const response = await this.request(`/sessions/${encodeURIComponent(sessionId)}`, {
|
|
1670
|
+
async update(sessionId, input, options = {}) {
|
|
1671
|
+
const response = await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}`, {
|
|
1672
|
+
method: "PATCH",
|
|
1673
|
+
body: input,
|
|
1266
1674
|
signal: options.signal
|
|
1267
1675
|
});
|
|
1268
1676
|
return response.session;
|
|
1269
1677
|
}
|
|
1270
|
-
async
|
|
1271
|
-
const response = await this.request(`/sessions/${encodeURIComponent(sessionId)}/fork`, {
|
|
1678
|
+
async fork(sessionId, input = {}, options = {}) {
|
|
1679
|
+
const response = await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/fork`, {
|
|
1272
1680
|
method: "POST",
|
|
1273
1681
|
body: input,
|
|
1274
1682
|
signal: options.signal
|
|
1275
1683
|
});
|
|
1276
1684
|
return response.session;
|
|
1277
1685
|
}
|
|
1278
|
-
async
|
|
1279
|
-
const response = await this.request(`/sessions/${encodeURIComponent(sessionId)}
|
|
1280
|
-
signal: options.signal
|
|
1281
|
-
});
|
|
1282
|
-
return decodeSessionStateSnapshot(response);
|
|
1283
|
-
}
|
|
1284
|
-
async archiveSession(sessionId, options = {}) {
|
|
1285
|
-
const response = await this.request(`/sessions/${encodeURIComponent(sessionId)}`, {
|
|
1686
|
+
async archive(sessionId, options = {}) {
|
|
1687
|
+
const response = await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}`, {
|
|
1286
1688
|
method: "DELETE",
|
|
1287
1689
|
signal: options.signal
|
|
1288
1690
|
});
|
|
1289
1691
|
return response.session;
|
|
1290
1692
|
}
|
|
1291
|
-
async
|
|
1292
|
-
const response = await this.request(`/sessions/${encodeURIComponent(sessionId)}/hard`, {
|
|
1693
|
+
async delete(sessionId, options = {}) {
|
|
1694
|
+
const response = await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/hard`, {
|
|
1293
1695
|
method: "DELETE",
|
|
1294
1696
|
signal: options.signal
|
|
1295
1697
|
});
|
|
1296
1698
|
return response.deletedSessionIds;
|
|
1297
1699
|
}
|
|
1298
|
-
async
|
|
1299
|
-
const response = await this.request(`/sessions/${encodeURIComponent(sessionId)}`, {
|
|
1300
|
-
method: "PATCH",
|
|
1301
|
-
body: input,
|
|
1700
|
+
async getState(sessionId, options = {}) {
|
|
1701
|
+
const response = await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/state`, {
|
|
1302
1702
|
signal: options.signal
|
|
1303
1703
|
});
|
|
1304
|
-
return response
|
|
1704
|
+
return decodeSessionStateSnapshot(response);
|
|
1305
1705
|
}
|
|
1306
1706
|
async listMessages(sessionId, options = {}) {
|
|
1307
1707
|
const { signal, ...query } = options;
|
|
1308
|
-
const response = await this.request(this.path(`/sessions/${encodeURIComponent(sessionId)}/messages`, query), { signal });
|
|
1708
|
+
const response = await this.transport.request(this.transport.path(`/sessions/${encodeURIComponent(sessionId)}/messages`, query), { signal });
|
|
1309
1709
|
return response.messages;
|
|
1310
1710
|
}
|
|
1311
1711
|
async listMessageParts(sessionId, options = {}) {
|
|
1312
1712
|
const { signal, ...query } = options;
|
|
1313
|
-
const response = await this.request(this.path(`/sessions/${encodeURIComponent(sessionId)}/parts`, query), { signal });
|
|
1713
|
+
const response = await this.transport.request(this.transport.path(`/sessions/${encodeURIComponent(sessionId)}/parts`, query), { signal });
|
|
1314
1714
|
return response.parts;
|
|
1315
1715
|
}
|
|
1316
1716
|
async admitPrompt(sessionId, input, options = {}) {
|
|
1317
|
-
return await this.request(`/sessions/${encodeURIComponent(sessionId)}/prompts`, {
|
|
1717
|
+
return await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/prompts`, {
|
|
1318
1718
|
method: "POST",
|
|
1319
1719
|
body: { ...input, id: input.id ?? createPromptRequestId() },
|
|
1320
1720
|
signal: options.signal
|
|
1321
1721
|
});
|
|
1322
1722
|
}
|
|
1323
1723
|
async editLatestPrompt(sessionId, input, options = {}) {
|
|
1324
|
-
return await this.request(`/sessions/${encodeURIComponent(sessionId)}/prompts/latest/edit`, {
|
|
1724
|
+
return await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/prompts/latest/edit`, {
|
|
1325
1725
|
method: "POST",
|
|
1326
1726
|
body: input,
|
|
1327
1727
|
signal: options.signal
|
|
1328
1728
|
});
|
|
1329
1729
|
}
|
|
1330
|
-
async promoteQueuedPrompt(sessionId, inputId, input, options = {}) {
|
|
1331
|
-
return await this.request(`/sessions/${encodeURIComponent(sessionId)}/prompts/${encodeURIComponent(inputId)}/promote`, { method: "POST", body: input, signal: options.signal });
|
|
1730
|
+
async promoteQueuedPrompt(sessionId, inputId, input, options = {}) {
|
|
1731
|
+
return await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/prompts/${encodeURIComponent(inputId)}/promote`, { method: "POST", body: input, signal: options.signal });
|
|
1732
|
+
}
|
|
1733
|
+
async cancelQueuedPrompt(sessionId, inputId, input, options = {}) {
|
|
1734
|
+
return await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/prompts/${encodeURIComponent(inputId)}/cancel`, { method: "POST", body: input, signal: options.signal });
|
|
1735
|
+
}
|
|
1736
|
+
async resumeInterruptedRun(sessionId, runId, input = {}, options = {}) {
|
|
1737
|
+
return await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/runs/${encodeURIComponent(runId)}/resume`, {
|
|
1738
|
+
method: "POST",
|
|
1739
|
+
body: { ...input, id: input.id ?? createPromptRequestId() },
|
|
1740
|
+
signal: options.signal
|
|
1741
|
+
});
|
|
1742
|
+
}
|
|
1743
|
+
async interrupt(sessionId, options = {}) {
|
|
1744
|
+
return await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/interrupt`, {
|
|
1745
|
+
method: "POST",
|
|
1746
|
+
body: options.expectedRunId ? { expectedRunId: options.expectedRunId } : undefined,
|
|
1747
|
+
signal: options.signal
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
async compact(sessionId, options = {}) {
|
|
1751
|
+
return await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/compact`, { method: "POST", signal: options.signal });
|
|
1752
|
+
}
|
|
1753
|
+
async rewind(sessionId, input = {}, options = {}) {
|
|
1754
|
+
return await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/rewind`, { method: "POST", body: input, signal: options.signal });
|
|
1755
|
+
}
|
|
1756
|
+
async remember(sessionId, options = {}) {
|
|
1757
|
+
return await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/remember`, { method: "POST", signal: options.signal });
|
|
1758
|
+
}
|
|
1759
|
+
async export(sessionId, input = {}, options = {}) {
|
|
1760
|
+
return await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/export`, { method: "POST", body: input, signal: options.signal });
|
|
1761
|
+
}
|
|
1762
|
+
async getUsage(sessionId, options = {}) {
|
|
1763
|
+
return await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/usage`, { signal: options.signal });
|
|
1764
|
+
}
|
|
1765
|
+
async getGoal(sessionId) {
|
|
1766
|
+
const response = await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/goal`);
|
|
1767
|
+
return response.goal;
|
|
1768
|
+
}
|
|
1769
|
+
async createGoal(sessionId, input) {
|
|
1770
|
+
const response = await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/goals`, { method: "POST", body: input });
|
|
1771
|
+
return response.goal;
|
|
1772
|
+
}
|
|
1773
|
+
async updateGoal(sessionId, goalId, input) {
|
|
1774
|
+
const response = await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/goals/${encodeURIComponent(goalId)}`, { method: "PATCH", body: input });
|
|
1775
|
+
return response.goal;
|
|
1776
|
+
}
|
|
1777
|
+
async applyGoalAction(sessionId, goalId, input) {
|
|
1778
|
+
const response = await this.transport.request(`/sessions/${encodeURIComponent(sessionId)}/goals/${encodeURIComponent(goalId)}/actions`, { method: "POST", body: input });
|
|
1779
|
+
return response.goal;
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
var promptRequestCounter = 0;
|
|
1783
|
+
var init_session_resource = __esm(() => {
|
|
1784
|
+
init_src();
|
|
1785
|
+
});
|
|
1786
|
+
|
|
1787
|
+
// ../../packages/client/src/resources/attachment-resource.ts
|
|
1788
|
+
class AttachmentResource {
|
|
1789
|
+
transport;
|
|
1790
|
+
constructor(transport) {
|
|
1791
|
+
this.transport = transport;
|
|
1792
|
+
}
|
|
1793
|
+
async upload(input) {
|
|
1794
|
+
const headers = {};
|
|
1795
|
+
headers["x-openharness-filename"] = encodeURIComponent(input.displayName);
|
|
1796
|
+
if (input.mediaType)
|
|
1797
|
+
headers["content-type"] = input.mediaType;
|
|
1798
|
+
const response = await this.transport.requestResponse("/attachments", {
|
|
1799
|
+
method: "POST",
|
|
1800
|
+
headers,
|
|
1801
|
+
body: input.body,
|
|
1802
|
+
signal: input.signal
|
|
1803
|
+
});
|
|
1804
|
+
return parseAttachmentAssetRecord(await response.json());
|
|
1805
|
+
}
|
|
1806
|
+
async get(id, options = {}) {
|
|
1807
|
+
const value = await this.transport.request(`/attachments/${encodeURIComponent(id)}`, { signal: options.signal });
|
|
1808
|
+
return parseAttachmentAssetRecord(value);
|
|
1809
|
+
}
|
|
1810
|
+
async download(id, options = {}) {
|
|
1811
|
+
const range = attachmentRangeHeader(options.range);
|
|
1812
|
+
const headers = {};
|
|
1813
|
+
if (range)
|
|
1814
|
+
headers.range = range;
|
|
1815
|
+
return await this.transport.requestResponse(`/attachments/${encodeURIComponent(id)}/content`, { method: "GET", headers, signal: options.signal });
|
|
1332
1816
|
}
|
|
1333
|
-
async
|
|
1334
|
-
|
|
1817
|
+
async delete(id, options = {}) {
|
|
1818
|
+
const value = await this.transport.request(`/attachments/${encodeURIComponent(id)}`, { method: "DELETE", signal: options.signal });
|
|
1819
|
+
return parseAttachmentAssetRecord(value);
|
|
1335
1820
|
}
|
|
1336
|
-
async
|
|
1337
|
-
return await this.request(
|
|
1821
|
+
async scanStorage(options = {}) {
|
|
1822
|
+
return await this.transport.request("/attachments/storage", { signal: options.signal });
|
|
1823
|
+
}
|
|
1824
|
+
async repairStorage(options = {}) {
|
|
1825
|
+
return await this.transport.request("/attachments/storage/actions", {
|
|
1338
1826
|
method: "POST",
|
|
1339
|
-
body: {
|
|
1827
|
+
body: { action: "repair-safe" },
|
|
1340
1828
|
signal: options.signal
|
|
1341
1829
|
});
|
|
1342
1830
|
}
|
|
1343
|
-
async
|
|
1344
|
-
return await this.request(
|
|
1831
|
+
async gcStorage(options = {}) {
|
|
1832
|
+
return await this.transport.request("/attachments/storage/actions", {
|
|
1345
1833
|
method: "POST",
|
|
1346
|
-
body:
|
|
1834
|
+
body: { action: "gc" },
|
|
1347
1835
|
signal: options.signal
|
|
1348
1836
|
});
|
|
1349
1837
|
}
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1838
|
+
}
|
|
1839
|
+
var init_attachment_resource = __esm(() => {
|
|
1840
|
+
init_src();
|
|
1841
|
+
init_http_transport();
|
|
1842
|
+
});
|
|
1843
|
+
|
|
1844
|
+
// ../../packages/client/src/resources/permission-resource.ts
|
|
1845
|
+
class PermissionResource {
|
|
1846
|
+
transport;
|
|
1847
|
+
constructor(transport) {
|
|
1848
|
+
this.transport = transport;
|
|
1356
1849
|
}
|
|
1357
|
-
async
|
|
1850
|
+
async list(options = {}) {
|
|
1358
1851
|
const { signal, ...query } = options;
|
|
1359
|
-
const response = await this.request(this.path("/permissions", query), { signal });
|
|
1852
|
+
const response = await this.transport.request(this.transport.path("/permissions", query), { signal });
|
|
1360
1853
|
return response.requests;
|
|
1361
1854
|
}
|
|
1362
|
-
async
|
|
1363
|
-
const response = await this.request(`/permissions/${encodeURIComponent(requestId)}/reply`, {
|
|
1855
|
+
async reply(requestId, input, options = {}) {
|
|
1856
|
+
const response = await this.transport.request(`/permissions/${encodeURIComponent(requestId)}/reply`, {
|
|
1364
1857
|
method: "POST",
|
|
1365
1858
|
body: input,
|
|
1366
1859
|
signal: options.signal
|
|
1367
1860
|
});
|
|
1368
1861
|
return response.request;
|
|
1369
1862
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
// ../../packages/client/src/resources/schedule-resource.ts
|
|
1866
|
+
class ScheduleResource {
|
|
1867
|
+
transport;
|
|
1868
|
+
constructor(transport) {
|
|
1869
|
+
this.transport = transport;
|
|
1870
|
+
}
|
|
1871
|
+
async getStatus(options = {}) {
|
|
1872
|
+
return await this.transport.request("/schedules/status", {
|
|
1372
1873
|
signal: options.signal
|
|
1373
1874
|
});
|
|
1374
1875
|
}
|
|
1375
|
-
async
|
|
1876
|
+
async listTasks(options = {}) {
|
|
1376
1877
|
const { signal, ...query } = options;
|
|
1377
|
-
const response = await this.request(this.path("/schedules/tasks", query), { signal });
|
|
1878
|
+
const response = await this.transport.request(this.transport.path("/schedules/tasks", query), { signal });
|
|
1378
1879
|
return response.tasks;
|
|
1379
1880
|
}
|
|
1380
|
-
async
|
|
1381
|
-
const response = await this.request(`/schedules/tasks/${encodeURIComponent(id)}`, { signal: options.signal });
|
|
1881
|
+
async getTask(id, options = {}) {
|
|
1882
|
+
const response = await this.transport.request(`/schedules/tasks/${encodeURIComponent(id)}`, { signal: options.signal });
|
|
1382
1883
|
return response.task;
|
|
1383
1884
|
}
|
|
1384
|
-
async
|
|
1385
|
-
const response = await this.request("/schedules/tasks", {
|
|
1885
|
+
async createTask(input, options = {}) {
|
|
1886
|
+
const response = await this.transport.request("/schedules/tasks", {
|
|
1386
1887
|
method: "POST",
|
|
1387
1888
|
body: input,
|
|
1388
1889
|
signal: options.signal
|
|
1389
1890
|
});
|
|
1390
1891
|
return response.task;
|
|
1391
1892
|
}
|
|
1392
|
-
async
|
|
1393
|
-
const response = await this.request(`/schedules/tasks/${encodeURIComponent(id)}`, { method: "PATCH", body: input, signal: options.signal });
|
|
1893
|
+
async updateTask(id, input, options = {}) {
|
|
1894
|
+
const response = await this.transport.request(`/schedules/tasks/${encodeURIComponent(id)}`, { method: "PATCH", body: input, signal: options.signal });
|
|
1394
1895
|
return response.task;
|
|
1395
1896
|
}
|
|
1396
|
-
async
|
|
1397
|
-
await this.request(`/schedules/tasks/${encodeURIComponent(id)}`, {
|
|
1897
|
+
async removeTask(id, options = {}) {
|
|
1898
|
+
await this.transport.request(`/schedules/tasks/${encodeURIComponent(id)}`, {
|
|
1398
1899
|
method: "DELETE",
|
|
1399
1900
|
signal: options.signal
|
|
1400
1901
|
});
|
|
1401
1902
|
}
|
|
1402
|
-
async
|
|
1403
|
-
const response = await this.request(`/schedules/tasks/${encodeURIComponent(id)}/run`, { method: "POST", signal: options.signal });
|
|
1903
|
+
async triggerTask(id, options = {}) {
|
|
1904
|
+
const response = await this.transport.request(`/schedules/tasks/${encodeURIComponent(id)}/run`, { method: "POST", signal: options.signal });
|
|
1404
1905
|
return response.run;
|
|
1405
1906
|
}
|
|
1406
|
-
async
|
|
1907
|
+
async listRuns(options = {}) {
|
|
1407
1908
|
const { signal, ...query } = options;
|
|
1408
|
-
const response = await this.request(this.path("/schedules/runs", query), { signal });
|
|
1909
|
+
const response = await this.transport.request(this.transport.path("/schedules/runs", query), { signal });
|
|
1409
1910
|
return response.runs;
|
|
1410
1911
|
}
|
|
1411
|
-
async
|
|
1412
|
-
const response = await this.request(`/schedules/runs/${encodeURIComponent(id)}/read`, { method: "PATCH", body: { unread }, signal: options.signal });
|
|
1912
|
+
async setRunUnread(id, unread, options = {}) {
|
|
1913
|
+
const response = await this.transport.request(`/schedules/runs/${encodeURIComponent(id)}/read`, { method: "PATCH", body: { unread }, signal: options.signal });
|
|
1413
1914
|
return response.run;
|
|
1414
1915
|
}
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
// ../../packages/client/src/resources/job-resource.ts
|
|
1919
|
+
class JobResource {
|
|
1920
|
+
transport;
|
|
1921
|
+
constructor(transport) {
|
|
1922
|
+
this.transport = transport;
|
|
1422
1923
|
}
|
|
1423
|
-
async
|
|
1924
|
+
async list(options) {
|
|
1424
1925
|
const { signal, kinds, statuses, includeFinished, ...query } = options;
|
|
1425
|
-
const response = await this.request(this.path("/jobs", {
|
|
1926
|
+
const response = await this.transport.request(this.transport.path("/jobs", {
|
|
1426
1927
|
...query,
|
|
1427
1928
|
...kinds ? { kinds: kinds.join(",") } : {},
|
|
1428
1929
|
...statuses ? { statuses: statuses.join(",") } : {},
|
|
@@ -1431,236 +1932,214 @@ class OpenHarnessClient {
|
|
|
1431
1932
|
return responseArray(response, "jobs", decodeJobSnapshot);
|
|
1432
1933
|
}
|
|
1433
1934
|
async createBackgroundShell(input, options = {}) {
|
|
1434
|
-
return await this.request("/background-shells", {
|
|
1935
|
+
return await this.transport.request("/background-shells", {
|
|
1435
1936
|
method: "POST",
|
|
1436
1937
|
body: input,
|
|
1437
1938
|
signal: options.signal
|
|
1438
1939
|
});
|
|
1439
1940
|
}
|
|
1440
|
-
async
|
|
1941
|
+
async read(jobId, options) {
|
|
1441
1942
|
const { signal, ...query } = options;
|
|
1442
|
-
const response = await this.request(this.path(`/jobs/${encodeURIComponent(jobId)}`, query), { signal });
|
|
1943
|
+
const response = await this.transport.request(this.transport.path(`/jobs/${encodeURIComponent(jobId)}`, query), { signal });
|
|
1443
1944
|
return decodeJobReadResult(response);
|
|
1444
1945
|
}
|
|
1445
|
-
async
|
|
1446
|
-
const response = await this.request(`/jobs/${encodeURIComponent(jobId)}/wait`, {
|
|
1946
|
+
async wait(jobId, input, options = {}) {
|
|
1947
|
+
const response = await this.transport.request(`/jobs/${encodeURIComponent(jobId)}/wait`, {
|
|
1447
1948
|
method: "POST",
|
|
1448
1949
|
body: input,
|
|
1449
1950
|
signal: options.signal
|
|
1450
1951
|
});
|
|
1451
1952
|
return decodeJobWaitResult(response);
|
|
1452
1953
|
}
|
|
1453
|
-
async
|
|
1454
|
-
await this.request(`/jobs/${encodeURIComponent(jobId)}/input`, {
|
|
1954
|
+
async send(jobId, input, options = {}) {
|
|
1955
|
+
await this.transport.request(`/jobs/${encodeURIComponent(jobId)}/input`, {
|
|
1455
1956
|
method: "POST",
|
|
1456
1957
|
body: input,
|
|
1457
1958
|
signal: options.signal
|
|
1458
1959
|
});
|
|
1459
1960
|
}
|
|
1460
|
-
async
|
|
1461
|
-
const response = await this.request(`/jobs/${encodeURIComponent(jobId)}/cancel`, { method: "POST", body: input, signal: options.signal });
|
|
1961
|
+
async cancel(jobId, input, options = {}) {
|
|
1962
|
+
const response = await this.transport.request(`/jobs/${encodeURIComponent(jobId)}/cancel`, { method: "POST", body: input, signal: options.signal });
|
|
1462
1963
|
return decodeJobSnapshot(responseField(response, "snapshot"));
|
|
1463
1964
|
}
|
|
1464
|
-
|
|
1965
|
+
}
|
|
1966
|
+
var init_job_resource = __esm(() => {
|
|
1967
|
+
init_src();
|
|
1968
|
+
init_http_transport();
|
|
1969
|
+
});
|
|
1970
|
+
|
|
1971
|
+
// ../../packages/client/src/resources/terminal-resource.ts
|
|
1972
|
+
class TerminalResource {
|
|
1973
|
+
transport;
|
|
1974
|
+
sse;
|
|
1975
|
+
constructor(transport, sse) {
|
|
1976
|
+
this.transport = transport;
|
|
1977
|
+
this.sse = sse;
|
|
1978
|
+
}
|
|
1979
|
+
async create(input, options = {}) {
|
|
1980
|
+
const response = await this.transport.request("/terminals", {
|
|
1981
|
+
method: "POST",
|
|
1982
|
+
body: input,
|
|
1983
|
+
signal: options.signal
|
|
1984
|
+
});
|
|
1985
|
+
return decodeTerminalSessionInfo(responseField(response, "terminal"));
|
|
1986
|
+
}
|
|
1987
|
+
async list(options = {}) {
|
|
1465
1988
|
const { signal, ...query } = options;
|
|
1466
|
-
const response = await this.request(this.path("/terminals", query), { signal });
|
|
1989
|
+
const response = await this.transport.request(this.transport.path("/terminals", query), { signal });
|
|
1467
1990
|
return responseArray(response, "terminals", decodeTerminalSessionInfo);
|
|
1468
1991
|
}
|
|
1469
|
-
async
|
|
1470
|
-
const response = await this.request(`/terminals/${encodeURIComponent(terminalId)}`, { signal: options.signal });
|
|
1992
|
+
async get(terminalId, options = {}) {
|
|
1993
|
+
const response = await this.transport.request(`/terminals/${encodeURIComponent(terminalId)}`, { signal: options.signal });
|
|
1471
1994
|
return decodeTerminalSessionInfo(responseField(response, "terminal"));
|
|
1472
1995
|
}
|
|
1473
|
-
async
|
|
1474
|
-
const response = await this.request(`/terminals/${encodeURIComponent(terminalId)}/output`, { signal: options.signal });
|
|
1996
|
+
async read(terminalId, options = {}) {
|
|
1997
|
+
const response = await this.transport.request(`/terminals/${encodeURIComponent(terminalId)}/output`, { signal: options.signal });
|
|
1475
1998
|
return decodeTerminalReadResult(responseField(response, "snapshot"));
|
|
1476
1999
|
}
|
|
1477
|
-
async
|
|
1478
|
-
await this.request(`/terminals/${encodeURIComponent(input.terminalId)}/input`, { method: "POST", body: { data: input.data }, signal: options.signal });
|
|
2000
|
+
async write(input, options = {}) {
|
|
2001
|
+
await this.transport.request(`/terminals/${encodeURIComponent(input.terminalId)}/input`, { method: "POST", body: { data: input.data }, signal: options.signal });
|
|
1479
2002
|
}
|
|
1480
|
-
async
|
|
1481
|
-
await this.request(`/terminals/${encodeURIComponent(input.terminalId)}/resize`, {
|
|
2003
|
+
async resize(input, options = {}) {
|
|
2004
|
+
await this.transport.request(`/terminals/${encodeURIComponent(input.terminalId)}/resize`, {
|
|
1482
2005
|
method: "POST",
|
|
1483
2006
|
body: { cols: input.cols, rows: input.rows },
|
|
1484
2007
|
signal: options.signal
|
|
1485
2008
|
});
|
|
1486
2009
|
}
|
|
1487
|
-
async
|
|
1488
|
-
await this.request(`/terminals/${encodeURIComponent(terminalId)}/signal`, { method: "POST", body: { signal }, signal: options.signal });
|
|
2010
|
+
async signal(terminalId, signal, options = {}) {
|
|
2011
|
+
await this.transport.request(`/terminals/${encodeURIComponent(terminalId)}/signal`, { method: "POST", body: { signal }, signal: options.signal });
|
|
1489
2012
|
}
|
|
1490
|
-
async
|
|
1491
|
-
await this.request(`/terminals/${encodeURIComponent(terminalId)}`, {
|
|
2013
|
+
async close(terminalId, options = {}) {
|
|
2014
|
+
await this.transport.request(`/terminals/${encodeURIComponent(terminalId)}`, {
|
|
1492
2015
|
method: "DELETE",
|
|
1493
2016
|
signal: options.signal
|
|
1494
2017
|
});
|
|
1495
2018
|
}
|
|
1496
|
-
streamTerminalEvents(options = {}) {
|
|
1497
|
-
return streamServerSentEvents(async () => {
|
|
1498
|
-
const response = await this.fetchImpl(`${this.baseUrl}/terminals/stream`, {
|
|
1499
|
-
headers: this.headers(),
|
|
1500
|
-
signal: options.signal
|
|
1501
|
-
});
|
|
1502
|
-
if (!response.ok)
|
|
1503
|
-
await this.throwResponseError(response);
|
|
1504
|
-
if (!response.body)
|
|
1505
|
-
throw new Error("Terminal event stream response has no body");
|
|
1506
|
-
return response.body;
|
|
1507
|
-
}, decodeTerminalEvent);
|
|
1508
|
-
}
|
|
1509
2019
|
streamEvents(options = {}) {
|
|
1510
|
-
return
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
const response = await this.fetchImpl(`${this.baseUrl}${this.path("/events/stream", query)}`, {
|
|
1516
|
-
headers: this.headers(),
|
|
1517
|
-
signal: options.signal
|
|
1518
|
-
});
|
|
1519
|
-
if (!response.ok)
|
|
1520
|
-
await this.throwResponseError(response);
|
|
1521
|
-
if (!response.body)
|
|
1522
|
-
throw new Error("Event stream response has no body");
|
|
1523
|
-
return response.body;
|
|
1524
|
-
}, decodeSessionEventRecord);
|
|
1525
|
-
}
|
|
1526
|
-
async request(path, options = {}) {
|
|
1527
|
-
const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
1528
|
-
method: options.method ?? "GET",
|
|
1529
|
-
headers: this.headers(options.body !== undefined, options.auth ?? true),
|
|
1530
|
-
body: options.body === undefined ? undefined : JSON.stringify(options.body),
|
|
1531
|
-
signal: options.signal
|
|
2020
|
+
return this.sse.stream(this.transport.resolveUrl("/terminals/stream"), {
|
|
2021
|
+
headers: this.transport.headers(),
|
|
2022
|
+
signal: options.signal,
|
|
2023
|
+
decode: decodeTerminalEvent,
|
|
2024
|
+
noBodyMessage: "Terminal event stream response has no body"
|
|
1532
2025
|
});
|
|
1533
|
-
if (!response.ok)
|
|
1534
|
-
await this.throwResponseError(response);
|
|
1535
|
-
return await response.json();
|
|
1536
|
-
}
|
|
1537
|
-
headers(json = false, auth = true) {
|
|
1538
|
-
return {
|
|
1539
|
-
...auth && this.token ? { authorization: `Bearer ${this.token}` } : {},
|
|
1540
|
-
...json ? { "content-type": "application/json" } : {}
|
|
1541
|
-
};
|
|
1542
2026
|
}
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
2027
|
+
}
|
|
2028
|
+
var init_terminal_resource = __esm(() => {
|
|
2029
|
+
init_src();
|
|
2030
|
+
init_http_transport();
|
|
2031
|
+
});
|
|
2032
|
+
|
|
2033
|
+
// ../../packages/client/src/resources/channel-resource.ts
|
|
2034
|
+
class ChannelResource {
|
|
2035
|
+
transport;
|
|
2036
|
+
constructor(transport) {
|
|
2037
|
+
this.transport = transport;
|
|
1552
2038
|
}
|
|
1553
|
-
async
|
|
1554
|
-
|
|
1555
|
-
try {
|
|
1556
|
-
body = await response.json();
|
|
1557
|
-
} catch {
|
|
1558
|
-
body = await response.text().catch(() => "");
|
|
1559
|
-
}
|
|
1560
|
-
const message = body && typeof body === "object" && "error" in body && typeof body.error === "string" ? body.error : body && typeof body === "object" && ("message" in body) && typeof body.message === "string" ? body.message : `OpenHarness API request failed with ${response.status}`;
|
|
1561
|
-
throw new OpenHarnessApiError(message, response.status, body);
|
|
2039
|
+
async handleMessage(input, options = {}) {
|
|
2040
|
+
return await this.transport.request("/channels/messages", { method: "POST", body: input, signal: options.signal });
|
|
1562
2041
|
}
|
|
1563
|
-
}
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
}
|
|
1567
|
-
function attachmentRangeHeader(range) {
|
|
1568
|
-
if (!range)
|
|
1569
|
-
return;
|
|
1570
|
-
const { start, end, suffixBytes } = range;
|
|
1571
|
-
if (suffixBytes !== undefined) {
|
|
1572
|
-
if (start !== undefined || end !== undefined) {
|
|
1573
|
-
throw new Error("suffixBytes cannot be combined with start or end");
|
|
1574
|
-
}
|
|
1575
|
-
assertPositiveSafeInteger(suffixBytes, "suffixBytes");
|
|
1576
|
-
return `bytes=-${suffixBytes}`;
|
|
2042
|
+
async recordDelivery(deliveryId, input, options = {}) {
|
|
2043
|
+
const response = await this.transport.request(`/channels/deliveries/${encodeURIComponent(deliveryId)}/result`, { method: "POST", body: input, signal: options.signal });
|
|
2044
|
+
return response.delivery;
|
|
1577
2045
|
}
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
throw new Error("range start is required when end is provided");
|
|
2046
|
+
async getStatus(options = {}) {
|
|
2047
|
+
const { signal, ...query } = options;
|
|
2048
|
+
return await this.transport.request(this.transport.path("/channels/status", query), { signal });
|
|
1582
2049
|
}
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
if (end < start)
|
|
1588
|
-
throw new Error("range end must not be less than start");
|
|
1589
|
-
return `bytes=${start}-${end}`;
|
|
1590
|
-
}
|
|
1591
|
-
function assertNonNegativeSafeInteger(value, field) {
|
|
1592
|
-
if (!Number.isSafeInteger(value) || value < 0) {
|
|
1593
|
-
throw new Error(`${field} must be a non-negative safe integer`);
|
|
2050
|
+
async listPendingDeliveries(options = {}) {
|
|
2051
|
+
const { signal, ...query } = options;
|
|
2052
|
+
const response = await this.transport.request(this.transport.path("/channels/deliveries/pending", query), { signal });
|
|
2053
|
+
return response.deliveries;
|
|
1594
2054
|
}
|
|
1595
2055
|
}
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
2056
|
+
|
|
2057
|
+
// ../../packages/client/src/resources/event-resource.ts
|
|
2058
|
+
class EventResource {
|
|
2059
|
+
transport;
|
|
2060
|
+
sse;
|
|
2061
|
+
constructor(transport, sse) {
|
|
2062
|
+
this.transport = transport;
|
|
2063
|
+
this.sse = sse;
|
|
2064
|
+
}
|
|
2065
|
+
async list(options = {}) {
|
|
2066
|
+
const { signal, ...query } = options;
|
|
2067
|
+
const response = await this.transport.request(this.transport.path("/events", query), { signal });
|
|
2068
|
+
return responseArray(response, "events", decodeSessionEventRecord);
|
|
1599
2069
|
}
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
const frames = buffer.split(/\r?\n\r?\n/);
|
|
1612
|
-
buffer = frames.pop() ?? "";
|
|
1613
|
-
for (const frame of frames) {
|
|
1614
|
-
const event = parseSseFrame(frame);
|
|
1615
|
-
if (event !== undefined)
|
|
1616
|
-
yield decode(event);
|
|
1617
|
-
}
|
|
1618
|
-
}
|
|
1619
|
-
buffer += decoder.decode();
|
|
1620
|
-
const event = parseSseFrame(buffer);
|
|
1621
|
-
if (event !== undefined)
|
|
1622
|
-
yield decode(event);
|
|
1623
|
-
} finally {
|
|
1624
|
-
reader.releaseLock();
|
|
2070
|
+
stream(options = {}) {
|
|
2071
|
+
const query = {
|
|
2072
|
+
cursor: options.cursor,
|
|
2073
|
+
sessionId: options.sessionId
|
|
2074
|
+
};
|
|
2075
|
+
return this.sse.stream(this.transport.resolveUrl("/events/stream", query), {
|
|
2076
|
+
headers: this.transport.headers(),
|
|
2077
|
+
signal: options.signal,
|
|
2078
|
+
decode: decodeSessionEventRecord,
|
|
2079
|
+
reconnect: options.transportReconnect ?? false
|
|
2080
|
+
});
|
|
1625
2081
|
}
|
|
1626
2082
|
}
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
2083
|
+
var init_event_resource = __esm(() => {
|
|
2084
|
+
init_src();
|
|
2085
|
+
init_http_transport();
|
|
2086
|
+
});
|
|
2087
|
+
|
|
2088
|
+
// ../../packages/client/src/resources/index.ts
|
|
2089
|
+
var init_resources = __esm(() => {
|
|
2090
|
+
init_session_resource();
|
|
2091
|
+
init_attachment_resource();
|
|
2092
|
+
init_job_resource();
|
|
2093
|
+
init_terminal_resource();
|
|
2094
|
+
init_event_resource();
|
|
2095
|
+
});
|
|
2096
|
+
|
|
2097
|
+
// ../../packages/client/src/transport/http-client.ts
|
|
2098
|
+
class OpenHarnessClient {
|
|
2099
|
+
protocol;
|
|
2100
|
+
system;
|
|
2101
|
+
providers;
|
|
2102
|
+
auth;
|
|
2103
|
+
projects;
|
|
2104
|
+
plugins;
|
|
2105
|
+
development;
|
|
2106
|
+
sessions;
|
|
2107
|
+
attachments;
|
|
2108
|
+
permissions;
|
|
2109
|
+
schedules;
|
|
2110
|
+
jobs;
|
|
2111
|
+
terminals;
|
|
2112
|
+
channels;
|
|
2113
|
+
events;
|
|
2114
|
+
constructor(options) {
|
|
2115
|
+
const transport = new HttpTransport(options);
|
|
2116
|
+
const sse = new SseTransport(transport);
|
|
2117
|
+
this.protocol = new ProtocolClient(transport);
|
|
2118
|
+
this.system = new SystemResource(transport);
|
|
2119
|
+
this.providers = new ProviderResource(transport);
|
|
2120
|
+
this.auth = new AuthResource(transport);
|
|
2121
|
+
this.projects = new ProjectResource(transport);
|
|
2122
|
+
this.plugins = new PluginResource(transport);
|
|
2123
|
+
this.development = new DevelopmentResource(transport);
|
|
2124
|
+
this.sessions = new SessionResource(transport);
|
|
2125
|
+
this.attachments = new AttachmentResource(transport);
|
|
2126
|
+
this.permissions = new PermissionResource(transport);
|
|
2127
|
+
this.schedules = new ScheduleResource(transport);
|
|
2128
|
+
this.jobs = new JobResource(transport);
|
|
2129
|
+
this.terminals = new TerminalResource(transport, sse);
|
|
2130
|
+
this.channels = new ChannelResource(transport);
|
|
2131
|
+
this.events = new EventResource(transport, sse);
|
|
1634
2132
|
}
|
|
1635
|
-
if (!data)
|
|
1636
|
-
return;
|
|
1637
|
-
return JSON.parse(data);
|
|
1638
2133
|
}
|
|
1639
|
-
var promptRequestCounter = 0, OpenHarnessApiError, IncompatibleProtocolError;
|
|
1640
2134
|
var init_http_client = __esm(() => {
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
body;
|
|
1645
|
-
constructor(message, status, body) {
|
|
1646
|
-
super(message);
|
|
1647
|
-
this.status = status;
|
|
1648
|
-
this.body = body;
|
|
1649
|
-
this.name = "OpenHarnessApiError";
|
|
1650
|
-
}
|
|
1651
|
-
};
|
|
1652
|
-
IncompatibleProtocolError = class IncompatibleProtocolError extends Error {
|
|
1653
|
-
capabilities;
|
|
1654
|
-
constructor(capabilities, message) {
|
|
1655
|
-
super(message);
|
|
1656
|
-
this.capabilities = capabilities;
|
|
1657
|
-
this.name = "IncompatibleProtocolError";
|
|
1658
|
-
}
|
|
1659
|
-
};
|
|
2135
|
+
init_http_transport();
|
|
2136
|
+
init_protocol();
|
|
2137
|
+
init_resources();
|
|
1660
2138
|
});
|
|
1661
2139
|
|
|
1662
2140
|
// ../../packages/client/src/transport/index.ts
|
|
1663
2141
|
var init_transport = __esm(() => {
|
|
2142
|
+
init_http_transport();
|
|
1664
2143
|
init_http_client();
|
|
1665
2144
|
});
|
|
1666
2145
|
|
|
@@ -1677,6 +2156,9 @@ function createInitialClientState() {
|
|
|
1677
2156
|
};
|
|
1678
2157
|
}
|
|
1679
2158
|
function applySessionSnapshot(state, snapshot) {
|
|
2159
|
+
const knownCursor = state.snapshotCursorBySession[snapshot.session.id] ?? 0;
|
|
2160
|
+
if (snapshot.cursor < knownCursor)
|
|
2161
|
+
return state;
|
|
1680
2162
|
const partsByMessageId = {};
|
|
1681
2163
|
for (const part of snapshot.parts) {
|
|
1682
2164
|
const parts = partsByMessageId[part.messageId] ?? [];
|
|
@@ -2010,126 +2492,221 @@ function selectSessionMessagesWithParts(bucket) {
|
|
|
2010
2492
|
parts: [...bucket.partsByMessageId[message.id] ?? []].sort((a, b) => a.seq - b.seq)
|
|
2011
2493
|
}));
|
|
2012
2494
|
}
|
|
2495
|
+
function selectFirstPendingPermission(state, sessionId) {
|
|
2496
|
+
if (!sessionId)
|
|
2497
|
+
return;
|
|
2498
|
+
const bucket = state.buckets[sessionId];
|
|
2499
|
+
if (!bucket)
|
|
2500
|
+
return;
|
|
2501
|
+
return Object.values(bucket.permissions).filter((request) => request.status === "pending").sort((a, b) => a.createdAt - b.createdAt).at(0);
|
|
2502
|
+
}
|
|
2013
2503
|
|
|
2014
2504
|
// ../../packages/client/src/state/sync.ts
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2505
|
+
var init_sync = __esm(() => {
|
|
2506
|
+
init_reducer();
|
|
2507
|
+
});
|
|
2508
|
+
|
|
2509
|
+
// ../../packages/client/src/state/session-sync-controller.ts
|
|
2510
|
+
class SessionSyncController {
|
|
2511
|
+
client;
|
|
2512
|
+
sessionId;
|
|
2513
|
+
initialCursor;
|
|
2514
|
+
generation;
|
|
2515
|
+
externalSignal;
|
|
2516
|
+
reconnectDelayMs;
|
|
2517
|
+
onUpdate;
|
|
2518
|
+
onStatusChange;
|
|
2519
|
+
onError;
|
|
2520
|
+
abortController = new AbortController;
|
|
2521
|
+
state;
|
|
2522
|
+
status = "idle";
|
|
2523
|
+
running = false;
|
|
2524
|
+
constructor(options) {
|
|
2525
|
+
this.client = options.client;
|
|
2526
|
+
this.sessionId = options.sessionId;
|
|
2527
|
+
this.state = options.initialState ?? createInitialClientState();
|
|
2528
|
+
if ((options.cursor ?? 0) > 0 && !options.initialState) {
|
|
2529
|
+
throw new Error("A non-zero cursor requires initialState so durable state is not skipped");
|
|
2530
|
+
}
|
|
2531
|
+
this.initialCursor = Math.max(0, options.cursor ?? 0, this.state.lastSeq);
|
|
2532
|
+
this.generation = options.generation ?? 0;
|
|
2533
|
+
this.externalSignal = options.signal;
|
|
2534
|
+
this.reconnectDelayMs = options.reconnectDelayMs ?? DEFAULT_RECONNECT_DELAY_MS;
|
|
2535
|
+
this.onUpdate = options.onUpdate;
|
|
2536
|
+
this.onStatusChange = options.onStatusChange;
|
|
2537
|
+
this.onError = options.onError;
|
|
2538
|
+
if (this.externalSignal) {
|
|
2539
|
+
if (this.externalSignal.aborted) {
|
|
2540
|
+
this.abortController.abort(this.externalSignal.reason);
|
|
2541
|
+
} else {
|
|
2542
|
+
this.externalSignal.addEventListener("abort", () => this.abortController.abort(this.externalSignal?.reason), { once: true });
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2023
2545
|
}
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
}
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2546
|
+
get currentStatus() {
|
|
2547
|
+
return this.status;
|
|
2548
|
+
}
|
|
2549
|
+
get currentState() {
|
|
2550
|
+
return this.state;
|
|
2551
|
+
}
|
|
2552
|
+
get currentGeneration() {
|
|
2553
|
+
return this.generation;
|
|
2554
|
+
}
|
|
2555
|
+
get signal() {
|
|
2556
|
+
return this.abortController.signal;
|
|
2557
|
+
}
|
|
2558
|
+
abort(reason) {
|
|
2559
|
+
this.abortController.abort(reason);
|
|
2560
|
+
}
|
|
2561
|
+
setStatus(status) {
|
|
2562
|
+
if (this.status === status)
|
|
2563
|
+
return;
|
|
2564
|
+
this.status = status;
|
|
2565
|
+
this.onStatusChange?.(status, this.generation);
|
|
2566
|
+
}
|
|
2567
|
+
emitUpdate(update) {
|
|
2568
|
+
if (this.abortController.signal.aborted)
|
|
2569
|
+
return;
|
|
2570
|
+
this.state = update.state;
|
|
2571
|
+
this.onUpdate?.(update, this.generation);
|
|
2572
|
+
}
|
|
2573
|
+
async start() {
|
|
2574
|
+
if (this.running)
|
|
2575
|
+
return;
|
|
2576
|
+
this.running = true;
|
|
2577
|
+
const signal = this.abortController.signal;
|
|
2578
|
+
if (signal.aborted) {
|
|
2579
|
+
this.setStatus("idle");
|
|
2580
|
+
return;
|
|
2581
|
+
}
|
|
2582
|
+
let cursor = this.initialCursor;
|
|
2583
|
+
let attempt = 0;
|
|
2041
2584
|
try {
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
signal
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2585
|
+
this.setStatus("connecting");
|
|
2586
|
+
if (this.sessionId) {
|
|
2587
|
+
const snapshot = await this.client.sessions.getState(this.sessionId, { signal });
|
|
2588
|
+
if (signal.aborted)
|
|
2589
|
+
return;
|
|
2590
|
+
this.state = applySessionSnapshot(this.state, snapshot);
|
|
2591
|
+
cursor = Math.max(cursor, snapshot.cursor, this.state.lastSeq);
|
|
2592
|
+
this.setStatus("connected");
|
|
2593
|
+
this.emitUpdate({ state: this.state, source: "snapshot" });
|
|
2594
|
+
} else {
|
|
2595
|
+
const replay = await this.client.events.list({
|
|
2596
|
+
cursor,
|
|
2597
|
+
sessionId: this.sessionId,
|
|
2598
|
+
signal
|
|
2599
|
+
});
|
|
2600
|
+
if (signal.aborted)
|
|
2601
|
+
return;
|
|
2602
|
+
for (const event of replay) {
|
|
2603
|
+
this.state = applyEvent(this.state, event);
|
|
2604
|
+
this.emitUpdate({ event, state: this.state, source: "replay" });
|
|
2605
|
+
}
|
|
2606
|
+
cursor = Math.max(cursor, this.state.lastSeq);
|
|
2607
|
+
this.setStatus("connected");
|
|
2608
|
+
}
|
|
2609
|
+
while (!signal.aborted) {
|
|
2610
|
+
try {
|
|
2611
|
+
for await (const event of this.client.events.stream({
|
|
2612
|
+
cursor,
|
|
2613
|
+
sessionId: this.sessionId,
|
|
2614
|
+
signal,
|
|
2615
|
+
transportReconnect: false
|
|
2616
|
+
})) {
|
|
2617
|
+
if (signal.aborted)
|
|
2618
|
+
return;
|
|
2619
|
+
attempt = 0;
|
|
2620
|
+
this.setStatus("connected");
|
|
2621
|
+
if (event.seq > cursor + 1) {
|
|
2622
|
+
const gap = await this.client.events.list({
|
|
2623
|
+
cursor,
|
|
2624
|
+
sessionId: this.sessionId,
|
|
2625
|
+
signal
|
|
2626
|
+
});
|
|
2627
|
+
if (signal.aborted)
|
|
2628
|
+
return;
|
|
2629
|
+
for (const missed of gap) {
|
|
2630
|
+
const beforeGap = this.state;
|
|
2631
|
+
this.state = applyEvent(this.state, missed);
|
|
2632
|
+
if (this.state !== beforeGap) {
|
|
2633
|
+
this.emitUpdate({ event: missed, state: this.state, source: "replay" });
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
cursor = Math.max(cursor, this.state.lastSeq);
|
|
2637
|
+
}
|
|
2638
|
+
const before = this.state;
|
|
2639
|
+
this.state = applyEvent(this.state, event);
|
|
2640
|
+
cursor = Math.max(cursor, this.state.lastSeq);
|
|
2641
|
+
if (this.state !== before) {
|
|
2642
|
+
this.emitUpdate({ event, state: this.state, source: "live" });
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
if (signal.aborted)
|
|
2646
|
+
return;
|
|
2647
|
+
this.setStatus("reconnecting");
|
|
2648
|
+
this.emitUpdate({ state: this.state, source: "reconnecting" });
|
|
2649
|
+
const delay = this.reconnectDelayMs(attempt);
|
|
2650
|
+
attempt += 1;
|
|
2651
|
+
cursor = this.state.lastSeq;
|
|
2652
|
+
if (!await this.waitForDelay(delay, signal))
|
|
2653
|
+
return;
|
|
2654
|
+
} catch (error) {
|
|
2655
|
+
if (error instanceof UnsupportedSessionEventSchemaVersionError) {
|
|
2656
|
+
throw error;
|
|
2058
2657
|
}
|
|
2059
|
-
|
|
2658
|
+
if (this.isAbortError(error) || signal.aborted)
|
|
2659
|
+
return;
|
|
2660
|
+
this.setStatus("reconnecting");
|
|
2661
|
+
this.emitUpdate({ state: this.state, source: "reconnecting" });
|
|
2662
|
+
const delay = this.reconnectDelayMs(attempt);
|
|
2663
|
+
attempt += 1;
|
|
2664
|
+
cursor = this.state.lastSeq;
|
|
2665
|
+
if (!await this.waitForDelay(delay, signal))
|
|
2666
|
+
return;
|
|
2060
2667
|
}
|
|
2061
|
-
const before = state;
|
|
2062
|
-
state = applyEvent(state, event);
|
|
2063
|
-
cursor = state.lastSeq;
|
|
2064
|
-
if (state !== before)
|
|
2065
|
-
yield { event, state, source: "live" };
|
|
2066
2668
|
}
|
|
2067
|
-
if (options.signal?.aborted)
|
|
2068
|
-
return;
|
|
2069
|
-
yield { state, source: "reconnecting" };
|
|
2070
|
-
if (!await waitForReconnect(delayMs(attempt), options.signal))
|
|
2071
|
-
return;
|
|
2072
|
-
attempt += 1;
|
|
2073
|
-
cursor = state.lastSeq;
|
|
2074
2669
|
} catch (error) {
|
|
2075
|
-
if (error
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2670
|
+
if (!this.isAbortError(error) && !signal.aborted) {
|
|
2671
|
+
this.setStatus("error");
|
|
2672
|
+
this.onError?.(error, this.generation);
|
|
2673
|
+
}
|
|
2674
|
+
} finally {
|
|
2675
|
+
this.running = false;
|
|
2676
|
+
if (signal.aborted && this.status !== "error") {
|
|
2677
|
+
this.setStatus("idle");
|
|
2678
|
+
}
|
|
2084
2679
|
}
|
|
2085
2680
|
}
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
try {
|
|
2089
|
-
await sleep(ms, signal);
|
|
2090
|
-
return !signal?.aborted;
|
|
2091
|
-
} catch (error) {
|
|
2092
|
-
if (isAbortError(error) || signal?.aborted)
|
|
2681
|
+
isAbortError(error) {
|
|
2682
|
+
if (!error || typeof error !== "object")
|
|
2093
2683
|
return false;
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
}
|
|
2097
|
-
function isAbortError(error) {
|
|
2098
|
-
if (!error || typeof error !== "object")
|
|
2684
|
+
if ("name" in error && error.name === "AbortError")
|
|
2685
|
+
return true;
|
|
2099
2686
|
return false;
|
|
2100
|
-
if ("name" in error && error.name === "AbortError")
|
|
2101
|
-
return true;
|
|
2102
|
-
return false;
|
|
2103
|
-
}
|
|
2104
|
-
function sleep(ms, signal) {
|
|
2105
|
-
if (ms <= 0) {
|
|
2106
|
-
if (signal?.aborted)
|
|
2107
|
-
return Promise.reject(abortError(signal));
|
|
2108
|
-
return Promise.resolve();
|
|
2109
2687
|
}
|
|
2110
|
-
|
|
2111
|
-
if (
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
}
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
return new DOMException("Aborted", "AbortError");
|
|
2688
|
+
waitForDelay(ms, signal) {
|
|
2689
|
+
if (ms <= 0)
|
|
2690
|
+
return Promise.resolve(!signal.aborted);
|
|
2691
|
+
return new Promise((resolve) => {
|
|
2692
|
+
if (signal.aborted) {
|
|
2693
|
+
resolve(false);
|
|
2694
|
+
return;
|
|
2695
|
+
}
|
|
2696
|
+
const timer = setTimeout(() => {
|
|
2697
|
+
signal.removeEventListener("abort", onAbort);
|
|
2698
|
+
resolve(!signal.aborted);
|
|
2699
|
+
}, ms);
|
|
2700
|
+
const onAbort = () => {
|
|
2701
|
+
clearTimeout(timer);
|
|
2702
|
+
resolve(false);
|
|
2703
|
+
};
|
|
2704
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
2705
|
+
});
|
|
2706
|
+
}
|
|
2130
2707
|
}
|
|
2131
2708
|
var DEFAULT_RECONNECT_DELAY_MS = (attempt) => Math.min(30000, 250 * 2 ** Math.max(0, attempt));
|
|
2132
|
-
var
|
|
2709
|
+
var init_session_sync_controller = __esm(() => {
|
|
2133
2710
|
init_reducer();
|
|
2134
2711
|
});
|
|
2135
2712
|
|
|
@@ -2137,6 +2714,7 @@ var init_sync = __esm(() => {
|
|
|
2137
2714
|
var init_state = __esm(() => {
|
|
2138
2715
|
init_reducer();
|
|
2139
2716
|
init_sync();
|
|
2717
|
+
init_session_sync_controller();
|
|
2140
2718
|
});
|
|
2141
2719
|
|
|
2142
2720
|
// ../../packages/client/src/commands/plugin-presentation.ts
|
|
@@ -2330,7 +2908,7 @@ async function dispatchSessionCommand(slash, host) {
|
|
|
2330
2908
|
}
|
|
2331
2909
|
patchStatus({ permission_mode: next });
|
|
2332
2910
|
if (sessionId) {
|
|
2333
|
-
await client.
|
|
2911
|
+
await client.sessions.update(sessionId, {
|
|
2334
2912
|
metadata: patchSessionRuntimeMetadata({}, { permissionMode: next })
|
|
2335
2913
|
});
|
|
2336
2914
|
}
|
|
@@ -2365,7 +2943,7 @@ async function dispatchSessionCommand(slash, host) {
|
|
|
2365
2943
|
}
|
|
2366
2944
|
if (slash?.name === "/version") {
|
|
2367
2945
|
await readPresentation("version", "Version", async () => {
|
|
2368
|
-
const health = await client.health();
|
|
2946
|
+
const health = await client.protocol.health();
|
|
2369
2947
|
return `OpenHarness${health.version ? ` v${health.version}` : ""}`;
|
|
2370
2948
|
});
|
|
2371
2949
|
return "handled";
|
|
@@ -2386,7 +2964,7 @@ async function dispatchSessionCommand(slash, host) {
|
|
|
2386
2964
|
const args = slash.args.trim();
|
|
2387
2965
|
if (!args || args === "show") {
|
|
2388
2966
|
await readPresentation(`config:${cwd}`, "Config", async () => {
|
|
2389
|
-
const settings = await client.getSettings();
|
|
2967
|
+
const settings = await client.system.getSettings();
|
|
2390
2968
|
return JSON.stringify(settings, null, 2);
|
|
2391
2969
|
});
|
|
2392
2970
|
return "handled";
|
|
@@ -2396,14 +2974,14 @@ async function dispatchSessionCommand(slash, host) {
|
|
|
2396
2974
|
emit("Usage: /config [show | set KEY VALUE]");
|
|
2397
2975
|
return "handled";
|
|
2398
2976
|
}
|
|
2399
|
-
await client.patchSettings({ path: setMatch[1], value: setMatch[2].trim() });
|
|
2977
|
+
await client.system.patchSettings({ path: setMatch[1], value: setMatch[2].trim() });
|
|
2400
2978
|
emit(`Set ${setMatch[1]} = ${setMatch[2].trim()}`);
|
|
2401
2979
|
return "handled";
|
|
2402
2980
|
}
|
|
2403
2981
|
if (slash?.name === "/provider") {
|
|
2404
2982
|
if (!slash.args) {
|
|
2405
2983
|
await readPresentation("providers", "Provider", async () => {
|
|
2406
|
-
const providers = await client.listProviders();
|
|
2984
|
+
const providers = await client.providers.listProviders();
|
|
2407
2985
|
const lines = ["Available providers:", ""];
|
|
2408
2986
|
for (const provider of providers) {
|
|
2409
2987
|
const marker = provider.active ? " (active)" : "";
|
|
@@ -2415,7 +2993,7 @@ async function dispatchSessionCommand(slash, host) {
|
|
|
2415
2993
|
});
|
|
2416
2994
|
return "handled";
|
|
2417
2995
|
}
|
|
2418
|
-
const settings = await client.patchSettings(slash.args === "auto" ? { provider: "auto" } : { provider: slash.args });
|
|
2996
|
+
const settings = await client.system.patchSettings(slash.args === "auto" ? { provider: "auto" } : { provider: slash.args });
|
|
2419
2997
|
if (typeof settings.model === "string") {
|
|
2420
2998
|
patchStatus({ model: settings.model });
|
|
2421
2999
|
}
|
|
@@ -2426,7 +3004,7 @@ async function dispatchSessionCommand(slash, host) {
|
|
|
2426
3004
|
if (!sessionId)
|
|
2427
3005
|
return "handled";
|
|
2428
3006
|
await readPresentation(`mcp:${sessionId}`, "MCP", async () => {
|
|
2429
|
-
const servers = await client.getSessionMcp(sessionId);
|
|
3007
|
+
const servers = await client.system.getSessionMcp(sessionId);
|
|
2430
3008
|
if (servers.length === 0)
|
|
2431
3009
|
return "No MCP servers connected.";
|
|
2432
3010
|
return [
|
|
@@ -2451,7 +3029,7 @@ async function dispatchSessionCommand(slash, host) {
|
|
|
2451
3029
|
const [sub, id, ...extra] = args.split(/\s+/).filter(Boolean);
|
|
2452
3030
|
if ((!sub || sub === "list") && !id) {
|
|
2453
3031
|
await readPresentation(`jobs:${sessionId}`, "Jobs", async () => {
|
|
2454
|
-
const jobs = await client.
|
|
3032
|
+
const jobs = await client.jobs.list({
|
|
2455
3033
|
sessionId,
|
|
2456
3034
|
includeFinished: true,
|
|
2457
3035
|
limit: 100
|
|
@@ -2469,13 +3047,13 @@ async function dispatchSessionCommand(slash, host) {
|
|
|
2469
3047
|
}
|
|
2470
3048
|
if (sub === "show" && id && extra.length === 0) {
|
|
2471
3049
|
await readPresentation(`job:${sessionId}:${id}`, "Jobs", async () => {
|
|
2472
|
-
const result = await client.
|
|
3050
|
+
const result = await client.jobs.read(id, { sessionId });
|
|
2473
3051
|
return formatJobReadResult(result);
|
|
2474
3052
|
});
|
|
2475
3053
|
return "handled";
|
|
2476
3054
|
}
|
|
2477
3055
|
if (sub === "cancel" && id && extra.length === 0) {
|
|
2478
|
-
const snapshot = await client.
|
|
3056
|
+
const snapshot = await client.jobs.cancel(id, {
|
|
2479
3057
|
sessionId,
|
|
2480
3058
|
reason: "Cancelled from slash command"
|
|
2481
3059
|
});
|
|
@@ -2493,7 +3071,7 @@ async function dispatchSessionCommand(slash, host) {
|
|
|
2493
3071
|
}
|
|
2494
3072
|
if (!sessionId)
|
|
2495
3073
|
return "handled";
|
|
2496
|
-
const result = await client.createBackgroundShell({ sessionId, command });
|
|
3074
|
+
const result = await client.jobs.createBackgroundShell({ sessionId, command });
|
|
2497
3075
|
emit(`Background shell started: ${result.jobId}. Use /jobs to inspect it.`);
|
|
2498
3076
|
return "handled";
|
|
2499
3077
|
}
|
|
@@ -2502,7 +3080,7 @@ async function dispatchSessionCommand(slash, host) {
|
|
|
2502
3080
|
const [sub, ...rest] = args.split(/\s+/).filter(Boolean);
|
|
2503
3081
|
if (!sub || sub === "list") {
|
|
2504
3082
|
await readPresentation(`memory:${cwd}:list`, "Memory", async () => {
|
|
2505
|
-
const listed = await client.listMemory({ cwd });
|
|
3083
|
+
const listed = await client.system.listMemory({ cwd });
|
|
2506
3084
|
if (listed.entries.length === 0)
|
|
2507
3085
|
return `Memory directory: ${listed.directory}
|
|
2508
3086
|
No entries found.`;
|
|
@@ -2522,7 +3100,7 @@ No entries found.`;
|
|
|
2522
3100
|
if (sub === "show" && rest[0]) {
|
|
2523
3101
|
const memoryId = rest[0];
|
|
2524
3102
|
await readPresentation(`memory:${cwd}:show:${memoryId}`, "Memory", async () => {
|
|
2525
|
-
const entry = await client.getMemory(memoryId, { cwd });
|
|
3103
|
+
const entry = await client.system.getMemory(memoryId, { cwd });
|
|
2526
3104
|
return [
|
|
2527
3105
|
`ID: ${entry.id}`,
|
|
2528
3106
|
`Created: ${new Date(entry.createdAt).toISOString()}`,
|
|
@@ -2541,12 +3119,12 @@ No entries found.`;
|
|
|
2541
3119
|
emit("Usage: /memory add <content>");
|
|
2542
3120
|
return "handled";
|
|
2543
3121
|
}
|
|
2544
|
-
const entry = await client.addMemory({ cwd, content });
|
|
3122
|
+
const entry = await client.system.addMemory({ cwd, content });
|
|
2545
3123
|
emit(`Memory added: ${entry.id}`);
|
|
2546
3124
|
return "handled";
|
|
2547
3125
|
}
|
|
2548
3126
|
if (sub === "remove" && rest[0]) {
|
|
2549
|
-
await client.removeMemory(rest[0], { cwd });
|
|
3127
|
+
await client.system.removeMemory(rest[0], { cwd });
|
|
2550
3128
|
emit(`Memory removed: ${rest[0]}`);
|
|
2551
3129
|
return "handled";
|
|
2552
3130
|
}
|
|
@@ -2558,7 +3136,7 @@ No entries found.`;
|
|
|
2558
3136
|
const [sub, provider, apiKey] = args.split(/\s+/).filter(Boolean);
|
|
2559
3137
|
if (!sub || sub === "status") {
|
|
2560
3138
|
await readPresentation("auth:status", "Auth", async () => {
|
|
2561
|
-
const auth = await client.
|
|
3139
|
+
const auth = await client.auth.getStatus();
|
|
2562
3140
|
const lines = ["Credential status:", "", " Auth sources:"];
|
|
2563
3141
|
lines.push(` codex_subscription: ${auth.codex.configured ? "ready" : auth.codex.state} (${auth.codex.source})`);
|
|
2564
3142
|
if (auth.storedProviders.length > 0) {
|
|
@@ -2586,7 +3164,7 @@ No entries found.`;
|
|
|
2586
3164
|
emit("Usage: /auth login <provider> <api-key> or /auth login codex");
|
|
2587
3165
|
return "handled";
|
|
2588
3166
|
}
|
|
2589
|
-
const result = await client.
|
|
3167
|
+
const result = await client.auth.login({ provider, apiKey });
|
|
2590
3168
|
emit(result.message);
|
|
2591
3169
|
return "handled";
|
|
2592
3170
|
}
|
|
@@ -2595,7 +3173,7 @@ No entries found.`;
|
|
|
2595
3173
|
emit("Usage: /auth logout <provider>");
|
|
2596
3174
|
return "handled";
|
|
2597
3175
|
}
|
|
2598
|
-
const result = await client.
|
|
3176
|
+
const result = await client.auth.logout({ provider });
|
|
2599
3177
|
emit(result.message);
|
|
2600
3178
|
return "handled";
|
|
2601
3179
|
}
|
|
@@ -2605,12 +3183,12 @@ No entries found.`;
|
|
|
2605
3183
|
if (slash?.name === "/context") {
|
|
2606
3184
|
const action = slash.args.trim().split(/\s+/).filter(Boolean)[0] ?? "preview";
|
|
2607
3185
|
if (action === "status") {
|
|
2608
|
-
await readPresentation(`context:${cwd}:status`, "Context", async () => await client.getContextStatus({ cwd }));
|
|
3186
|
+
await readPresentation(`context:${cwd}:status`, "Context", async () => await client.system.getContextStatus({ cwd }));
|
|
2609
3187
|
return "handled";
|
|
2610
3188
|
}
|
|
2611
3189
|
if (action === "usage") {
|
|
2612
3190
|
await readPresentation(`context:${cwd}:usage:${sessionId ?? "none"}`, "Context", async () => {
|
|
2613
|
-
const result = await client.getContextUsage({
|
|
3191
|
+
const result = await client.system.getContextUsage({
|
|
2614
3192
|
cwd,
|
|
2615
3193
|
...sessionId ? { sessionId } : {}
|
|
2616
3194
|
});
|
|
@@ -2622,7 +3200,7 @@ No entries found.`;
|
|
|
2622
3200
|
emit("Usage: /context [preview|status|usage]");
|
|
2623
3201
|
return "handled";
|
|
2624
3202
|
}
|
|
2625
|
-
await readPresentation(`context:${cwd}`, "Context", async () => await client.getContextPreview({ cwd }));
|
|
3203
|
+
await readPresentation(`context:${cwd}`, "Context", async () => await client.system.getContextPreview({ cwd }));
|
|
2626
3204
|
return "handled";
|
|
2627
3205
|
}
|
|
2628
3206
|
if (slash?.name === "/stats") {
|
|
@@ -2633,11 +3211,11 @@ No entries found.`;
|
|
|
2633
3211
|
const text = (bucket?.messages ?? []).flatMap((message) => bucket?.partsByMessageId[message.id] ?? []).map((part) => part.text ?? "").join(" ");
|
|
2634
3212
|
const estimatedTokens = Math.max(1, Math.ceil(text.length / 4));
|
|
2635
3213
|
const [memory, jobsResult, settings] = await Promise.all([
|
|
2636
|
-
client.listMemory({ cwd }).catch(() => ({ entries: [] })),
|
|
2637
|
-
client.
|
|
3214
|
+
client.system.listMemory({ cwd }).catch(() => ({ entries: [] })),
|
|
3215
|
+
client.jobs.list({ sessionId, includeFinished: true, limit: 100 }).then((jobs) => ({ jobs })).catch((error) => ({
|
|
2638
3216
|
error: error instanceof Error ? error.message : String(error)
|
|
2639
3217
|
})),
|
|
2640
|
-
client.getSettings().catch(() => ({}))
|
|
3218
|
+
client.system.getSettings().catch(() => ({}))
|
|
2641
3219
|
]);
|
|
2642
3220
|
const jobsSummary = "jobs" in jobsResult ? String(jobsResult.jobs.length) : `unavailable (${jobsResult.error})`;
|
|
2643
3221
|
emit([
|
|
@@ -2654,7 +3232,7 @@ No entries found.`;
|
|
|
2654
3232
|
if (slash?.name === "/agents") {
|
|
2655
3233
|
if (!sessionId)
|
|
2656
3234
|
return "handled";
|
|
2657
|
-
const agents = await client.
|
|
3235
|
+
const agents = await client.jobs.list({
|
|
2658
3236
|
sessionId,
|
|
2659
3237
|
kinds: ["agent"],
|
|
2660
3238
|
includeFinished: true,
|
|
@@ -2681,21 +3259,21 @@ No entries found.`;
|
|
|
2681
3259
|
emit("Count must be a positive integer");
|
|
2682
3260
|
return "handled";
|
|
2683
3261
|
}
|
|
2684
|
-
const result = await client.
|
|
3262
|
+
const result = await client.sessions.rewind(sessionId, { count });
|
|
2685
3263
|
emit(`Rewound ${result.turns} turn(s), removed ${result.removed} message(s).`);
|
|
2686
3264
|
return "handled";
|
|
2687
3265
|
}
|
|
2688
3266
|
if (slash?.name === "/compact") {
|
|
2689
3267
|
if (!sessionId)
|
|
2690
3268
|
return "handled";
|
|
2691
|
-
const result = await client.
|
|
3269
|
+
const result = await client.sessions.compact(sessionId);
|
|
2692
3270
|
emit(`Conversation compacted (${result.messageCount} messages retained).`);
|
|
2693
3271
|
return "handled";
|
|
2694
3272
|
}
|
|
2695
3273
|
if (slash?.name === "/remember") {
|
|
2696
3274
|
if (!sessionId)
|
|
2697
3275
|
return "handled";
|
|
2698
|
-
const result = await client.
|
|
3276
|
+
const result = await client.sessions.remember(sessionId);
|
|
2699
3277
|
if (result.skipped) {
|
|
2700
3278
|
emit(`\u672A\u5199\u5165\u8BB0\u5FC6:${result.reason ?? "skipped"}`);
|
|
2701
3279
|
return "handled";
|
|
@@ -2705,7 +3283,7 @@ No entries found.`;
|
|
|
2705
3283
|
}
|
|
2706
3284
|
if (slash?.name === "/dream") {
|
|
2707
3285
|
const preview = slash.args.includes("--preview");
|
|
2708
|
-
const result = await client.startDream({
|
|
3286
|
+
const result = await client.system.startDream({
|
|
2709
3287
|
cwd,
|
|
2710
3288
|
...sessionId ? { sessionId } : {},
|
|
2711
3289
|
preview
|
|
@@ -2716,11 +3294,11 @@ No entries found.`;
|
|
|
2716
3294
|
if (slash?.name === "/profile") {
|
|
2717
3295
|
const action = slash.args.trim().split(/\s+/).filter(Boolean)[0] ?? "status";
|
|
2718
3296
|
if (action === "status" || action === "show") {
|
|
2719
|
-
emit(await client.getProfileStatus());
|
|
3297
|
+
emit(await client.system.getProfileStatus());
|
|
2720
3298
|
return "handled";
|
|
2721
3299
|
}
|
|
2722
3300
|
if (action === "init") {
|
|
2723
|
-
emit(await client.initProfile());
|
|
3301
|
+
emit(await client.system.initProfile());
|
|
2724
3302
|
return "handled";
|
|
2725
3303
|
}
|
|
2726
3304
|
emit("Usage: /profile [status|init]");
|
|
@@ -2728,11 +3306,11 @@ No entries found.`;
|
|
|
2728
3306
|
}
|
|
2729
3307
|
if (slash?.name === "/doctor") {
|
|
2730
3308
|
const [settings, auth, memory, mcp, jobsResult] = await Promise.all([
|
|
2731
|
-
client.getSettings().catch(() => ({})),
|
|
2732
|
-
client.
|
|
2733
|
-
client.listMemory({ cwd }).catch(() => ({ directory: "(unavailable)", entries: [] })),
|
|
2734
|
-
sessionId ? client.getSessionMcp(sessionId).catch(() => []) : Promise.resolve([]),
|
|
2735
|
-
sessionId ? client.
|
|
3309
|
+
client.system.getSettings().catch(() => ({})),
|
|
3310
|
+
client.auth.getStatus().catch(() => null),
|
|
3311
|
+
client.system.listMemory({ cwd }).catch(() => ({ directory: "(unavailable)", entries: [] })),
|
|
3312
|
+
sessionId ? client.system.getSessionMcp(sessionId).catch(() => []) : Promise.resolve([]),
|
|
3313
|
+
sessionId ? client.jobs.list({ sessionId, includeFinished: true, limit: 100 }).then((jobs) => ({ jobs })).catch((error) => ({
|
|
2736
3314
|
error: error instanceof Error ? error.message : String(error)
|
|
2737
3315
|
})) : Promise.resolve({ jobs: [] })
|
|
2738
3316
|
]);
|
|
@@ -2782,7 +3360,7 @@ No entries found.`;
|
|
|
2782
3360
|
if (slash?.name === "/effort") {
|
|
2783
3361
|
const level = slash.args.trim().split(/\s+/).filter(Boolean)[0];
|
|
2784
3362
|
if (!level) {
|
|
2785
|
-
const settings = await client.getSettings();
|
|
3363
|
+
const settings = await client.system.getSettings();
|
|
2786
3364
|
emit(`Current effort: ${String(settings.effort ?? "medium")}`);
|
|
2787
3365
|
return "handled";
|
|
2788
3366
|
}
|
|
@@ -2790,13 +3368,13 @@ No entries found.`;
|
|
|
2790
3368
|
emit("Invalid effort. Use: low, medium, or high");
|
|
2791
3369
|
return "handled";
|
|
2792
3370
|
}
|
|
2793
|
-
await client.patchSettings({ effort: level });
|
|
3371
|
+
await client.system.patchSettings({ effort: level });
|
|
2794
3372
|
emit(`Effort set to: ${level}`);
|
|
2795
3373
|
return "handled";
|
|
2796
3374
|
}
|
|
2797
3375
|
if (slash?.name === "/fast") {
|
|
2798
3376
|
const arg = slash.args.trim().split(/\s+/).filter(Boolean)[0];
|
|
2799
|
-
const settings = await client.getSettings();
|
|
3377
|
+
const settings = await client.system.getSettings();
|
|
2800
3378
|
const current = settings.fastMode === true;
|
|
2801
3379
|
let next;
|
|
2802
3380
|
if (arg === "on")
|
|
@@ -2805,14 +3383,14 @@ No entries found.`;
|
|
|
2805
3383
|
next = false;
|
|
2806
3384
|
else
|
|
2807
3385
|
next = !current;
|
|
2808
|
-
await client.patchSettings({ fastMode: next });
|
|
3386
|
+
await client.system.patchSettings({ fastMode: next });
|
|
2809
3387
|
emit(`Fast mode: ${next ? "ON" : "OFF"}`);
|
|
2810
3388
|
return "handled";
|
|
2811
3389
|
}
|
|
2812
3390
|
if (slash?.name === "/turns") {
|
|
2813
3391
|
const value = slash.args.trim().split(/\s+/).filter(Boolean)[0];
|
|
2814
3392
|
if (!value) {
|
|
2815
|
-
const settings = await client.getSettings();
|
|
3393
|
+
const settings = await client.system.getSettings();
|
|
2816
3394
|
emit(`Current max turns: ${String(settings.maxTurns ?? "(default)")}`);
|
|
2817
3395
|
return "handled";
|
|
2818
3396
|
}
|
|
@@ -2821,7 +3399,7 @@ No entries found.`;
|
|
|
2821
3399
|
emit("Value must be between 1 and 512");
|
|
2822
3400
|
return "handled";
|
|
2823
3401
|
}
|
|
2824
|
-
await client.patchSettings({ maxTurns: n });
|
|
3402
|
+
await client.system.patchSettings({ maxTurns: n });
|
|
2825
3403
|
emit(`Max turns set to: ${n}`);
|
|
2826
3404
|
return "handled";
|
|
2827
3405
|
}
|
|
@@ -2830,7 +3408,7 @@ No entries found.`;
|
|
|
2830
3408
|
return "handled";
|
|
2831
3409
|
if (slash.name === "/cost") {
|
|
2832
3410
|
await readPresentation(`cost:${sessionId}`, "Cost", async () => {
|
|
2833
|
-
const usage = await client.
|
|
3411
|
+
const usage = await client.sessions.getUsage(sessionId);
|
|
2834
3412
|
return [
|
|
2835
3413
|
"Cost estimate:",
|
|
2836
3414
|
` Model: ${usage.model}`,
|
|
@@ -2845,7 +3423,7 @@ No entries found.`;
|
|
|
2845
3423
|
return "handled";
|
|
2846
3424
|
}
|
|
2847
3425
|
await readPresentation(`usage:${sessionId}`, "Usage", async () => {
|
|
2848
|
-
const usage = await client.
|
|
3426
|
+
const usage = await client.sessions.getUsage(sessionId);
|
|
2849
3427
|
return [
|
|
2850
3428
|
"Token usage:",
|
|
2851
3429
|
` Input: ${usage.inputTokens.toLocaleString()}`,
|
|
@@ -2866,7 +3444,7 @@ No entries found.`;
|
|
|
2866
3444
|
const args = slash.args.trim().split(/\s+/).filter(Boolean);
|
|
2867
3445
|
const forceJson = args.includes("--json");
|
|
2868
3446
|
const filename = args.find((arg) => !arg.startsWith("--"));
|
|
2869
|
-
const result = await client.
|
|
3447
|
+
const result = await client.sessions.export(sessionId, {
|
|
2870
3448
|
...filename ? { filename } : {},
|
|
2871
3449
|
json: forceJson
|
|
2872
3450
|
});
|
|
@@ -2875,8 +3453,8 @@ No entries found.`;
|
|
|
2875
3453
|
}
|
|
2876
3454
|
if (slash?.name === "/output-style") {
|
|
2877
3455
|
const args = slash.args.trim();
|
|
2878
|
-
const styles = await client.listOutputStyles();
|
|
2879
|
-
const settings = await client.getSettings();
|
|
3456
|
+
const styles = await client.system.listOutputStyles();
|
|
3457
|
+
const settings = await client.system.getSettings();
|
|
2880
3458
|
const current = typeof settings.outputStyle === "string" ? settings.outputStyle : "default";
|
|
2881
3459
|
const firstSpace = args.search(/\s/);
|
|
2882
3460
|
const first = firstSpace === -1 ? args : args.slice(0, firstSpace);
|
|
@@ -2899,12 +3477,12 @@ No entries found.`;
|
|
|
2899
3477
|
emit(`Unknown output style: ${styleName}`);
|
|
2900
3478
|
return "handled";
|
|
2901
3479
|
}
|
|
2902
|
-
await client.patchSettings({ outputStyle: styleName });
|
|
3480
|
+
await client.system.patchSettings({ outputStyle: styleName });
|
|
2903
3481
|
emit(`Output style set to ${styleName}`);
|
|
2904
3482
|
return "handled";
|
|
2905
3483
|
}
|
|
2906
3484
|
if (slash?.name === "/init") {
|
|
2907
|
-
emit(await client.
|
|
3485
|
+
emit(await client.projects.init({ cwd }));
|
|
2908
3486
|
return "handled";
|
|
2909
3487
|
}
|
|
2910
3488
|
if (slash?.name === "/plugin") {
|
|
@@ -2912,7 +3490,7 @@ No entries found.`;
|
|
|
2912
3490
|
const sub = args[0];
|
|
2913
3491
|
if (!sub || sub === "list") {
|
|
2914
3492
|
await readPresentation(`plugins:${cwd}`, "Plugin", async () => {
|
|
2915
|
-
const listed = await client.
|
|
3493
|
+
const listed = await client.plugins.list({ cwd });
|
|
2916
3494
|
if (listed.plugins.length === 0)
|
|
2917
3495
|
return "No plugins discovered.";
|
|
2918
3496
|
return [
|
|
@@ -2925,7 +3503,7 @@ No entries found.`;
|
|
|
2925
3503
|
return "handled";
|
|
2926
3504
|
}
|
|
2927
3505
|
if ((sub === "enable" || sub === "disable") && args[1]) {
|
|
2928
|
-
const result = sub === "enable" ? await client.
|
|
3506
|
+
const result = sub === "enable" ? await client.plugins.enable(args[1], { cwd }) : await client.plugins.disable(args[1], { cwd });
|
|
2929
3507
|
emit(result.message);
|
|
2930
3508
|
return "handled";
|
|
2931
3509
|
}
|
|
@@ -2933,13 +3511,13 @@ No entries found.`;
|
|
|
2933
3511
|
return "handled";
|
|
2934
3512
|
}
|
|
2935
3513
|
if (slash?.name === "/reload-plugins") {
|
|
2936
|
-
const result = await client.
|
|
3514
|
+
const result = await client.plugins.reload({ cwd });
|
|
2937
3515
|
emit(formatPluginReload(result));
|
|
2938
3516
|
return "handled";
|
|
2939
3517
|
}
|
|
2940
3518
|
if (slash?.name === "/hooks") {
|
|
2941
3519
|
await readPresentation(`hooks:${cwd}:${sessionId ?? "global"}`, "Hooks", async () => {
|
|
2942
|
-
const hooks = await client.listHooks({
|
|
3520
|
+
const hooks = await client.development.listHooks({
|
|
2943
3521
|
cwd,
|
|
2944
3522
|
...sessionId ? { sessionId } : {}
|
|
2945
3523
|
});
|
|
@@ -2967,7 +3545,7 @@ No entries found.`;
|
|
|
2967
3545
|
return "handled";
|
|
2968
3546
|
}
|
|
2969
3547
|
if (slash?.name === "/subagents") {
|
|
2970
|
-
const agents = await client.listAgentPersonas();
|
|
3548
|
+
const agents = await client.development.listAgentPersonas();
|
|
2971
3549
|
emit([
|
|
2972
3550
|
`Available subagent personas (${agents.length}):`,
|
|
2973
3551
|
"",
|
|
@@ -2984,21 +3562,21 @@ No entries found.`;
|
|
|
2984
3562
|
}
|
|
2985
3563
|
if (slash?.name === "/diff") {
|
|
2986
3564
|
const full = slash.args.trim().split(/\s+/).includes("full");
|
|
2987
|
-
await readPresentation(`git:diff:${cwd}:${full ? "full" : "summary"}`, "Diff", async () => await client.getGitDiff({ cwd, full }));
|
|
3565
|
+
await readPresentation(`git:diff:${cwd}:${full ? "full" : "summary"}`, "Diff", async () => await client.development.getGitDiff({ cwd, full }));
|
|
2988
3566
|
return "handled";
|
|
2989
3567
|
}
|
|
2990
3568
|
if (slash?.name === "/branch") {
|
|
2991
3569
|
const list = slash.args.trim().split(/\s+/).includes("list");
|
|
2992
|
-
await readPresentation(`git:branch:${cwd}:${list ? "list" : "current"}`, "Branch", async () => await client.getGitBranch({ cwd, list }));
|
|
3570
|
+
await readPresentation(`git:branch:${cwd}:${list ? "list" : "current"}`, "Branch", async () => await client.development.getGitBranch({ cwd, list }));
|
|
2993
3571
|
return "handled";
|
|
2994
3572
|
}
|
|
2995
3573
|
if (slash?.name === "/commit") {
|
|
2996
3574
|
const message = slash.args.trim();
|
|
2997
3575
|
if (!message) {
|
|
2998
|
-
await readPresentation(`git:status:${cwd}`, "Commit", async () => await client.getGitStatus({ cwd }));
|
|
3576
|
+
await readPresentation(`git:status:${cwd}`, "Commit", async () => await client.development.getGitStatus({ cwd }));
|
|
2999
3577
|
return "handled";
|
|
3000
3578
|
}
|
|
3001
|
-
emit(await client.gitCommit({ cwd, message }));
|
|
3579
|
+
emit(await client.development.gitCommit({ cwd, message }));
|
|
3002
3580
|
return "handled";
|
|
3003
3581
|
}
|
|
3004
3582
|
if (slash && LOCAL_COMMAND_NAMES.has(slash.name)) {
|
|
@@ -3031,6 +3609,8 @@ var init_commands = __esm(() => {
|
|
|
3031
3609
|
// ../../packages/client/src/index.ts
|
|
3032
3610
|
var init_src2 = __esm(() => {
|
|
3033
3611
|
init_transport();
|
|
3612
|
+
init_protocol();
|
|
3613
|
+
init_resources();
|
|
3034
3614
|
init_src();
|
|
3035
3615
|
init_src();
|
|
3036
3616
|
init_state();
|
|
@@ -3301,128 +3881,588 @@ async function dispatchSessionSlashCommand(slash, ctx) {
|
|
|
3301
3881
|
return "local_ui_ignored";
|
|
3302
3882
|
return outcome;
|
|
3303
3883
|
}
|
|
3304
|
-
var init_sessionSlashCommands = __esm(() => {
|
|
3884
|
+
var init_sessionSlashCommands = __esm(() => {
|
|
3885
|
+
init_src2();
|
|
3886
|
+
});
|
|
3887
|
+
|
|
3888
|
+
// ../frontend/src/hooks/sync-submodules/connection.ts
|
|
3889
|
+
function stringSetting(value) {
|
|
3890
|
+
return typeof value === "string" && value.trim() ? value : undefined;
|
|
3891
|
+
}
|
|
3892
|
+
function normalizeSessionMode(value) {
|
|
3893
|
+
return value === "coordinator" ? "coordinator" : null;
|
|
3894
|
+
}
|
|
3895
|
+
function statusSessionMode(value) {
|
|
3896
|
+
return normalizeSessionMode(value) ?? "direct";
|
|
3897
|
+
}
|
|
3898
|
+
function shouldAutoActivateSession(session, defaultModel, pluginsEnabled) {
|
|
3899
|
+
const runtime = readSessionRuntimeConfig(session);
|
|
3900
|
+
return runtime.model === defaultModel && (pluginsEnabled == null || (runtime.pluginsEnabled ?? true) === pluginsEnabled);
|
|
3901
|
+
}
|
|
3902
|
+
function createDaemonClient(daemon) {
|
|
3903
|
+
if (!daemon?.url)
|
|
3904
|
+
return null;
|
|
3905
|
+
return new OpenHarnessClient({
|
|
3906
|
+
baseUrl: daemon.url,
|
|
3907
|
+
token: daemon.token ?? undefined
|
|
3908
|
+
});
|
|
3909
|
+
}
|
|
3910
|
+
var init_connection = __esm(() => {
|
|
3911
|
+
init_src2();
|
|
3912
|
+
});
|
|
3913
|
+
|
|
3914
|
+
// ../frontend/src/hooks/sync-submodules/permissions.ts
|
|
3915
|
+
function permissionToModal(request) {
|
|
3916
|
+
const input = request.payload.input && typeof request.payload.input === "object" ? request.payload.input : {};
|
|
3917
|
+
return {
|
|
3918
|
+
kind: "permission",
|
|
3919
|
+
request_id: request.id,
|
|
3920
|
+
tool_name: request.toolName,
|
|
3921
|
+
reason: typeof request.payload.reason === "string" ? request.payload.reason : null,
|
|
3922
|
+
input
|
|
3923
|
+
};
|
|
3924
|
+
}
|
|
3925
|
+
function firstPendingPermission(state, sessionId) {
|
|
3926
|
+
return selectFirstPendingPermission(state, sessionId);
|
|
3927
|
+
}
|
|
3928
|
+
var init_permissions = __esm(() => {
|
|
3929
|
+
init_src2();
|
|
3930
|
+
});
|
|
3931
|
+
|
|
3932
|
+
// ../frontend/src/hooks/sync-submodules/view-model.ts
|
|
3933
|
+
function isRecord5(value) {
|
|
3934
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
3935
|
+
}
|
|
3936
|
+
function sessionRuntimeMetadata(input) {
|
|
3937
|
+
const runtime = {};
|
|
3938
|
+
if (typeof input.model === "string" && input.model) {
|
|
3939
|
+
runtime.model = input.model;
|
|
3940
|
+
}
|
|
3941
|
+
if (typeof input.provider === "string" && input.provider) {
|
|
3942
|
+
runtime.provider = input.provider;
|
|
3943
|
+
}
|
|
3944
|
+
if (typeof input.baseUrl === "string" && input.baseUrl) {
|
|
3945
|
+
runtime.baseUrl = input.baseUrl;
|
|
3946
|
+
}
|
|
3947
|
+
if (input.apiFormat === "anthropic" || input.apiFormat === "openai") {
|
|
3948
|
+
runtime.apiFormat = input.apiFormat;
|
|
3949
|
+
}
|
|
3950
|
+
if (input.permissionMode === "default" || input.permissionMode === "plan" || input.permissionMode === "full_auto") {
|
|
3951
|
+
runtime.permissionMode = input.permissionMode;
|
|
3952
|
+
}
|
|
3953
|
+
if (typeof input.maxTurns === "number" && Number.isFinite(input.maxTurns)) {
|
|
3954
|
+
runtime.maxTurns = input.maxTurns;
|
|
3955
|
+
}
|
|
3956
|
+
if (input.sessionMode === "coordinator" || input.sessionMode === "direct") {
|
|
3957
|
+
runtime.sessionMode = input.sessionMode;
|
|
3958
|
+
}
|
|
3959
|
+
if (typeof input.pluginsEnabled === "boolean") {
|
|
3960
|
+
runtime.pluginsEnabled = input.pluginsEnabled;
|
|
3961
|
+
}
|
|
3962
|
+
return patchSessionRuntimeMetadata({}, runtime);
|
|
3963
|
+
}
|
|
3964
|
+
function archiveClientSession(state, sessionId, archivedAt) {
|
|
3965
|
+
const current = state.sessions[sessionId];
|
|
3966
|
+
if (!current || current.status === "archived")
|
|
3967
|
+
return state;
|
|
3968
|
+
const archived = {
|
|
3969
|
+
...current,
|
|
3970
|
+
status: "archived",
|
|
3971
|
+
archivedAt,
|
|
3972
|
+
updatedAt: Math.max(current.updatedAt, archivedAt)
|
|
3973
|
+
};
|
|
3974
|
+
const bucket = state.buckets[sessionId];
|
|
3975
|
+
return {
|
|
3976
|
+
...state,
|
|
3977
|
+
sessions: { ...state.sessions, [sessionId]: archived },
|
|
3978
|
+
buckets: bucket ? { ...state.buckets, [sessionId]: { ...bucket, session: archived } } : state.buckets
|
|
3979
|
+
};
|
|
3980
|
+
}
|
|
3981
|
+
function listTopLevelSessions(sessions, activeSessionId) {
|
|
3982
|
+
return [...sessions].filter((session) => !session.parentId && session.status !== "archived").sort((a, b) => {
|
|
3983
|
+
if (a.id === activeSessionId)
|
|
3984
|
+
return -1;
|
|
3985
|
+
if (b.id === activeSessionId)
|
|
3986
|
+
return 1;
|
|
3987
|
+
return b.updatedAt - a.updatedAt;
|
|
3988
|
+
});
|
|
3989
|
+
}
|
|
3990
|
+
function sessionSelectOptions(sessions, activeSessionId) {
|
|
3991
|
+
return listTopLevelSessions(sessions, activeSessionId).map((session) => ({
|
|
3992
|
+
value: session.id,
|
|
3993
|
+
label: `${session.id === activeSessionId ? "* " : ""}${session.title || session.id}`,
|
|
3994
|
+
description: `${session.model} | ${session.status}`
|
|
3995
|
+
}));
|
|
3996
|
+
}
|
|
3997
|
+
function recoverableInterruptedRuns(bucket) {
|
|
3998
|
+
if (!bucket)
|
|
3999
|
+
return [];
|
|
4000
|
+
const recoveredSourceRunIds = new Set(bucket.inputs.flatMap((input) => isRecord5(input.metadata.recovery) && typeof input.metadata.recovery.sourceRunId === "string" ? [input.metadata.recovery.sourceRunId] : []));
|
|
4001
|
+
return Object.values(bucket.runs).filter((run) => run.status === "interrupted" && !!run.inputId && !recoveredSourceRunIds.has(run.id)).sort((a, b) => b.updatedAt - a.updatedAt).flatMap((run) => {
|
|
4002
|
+
const input = bucket.inputs.find((candidate) => candidate.id === run.inputId);
|
|
4003
|
+
return input ? [{ id: run.id, error: run.error, prompt: input.content }] : [];
|
|
4004
|
+
});
|
|
4005
|
+
}
|
|
4006
|
+
function shouldCoalesceClientState(update) {
|
|
4007
|
+
return update.source === "live" && update.event?.type === "session.message.part.delta";
|
|
4008
|
+
}
|
|
4009
|
+
var init_view_model = __esm(() => {
|
|
4010
|
+
init_src2();
|
|
4011
|
+
});
|
|
4012
|
+
|
|
4013
|
+
// ../frontend/src/hooks/sync-submodules/mcp.ts
|
|
4014
|
+
function mcpServerSnapshot(server) {
|
|
4015
|
+
return {
|
|
4016
|
+
name: server.name,
|
|
4017
|
+
state: server.status,
|
|
4018
|
+
...server.error || server.command ? { detail: server.error ?? server.command } : {},
|
|
4019
|
+
tool_count: server.toolCount,
|
|
4020
|
+
resource_count: server.resourceCount
|
|
4021
|
+
};
|
|
4022
|
+
}
|
|
4023
|
+
|
|
4024
|
+
// ../frontend/src/hooks/sync-submodules/actions.ts
|
|
4025
|
+
async function executeTuiAction(action, ctx) {
|
|
4026
|
+
const client = ctx.clientRef.current;
|
|
4027
|
+
let sessionId = ctx.activeSessionIdRef.current;
|
|
4028
|
+
const runtimeAction = action;
|
|
4029
|
+
const runtimeType = typeof runtimeAction.type === "string" ? runtimeAction.type : "unknown";
|
|
4030
|
+
switch (action.type) {
|
|
4031
|
+
case "select_model": {
|
|
4032
|
+
if (!client)
|
|
4033
|
+
return;
|
|
4034
|
+
const model = action.model.trim();
|
|
4035
|
+
const provider = action.provider?.trim() ?? "";
|
|
4036
|
+
if (!model)
|
|
4037
|
+
return;
|
|
4038
|
+
if (sessionId) {
|
|
4039
|
+
const session = await client.sessions.update(sessionId, {
|
|
4040
|
+
metadata: patchSessionRuntimeMetadata({}, {
|
|
4041
|
+
model,
|
|
4042
|
+
...provider ? { provider } : {}
|
|
4043
|
+
})
|
|
4044
|
+
});
|
|
4045
|
+
ctx.activateSession(session);
|
|
4046
|
+
} else {
|
|
4047
|
+
const settingsPatch = { model };
|
|
4048
|
+
if (provider)
|
|
4049
|
+
settingsPatch.provider = provider;
|
|
4050
|
+
await client.system.patchSettings(settingsPatch);
|
|
4051
|
+
ctx.defaultRuntimeRef.current = {
|
|
4052
|
+
...ctx.defaultRuntimeRef.current,
|
|
4053
|
+
model,
|
|
4054
|
+
...provider ? { provider } : {}
|
|
4055
|
+
};
|
|
4056
|
+
ctx.setStatus((current) => ({
|
|
4057
|
+
...current,
|
|
4058
|
+
model,
|
|
4059
|
+
...provider ? { provider } : {}
|
|
4060
|
+
}));
|
|
4061
|
+
}
|
|
4062
|
+
ctx.pushSystem(`Model selected: ${model}`);
|
|
4063
|
+
return;
|
|
4064
|
+
}
|
|
4065
|
+
case "submit_line": {
|
|
4066
|
+
if (!client)
|
|
4067
|
+
return;
|
|
4068
|
+
const line = action.line;
|
|
4069
|
+
const slash = parseSlashLine(line);
|
|
4070
|
+
const newSession = line.match(/^\/new(?:\s+(.+))?$/);
|
|
4071
|
+
if (newSession) {
|
|
4072
|
+
ctx.returnToHome(newSession[1]);
|
|
4073
|
+
return;
|
|
4074
|
+
}
|
|
4075
|
+
const switchSession = line.match(/^\/sessions\s+open\s+(.+)$/);
|
|
4076
|
+
if (switchSession?.[1]) {
|
|
4077
|
+
const target = switchSession[1].trim();
|
|
4078
|
+
ctx.setLocalBusy(false);
|
|
4079
|
+
ctx.setSubmittedRun(null);
|
|
4080
|
+
ctx.pendingNewSessionTitleRef.current = undefined;
|
|
4081
|
+
ctx.setSelectRequest(null);
|
|
4082
|
+
const knownSession = ctx.clientState.sessions[target] ?? ctx.listedSessionsRef.current[target];
|
|
4083
|
+
if (knownSession) {
|
|
4084
|
+
ctx.activateSession(knownSession);
|
|
4085
|
+
return;
|
|
4086
|
+
}
|
|
4087
|
+
const session = await client.sessions.get(target);
|
|
4088
|
+
ctx.activateSession(session);
|
|
4089
|
+
return;
|
|
4090
|
+
}
|
|
4091
|
+
if (slash?.name === "/resume") {
|
|
4092
|
+
if (!sessionId) {
|
|
4093
|
+
ctx.pushSystem("No active session to resume.");
|
|
4094
|
+
return;
|
|
4095
|
+
}
|
|
4096
|
+
const recoverable = recoverableInterruptedRuns(ctx.clientState.buckets[sessionId]);
|
|
4097
|
+
if (!slash.args) {
|
|
4098
|
+
if (recoverable.length === 0) {
|
|
4099
|
+
ctx.pushSystem("No interrupted prompt runs are available to resume.");
|
|
4100
|
+
return;
|
|
4101
|
+
}
|
|
4102
|
+
ctx.clearDisplayRequest();
|
|
4103
|
+
ctx.setSelectRequest({
|
|
4104
|
+
title: "Resume interrupted run",
|
|
4105
|
+
submitPrefix: "/resume ",
|
|
4106
|
+
options: recoverable.map((run) => ({
|
|
4107
|
+
value: run.id,
|
|
4108
|
+
label: run.prompt.length > 72 ? `${run.prompt.slice(0, 72)}...` : run.prompt,
|
|
4109
|
+
description: run.error ?? "Interrupted before completion"
|
|
4110
|
+
}))
|
|
4111
|
+
});
|
|
4112
|
+
return;
|
|
4113
|
+
}
|
|
4114
|
+
const runId = slash.args.trim();
|
|
4115
|
+
if (!recoverable.some((run) => run.id === runId)) {
|
|
4116
|
+
ctx.pushSystem(`Run is not available for recovery: ${runId}`);
|
|
4117
|
+
return;
|
|
4118
|
+
}
|
|
4119
|
+
ctx.setLocalBusy(true);
|
|
4120
|
+
const response = await client.sessions.resumeInterruptedRun(sessionId, runId, { id: createPromptRequestId() });
|
|
4121
|
+
ctx.setLocalBusy(false);
|
|
4122
|
+
ctx.setSubmittedRun(response.run ? { sessionId, runId: response.run.id } : null);
|
|
4123
|
+
ctx.setSelectRequest(null);
|
|
4124
|
+
return;
|
|
4125
|
+
}
|
|
4126
|
+
let slashResult;
|
|
4127
|
+
try {
|
|
4128
|
+
slashResult = await dispatchSessionSlashCommand(slash, {
|
|
4129
|
+
client,
|
|
4130
|
+
sessionId,
|
|
4131
|
+
pushSystem: ctx.pushSystem,
|
|
4132
|
+
presentSystem: (title, content) => ctx.showDisplayRequest({ title, content }),
|
|
4133
|
+
statusRef: ctx.statusRef,
|
|
4134
|
+
commandCatalogRef: ctx.commandCatalogRef,
|
|
4135
|
+
clientState: ctx.clientState,
|
|
4136
|
+
localBusy: ctx.localBusy,
|
|
4137
|
+
cacheFirstRead: ctx.cacheFirstRead,
|
|
4138
|
+
daemon: ctx.daemon,
|
|
4139
|
+
setStatus: ctx.setStatusAndDefault
|
|
4140
|
+
});
|
|
4141
|
+
} catch (error) {
|
|
4142
|
+
if (slash && JOBS_AUXILIARY_SLASH_COMMANDS.has(slash.name)) {
|
|
4143
|
+
ctx.reportAuxiliaryError("Jobs", error);
|
|
4144
|
+
return;
|
|
4145
|
+
}
|
|
4146
|
+
throw error;
|
|
4147
|
+
}
|
|
4148
|
+
if (slashResult === "handled") {
|
|
4149
|
+
if (slash?.name === "/background" && slash.args.trim() && sessionId) {
|
|
4150
|
+
await ctx.refreshJobs();
|
|
4151
|
+
}
|
|
4152
|
+
return;
|
|
4153
|
+
}
|
|
4154
|
+
if (slashResult === "local_ui_ignored")
|
|
4155
|
+
return;
|
|
4156
|
+
if (slash) {
|
|
4157
|
+
const catalogEntry = ctx.commandCatalogRef.current.find((entry) => entry.name === slash.name);
|
|
4158
|
+
if (catalogEntry?.kind === "template") {
|
|
4159
|
+
if (!sessionId)
|
|
4160
|
+
return;
|
|
4161
|
+
ctx.setLocalBusy(true);
|
|
4162
|
+
const response = await client.sessions.admitPrompt(sessionId, {
|
|
4163
|
+
id: createPromptRequestId(),
|
|
4164
|
+
items: [
|
|
4165
|
+
{
|
|
4166
|
+
type: "skill",
|
|
4167
|
+
name: catalogEntry.skillName,
|
|
4168
|
+
path: catalogEntry.path,
|
|
4169
|
+
...catalogEntry.displayName ? { displayName: catalogEntry.displayName } : {},
|
|
4170
|
+
...catalogEntry.source && catalogEntry.source !== "builtin" ? { source: catalogEntry.source } : {}
|
|
4171
|
+
},
|
|
4172
|
+
...slash.args ? [{ type: "text", text: ` ${slash.args}` }] : []
|
|
4173
|
+
]
|
|
4174
|
+
});
|
|
4175
|
+
ctx.setLocalBusy(false);
|
|
4176
|
+
ctx.setSubmittedRun(response.run ? { sessionId, runId: response.run.id } : null);
|
|
4177
|
+
return;
|
|
4178
|
+
}
|
|
4179
|
+
ctx.pushSystem(`Unknown command: ${slash.name}`);
|
|
4180
|
+
return;
|
|
4181
|
+
}
|
|
4182
|
+
if (!sessionId) {
|
|
4183
|
+
const session = await ctx.createAndSwitchSession(ctx.pendingNewSessionTitleRef.current);
|
|
4184
|
+
if (!session)
|
|
4185
|
+
return;
|
|
4186
|
+
sessionId = session.id;
|
|
4187
|
+
}
|
|
4188
|
+
ctx.setLocalBusy(true);
|
|
4189
|
+
const response = await client.sessions.admitPrompt(sessionId, {
|
|
4190
|
+
id: createPromptRequestId(),
|
|
4191
|
+
items: [{ type: "text", text: line }]
|
|
4192
|
+
});
|
|
4193
|
+
ctx.setLocalBusy(false);
|
|
4194
|
+
ctx.setSubmittedRun(response.run ? { sessionId, runId: response.run.id } : null);
|
|
4195
|
+
return;
|
|
4196
|
+
}
|
|
4197
|
+
case "delete_session": {
|
|
4198
|
+
if (!client)
|
|
4199
|
+
return;
|
|
4200
|
+
const target = action.session_id;
|
|
4201
|
+
if (!target)
|
|
4202
|
+
return;
|
|
4203
|
+
const archived = await client.sessions.archive(target);
|
|
4204
|
+
const archivedAt = archived.archivedAt ?? Date.now();
|
|
4205
|
+
delete ctx.listedSessionsRef.current[target];
|
|
4206
|
+
ctx.setClientState((current) => archiveClientSession(current, target, archivedAt));
|
|
4207
|
+
ctx.setLocalBusy(false);
|
|
4208
|
+
ctx.setSubmittedRun(null);
|
|
4209
|
+
ctx.setSelectRequest((current) => current ? {
|
|
4210
|
+
...current,
|
|
4211
|
+
options: current.options.filter((option) => option.value !== target)
|
|
4212
|
+
} : current);
|
|
4213
|
+
if (target === ctx.activeSessionIdRef.current) {
|
|
4214
|
+
const remaining = listTopLevelSessions(Object.values({
|
|
4215
|
+
...ctx.clientState.sessions,
|
|
4216
|
+
...ctx.listedSessionsRef.current,
|
|
4217
|
+
[target]: { ...archived, status: "archived", archivedAt }
|
|
4218
|
+
}));
|
|
4219
|
+
if (remaining[0]) {
|
|
4220
|
+
ctx.activateSession(remaining[0]);
|
|
4221
|
+
} else {
|
|
4222
|
+
const sessions = await client.sessions.list({
|
|
4223
|
+
cwd: ctx.daemon?.cwd ?? undefined,
|
|
4224
|
+
includeArchived: false,
|
|
4225
|
+
limit: 20
|
|
4226
|
+
});
|
|
4227
|
+
ctx.listedSessionsRef.current = Object.fromEntries(sessions.map((session) => [session.id, session]));
|
|
4228
|
+
const remoteNext = sessions.find((session) => session.id !== target);
|
|
4229
|
+
if (remoteNext)
|
|
4230
|
+
ctx.activateSession(remoteNext);
|
|
4231
|
+
else
|
|
4232
|
+
ctx.returnToHome();
|
|
4233
|
+
}
|
|
4234
|
+
}
|
|
4235
|
+
return;
|
|
4236
|
+
}
|
|
4237
|
+
case "interrupt": {
|
|
4238
|
+
if (!client)
|
|
4239
|
+
return;
|
|
4240
|
+
if (sessionId)
|
|
4241
|
+
await client.sessions.interrupt(sessionId);
|
|
4242
|
+
ctx.setLocalBusy(false);
|
|
4243
|
+
ctx.setSubmittedRun(null);
|
|
4244
|
+
return;
|
|
4245
|
+
}
|
|
4246
|
+
case "permission_response": {
|
|
4247
|
+
if (!client)
|
|
4248
|
+
return;
|
|
4249
|
+
const requestId = action.request_id;
|
|
4250
|
+
const allowed = action.allowed;
|
|
4251
|
+
await client.permissions.reply(requestId, {
|
|
4252
|
+
status: allowed ? "approved" : "denied",
|
|
4253
|
+
decision: action.scope === "session" ? "session" : "once",
|
|
4254
|
+
clientId: "tui"
|
|
4255
|
+
});
|
|
4256
|
+
ctx.setModal(null);
|
|
4257
|
+
return;
|
|
4258
|
+
}
|
|
4259
|
+
case "list_sessions": {
|
|
4260
|
+
if (!client)
|
|
4261
|
+
return;
|
|
4262
|
+
const cachedSessions = {
|
|
4263
|
+
...ctx.listedSessionsRef.current,
|
|
4264
|
+
...ctx.clientState.sessions
|
|
4265
|
+
};
|
|
4266
|
+
const cachedOptions = sessionSelectOptions(Object.values(cachedSessions), ctx.activeSessionIdRef.current);
|
|
4267
|
+
ctx.clearDisplayRequest();
|
|
4268
|
+
ctx.setSelectRequest({
|
|
4269
|
+
title: "Sessions",
|
|
4270
|
+
submitPrefix: "/sessions open ",
|
|
4271
|
+
options: cachedOptions
|
|
4272
|
+
});
|
|
4273
|
+
const sessions = await client.sessions.list({
|
|
4274
|
+
cwd: ctx.daemon?.cwd ?? undefined,
|
|
4275
|
+
includeArchived: false,
|
|
4276
|
+
limit: 20
|
|
4277
|
+
});
|
|
4278
|
+
ctx.listedSessionsRef.current = Object.fromEntries(sessions.map((session) => [session.id, session]));
|
|
4279
|
+
ctx.setSelectRequest((current) => current?.submitPrefix === "/sessions open " ? {
|
|
4280
|
+
title: "Sessions",
|
|
4281
|
+
submitPrefix: "/sessions open ",
|
|
4282
|
+
options: sessionSelectOptions(sessions, ctx.activeSessionIdRef.current)
|
|
4283
|
+
} : current);
|
|
4284
|
+
return;
|
|
4285
|
+
}
|
|
4286
|
+
case "set_permission_mode": {
|
|
4287
|
+
if (!client)
|
|
4288
|
+
return;
|
|
4289
|
+
const mode = action.permission_mode;
|
|
4290
|
+
ctx.setStatus((current) => ({ ...current, permission_mode: mode }));
|
|
4291
|
+
if (sessionId) {
|
|
4292
|
+
await client.sessions.update(sessionId, {
|
|
4293
|
+
metadata: patchSessionRuntimeMetadata({}, { permissionMode: mode })
|
|
4294
|
+
});
|
|
4295
|
+
}
|
|
4296
|
+
return;
|
|
4297
|
+
}
|
|
4298
|
+
case "question_response": {
|
|
4299
|
+
if (!client)
|
|
4300
|
+
return;
|
|
4301
|
+
ctx.reportError("Interactive question responses are not available through the daemon client.");
|
|
4302
|
+
return;
|
|
4303
|
+
}
|
|
4304
|
+
case "set_session_mode": {
|
|
4305
|
+
if (!client)
|
|
4306
|
+
return;
|
|
4307
|
+
if (sessionId) {
|
|
4308
|
+
ctx.pushSystem("Coordinator mode can only be changed before starting a new session. Use /new first.");
|
|
4309
|
+
return;
|
|
4310
|
+
}
|
|
4311
|
+
const mode = normalizeSessionMode(action.session_mode);
|
|
4312
|
+
ctx.nextSessionModeRef.current = statusSessionMode(mode);
|
|
4313
|
+
ctx.setStatus((current) => ({
|
|
4314
|
+
...current,
|
|
4315
|
+
session_mode: ctx.nextSessionModeRef.current
|
|
4316
|
+
}));
|
|
4317
|
+
return;
|
|
4318
|
+
}
|
|
4319
|
+
case "job_request": {
|
|
4320
|
+
if (!client) {
|
|
4321
|
+
ctx.reportAuxiliaryError("Jobs", "The daemon client is not connected.");
|
|
4322
|
+
return;
|
|
4323
|
+
}
|
|
4324
|
+
const currentSessionId = ctx.activeSessionIdRef.current;
|
|
4325
|
+
if (!currentSessionId)
|
|
4326
|
+
return;
|
|
4327
|
+
try {
|
|
4328
|
+
switch (action.job_action) {
|
|
4329
|
+
case "open":
|
|
4330
|
+
await ctx.refreshJobs();
|
|
4331
|
+
return;
|
|
4332
|
+
case "refresh": {
|
|
4333
|
+
ctx.jobControlGenerationRef.current += 1;
|
|
4334
|
+
ctx.jobControlAbortRef.current?.abort();
|
|
4335
|
+
ctx.jobControlAbortRef.current = null;
|
|
4336
|
+
const detail = ctx.jobDetailStateRef.current;
|
|
4337
|
+
const detailJobId = detail.status === "idle" ? undefined : detail.jobId;
|
|
4338
|
+
await Promise.all([
|
|
4339
|
+
ctx.refreshJobs(),
|
|
4340
|
+
detailJobId ? ctx.loadJobDetail(client, currentSessionId, detailJobId) : Promise.resolve()
|
|
4341
|
+
]);
|
|
4342
|
+
return;
|
|
4343
|
+
}
|
|
4344
|
+
case "select":
|
|
4345
|
+
ctx.jobControlGenerationRef.current += 1;
|
|
4346
|
+
ctx.jobControlAbortRef.current?.abort();
|
|
4347
|
+
ctx.jobControlAbortRef.current = null;
|
|
4348
|
+
await ctx.loadJobDetail(client, currentSessionId, action.job_id);
|
|
4349
|
+
return;
|
|
4350
|
+
case "cancel": {
|
|
4351
|
+
const controlGeneration = ++ctx.jobControlGenerationRef.current;
|
|
4352
|
+
const detailGeneration = ctx.jobDetailGenerationRef.current;
|
|
4353
|
+
ctx.jobControlAbortRef.current?.abort();
|
|
4354
|
+
const controller = new AbortController;
|
|
4355
|
+
ctx.jobControlAbortRef.current = controller;
|
|
4356
|
+
let response;
|
|
4357
|
+
try {
|
|
4358
|
+
response = await client.jobs.cancel(action.job_id, {
|
|
4359
|
+
sessionId: currentSessionId,
|
|
4360
|
+
reason: action.reason
|
|
4361
|
+
}, { signal: controller.signal });
|
|
4362
|
+
} catch (error) {
|
|
4363
|
+
if (ctx.activeSessionIdRef.current !== currentSessionId)
|
|
4364
|
+
return;
|
|
4365
|
+
if (controller.signal.aborted || ctx.jobControlGenerationRef.current !== controlGeneration) {
|
|
4366
|
+
await ctx.refreshJobs();
|
|
4367
|
+
return;
|
|
4368
|
+
}
|
|
4369
|
+
throw error;
|
|
4370
|
+
} finally {
|
|
4371
|
+
if (ctx.jobControlAbortRef.current === controller)
|
|
4372
|
+
ctx.jobControlAbortRef.current = null;
|
|
4373
|
+
}
|
|
4374
|
+
if (ctx.activeSessionIdRef.current !== currentSessionId)
|
|
4375
|
+
return;
|
|
4376
|
+
const ownsDetail = !controller.signal.aborted && ctx.jobControlGenerationRef.current === controlGeneration && ctx.jobDetailGenerationRef.current === detailGeneration;
|
|
4377
|
+
const validated = validateJobSnapshot(response, currentSessionId, action.job_id);
|
|
4378
|
+
if (!validated.snapshot) {
|
|
4379
|
+
if (controller.signal.aborted || ctx.jobControlGenerationRef.current !== controlGeneration) {
|
|
4380
|
+
await ctx.refreshJobs();
|
|
4381
|
+
return;
|
|
4382
|
+
}
|
|
4383
|
+
throw new Error(validated.error ?? "Job snapshot has invalid fields.");
|
|
4384
|
+
}
|
|
4385
|
+
const snapshot = validated.snapshot;
|
|
4386
|
+
const next = mergeJobSnapshot(ctx.jobStateRef.current, snapshot, Date.now());
|
|
4387
|
+
ctx.jobStateRef.current = next;
|
|
4388
|
+
ctx.setJobState(next);
|
|
4389
|
+
if (ownsDetail) {
|
|
4390
|
+
await ctx.loadJobDetail(client, currentSessionId, action.job_id);
|
|
4391
|
+
}
|
|
4392
|
+
await ctx.refreshJobs();
|
|
4393
|
+
return;
|
|
4394
|
+
}
|
|
4395
|
+
case "send": {
|
|
4396
|
+
const controlGeneration = ++ctx.jobControlGenerationRef.current;
|
|
4397
|
+
const detailGeneration = ctx.jobDetailGenerationRef.current;
|
|
4398
|
+
ctx.jobControlAbortRef.current?.abort();
|
|
4399
|
+
const controller = new AbortController;
|
|
4400
|
+
ctx.jobControlAbortRef.current = controller;
|
|
4401
|
+
try {
|
|
4402
|
+
await client.jobs.send(action.job_id, {
|
|
4403
|
+
sessionId: currentSessionId,
|
|
4404
|
+
data: action.data
|
|
4405
|
+
}, { signal: controller.signal });
|
|
4406
|
+
} catch (error) {
|
|
4407
|
+
if (ctx.activeSessionIdRef.current !== currentSessionId)
|
|
4408
|
+
return;
|
|
4409
|
+
if (controller.signal.aborted || ctx.jobControlGenerationRef.current !== controlGeneration) {
|
|
4410
|
+
await ctx.refreshJobs();
|
|
4411
|
+
return;
|
|
4412
|
+
}
|
|
4413
|
+
throw error;
|
|
4414
|
+
} finally {
|
|
4415
|
+
if (ctx.jobControlAbortRef.current === controller)
|
|
4416
|
+
ctx.jobControlAbortRef.current = null;
|
|
4417
|
+
}
|
|
4418
|
+
if (ctx.activeSessionIdRef.current !== currentSessionId)
|
|
4419
|
+
return;
|
|
4420
|
+
const ownsDetail = !controller.signal.aborted && ctx.jobControlGenerationRef.current === controlGeneration && ctx.jobDetailGenerationRef.current === detailGeneration;
|
|
4421
|
+
if (ownsDetail) {
|
|
4422
|
+
await ctx.loadJobDetail(client, currentSessionId, action.job_id);
|
|
4423
|
+
}
|
|
4424
|
+
await ctx.refreshJobs();
|
|
4425
|
+
return;
|
|
4426
|
+
}
|
|
4427
|
+
}
|
|
4428
|
+
} catch (error) {
|
|
4429
|
+
ctx.reportAuxiliaryError("Jobs", error);
|
|
4430
|
+
return;
|
|
4431
|
+
}
|
|
4432
|
+
}
|
|
4433
|
+
default: {
|
|
4434
|
+
const exhaustive = action;
|
|
4435
|
+
ctx.reportError(`Unsupported TUI action: ${runtimeType}`);
|
|
4436
|
+
return;
|
|
4437
|
+
}
|
|
4438
|
+
}
|
|
4439
|
+
}
|
|
4440
|
+
var JOBS_AUXILIARY_SLASH_COMMANDS;
|
|
4441
|
+
var init_actions = __esm(() => {
|
|
3305
4442
|
init_src2();
|
|
4443
|
+
init_job_remote_state();
|
|
4444
|
+
init_sessionSlashCommands();
|
|
4445
|
+
init_view_model();
|
|
4446
|
+
init_connection();
|
|
4447
|
+
JOBS_AUXILIARY_SLASH_COMMANDS = new Set([
|
|
4448
|
+
"/agents",
|
|
4449
|
+
"/background",
|
|
4450
|
+
"/doctor",
|
|
4451
|
+
"/jobs",
|
|
4452
|
+
"/stats"
|
|
4453
|
+
]);
|
|
4454
|
+
});
|
|
4455
|
+
|
|
4456
|
+
// ../frontend/src/hooks/sync-submodules/index.ts
|
|
4457
|
+
var init_sync_submodules = __esm(() => {
|
|
4458
|
+
init_connection();
|
|
4459
|
+
init_permissions();
|
|
4460
|
+
init_view_model();
|
|
4461
|
+
init_actions();
|
|
3306
4462
|
});
|
|
3307
4463
|
|
|
3308
4464
|
// ../frontend/src/hooks/useServerSync.ts
|
|
3309
4465
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3310
|
-
function isRecord5(value) {
|
|
3311
|
-
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
3312
|
-
}
|
|
3313
|
-
function sessionRuntimeMetadata(input) {
|
|
3314
|
-
const runtime = {};
|
|
3315
|
-
if (typeof input.model === "string" && input.model) {
|
|
3316
|
-
runtime.model = input.model;
|
|
3317
|
-
}
|
|
3318
|
-
if (typeof input.provider === "string" && input.provider) {
|
|
3319
|
-
runtime.provider = input.provider;
|
|
3320
|
-
}
|
|
3321
|
-
if (typeof input.baseUrl === "string" && input.baseUrl) {
|
|
3322
|
-
runtime.baseUrl = input.baseUrl;
|
|
3323
|
-
}
|
|
3324
|
-
if (input.apiFormat === "anthropic" || input.apiFormat === "openai") {
|
|
3325
|
-
runtime.apiFormat = input.apiFormat;
|
|
3326
|
-
}
|
|
3327
|
-
if (input.permissionMode === "default" || input.permissionMode === "plan" || input.permissionMode === "full_auto") {
|
|
3328
|
-
runtime.permissionMode = input.permissionMode;
|
|
3329
|
-
}
|
|
3330
|
-
if (typeof input.maxTurns === "number" && Number.isFinite(input.maxTurns)) {
|
|
3331
|
-
runtime.maxTurns = input.maxTurns;
|
|
3332
|
-
}
|
|
3333
|
-
if (input.sessionMode === "coordinator" || input.sessionMode === "direct") {
|
|
3334
|
-
runtime.sessionMode = input.sessionMode;
|
|
3335
|
-
}
|
|
3336
|
-
if (typeof input.pluginsEnabled === "boolean") {
|
|
3337
|
-
runtime.pluginsEnabled = input.pluginsEnabled;
|
|
3338
|
-
}
|
|
3339
|
-
return patchSessionRuntimeMetadata({}, runtime);
|
|
3340
|
-
}
|
|
3341
|
-
function mcpServerSnapshot(server) {
|
|
3342
|
-
return {
|
|
3343
|
-
name: server.name,
|
|
3344
|
-
state: server.status,
|
|
3345
|
-
...server.error || server.command ? { detail: server.error ?? server.command } : {},
|
|
3346
|
-
tool_count: server.toolCount,
|
|
3347
|
-
resource_count: server.resourceCount
|
|
3348
|
-
};
|
|
3349
|
-
}
|
|
3350
|
-
function normalizeSessionMode(value) {
|
|
3351
|
-
return value === "coordinator" ? "coordinator" : null;
|
|
3352
|
-
}
|
|
3353
|
-
function statusSessionMode(value) {
|
|
3354
|
-
return normalizeSessionMode(value) ?? "direct";
|
|
3355
|
-
}
|
|
3356
|
-
function stringSetting(value) {
|
|
3357
|
-
return typeof value === "string" && value.trim() ? value : undefined;
|
|
3358
|
-
}
|
|
3359
|
-
function archiveClientSession(state, sessionId, archivedAt) {
|
|
3360
|
-
const current = state.sessions[sessionId];
|
|
3361
|
-
if (!current || current.status === "archived")
|
|
3362
|
-
return state;
|
|
3363
|
-
const archived = {
|
|
3364
|
-
...current,
|
|
3365
|
-
status: "archived",
|
|
3366
|
-
archivedAt,
|
|
3367
|
-
updatedAt: Math.max(current.updatedAt, archivedAt)
|
|
3368
|
-
};
|
|
3369
|
-
const bucket = state.buckets[sessionId];
|
|
3370
|
-
return {
|
|
3371
|
-
...state,
|
|
3372
|
-
sessions: { ...state.sessions, [sessionId]: archived },
|
|
3373
|
-
buckets: bucket ? { ...state.buckets, [sessionId]: { ...bucket, session: archived } } : state.buckets
|
|
3374
|
-
};
|
|
3375
|
-
}
|
|
3376
|
-
function listTopLevelSessions(sessions, activeSessionId) {
|
|
3377
|
-
return [...sessions].filter((session) => !session.parentId && session.status !== "archived").sort((a, b) => {
|
|
3378
|
-
if (a.id === activeSessionId)
|
|
3379
|
-
return -1;
|
|
3380
|
-
if (b.id === activeSessionId)
|
|
3381
|
-
return 1;
|
|
3382
|
-
return b.updatedAt - a.updatedAt;
|
|
3383
|
-
});
|
|
3384
|
-
}
|
|
3385
|
-
function sessionSelectOptions(sessions, activeSessionId) {
|
|
3386
|
-
return listTopLevelSessions(sessions, activeSessionId).map((session) => ({
|
|
3387
|
-
value: session.id,
|
|
3388
|
-
label: `${session.id === activeSessionId ? "* " : ""}${session.title || session.id}`,
|
|
3389
|
-
description: `${session.model} | ${session.status}`
|
|
3390
|
-
}));
|
|
3391
|
-
}
|
|
3392
|
-
function shouldAutoActivateSession(session, defaultModel, pluginsEnabled) {
|
|
3393
|
-
const runtime = readSessionRuntimeConfig(session);
|
|
3394
|
-
return runtime.model === defaultModel && (pluginsEnabled == null || (runtime.pluginsEnabled ?? true) === pluginsEnabled);
|
|
3395
|
-
}
|
|
3396
|
-
function recoverableInterruptedRuns(bucket) {
|
|
3397
|
-
if (!bucket)
|
|
3398
|
-
return [];
|
|
3399
|
-
const recoveredSourceRunIds = new Set(bucket.inputs.flatMap((input) => isRecord5(input.metadata.recovery) && typeof input.metadata.recovery.sourceRunId === "string" ? [input.metadata.recovery.sourceRunId] : []));
|
|
3400
|
-
return Object.values(bucket.runs).filter((run) => run.status === "interrupted" && !!run.inputId && !recoveredSourceRunIds.has(run.id)).sort((a, b) => b.updatedAt - a.updatedAt).flatMap((run) => {
|
|
3401
|
-
const input = bucket.inputs.find((candidate) => candidate.id === run.inputId);
|
|
3402
|
-
return input ? [{ id: run.id, error: run.error, prompt: input.content }] : [];
|
|
3403
|
-
});
|
|
3404
|
-
}
|
|
3405
|
-
function shouldCoalesceClientState(update) {
|
|
3406
|
-
return update.source === "live" && update.event?.type === "session.message.part.delta";
|
|
3407
|
-
}
|
|
3408
|
-
function permissionToModal(request) {
|
|
3409
|
-
const input = request.payload.input && typeof request.payload.input === "object" ? request.payload.input : {};
|
|
3410
|
-
return {
|
|
3411
|
-
kind: "permission",
|
|
3412
|
-
request_id: request.id,
|
|
3413
|
-
tool_name: request.toolName,
|
|
3414
|
-
reason: typeof request.payload.reason === "string" ? request.payload.reason : null,
|
|
3415
|
-
input
|
|
3416
|
-
};
|
|
3417
|
-
}
|
|
3418
|
-
function firstPendingPermission(state, sessionId) {
|
|
3419
|
-
if (!sessionId)
|
|
3420
|
-
return;
|
|
3421
|
-
const bucket = state.buckets[sessionId];
|
|
3422
|
-
if (!bucket)
|
|
3423
|
-
return;
|
|
3424
|
-
return Object.values(bucket.permissions).filter((request) => request.status === "pending").sort((a, b) => a.createdAt - b.createdAt).at(0);
|
|
3425
|
-
}
|
|
3426
4466
|
function useServerSync(config, onError) {
|
|
3427
4467
|
const daemon = config.daemon;
|
|
3428
4468
|
const [clientState, setClientState] = useState(() => createInitialClientState());
|
|
@@ -3462,6 +4502,7 @@ function useServerSync(config, onError) {
|
|
|
3462
4502
|
const pendingClientStateTimerRef = useRef(null);
|
|
3463
4503
|
const shownPermissionIdRef = useRef(undefined);
|
|
3464
4504
|
const auxiliaryGenerationRef = useRef(0);
|
|
4505
|
+
const syncGenerationRef = useRef(0);
|
|
3465
4506
|
const jobStateRef = useRef(jobState);
|
|
3466
4507
|
const jobDetailStateRef = useRef(jobDetailState);
|
|
3467
4508
|
const jobGenerationRef = useRef(0);
|
|
@@ -3576,7 +4617,7 @@ function useServerSync(config, onError) {
|
|
|
3576
4617
|
return next;
|
|
3577
4618
|
});
|
|
3578
4619
|
try {
|
|
3579
|
-
const response = await client.
|
|
4620
|
+
const response = await client.jobs.list({
|
|
3580
4621
|
sessionId,
|
|
3581
4622
|
includeFinished: true,
|
|
3582
4623
|
limit: 100,
|
|
@@ -3635,7 +4676,7 @@ function useServerSync(config, onError) {
|
|
|
3635
4676
|
jobDetailStateRef.current = loading;
|
|
3636
4677
|
setJobDetailState(loading);
|
|
3637
4678
|
try {
|
|
3638
|
-
const response = await client.
|
|
4679
|
+
const response = await client.jobs.read(jobId, {
|
|
3639
4680
|
sessionId,
|
|
3640
4681
|
signal: controller.signal
|
|
3641
4682
|
});
|
|
@@ -3678,7 +4719,7 @@ function useServerSync(config, onError) {
|
|
|
3678
4719
|
const client = clientRef.current;
|
|
3679
4720
|
if (!client)
|
|
3680
4721
|
return [];
|
|
3681
|
-
return await client.listModels();
|
|
4722
|
+
return await client.providers.listModels();
|
|
3682
4723
|
}, []);
|
|
3683
4724
|
const cacheFirstRead = useCallback((request) => {
|
|
3684
4725
|
const cached = presentationCacheRef.current[request.key];
|
|
@@ -3787,16 +4828,19 @@ Refresh failed: ${message}` : `Failed to load ${request.title}: ${message}`;
|
|
|
3787
4828
|
return;
|
|
3788
4829
|
}
|
|
3789
4830
|
let cancelled = false;
|
|
3790
|
-
const client =
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
});
|
|
4831
|
+
const client = createDaemonClient(daemon);
|
|
4832
|
+
if (!client)
|
|
4833
|
+
return;
|
|
3794
4834
|
clientRef.current = client;
|
|
3795
4835
|
(async () => {
|
|
3796
4836
|
try {
|
|
3797
|
-
await client.health();
|
|
4837
|
+
await client.protocol.health();
|
|
3798
4838
|
const cwd = daemon.cwd ?? process.cwd();
|
|
3799
|
-
const [settings, sessions, commands] = await Promise.all([
|
|
4839
|
+
const [settings, sessions, commands] = await Promise.all([
|
|
4840
|
+
client.system.getSettings().catch(() => ({})),
|
|
4841
|
+
client.sessions.list({ cwd, limit: 20 }),
|
|
4842
|
+
client.system.listCommands({ cwd }).catch(() => [])
|
|
4843
|
+
]);
|
|
3800
4844
|
const model = daemon.model ?? stringSetting(settings.model) ?? "default";
|
|
3801
4845
|
const provider = stringSetting(settings.provider);
|
|
3802
4846
|
const baseUrl = stringSetting(settings.baseUrl);
|
|
@@ -3823,7 +4867,7 @@ Refresh failed: ${message}` : `Failed to load ${request.title}: ${message}`;
|
|
|
3823
4867
|
const session = sessions[0];
|
|
3824
4868
|
if (session && shouldAutoActivateSession(session, model, daemon?.pluginsEnabled)) {
|
|
3825
4869
|
activateSession(session);
|
|
3826
|
-
client.
|
|
4870
|
+
client.sessions.get(session.id).catch(() => {});
|
|
3827
4871
|
}
|
|
3828
4872
|
setReady(true);
|
|
3829
4873
|
} catch (error) {
|
|
@@ -3842,36 +4886,46 @@ Refresh failed: ${message}` : `Failed to load ${request.title}: ${message}`;
|
|
|
3842
4886
|
const client = clientRef.current;
|
|
3843
4887
|
if (!client || !activeSessionId)
|
|
3844
4888
|
return;
|
|
3845
|
-
const
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
continue;
|
|
4889
|
+
const generation = ++syncGenerationRef.current;
|
|
4890
|
+
let reconnectNotice = false;
|
|
4891
|
+
const controller = new SessionSyncController({
|
|
4892
|
+
client,
|
|
4893
|
+
sessionId: activeSessionId,
|
|
4894
|
+
generation,
|
|
4895
|
+
onUpdate: (update, gen) => {
|
|
4896
|
+
if (gen !== syncGenerationRef.current)
|
|
4897
|
+
return;
|
|
4898
|
+
if (update.source === "reconnecting") {
|
|
4899
|
+
if (!reconnectNotice) {
|
|
4900
|
+
reconnectNotice = true;
|
|
4901
|
+
pushSystem("reconnecting...");
|
|
3859
4902
|
}
|
|
3860
|
-
|
|
3861
|
-
reconnectNotice = false;
|
|
3862
|
-
commitClientState(update.state, shouldCoalesceClientState(update));
|
|
4903
|
+
return;
|
|
3863
4904
|
}
|
|
3864
|
-
|
|
3865
|
-
|
|
4905
|
+
if (reconnectNotice)
|
|
4906
|
+
reconnectNotice = false;
|
|
4907
|
+
commitClientState(update.state, shouldCoalesceClientState(update));
|
|
4908
|
+
},
|
|
4909
|
+
onError: (error, gen) => {
|
|
4910
|
+
if (gen !== syncGenerationRef.current)
|
|
3866
4911
|
return;
|
|
3867
4912
|
reportError(error instanceof Error ? error.message : String(error));
|
|
3868
4913
|
}
|
|
3869
|
-
})
|
|
4914
|
+
});
|
|
4915
|
+
controller.start();
|
|
3870
4916
|
return () => {
|
|
3871
4917
|
clearPendingClientState();
|
|
3872
4918
|
controller.abort();
|
|
3873
4919
|
};
|
|
3874
|
-
}, [
|
|
4920
|
+
}, [
|
|
4921
|
+
activeSessionId,
|
|
4922
|
+
clearPendingClientState,
|
|
4923
|
+
commitClientState,
|
|
4924
|
+
daemon?.token,
|
|
4925
|
+
daemon?.url,
|
|
4926
|
+
pushSystem,
|
|
4927
|
+
reportError
|
|
4928
|
+
]);
|
|
3875
4929
|
useEffect(() => {
|
|
3876
4930
|
const client = clientRef.current;
|
|
3877
4931
|
const sessionId = activeSessionId;
|
|
@@ -3882,7 +4936,7 @@ Refresh failed: ${message}` : `Failed to load ${request.title}: ${message}`;
|
|
|
3882
4936
|
const controller = new AbortController;
|
|
3883
4937
|
mcpAbortRef.current = controller;
|
|
3884
4938
|
const isCurrent = () => activeSessionIdRef.current === sessionId && auxiliaryGenerationRef.current === generation;
|
|
3885
|
-
client.getSessionMcp(sessionId, { signal: controller.signal }).then((servers) => {
|
|
4939
|
+
client.system.getSessionMcp(sessionId, { signal: controller.signal }).then((servers) => {
|
|
3886
4940
|
if (!isCurrent())
|
|
3887
4941
|
return;
|
|
3888
4942
|
setMcpServers(Array.isArray(servers) ? servers.map(mcpServerSnapshot) : []);
|
|
@@ -3957,7 +5011,7 @@ Refresh failed: ${message}` : `Failed to load ${request.title}: ${message}`;
|
|
|
3957
5011
|
sessionMode: nextSessionModeRef.current,
|
|
3958
5012
|
pluginsEnabled: daemon?.pluginsEnabled
|
|
3959
5013
|
});
|
|
3960
|
-
const session = await client.
|
|
5014
|
+
const session = await client.sessions.create({
|
|
3961
5015
|
cwd,
|
|
3962
5016
|
model,
|
|
3963
5017
|
title: title?.trim() || "TUI",
|
|
@@ -3979,12 +5033,12 @@ Refresh failed: ${message}` : `Failed to load ${request.title}: ${message}`;
|
|
|
3979
5033
|
return;
|
|
3980
5034
|
setLocalBusy(true);
|
|
3981
5035
|
(async () => {
|
|
3982
|
-
const session = activeSessionId ? clientState.sessions[activeSessionId] ?? await client.
|
|
5036
|
+
const session = activeSessionId ? clientState.sessions[activeSessionId] ?? await client.sessions.get(activeSessionId) : await createAndSwitchSession();
|
|
3983
5037
|
if (!session) {
|
|
3984
5038
|
setLocalBusy(false);
|
|
3985
5039
|
return;
|
|
3986
5040
|
}
|
|
3987
|
-
const response = await client.admitPrompt(session.id, {
|
|
5041
|
+
const response = await client.sessions.admitPrompt(session.id, {
|
|
3988
5042
|
id: createPromptRequestId(),
|
|
3989
5043
|
items: [{ type: "text", text: config.initial_prompt }]
|
|
3990
5044
|
});
|
|
@@ -3993,424 +5047,46 @@ Refresh failed: ${message}` : `Failed to load ${request.title}: ${message}`;
|
|
|
3993
5047
|
})().catch((error) => reportError(error instanceof Error ? error.message : String(error)));
|
|
3994
5048
|
}, [activeSessionId, clientState.sessions, config.initial_prompt, createAndSwitchSession, ready, reportError]);
|
|
3995
5049
|
const sendRequest = useCallback((action) => {
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
pushSystem(`Model selected: ${model}`);
|
|
4034
|
-
return;
|
|
4035
|
-
}
|
|
4036
|
-
case "submit_line": {
|
|
4037
|
-
if (!client)
|
|
4038
|
-
return;
|
|
4039
|
-
const line = action.line;
|
|
4040
|
-
const slash = parseSlashLine(line);
|
|
4041
|
-
const newSession = line.match(/^\/new(?:\s+(.+))?$/);
|
|
4042
|
-
if (newSession) {
|
|
4043
|
-
returnToHome(newSession[1]);
|
|
4044
|
-
return;
|
|
4045
|
-
}
|
|
4046
|
-
const switchSession = line.match(/^\/sessions\s+open\s+(.+)$/);
|
|
4047
|
-
if (switchSession?.[1]) {
|
|
4048
|
-
const target = switchSession[1].trim();
|
|
4049
|
-
setLocalBusy(false);
|
|
4050
|
-
setSubmittedRun(null);
|
|
4051
|
-
pendingNewSessionTitleRef.current = undefined;
|
|
4052
|
-
setSelectRequest(null);
|
|
4053
|
-
const knownSession = clientState.sessions[target] ?? listedSessionsRef.current[target];
|
|
4054
|
-
if (knownSession) {
|
|
4055
|
-
activateSession(knownSession);
|
|
4056
|
-
return;
|
|
4057
|
-
}
|
|
4058
|
-
const session = await client.getSession(target);
|
|
4059
|
-
activateSession(session);
|
|
4060
|
-
return;
|
|
4061
|
-
}
|
|
4062
|
-
if (slash?.name === "/resume") {
|
|
4063
|
-
if (!sessionId) {
|
|
4064
|
-
pushSystem("No active session to resume.");
|
|
4065
|
-
return;
|
|
4066
|
-
}
|
|
4067
|
-
const recoverable = recoverableInterruptedRuns(clientState.buckets[sessionId]);
|
|
4068
|
-
if (!slash.args) {
|
|
4069
|
-
if (recoverable.length === 0) {
|
|
4070
|
-
pushSystem("No interrupted prompt runs are available to resume.");
|
|
4071
|
-
return;
|
|
4072
|
-
}
|
|
4073
|
-
clearDisplayRequest();
|
|
4074
|
-
setSelectRequest({
|
|
4075
|
-
title: "Resume interrupted run",
|
|
4076
|
-
submitPrefix: "/resume ",
|
|
4077
|
-
options: recoverable.map((run) => ({
|
|
4078
|
-
value: run.id,
|
|
4079
|
-
label: run.prompt.length > 72 ? `${run.prompt.slice(0, 72)}...` : run.prompt,
|
|
4080
|
-
description: run.error ?? "Interrupted before completion"
|
|
4081
|
-
}))
|
|
4082
|
-
});
|
|
4083
|
-
return;
|
|
4084
|
-
}
|
|
4085
|
-
const runId = slash.args.trim();
|
|
4086
|
-
if (!recoverable.some((run) => run.id === runId)) {
|
|
4087
|
-
pushSystem(`Run is not available for recovery: ${runId}`);
|
|
4088
|
-
return;
|
|
4089
|
-
}
|
|
4090
|
-
setLocalBusy(true);
|
|
4091
|
-
const response = await client.resumeInterruptedRun(sessionId, runId, { id: createPromptRequestId() });
|
|
4092
|
-
setLocalBusy(false);
|
|
4093
|
-
setSubmittedRun(response.run ? { sessionId, runId: response.run.id } : null);
|
|
4094
|
-
setSelectRequest(null);
|
|
4095
|
-
return;
|
|
4096
|
-
}
|
|
4097
|
-
let slashResult;
|
|
4098
|
-
try {
|
|
4099
|
-
slashResult = await dispatchSessionSlashCommand(slash, {
|
|
4100
|
-
client,
|
|
4101
|
-
sessionId,
|
|
4102
|
-
pushSystem,
|
|
4103
|
-
presentSystem: (title, content) => showDisplayRequest({ title, content }),
|
|
4104
|
-
statusRef,
|
|
4105
|
-
commandCatalogRef,
|
|
4106
|
-
clientState,
|
|
4107
|
-
localBusy,
|
|
4108
|
-
cacheFirstRead,
|
|
4109
|
-
daemon,
|
|
4110
|
-
setStatus: setStatusAndDefault
|
|
4111
|
-
});
|
|
4112
|
-
} catch (error) {
|
|
4113
|
-
if (slash && JOBS_AUXILIARY_SLASH_COMMANDS.has(slash.name)) {
|
|
4114
|
-
reportAuxiliaryError("Jobs", error);
|
|
4115
|
-
return;
|
|
4116
|
-
}
|
|
4117
|
-
throw error;
|
|
4118
|
-
}
|
|
4119
|
-
if (slashResult === "handled") {
|
|
4120
|
-
if (slash?.name === "/background" && slash.args.trim() && sessionId) {
|
|
4121
|
-
await refreshJobs();
|
|
4122
|
-
}
|
|
4123
|
-
return;
|
|
4124
|
-
}
|
|
4125
|
-
if (slashResult === "local_ui_ignored")
|
|
4126
|
-
return;
|
|
4127
|
-
if (slash) {
|
|
4128
|
-
const catalogEntry = commandCatalogRef.current.find((entry) => entry.name === slash.name);
|
|
4129
|
-
if (catalogEntry?.kind === "template") {
|
|
4130
|
-
if (!sessionId)
|
|
4131
|
-
return;
|
|
4132
|
-
setLocalBusy(true);
|
|
4133
|
-
const response = await client.admitPrompt(sessionId, {
|
|
4134
|
-
id: createPromptRequestId(),
|
|
4135
|
-
items: [
|
|
4136
|
-
{
|
|
4137
|
-
type: "skill",
|
|
4138
|
-
name: catalogEntry.skillName,
|
|
4139
|
-
path: catalogEntry.path,
|
|
4140
|
-
...catalogEntry.displayName ? { displayName: catalogEntry.displayName } : {},
|
|
4141
|
-
...catalogEntry.source && catalogEntry.source !== "builtin" ? { source: catalogEntry.source } : {}
|
|
4142
|
-
},
|
|
4143
|
-
...slash.args ? [{ type: "text", text: ` ${slash.args}` }] : []
|
|
4144
|
-
]
|
|
4145
|
-
});
|
|
4146
|
-
setLocalBusy(false);
|
|
4147
|
-
setSubmittedRun(response.run ? { sessionId, runId: response.run.id } : null);
|
|
4148
|
-
return;
|
|
4149
|
-
}
|
|
4150
|
-
pushSystem(`Unknown command: ${slash.name}`);
|
|
4151
|
-
return;
|
|
4152
|
-
}
|
|
4153
|
-
if (!sessionId) {
|
|
4154
|
-
const session = await createAndSwitchSession(pendingNewSessionTitleRef.current);
|
|
4155
|
-
if (!session)
|
|
4156
|
-
return;
|
|
4157
|
-
sessionId = session.id;
|
|
4158
|
-
}
|
|
4159
|
-
setLocalBusy(true);
|
|
4160
|
-
const response = await client.admitPrompt(sessionId, {
|
|
4161
|
-
id: createPromptRequestId(),
|
|
4162
|
-
items: [{ type: "text", text: line }]
|
|
4163
|
-
});
|
|
4164
|
-
setLocalBusy(false);
|
|
4165
|
-
setSubmittedRun(response.run ? { sessionId, runId: response.run.id } : null);
|
|
4166
|
-
return;
|
|
4167
|
-
}
|
|
4168
|
-
case "delete_session": {
|
|
4169
|
-
if (!client)
|
|
4170
|
-
return;
|
|
4171
|
-
const target = action.session_id;
|
|
4172
|
-
if (!target)
|
|
4173
|
-
return;
|
|
4174
|
-
const archived = await client.archiveSession(target);
|
|
4175
|
-
const archivedAt = archived.archivedAt ?? Date.now();
|
|
4176
|
-
delete listedSessionsRef.current[target];
|
|
4177
|
-
setClientState((current) => archiveClientSession(current, target, archivedAt));
|
|
4178
|
-
setLocalBusy(false);
|
|
4179
|
-
setSubmittedRun(null);
|
|
4180
|
-
setSelectRequest((current) => current ? {
|
|
4181
|
-
...current,
|
|
4182
|
-
options: current.options.filter((option) => option.value !== target)
|
|
4183
|
-
} : current);
|
|
4184
|
-
if (target === activeSessionIdRef.current) {
|
|
4185
|
-
const remaining = listTopLevelSessions(Object.values({
|
|
4186
|
-
...clientState.sessions,
|
|
4187
|
-
...listedSessionsRef.current,
|
|
4188
|
-
[target]: { ...archived, status: "archived", archivedAt }
|
|
4189
|
-
}));
|
|
4190
|
-
if (remaining[0]) {
|
|
4191
|
-
activateSession(remaining[0]);
|
|
4192
|
-
} else {
|
|
4193
|
-
const sessions = await client.listSessions({
|
|
4194
|
-
cwd: daemon?.cwd ?? undefined,
|
|
4195
|
-
includeArchived: false,
|
|
4196
|
-
limit: 20
|
|
4197
|
-
});
|
|
4198
|
-
listedSessionsRef.current = Object.fromEntries(sessions.map((session) => [session.id, session]));
|
|
4199
|
-
const remoteNext = sessions.find((session) => session.id !== target);
|
|
4200
|
-
if (remoteNext)
|
|
4201
|
-
activateSession(remoteNext);
|
|
4202
|
-
else
|
|
4203
|
-
returnToHome();
|
|
4204
|
-
}
|
|
4205
|
-
}
|
|
4206
|
-
return;
|
|
4207
|
-
}
|
|
4208
|
-
case "interrupt": {
|
|
4209
|
-
if (!client)
|
|
4210
|
-
return;
|
|
4211
|
-
if (sessionId)
|
|
4212
|
-
await client.interruptSession(sessionId);
|
|
4213
|
-
setLocalBusy(false);
|
|
4214
|
-
setSubmittedRun(null);
|
|
4215
|
-
return;
|
|
4216
|
-
}
|
|
4217
|
-
case "permission_response": {
|
|
4218
|
-
if (!client)
|
|
4219
|
-
return;
|
|
4220
|
-
const requestId = action.request_id;
|
|
4221
|
-
const allowed = action.allowed;
|
|
4222
|
-
await client.replyPermission(requestId, {
|
|
4223
|
-
status: allowed ? "approved" : "denied",
|
|
4224
|
-
decision: action.scope === "session" ? "session" : "once",
|
|
4225
|
-
clientId: "tui"
|
|
4226
|
-
});
|
|
4227
|
-
setModal(null);
|
|
4228
|
-
return;
|
|
4229
|
-
}
|
|
4230
|
-
case "list_sessions": {
|
|
4231
|
-
if (!client)
|
|
4232
|
-
return;
|
|
4233
|
-
const cachedSessions = {
|
|
4234
|
-
...listedSessionsRef.current,
|
|
4235
|
-
...clientState.sessions
|
|
4236
|
-
};
|
|
4237
|
-
const cachedOptions = sessionSelectOptions(Object.values(cachedSessions), activeSessionIdRef.current);
|
|
4238
|
-
clearDisplayRequest();
|
|
4239
|
-
setSelectRequest({
|
|
4240
|
-
title: "Sessions",
|
|
4241
|
-
submitPrefix: "/sessions open ",
|
|
4242
|
-
options: cachedOptions
|
|
4243
|
-
});
|
|
4244
|
-
const sessions = await client.listSessions({
|
|
4245
|
-
cwd: daemon?.cwd ?? undefined,
|
|
4246
|
-
includeArchived: false,
|
|
4247
|
-
limit: 20
|
|
4248
|
-
});
|
|
4249
|
-
listedSessionsRef.current = Object.fromEntries(sessions.map((session) => [session.id, session]));
|
|
4250
|
-
setSelectRequest((current) => current?.submitPrefix === "/sessions open " ? {
|
|
4251
|
-
title: "Sessions",
|
|
4252
|
-
submitPrefix: "/sessions open ",
|
|
4253
|
-
options: sessionSelectOptions(sessions, activeSessionIdRef.current)
|
|
4254
|
-
} : current);
|
|
4255
|
-
return;
|
|
4256
|
-
}
|
|
4257
|
-
case "set_permission_mode": {
|
|
4258
|
-
if (!client)
|
|
4259
|
-
return;
|
|
4260
|
-
const mode = action.permission_mode;
|
|
4261
|
-
setStatus((current) => ({ ...current, permission_mode: mode }));
|
|
4262
|
-
if (sessionId) {
|
|
4263
|
-
await client.updateSession(sessionId, {
|
|
4264
|
-
metadata: patchSessionRuntimeMetadata({}, { permissionMode: mode })
|
|
4265
|
-
});
|
|
4266
|
-
}
|
|
4267
|
-
return;
|
|
4268
|
-
}
|
|
4269
|
-
case "question_response": {
|
|
4270
|
-
if (!client)
|
|
4271
|
-
return;
|
|
4272
|
-
reportError("Interactive question responses are not available through the daemon client.");
|
|
4273
|
-
return;
|
|
4274
|
-
}
|
|
4275
|
-
case "set_session_mode": {
|
|
4276
|
-
if (!client)
|
|
4277
|
-
return;
|
|
4278
|
-
if (sessionId) {
|
|
4279
|
-
pushSystem("Coordinator mode can only be changed before starting a new session. Use /new first.");
|
|
4280
|
-
return;
|
|
4281
|
-
}
|
|
4282
|
-
const mode = normalizeSessionMode(action.session_mode);
|
|
4283
|
-
nextSessionModeRef.current = statusSessionMode(mode);
|
|
4284
|
-
setStatus((current) => ({
|
|
4285
|
-
...current,
|
|
4286
|
-
session_mode: nextSessionModeRef.current
|
|
4287
|
-
}));
|
|
4288
|
-
return;
|
|
4289
|
-
}
|
|
4290
|
-
case "job_request": {
|
|
4291
|
-
if (!client) {
|
|
4292
|
-
reportAuxiliaryError("Jobs", "The daemon client is not connected.");
|
|
4293
|
-
return;
|
|
4294
|
-
}
|
|
4295
|
-
const currentSessionId = activeSessionIdRef.current;
|
|
4296
|
-
if (!currentSessionId)
|
|
4297
|
-
return;
|
|
4298
|
-
try {
|
|
4299
|
-
switch (action.job_action) {
|
|
4300
|
-
case "open":
|
|
4301
|
-
await refreshJobs();
|
|
4302
|
-
return;
|
|
4303
|
-
case "refresh": {
|
|
4304
|
-
jobControlGenerationRef.current += 1;
|
|
4305
|
-
jobControlAbortRef.current?.abort();
|
|
4306
|
-
jobControlAbortRef.current = null;
|
|
4307
|
-
const detail = jobDetailStateRef.current;
|
|
4308
|
-
const detailJobId = detail.status === "idle" ? undefined : detail.jobId;
|
|
4309
|
-
await Promise.all([
|
|
4310
|
-
refreshJobs(),
|
|
4311
|
-
detailJobId ? loadJobDetail(client, currentSessionId, detailJobId) : Promise.resolve()
|
|
4312
|
-
]);
|
|
4313
|
-
return;
|
|
4314
|
-
}
|
|
4315
|
-
case "select":
|
|
4316
|
-
jobControlGenerationRef.current += 1;
|
|
4317
|
-
jobControlAbortRef.current?.abort();
|
|
4318
|
-
jobControlAbortRef.current = null;
|
|
4319
|
-
await loadJobDetail(client, currentSessionId, action.job_id);
|
|
4320
|
-
return;
|
|
4321
|
-
case "cancel": {
|
|
4322
|
-
const controlGeneration = ++jobControlGenerationRef.current;
|
|
4323
|
-
const detailGeneration = jobDetailGenerationRef.current;
|
|
4324
|
-
jobControlAbortRef.current?.abort();
|
|
4325
|
-
const controller = new AbortController;
|
|
4326
|
-
jobControlAbortRef.current = controller;
|
|
4327
|
-
let response;
|
|
4328
|
-
try {
|
|
4329
|
-
response = await client.cancelJob(action.job_id, {
|
|
4330
|
-
sessionId: currentSessionId,
|
|
4331
|
-
reason: action.reason
|
|
4332
|
-
}, { signal: controller.signal });
|
|
4333
|
-
} catch (error) {
|
|
4334
|
-
if (activeSessionIdRef.current !== currentSessionId)
|
|
4335
|
-
return;
|
|
4336
|
-
if (controller.signal.aborted || jobControlGenerationRef.current !== controlGeneration) {
|
|
4337
|
-
await refreshJobs();
|
|
4338
|
-
return;
|
|
4339
|
-
}
|
|
4340
|
-
throw error;
|
|
4341
|
-
} finally {
|
|
4342
|
-
if (jobControlAbortRef.current === controller)
|
|
4343
|
-
jobControlAbortRef.current = null;
|
|
4344
|
-
}
|
|
4345
|
-
if (activeSessionIdRef.current !== currentSessionId)
|
|
4346
|
-
return;
|
|
4347
|
-
const ownsDetail = !controller.signal.aborted && jobControlGenerationRef.current === controlGeneration && jobDetailGenerationRef.current === detailGeneration;
|
|
4348
|
-
const validated = validateJobSnapshot(response, currentSessionId, action.job_id);
|
|
4349
|
-
if (!validated.snapshot) {
|
|
4350
|
-
if (controller.signal.aborted || jobControlGenerationRef.current !== controlGeneration) {
|
|
4351
|
-
await refreshJobs();
|
|
4352
|
-
return;
|
|
4353
|
-
}
|
|
4354
|
-
throw new Error(validated.error ?? "Job snapshot has invalid fields.");
|
|
4355
|
-
}
|
|
4356
|
-
const snapshot = validated.snapshot;
|
|
4357
|
-
const next = mergeJobSnapshot(jobStateRef.current, snapshot, Date.now());
|
|
4358
|
-
jobStateRef.current = next;
|
|
4359
|
-
setJobState(next);
|
|
4360
|
-
if (ownsDetail) {
|
|
4361
|
-
await loadJobDetail(client, currentSessionId, action.job_id);
|
|
4362
|
-
}
|
|
4363
|
-
await refreshJobs();
|
|
4364
|
-
return;
|
|
4365
|
-
}
|
|
4366
|
-
case "send": {
|
|
4367
|
-
const controlGeneration = ++jobControlGenerationRef.current;
|
|
4368
|
-
const detailGeneration = jobDetailGenerationRef.current;
|
|
4369
|
-
jobControlAbortRef.current?.abort();
|
|
4370
|
-
const controller = new AbortController;
|
|
4371
|
-
jobControlAbortRef.current = controller;
|
|
4372
|
-
try {
|
|
4373
|
-
await client.sendJob(action.job_id, {
|
|
4374
|
-
sessionId: currentSessionId,
|
|
4375
|
-
data: action.data
|
|
4376
|
-
}, { signal: controller.signal });
|
|
4377
|
-
} catch (error) {
|
|
4378
|
-
if (activeSessionIdRef.current !== currentSessionId)
|
|
4379
|
-
return;
|
|
4380
|
-
if (controller.signal.aborted || jobControlGenerationRef.current !== controlGeneration) {
|
|
4381
|
-
await refreshJobs();
|
|
4382
|
-
return;
|
|
4383
|
-
}
|
|
4384
|
-
throw error;
|
|
4385
|
-
} finally {
|
|
4386
|
-
if (jobControlAbortRef.current === controller)
|
|
4387
|
-
jobControlAbortRef.current = null;
|
|
4388
|
-
}
|
|
4389
|
-
if (activeSessionIdRef.current !== currentSessionId)
|
|
4390
|
-
return;
|
|
4391
|
-
const ownsDetail = !controller.signal.aborted && jobControlGenerationRef.current === controlGeneration && jobDetailGenerationRef.current === detailGeneration;
|
|
4392
|
-
if (ownsDetail) {
|
|
4393
|
-
await loadJobDetail(client, currentSessionId, action.job_id);
|
|
4394
|
-
}
|
|
4395
|
-
await refreshJobs();
|
|
4396
|
-
return;
|
|
4397
|
-
}
|
|
4398
|
-
}
|
|
4399
|
-
} catch (error) {
|
|
4400
|
-
reportAuxiliaryError("Jobs", error);
|
|
4401
|
-
return;
|
|
4402
|
-
}
|
|
4403
|
-
}
|
|
4404
|
-
default: {
|
|
4405
|
-
const exhaustive = action;
|
|
4406
|
-
reportError(`Unsupported TUI action: ${runtimeType}`);
|
|
4407
|
-
return;
|
|
4408
|
-
}
|
|
4409
|
-
}
|
|
4410
|
-
})().catch((error) => {
|
|
5050
|
+
executeTuiAction(action, {
|
|
5051
|
+
clientRef,
|
|
5052
|
+
activeSessionIdRef,
|
|
5053
|
+
clientState,
|
|
5054
|
+
setClientState,
|
|
5055
|
+
daemon,
|
|
5056
|
+
defaultRuntimeRef,
|
|
5057
|
+
nextSessionModeRef,
|
|
5058
|
+
statusRef,
|
|
5059
|
+
setStatus,
|
|
5060
|
+
setStatusAndDefault,
|
|
5061
|
+
listedSessionsRef,
|
|
5062
|
+
commandCatalogRef,
|
|
5063
|
+
pendingNewSessionTitleRef,
|
|
5064
|
+
localBusy,
|
|
5065
|
+
setLocalBusy,
|
|
5066
|
+
setSubmittedRun,
|
|
5067
|
+
setModal,
|
|
5068
|
+
setSelectRequest,
|
|
5069
|
+
clearDisplayRequest,
|
|
5070
|
+
showDisplayRequest,
|
|
5071
|
+
pushSystem,
|
|
5072
|
+
reportError,
|
|
5073
|
+
reportAuxiliaryError,
|
|
5074
|
+
activateSession,
|
|
5075
|
+
returnToHome,
|
|
5076
|
+
refreshJobs,
|
|
5077
|
+
loadJobDetail,
|
|
5078
|
+
createAndSwitchSession,
|
|
5079
|
+
cacheFirstRead,
|
|
5080
|
+
jobStateRef,
|
|
5081
|
+
setJobState,
|
|
5082
|
+
jobDetailStateRef,
|
|
5083
|
+
jobControlGenerationRef,
|
|
5084
|
+
jobDetailGenerationRef,
|
|
5085
|
+
jobControlAbortRef
|
|
5086
|
+
}).catch((error) => {
|
|
4411
5087
|
reportError(error instanceof Error ? error.message : String(error));
|
|
4412
5088
|
});
|
|
4413
|
-
}, [
|
|
5089
|
+
}, [activateSession, cacheFirstRead, clearDisplayRequest, clientState, createAndSwitchSession, daemon, loadJobDetail, localBusy, pushSystem, refreshJobs, reportAuxiliaryError, reportError, returnToHome, setStatusAndDefault, showDisplayRequest]);
|
|
4414
5090
|
const bucket = activeSessionId ? clientState.buckets[activeSessionId] : undefined;
|
|
4415
5091
|
const recoveryItems = useMemo(() => recoverableInterruptedRuns(bucket).map((run) => ({
|
|
4416
5092
|
id: `recovery:${run.id}`,
|
|
@@ -4452,19 +5128,14 @@ Use /resume ${run.id} to replay its original prompt.`
|
|
|
4452
5128
|
sendRequest
|
|
4453
5129
|
}), [commandDetails, commands, displayRequest, jobDetailState, jobState, loadModels, localBusy, mcpServers, modal, ready, running, selectRequest, sendRequest, status, transcriptView, waitingForSubmittedRun]);
|
|
4454
5130
|
}
|
|
4455
|
-
var
|
|
5131
|
+
var LIVE_TEXT_DELTA_FLUSH_MS = 33, PRESENTATION_LOADING_TEXT = "Loading...";
|
|
4456
5132
|
var init_useServerSync = __esm(() => {
|
|
4457
5133
|
init_src2();
|
|
4458
5134
|
init_job_remote_state();
|
|
4459
5135
|
init_transcript();
|
|
4460
5136
|
init_sessionSlashCommands();
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
"/background",
|
|
4464
|
-
"/doctor",
|
|
4465
|
-
"/jobs",
|
|
4466
|
-
"/stats"
|
|
4467
|
-
]);
|
|
5137
|
+
init_sync_submodules();
|
|
5138
|
+
init_sync_submodules();
|
|
4468
5139
|
});
|
|
4469
5140
|
|
|
4470
5141
|
// ../frontend/src/ui/constants.ts
|
|
@@ -8167,4 +8838,4 @@ try {
|
|
|
8167
8838
|
process.exit(1);
|
|
8168
8839
|
}
|
|
8169
8840
|
|
|
8170
|
-
//# debugId=
|
|
8841
|
+
//# debugId=9F3BE548A8F89F3864756E2164756E21
|