@gajae-code/coding-agent 0.15.6 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +59 -0
- package/dist/types/cli/args.d.ts +2 -0
- package/dist/types/cli/root-flags.d.ts +14 -0
- package/dist/types/cli/update-cli.d.ts +13 -0
- package/dist/types/cli.d.ts +7 -0
- package/dist/types/commands/launch.d.ts +10 -0
- package/dist/types/config/autorouting-tier-map.d.ts +24 -0
- package/dist/types/config/file-lock.d.ts +5 -0
- package/dist/types/config/model-registry.d.ts +6 -0
- package/dist/types/config/settings-schema.d.ts +10 -1
- package/dist/types/config/settings.d.ts +2 -0
- package/dist/types/coordinator-mcp/projection-scan.d.ts +8 -0
- package/dist/types/crash/record-loader.d.ts +15 -0
- package/dist/types/gjc-runtime/launch-worktree-reservation.d.ts +21 -0
- package/dist/types/gjc-runtime/managed-owner-supervisor.d.ts +2 -0
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +66 -1
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +1 -0
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +27 -0
- package/dist/types/master-mode/context.d.ts +21 -0
- package/dist/types/master-mode/first-request.d.ts +34 -0
- package/dist/types/master-mode/snapshot.d.ts +32 -0
- package/dist/types/modes/components/frictionless-onboarding-selector.d.ts +10 -0
- package/dist/types/modes/components/oauth-selector.d.ts +1 -0
- package/dist/types/modes/components/status-line/model-name.d.ts +18 -0
- package/dist/types/modes/components/status-line/priority-row.d.ts +34 -0
- package/dist/types/modes/components/status-line/segments.d.ts +10 -0
- package/dist/types/modes/print-mode.d.ts +17 -0
- package/dist/types/modes/ui-language.d.ts +7 -1
- package/dist/types/sdk/broker/broker.d.ts +77 -1
- package/dist/types/sdk/broker/endpoint-authority.d.ts +24 -0
- package/dist/types/sdk/broker/index.d.ts +3 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +26 -0
- package/dist/types/sdk/broker/master-capability.d.ts +10 -0
- package/dist/types/sdk/broker/session-index.d.ts +40 -11
- package/dist/types/sdk/broker/session-scope.d.ts +72 -0
- package/dist/types/sdk/broker/spawn-authority.d.ts +201 -0
- package/dist/types/sdk/broker/spawn-substrate.d.ts +30 -0
- package/dist/types/sdk/broker/state-version.d.ts +4 -1
- package/dist/types/sdk/broker/worktree-occupancy.d.ts +28 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +3 -0
- package/dist/types/sdk/bus/index.d.ts +6 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
- package/dist/types/sdk/cli/index.d.ts +1 -0
- package/dist/types/sdk/cli/master-cli.d.ts +63 -0
- package/dist/types/sdk/cli/rows.d.ts +4 -3
- package/dist/types/sdk/cli/session-cli.d.ts +18 -2
- package/dist/types/sdk/client/client.d.ts +3 -2
- package/dist/types/sdk/host/control/dispatch.d.ts +10 -0
- package/dist/types/sdk/host/control/index.d.ts +1 -1
- package/dist/types/sdk/host/control/operations.d.ts +2 -0
- package/dist/types/sdk/host/control/runtime-gate.d.ts +21 -7
- package/dist/types/sdk/host/host.d.ts +10 -0
- package/dist/types/sdk/host/session-runtime.d.ts +52 -0
- package/dist/types/sdk/lifecycle/broker-client.d.ts +6 -0
- package/dist/types/sdk/lifecycle/service.d.ts +15 -3
- package/dist/types/sdk/lifecycle-session.d.ts +2 -0
- package/dist/types/sdk/router/session-router.d.ts +2 -0
- package/dist/types/sdk/session.d.ts +16 -0
- package/dist/types/sdk/startup-capability.d.ts +2 -1
- package/dist/types/session/agent-session.d.ts +5 -0
- package/dist/types/session/credential-store-errors.d.ts +1 -0
- package/dist/types/session/session-manager.d.ts +65 -0
- package/dist/types/session/yield-queue.d.ts +5 -4
- package/dist/types/setup/frictionless-onboarding.d.ts +1 -0
- package/dist/types/tools/bash.d.ts +4 -0
- package/dist/types/tools/gh.d.ts +8 -0
- package/dist/types/tools/index.d.ts +4 -0
- package/package.json +7 -7
- package/scripts/generate-sdk-operation-inventory.ts +6 -0
- package/scripts/verify-gjc-sdk-canonicalization.ts +35 -1
- package/src/cli/accounts-cli.ts +9 -5
- package/src/cli/args.ts +17 -0
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/root-flags.ts +5 -0
- package/src/cli/update-cli.ts +77 -11
- package/src/commands/launch.ts +86 -18
- package/src/commands/sdk.ts +113 -21
- package/src/config/autorouting-tier-map.ts +12 -0
- package/src/config/file-lock.ts +158 -83
- package/src/config/model-preset-registry.ts +1 -5
- package/src/config/model-profiles.ts +5 -5
- package/src/config/model-registry.ts +23 -0
- package/src/config/model-resolver.ts +5 -0
- package/src/config/settings-schema.ts +8 -1
- package/src/config/settings.ts +5 -0
- package/src/coordinator-mcp/projection-scan.ts +21 -0
- package/src/coordinator-mcp/question-state.ts +9 -11
- package/src/coordinator-mcp/server.ts +94 -20
- package/src/crash/index-store.ts +2 -0
- package/src/crash/record-loader.ts +10 -0
- package/src/gjc-runtime/launch-worktree-reservation.ts +242 -0
- package/src/gjc-runtime/managed-owner-supervisor.ts +63 -51
- package/src/gjc-runtime/session-state-lock.ts +79 -6
- package/src/gjc-runtime/session-state-sidecar.ts +929 -23
- package/src/gjc-runtime/tmux-owner-isolation-cli.ts +4 -7
- package/src/gjc-runtime/tmux-owner-isolation.ts +2 -2
- package/src/gjc-runtime/tmux-sessions.ts +252 -13
- package/src/hooks/skill-state.ts +6 -0
- package/src/internal-urls/docs-index.generated.ts +7 -7
- package/src/internal-urls/issue-pr-protocol.ts +4 -2
- package/src/main.ts +57 -2
- package/src/master-mode/context.ts +50 -0
- package/src/master-mode/first-request.ts +65 -0
- package/src/master-mode/snapshot.ts +205 -0
- package/src/modes/acp/acp-agent.ts +605 -156
- package/src/modes/components/footer.ts +4 -2
- package/src/modes/components/frictionless-onboarding-selector.ts +48 -2
- package/src/modes/components/oauth-selector.ts +6 -1
- package/src/modes/components/settings-selector.ts +1 -0
- package/src/modes/components/status-line/model-name.ts +53 -0
- package/src/modes/components/status-line/priority-row.ts +107 -0
- package/src/modes/components/status-line/segments.ts +23 -9
- package/src/modes/components/tool-status-header.ts +151 -15
- package/src/modes/controllers/input-controller.ts +28 -0
- package/src/modes/controllers/selector-controller.ts +191 -96
- package/src/modes/print-mode.ts +64 -0
- package/src/modes/ui-language.ts +49 -2
- package/src/prompts/system/master-mode.md +28 -0
- package/src/sdk/broker/broker.ts +1636 -26
- package/src/sdk/broker/endpoint-authority.ts +86 -0
- package/src/sdk/broker/ensure.ts +5 -0
- package/src/sdk/broker/index.ts +3 -0
- package/src/sdk/broker/lifecycle.ts +186 -41
- package/src/sdk/broker/master-capability.ts +232 -0
- package/src/sdk/broker/session-index.ts +121 -17
- package/src/sdk/broker/session-scope.ts +272 -0
- package/src/sdk/broker/spawn-authority.ts +1031 -0
- package/src/sdk/broker/spawn-substrate.ts +548 -0
- package/src/sdk/broker/state-version.ts +26 -14
- package/src/sdk/broker/transport.ts +1 -0
- package/src/sdk/broker/worktree-occupancy.ts +90 -0
- package/src/sdk/bus/chat-daemon-control.ts +5 -2
- package/src/sdk/bus/chat-daemon-runtime.ts +35 -4
- package/src/sdk/bus/index.ts +51 -4
- package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
- package/src/sdk/cli/index.ts +1 -0
- package/src/sdk/cli/master-cli.ts +259 -0
- package/src/sdk/cli/rows.ts +11 -8
- package/src/sdk/cli/session-cli.ts +264 -5
- package/src/sdk/client/client.ts +14 -8
- package/src/sdk/host/control/dispatch.ts +99 -38
- package/src/sdk/host/control/index.ts +2 -0
- package/src/sdk/host/control/operations.ts +2 -0
- package/src/sdk/host/control/runtime-gate.ts +203 -11
- package/src/sdk/host/host.ts +27 -2
- package/src/sdk/host/session-runtime.test.ts +210 -6
- package/src/sdk/host/session-runtime.ts +291 -49
- package/src/sdk/lifecycle/broker-client.ts +28 -0
- package/src/sdk/lifecycle/service.ts +279 -20
- package/src/sdk/lifecycle-session.ts +10 -2
- package/src/sdk/protocol/operation-inventory.generated.json +51 -0
- package/src/sdk/protocol/operation-registry.ts +13 -3
- package/src/sdk/router/session-router.ts +67 -59
- package/src/sdk/session.ts +357 -155
- package/src/sdk/startup-capability.ts +1 -0
- package/src/session/agent-session.ts +640 -103
- package/src/session/blob-store.ts +15 -5
- package/src/session/credential-store-errors.ts +2 -0
- package/src/session/internal/managed-session-storage.ts +153 -78
- package/src/session/session-manager.ts +337 -24
- package/src/session/yield-queue.ts +24 -10
- package/src/setup/frictionless-onboarding.ts +2 -0
- package/src/telemetry/events.ts +1138 -12
- package/src/tools/bash.ts +256 -42
- package/src/tools/gh.ts +104 -48
- package/src/tools/github-cache.ts +2 -2
- package/src/tools/index.ts +4 -0
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
resolvedScopeV1,
|
|
5
|
+
resolveScopeRequest,
|
|
6
|
+
type ScopeRequestV1,
|
|
7
|
+
type SdkSearchResultV1,
|
|
8
|
+
type SdkSearchRowV1,
|
|
9
|
+
scopeRequestV1,
|
|
10
|
+
searchRowV1,
|
|
11
|
+
} from "../broker/session-scope";
|
|
3
12
|
import {
|
|
4
13
|
SessionListTraversalError,
|
|
5
14
|
type SessionListTraversalPage,
|
|
@@ -141,6 +150,9 @@ export interface SessionDeleteTarget {
|
|
|
141
150
|
export interface SessionListTarget {
|
|
142
151
|
readonly cwd?: string;
|
|
143
152
|
readonly resolveSessionId?: string;
|
|
153
|
+
readonly scope?: ScopeRequestV1;
|
|
154
|
+
readonly limit?: number;
|
|
155
|
+
readonly cursor?: string;
|
|
144
156
|
}
|
|
145
157
|
|
|
146
158
|
interface SessionLifecycleMutationRequestBase<
|
|
@@ -197,7 +209,8 @@ export interface SessionLifecycleListEntry {
|
|
|
197
209
|
readonly live?: boolean;
|
|
198
210
|
readonly endpointGeneration?: number;
|
|
199
211
|
readonly terminalUncertain?: boolean;
|
|
200
|
-
readonly
|
|
212
|
+
readonly cwd?: string;
|
|
213
|
+
readonly locator?: { readonly cwd: string; readonly worktreeRoot: string | null; readonly stateRoot: string };
|
|
201
214
|
}
|
|
202
215
|
|
|
203
216
|
export interface SessionLifecycleListResult {
|
|
@@ -207,6 +220,8 @@ export interface SessionLifecycleListResult {
|
|
|
207
220
|
readonly savedSession?: SessionLifecycleSavedSession;
|
|
208
221
|
}
|
|
209
222
|
|
|
223
|
+
export type SessionScopedListResult = SdkSearchResultV1;
|
|
224
|
+
|
|
210
225
|
export interface SessionCreateResult {
|
|
211
226
|
readonly ok: true;
|
|
212
227
|
readonly operation: "session.create";
|
|
@@ -240,7 +255,7 @@ export interface SessionReconcileUncertainResult {
|
|
|
240
255
|
export interface SessionListSuccessResult {
|
|
241
256
|
readonly ok: true;
|
|
242
257
|
readonly operation: "session.list";
|
|
243
|
-
readonly result: SessionLifecycleListResult;
|
|
258
|
+
readonly result: SessionLifecycleListResult | SessionScopedListResult;
|
|
244
259
|
}
|
|
245
260
|
|
|
246
261
|
export interface SessionLifecycleError {
|
|
@@ -289,6 +304,7 @@ export type SessionListFailure = {
|
|
|
289
304
|
readonly operation: "session.list";
|
|
290
305
|
readonly certainty: SessionLifecycleCertainty;
|
|
291
306
|
readonly error: SessionLifecycleError;
|
|
307
|
+
readonly result?: SessionScopedListResult;
|
|
292
308
|
};
|
|
293
309
|
|
|
294
310
|
export type SessionCreateOutcome = SessionCreateResult | SessionCreateFailure;
|
|
@@ -582,12 +598,24 @@ function listResult(value: unknown): SessionLifecycleListResult | undefined {
|
|
|
582
598
|
live?: boolean;
|
|
583
599
|
endpointGeneration?: number;
|
|
584
600
|
terminalUncertain?: boolean;
|
|
585
|
-
|
|
601
|
+
cwd?: string;
|
|
602
|
+
locator?: { cwd: string; worktreeRoot: string | null; stateRoot: string };
|
|
586
603
|
} = { sessionId: entry.sessionId };
|
|
587
604
|
if (typeof entry.live === "boolean") item.live = entry.live;
|
|
588
605
|
if (typeof entry.endpointGeneration === "number") item.endpointGeneration = entry.endpointGeneration;
|
|
589
606
|
if (typeof entry.terminalUncertain === "boolean") item.terminalUncertain = entry.terminalUncertain;
|
|
590
|
-
if (isRecord(entry.locator) && typeof entry.locator.
|
|
607
|
+
if (isRecord(entry.locator) && typeof entry.locator.cwd === "string") item.cwd = entry.locator.cwd;
|
|
608
|
+
if (
|
|
609
|
+
isRecord(entry.locator) &&
|
|
610
|
+
typeof entry.locator.cwd === "string" &&
|
|
611
|
+
(entry.locator.worktreeRoot === null || typeof entry.locator.worktreeRoot === "string") &&
|
|
612
|
+
typeof entry.locator.stateRoot === "string"
|
|
613
|
+
)
|
|
614
|
+
item.locator = {
|
|
615
|
+
cwd: entry.locator.cwd,
|
|
616
|
+
worktreeRoot: entry.locator.worktreeRoot,
|
|
617
|
+
stateRoot: entry.locator.stateRoot,
|
|
618
|
+
};
|
|
591
619
|
sessions.push(item);
|
|
592
620
|
}
|
|
593
621
|
const warnings: string[] = [];
|
|
@@ -600,10 +628,40 @@ function listResult(value: unknown): SessionLifecycleListResult | undefined {
|
|
|
600
628
|
if (savedSessionPresent && !savedSession) return undefined;
|
|
601
629
|
return { indexSeq, sessions, warnings, ...(savedSession ? { savedSession } : {}) };
|
|
602
630
|
}
|
|
631
|
+
|
|
632
|
+
function scopedPage(value: unknown): { scope: SdkSearchResultV1["scope"]; observedAt: string } | undefined {
|
|
633
|
+
if (!isRecord(value)) return undefined;
|
|
634
|
+
const scope = resolvedScopeV1(value.scope);
|
|
635
|
+
return scope && typeof value.observedAt === "string" ? { scope, observedAt: value.observedAt } : undefined;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
function scopedSearchRows(sessions: readonly SessionLifecycleListEntry[]): SdkSearchRowV1[] | undefined {
|
|
639
|
+
const rows: SdkSearchRowV1[] = [];
|
|
640
|
+
for (const session of sessions) {
|
|
641
|
+
const locator = session.locator;
|
|
642
|
+
if (
|
|
643
|
+
locator === undefined ||
|
|
644
|
+
typeof locator.cwd !== "string" ||
|
|
645
|
+
(locator.worktreeRoot !== null && typeof locator.worktreeRoot !== "string") ||
|
|
646
|
+
typeof locator.stateRoot !== "string"
|
|
647
|
+
)
|
|
648
|
+
return undefined;
|
|
649
|
+
rows.push(
|
|
650
|
+
searchRowV1({
|
|
651
|
+
sessionId: session.sessionId,
|
|
652
|
+
locator: { cwd: locator.cwd, worktreeRoot: locator.worktreeRoot, stateRoot: locator.stateRoot },
|
|
653
|
+
live: session.live === true,
|
|
654
|
+
}),
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
return rows;
|
|
658
|
+
}
|
|
603
659
|
type LifecycleListPage = {
|
|
604
660
|
readonly result: SessionLifecycleListResult;
|
|
605
661
|
readonly sessions: readonly SessionLifecycleListEntry[];
|
|
606
662
|
readonly continuationCursor?: unknown;
|
|
663
|
+
readonly scope?: SdkSearchResultV1["scope"];
|
|
664
|
+
readonly observedAt?: string;
|
|
607
665
|
};
|
|
608
666
|
|
|
609
667
|
function brokerError(value: unknown): { code: string; message: string } | undefined {
|
|
@@ -647,6 +705,24 @@ function brokerErrorFromThrown(value: unknown): { code: string; message: string;
|
|
|
647
705
|
return { code, message, ...(requestSent === undefined ? {} : { requestSent }) };
|
|
648
706
|
}
|
|
649
707
|
|
|
708
|
+
function unavailableScopedList(scope: SdkSearchResultV1["scope"]): SessionListFailure {
|
|
709
|
+
return {
|
|
710
|
+
ok: false,
|
|
711
|
+
operation: "session.list",
|
|
712
|
+
certainty: "retryable",
|
|
713
|
+
error: { code: "unavailable", message: "broker search is unavailable" },
|
|
714
|
+
result: {
|
|
715
|
+
version: 1,
|
|
716
|
+
scope,
|
|
717
|
+
status: "unavailable",
|
|
718
|
+
observedAt: new Date().toISOString(),
|
|
719
|
+
rows: [],
|
|
720
|
+
warnings: [],
|
|
721
|
+
error: { code: "unavailable", message: "broker search is unavailable" },
|
|
722
|
+
},
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
|
|
650
726
|
const TRANSPORT_ERROR_CODES = new Set([
|
|
651
727
|
"timeout",
|
|
652
728
|
"connection_closed",
|
|
@@ -678,7 +754,110 @@ export class SessionLifecycleService {
|
|
|
678
754
|
this.#client = client;
|
|
679
755
|
}
|
|
680
756
|
|
|
681
|
-
async
|
|
757
|
+
async scopedList(scope: ScopeRequestV1, limit?: number, cursor?: string): Promise<SessionListOutcome> {
|
|
758
|
+
return await this.#list(
|
|
759
|
+
{
|
|
760
|
+
actor: { id: "gjc-sdk-search-cli", namespace: "sdk:search-cli" },
|
|
761
|
+
capability: "session.list",
|
|
762
|
+
target: {
|
|
763
|
+
scope,
|
|
764
|
+
...(limit === undefined ? {} : { limit }),
|
|
765
|
+
...(cursor === undefined ? {} : { cursor }),
|
|
766
|
+
},
|
|
767
|
+
},
|
|
768
|
+
true,
|
|
769
|
+
);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
async #singleScopedList(
|
|
773
|
+
request: Omit<SessionListRequest, "operation">,
|
|
774
|
+
target: Readonly<Record<string, unknown>>,
|
|
775
|
+
locallyResolvedScope: SdkSearchResultV1["scope"],
|
|
776
|
+
): Promise<SessionListOutcome> {
|
|
777
|
+
let response: unknown;
|
|
778
|
+
try {
|
|
779
|
+
response = await this.#client.global(
|
|
780
|
+
"session.list",
|
|
781
|
+
{ ...target },
|
|
782
|
+
{
|
|
783
|
+
...(request.timeoutMs === undefined ? {} : { timeoutMs: request.timeoutMs }),
|
|
784
|
+
},
|
|
785
|
+
);
|
|
786
|
+
} catch (thrown) {
|
|
787
|
+
const error = brokerError(thrown) ?? brokerErrorFromThrown(thrown);
|
|
788
|
+
if (!error || error.code === "unavailable") return unavailableScopedList(locallyResolvedScope);
|
|
789
|
+
return failure("session.list", certaintyForThrownError(error), error.code, error.message);
|
|
790
|
+
}
|
|
791
|
+
const error = brokerError(response);
|
|
792
|
+
if (error) {
|
|
793
|
+
if (error.code === "unavailable") return unavailableScopedList(locallyResolvedScope);
|
|
794
|
+
return failure("session.list", certaintyForBrokerCode(error.code), error.code, error.message);
|
|
795
|
+
}
|
|
796
|
+
if (!isRecord(response) || response.ok !== true)
|
|
797
|
+
return failure(
|
|
798
|
+
"session.list",
|
|
799
|
+
"uncertain",
|
|
800
|
+
"malformed_response",
|
|
801
|
+
"lifecycle broker returned a malformed scoped list result",
|
|
802
|
+
);
|
|
803
|
+
const page = sessionListPageFromResponse(response);
|
|
804
|
+
const result = page === undefined ? undefined : listResult(page);
|
|
805
|
+
const pageScope = page === undefined ? undefined : scopedPage(page);
|
|
806
|
+
if (page === undefined || !result || !pageScope)
|
|
807
|
+
return failure(
|
|
808
|
+
"session.list",
|
|
809
|
+
"uncertain",
|
|
810
|
+
"malformed_response",
|
|
811
|
+
"lifecycle broker returned a malformed scoped list result",
|
|
812
|
+
);
|
|
813
|
+
if (JSON.stringify(pageScope.scope) !== JSON.stringify(locallyResolvedScope))
|
|
814
|
+
return failure(
|
|
815
|
+
"session.list",
|
|
816
|
+
"uncertain",
|
|
817
|
+
"scope_observation_drift",
|
|
818
|
+
"lifecycle broker scope does not match the locally resolved request scope",
|
|
819
|
+
);
|
|
820
|
+
const continuationCursor = page.continuationCursor;
|
|
821
|
+
if (
|
|
822
|
+
continuationCursor !== undefined &&
|
|
823
|
+
(typeof continuationCursor !== "string" || continuationCursor.length === 0)
|
|
824
|
+
)
|
|
825
|
+
return failure(
|
|
826
|
+
"session.list",
|
|
827
|
+
"uncertain",
|
|
828
|
+
"malformed_response",
|
|
829
|
+
"lifecycle broker returned a malformed scoped list result",
|
|
830
|
+
);
|
|
831
|
+
const rows = scopedSearchRows(result.sessions);
|
|
832
|
+
if (!rows)
|
|
833
|
+
return failure(
|
|
834
|
+
"session.list",
|
|
835
|
+
"uncertain",
|
|
836
|
+
"malformed_response",
|
|
837
|
+
"lifecycle broker returned a malformed scoped list result",
|
|
838
|
+
);
|
|
839
|
+
return {
|
|
840
|
+
ok: true,
|
|
841
|
+
operation: "session.list",
|
|
842
|
+
result: {
|
|
843
|
+
version: 1,
|
|
844
|
+
scope: pageScope.scope,
|
|
845
|
+
status:
|
|
846
|
+
pageScope.scope.resolution === "not-in-git-worktree"
|
|
847
|
+
? "not-in-git-worktree"
|
|
848
|
+
: rows.length === 0
|
|
849
|
+
? "empty"
|
|
850
|
+
: "populated",
|
|
851
|
+
observedAt: pageScope.observedAt,
|
|
852
|
+
indexSeq: result.indexSeq,
|
|
853
|
+
rows,
|
|
854
|
+
...(continuationCursor === undefined ? {} : { cursor: continuationCursor }),
|
|
855
|
+
warnings: result.warnings,
|
|
856
|
+
},
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
async execute(
|
|
682
861
|
request: SessionLifecycleMutationRequest,
|
|
683
862
|
idempotencyKeyOverride?: string,
|
|
684
863
|
): Promise<
|
|
@@ -759,19 +938,6 @@ export class SessionLifecycleService {
|
|
|
759
938
|
| SessionReconcileUncertainOutcome;
|
|
760
939
|
}
|
|
761
940
|
|
|
762
|
-
async execute(
|
|
763
|
-
request: SessionLifecycleMutationRequest,
|
|
764
|
-
): Promise<
|
|
765
|
-
| SessionCreateOutcome
|
|
766
|
-
| SessionForkOutcome
|
|
767
|
-
| SessionResumeOutcome
|
|
768
|
-
| SessionCloseOutcome
|
|
769
|
-
| SessionDeleteOutcome
|
|
770
|
-
| SessionReconcileUncertainOutcome
|
|
771
|
-
> {
|
|
772
|
-
return this.#execute(request);
|
|
773
|
-
}
|
|
774
|
-
|
|
775
941
|
async executeWithIdempotencyKey(
|
|
776
942
|
request: SessionLifecycleMutationRequest,
|
|
777
943
|
idempotencyKey: string,
|
|
@@ -783,7 +949,7 @@ export class SessionLifecycleService {
|
|
|
783
949
|
| SessionDeleteOutcome
|
|
784
950
|
| SessionReconcileUncertainOutcome
|
|
785
951
|
> {
|
|
786
|
-
return this
|
|
952
|
+
return this.execute(request, idempotencyKey);
|
|
787
953
|
}
|
|
788
954
|
|
|
789
955
|
async create(request: Omit<SessionCreateRequest, "operation">): Promise<SessionCreateOutcome> {
|
|
@@ -816,6 +982,9 @@ export class SessionLifecycleService {
|
|
|
816
982
|
}
|
|
817
983
|
|
|
818
984
|
async list(request: Omit<SessionListRequest, "operation">): Promise<SessionListOutcome> {
|
|
985
|
+
return await this.#list(request, false);
|
|
986
|
+
}
|
|
987
|
+
async #list(request: Omit<SessionListRequest, "operation">, singleScopedPage: boolean): Promise<SessionListOutcome> {
|
|
819
988
|
if (!validActor((request as { actor?: unknown }).actor))
|
|
820
989
|
return failure("session.list", "terminal", "unauthorized", "authenticated actor is required");
|
|
821
990
|
if ((request as { capability?: unknown }).capability !== "session.list")
|
|
@@ -823,6 +992,24 @@ export class SessionLifecycleService {
|
|
|
823
992
|
const target = request.target ?? {};
|
|
824
993
|
if (!validTarget(target))
|
|
825
994
|
return failure("session.list", "terminal", "invalid_request", "target must be an object");
|
|
995
|
+
const scopeRequest = target.scope === undefined ? undefined : scopeRequestV1(target.scope);
|
|
996
|
+
if (target.scope !== undefined && !scopeRequest)
|
|
997
|
+
return failure("session.list", "terminal", "invalid_request", "scope must be a valid ScopeRequestV1");
|
|
998
|
+
let locallyResolvedScope: SdkSearchResultV1["scope"] | undefined;
|
|
999
|
+
if (scopeRequest !== undefined) {
|
|
1000
|
+
try {
|
|
1001
|
+
locallyResolvedScope = await resolveScopeRequest(scopeRequest);
|
|
1002
|
+
} catch (cause) {
|
|
1003
|
+
return failure(
|
|
1004
|
+
"session.list",
|
|
1005
|
+
"terminal",
|
|
1006
|
+
"invalid_request",
|
|
1007
|
+
cause instanceof Error ? cause.message : "scope could not be resolved",
|
|
1008
|
+
);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
if (singleScopedPage && locallyResolvedScope !== undefined)
|
|
1012
|
+
return await this.#singleScopedList(request, target, locallyResolvedScope);
|
|
826
1013
|
let pages: readonly SessionListTraversalPage<unknown, LifecycleListPage>[];
|
|
827
1014
|
try {
|
|
828
1015
|
pages = await traverseSessionList<Record<string, unknown>, unknown, LifecycleListPage>(
|
|
@@ -838,14 +1025,22 @@ export class SessionLifecycleService {
|
|
|
838
1025
|
const page = sessionListPageFromResponse(response);
|
|
839
1026
|
if (!page) return undefined;
|
|
840
1027
|
const result = listResult(page);
|
|
1028
|
+
const scoped = scopedPage(page);
|
|
841
1029
|
return result
|
|
842
|
-
? {
|
|
1030
|
+
? {
|
|
1031
|
+
result,
|
|
1032
|
+
sessions: result.sessions,
|
|
1033
|
+
continuationCursor: page.continuationCursor,
|
|
1034
|
+
...(scoped === undefined ? {} : scoped),
|
|
1035
|
+
}
|
|
843
1036
|
: undefined;
|
|
844
1037
|
},
|
|
845
1038
|
);
|
|
846
1039
|
} catch (thrown) {
|
|
847
1040
|
if (thrown instanceof BrokerSessionListResponseError) {
|
|
848
1041
|
const error = thrown.brokerError;
|
|
1042
|
+
if (error.code === "unavailable" && locallyResolvedScope)
|
|
1043
|
+
return unavailableScopedList(locallyResolvedScope);
|
|
849
1044
|
return failure("session.list", certaintyForBrokerCode(error.code), error.code, error.message);
|
|
850
1045
|
}
|
|
851
1046
|
if (thrown instanceof SessionListTraversalError)
|
|
@@ -860,6 +1055,8 @@ export class SessionLifecycleService {
|
|
|
860
1055
|
: "session.list exceeded the page budget",
|
|
861
1056
|
);
|
|
862
1057
|
const error = brokerError(thrown) ?? brokerErrorFromThrown(thrown);
|
|
1058
|
+
if (locallyResolvedScope && (!error || error.code === "unavailable"))
|
|
1059
|
+
return unavailableScopedList(locallyResolvedScope);
|
|
863
1060
|
return error
|
|
864
1061
|
? failure("session.list", certaintyForThrownError(error), error.code, error.message)
|
|
865
1062
|
: failure("session.list", "retryable", "unavailable", "lifecycle broker request was unavailable");
|
|
@@ -873,6 +1070,68 @@ export class SessionLifecycleService {
|
|
|
873
1070
|
"lifecycle broker returned a malformed list result",
|
|
874
1071
|
);
|
|
875
1072
|
const { result } = firstPage.page;
|
|
1073
|
+
if (request.target?.scope !== undefined) {
|
|
1074
|
+
const scope = firstPage.page.scope;
|
|
1075
|
+
const observedAt = firstPage.page.observedAt;
|
|
1076
|
+
if (!scope || !observedAt)
|
|
1077
|
+
return failure(
|
|
1078
|
+
"session.list",
|
|
1079
|
+
"uncertain",
|
|
1080
|
+
"malformed_response",
|
|
1081
|
+
"lifecycle broker returned a malformed scoped list result",
|
|
1082
|
+
);
|
|
1083
|
+
const frozenScope = JSON.stringify(scope);
|
|
1084
|
+
const frozenIndexSeq = result.indexSeq;
|
|
1085
|
+
for (const page of pages) {
|
|
1086
|
+
const pageScope = page.page.scope;
|
|
1087
|
+
const pageObservedAt = page.page.observedAt;
|
|
1088
|
+
if (
|
|
1089
|
+
pageScope === undefined ||
|
|
1090
|
+
pageObservedAt !== observedAt ||
|
|
1091
|
+
page.page.result.indexSeq !== frozenIndexSeq ||
|
|
1092
|
+
JSON.stringify(pageScope) !== frozenScope
|
|
1093
|
+
)
|
|
1094
|
+
return failure(
|
|
1095
|
+
"session.list",
|
|
1096
|
+
"uncertain",
|
|
1097
|
+
"scope_observation_drift",
|
|
1098
|
+
"lifecycle broker changed the frozen scope observation across list pages",
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1101
|
+
if (locallyResolvedScope && JSON.stringify(locallyResolvedScope) !== frozenScope)
|
|
1102
|
+
return failure(
|
|
1103
|
+
"session.list",
|
|
1104
|
+
"uncertain",
|
|
1105
|
+
"scope_observation_drift",
|
|
1106
|
+
"lifecycle broker scope does not match the locally resolved request scope",
|
|
1107
|
+
);
|
|
1108
|
+
const rows = scopedSearchRows(pages.flatMap(page => page.page.result.sessions));
|
|
1109
|
+
if (!rows)
|
|
1110
|
+
return failure(
|
|
1111
|
+
"session.list",
|
|
1112
|
+
"uncertain",
|
|
1113
|
+
"malformed_response",
|
|
1114
|
+
"lifecycle broker returned a malformed scoped list result",
|
|
1115
|
+
);
|
|
1116
|
+
return {
|
|
1117
|
+
ok: true,
|
|
1118
|
+
operation: "session.list",
|
|
1119
|
+
result: {
|
|
1120
|
+
version: 1,
|
|
1121
|
+
scope,
|
|
1122
|
+
status:
|
|
1123
|
+
scope.resolution === "not-in-git-worktree"
|
|
1124
|
+
? "not-in-git-worktree"
|
|
1125
|
+
: rows.length === 0
|
|
1126
|
+
? "empty"
|
|
1127
|
+
: "populated",
|
|
1128
|
+
observedAt,
|
|
1129
|
+
indexSeq: result.indexSeq,
|
|
1130
|
+
rows,
|
|
1131
|
+
warnings: result.warnings,
|
|
1132
|
+
},
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
876
1135
|
return {
|
|
877
1136
|
ok: true,
|
|
878
1137
|
operation: "session.list",
|
|
@@ -55,6 +55,8 @@ export type CreateLifecycleAgentSessionOptions = Omit<CreateAgentSessionOptions,
|
|
|
55
55
|
* a prepared signal instead of readiness until it is explicitly activated.
|
|
56
56
|
*/
|
|
57
57
|
readiness?: "immediate" | "deferred";
|
|
58
|
+
/** Broker-issued lifecycle request identity published with host registration. */
|
|
59
|
+
lifecycleRequestId?: string;
|
|
58
60
|
};
|
|
59
61
|
|
|
60
62
|
/** Internal lifecycle-only session construction with an owner-bound SDK startup result. */
|
|
@@ -62,9 +64,15 @@ export async function createLifecycleAgentSession(
|
|
|
62
64
|
options: CreateLifecycleAgentSessionOptions = {},
|
|
63
65
|
): Promise<CreateLifecycleAgentSessionResult> {
|
|
64
66
|
const rollback = new SdkStartupRollbackTracker();
|
|
65
|
-
const capability = new SdkStartupCapability(rollback, options.readiness ?? "immediate");
|
|
67
|
+
const capability = new SdkStartupCapability(rollback, options.readiness ?? "immediate", options.lifecycleRequestId);
|
|
66
68
|
try {
|
|
67
|
-
const {
|
|
69
|
+
const {
|
|
70
|
+
modelId,
|
|
71
|
+
mcpStartupTimeoutMs,
|
|
72
|
+
readiness: _readiness,
|
|
73
|
+
lifecycleRequestId: _lifecycleRequestId,
|
|
74
|
+
...sessionOptions
|
|
75
|
+
} = options;
|
|
68
76
|
const internalOptions = {
|
|
69
77
|
...sessionOptions,
|
|
70
78
|
// Explicit model pin (#4707): resolve through the staged selector
|
|
@@ -1097,6 +1097,24 @@
|
|
|
1097
1097
|
"packages/coding-agent/test/sdk-operation-inventory.test.ts"
|
|
1098
1098
|
]
|
|
1099
1099
|
},
|
|
1100
|
+
{
|
|
1101
|
+
"sourceId": "registry:G09",
|
|
1102
|
+
"sourceFile": "packages/coding-agent/src/sdk/protocol/operation-registry.ts",
|
|
1103
|
+
"sourceKind": "registry",
|
|
1104
|
+
"decision": "include",
|
|
1105
|
+
"sdkId": "session.spawn",
|
|
1106
|
+
"adapterMappings": {
|
|
1107
|
+
"telegram": "prohibited",
|
|
1108
|
+
"discord": "prohibited",
|
|
1109
|
+
"slack": "prohibited",
|
|
1110
|
+
"mcp": "prohibited",
|
|
1111
|
+
"acp": "prohibited",
|
|
1112
|
+
"daemonCli": "prohibited"
|
|
1113
|
+
},
|
|
1114
|
+
"testIds": [
|
|
1115
|
+
"packages/coding-agent/test/sdk-operation-inventory.test.ts"
|
|
1116
|
+
]
|
|
1117
|
+
},
|
|
1100
1118
|
{
|
|
1101
1119
|
"sourceId": "registry:Q01",
|
|
1102
1120
|
"sourceFile": "packages/coding-agent/src/sdk/protocol/operation-registry.ts",
|
|
@@ -2845,6 +2863,39 @@
|
|
|
2845
2863
|
"testIds": "not_applicable"
|
|
2846
2864
|
}
|
|
2847
2865
|
},
|
|
2866
|
+
{
|
|
2867
|
+
"sourceId": "agent_session:queueCoordinatorRuntimeStatePersistForTests",
|
|
2868
|
+
"sourceFile": "packages/coding-agent/src/session/agent-session.ts",
|
|
2869
|
+
"sourceKind": "agent_session",
|
|
2870
|
+
"decision": "exclude",
|
|
2871
|
+
"rationale": "test-only coordinator persistence ordering seam, not a user-facing SDK control seam",
|
|
2872
|
+
"exclusionMetadata": {
|
|
2873
|
+
"adapterMappings": "not_applicable",
|
|
2874
|
+
"testIds": "not_applicable"
|
|
2875
|
+
}
|
|
2876
|
+
},
|
|
2877
|
+
{
|
|
2878
|
+
"sourceId": "agent_session:parkAgentEndForCoordinatorPersistForTests",
|
|
2879
|
+
"sourceFile": "packages/coding-agent/src/session/agent-session.ts",
|
|
2880
|
+
"sourceKind": "agent_session",
|
|
2881
|
+
"decision": "exclude",
|
|
2882
|
+
"rationale": "test-only parked terminal persistence seam, not a user-facing SDK control seam",
|
|
2883
|
+
"exclusionMetadata": {
|
|
2884
|
+
"adapterMappings": "not_applicable",
|
|
2885
|
+
"testIds": "not_applicable"
|
|
2886
|
+
}
|
|
2887
|
+
},
|
|
2888
|
+
{
|
|
2889
|
+
"sourceId": "agent_session:flushParkedAgentEndForCoordinatorPersistForTests",
|
|
2890
|
+
"sourceFile": "packages/coding-agent/src/session/agent-session.ts",
|
|
2891
|
+
"sourceKind": "agent_session",
|
|
2892
|
+
"decision": "exclude",
|
|
2893
|
+
"rationale": "test-only parked terminal flush seam, not a user-facing SDK control seam",
|
|
2894
|
+
"exclusionMetadata": {
|
|
2895
|
+
"adapterMappings": "not_applicable",
|
|
2896
|
+
"testIds": "not_applicable"
|
|
2897
|
+
}
|
|
2898
|
+
},
|
|
2848
2899
|
{
|
|
2849
2900
|
"sourceId": "agent_session:drainAsyncJobDeliveriesForAcp",
|
|
2850
2901
|
"sourceFile": "packages/coding-agent/src/session/agent-session.ts",
|
|
@@ -136,6 +136,7 @@ const globals = [
|
|
|
136
136
|
["session.close", "Close a saved session."],
|
|
137
137
|
["session.delete", "Delete a saved session."],
|
|
138
138
|
["session.reconcile_uncertain", "Retire an indexed terminalUncertain create effect after dead-host proof."],
|
|
139
|
+
["session.spawn", "Spawn a task-seeded background child session (local interactive master only)."],
|
|
139
140
|
] as const;
|
|
140
141
|
|
|
141
142
|
const queries = [
|
|
@@ -353,9 +354,18 @@ export const OPERATIONS: readonly Operation[] = [
|
|
|
353
354
|
acp: "machine_only",
|
|
354
355
|
daemonCli: "machine_only",
|
|
355
356
|
})
|
|
356
|
-
:
|
|
357
|
-
? dispositions({
|
|
358
|
-
|
|
357
|
+
: id === "G09"
|
|
358
|
+
? dispositions({
|
|
359
|
+
telegram: "prohibited",
|
|
360
|
+
discord: "prohibited",
|
|
361
|
+
slack: "prohibited",
|
|
362
|
+
mcp: "prohibited",
|
|
363
|
+
acp: "prohibited",
|
|
364
|
+
daemonCli: "prohibited",
|
|
365
|
+
})
|
|
366
|
+
: ["G03", "G04", "G05", "G06", "G07", "G08"].includes(id)
|
|
367
|
+
? dispositions({ telegram: "prohibited", discord: "prohibited", slack: "prohibited" })
|
|
368
|
+
: dispositions(),
|
|
359
369
|
testIds: ["packages/coding-agent/test/sdk-operation-inventory.test.ts"],
|
|
360
370
|
};
|
|
361
371
|
}),
|