agent-transport-system 0.7.4 → 0.7.6
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/ats.js +314 -78
- package/dist/ats.js.map +1 -1
- package/package.json +1 -1
package/dist/ats.js
CHANGED
|
@@ -27,7 +27,7 @@ import wrapAnsi from "wrap-ansi";
|
|
|
27
27
|
import { Box, Container, Editor, Key, ProcessTerminal, TUI, Text, getEditorKeybindings, matchesKey } from "@mariozechner/pi-tui";
|
|
28
28
|
|
|
29
29
|
//#region package.json
|
|
30
|
-
var version = "0.7.
|
|
30
|
+
var version = "0.7.6";
|
|
31
31
|
var package_default = {
|
|
32
32
|
$schema: "https://www.schemastore.org/package.json",
|
|
33
33
|
name: "agent-transport-system",
|
|
@@ -2492,6 +2492,14 @@ const SPACE_ADD_MEMBERS_PROGRESS_PHASES = [
|
|
|
2492
2492
|
factSource: "space_membership_api_write",
|
|
2493
2493
|
summary: "Adding selected profiles to the Space."
|
|
2494
2494
|
},
|
|
2495
|
+
{
|
|
2496
|
+
stage: "add_members",
|
|
2497
|
+
phase: "confirm_membership_projection",
|
|
2498
|
+
owner: "space",
|
|
2499
|
+
waitingFor: "Space membership and Wake availability projection",
|
|
2500
|
+
factSource: "space_membership_projection",
|
|
2501
|
+
summary: "Confirming the Space can see newly added wakeable members before returning."
|
|
2502
|
+
},
|
|
2495
2503
|
{
|
|
2496
2504
|
stage: "record_join_notices",
|
|
2497
2505
|
phase: "write_join_notices",
|
|
@@ -2502,6 +2510,14 @@ const SPACE_ADD_MEMBERS_PROGRESS_PHASES = [
|
|
|
2502
2510
|
}
|
|
2503
2511
|
];
|
|
2504
2512
|
const SPACE_ADD_MEMBERS_PROGRESS_OVERVIEW_STAGES = SPACE_ADD_MEMBERS_PROGRESS_PHASES.map((phase) => `${phase.stage}/${phase.phase}`);
|
|
2513
|
+
const SPACE_ADD_MEMBERS_AGENT_OVERVIEW_STAGES = [
|
|
2514
|
+
"check_arguments",
|
|
2515
|
+
"authenticate",
|
|
2516
|
+
"check_profile",
|
|
2517
|
+
"resolve_target",
|
|
2518
|
+
"add_members/write_membership",
|
|
2519
|
+
"record_join_notices/write_join_notices"
|
|
2520
|
+
];
|
|
2505
2521
|
function resolveSpaceAddMembersProgressPhase(input) {
|
|
2506
2522
|
const contract = SPACE_ADD_MEMBERS_PROGRESS_PHASES.find((phase) => phase.stage === input.stage && phase.phase === input.phase);
|
|
2507
2523
|
if (!contract) throw new Error(`unknown space add-members progress phase: ${input.stage}/${input.phase}`);
|
|
@@ -3265,7 +3281,7 @@ const COMMAND_ENTRY_CONTRACTS = {
|
|
|
3265
3281
|
},
|
|
3266
3282
|
notes: ["space is single-select; members support one or many selections.", "already-joined profiles are skipped automatically."],
|
|
3267
3283
|
pattern: getSpaceMemberSelectionPatternContract("add-members"),
|
|
3268
|
-
stages:
|
|
3284
|
+
stages: [...SPACE_ADD_MEMBERS_AGENT_OVERVIEW_STAGES],
|
|
3269
3285
|
summary: "Use `ats space add-members --profile <profile-id> <space-id> --member <profile-id...> --view agent` with explicit acting profile, Space ID, and member selection."
|
|
3270
3286
|
},
|
|
3271
3287
|
buildHints: (context) => getSpaceMemberSelectionPatternContract("add-members").buildHints?.({
|
|
@@ -28706,11 +28722,11 @@ async function readSystemLayoutWithRetry(path) {
|
|
|
28706
28722
|
}
|
|
28707
28723
|
const parsed = raw ? parseSystemLayout(raw) : null;
|
|
28708
28724
|
if (parsed) return parsed;
|
|
28709
|
-
if (attempt < SYSTEM_LAYOUT_READ_RETRY_COUNT - 1) await delay(SYSTEM_LAYOUT_READ_RETRY_DELAY_MS);
|
|
28725
|
+
if (attempt < SYSTEM_LAYOUT_READ_RETRY_COUNT - 1) await delay$1(SYSTEM_LAYOUT_READ_RETRY_DELAY_MS);
|
|
28710
28726
|
}
|
|
28711
28727
|
return null;
|
|
28712
28728
|
}
|
|
28713
|
-
function delay(ms) {
|
|
28729
|
+
function delay$1(ms) {
|
|
28714
28730
|
return new Promise((resolve) => {
|
|
28715
28731
|
setTimeout(resolve, ms);
|
|
28716
28732
|
});
|
|
@@ -60432,13 +60448,7 @@ function renderProfileSummaryCard(input) {
|
|
|
60432
60448
|
});
|
|
60433
60449
|
}
|
|
60434
60450
|
function buildAgentCreateNextSteps(profile) {
|
|
60435
|
-
if (profile.profileKind === "agent") return [
|
|
60436
|
-
formatAtsCliCommand(`ats setup --profile ${profile.atsProfileId} --local-agent <local-agent-id> --view agent`),
|
|
60437
|
-
formatAtsCliCommand(`ats setup --profile ${profile.atsProfileId} --view agent`),
|
|
60438
|
-
formatAtsCliCommand(`ats service status --profile ${profile.atsProfileId} --view agent`),
|
|
60439
|
-
formatAtsCliCommand(`ats profiles show ${profile.atsProfileId} --view agent`),
|
|
60440
|
-
formatAtsCliCommand(`ats whoami --profile ${profile.atsProfileId} --view agent`)
|
|
60441
|
-
];
|
|
60451
|
+
if (profile.profileKind === "agent") return [formatAtsCliCommand(`ats space add-members <space-id> --member ${profile.atsProfileId} --profile <human-profile-id> --view agent`)];
|
|
60442
60452
|
return [
|
|
60443
60453
|
formatAtsCliCommand("ats profiles list --view agent"),
|
|
60444
60454
|
formatAtsCliCommand(`ats profiles set ${profile.atsProfileId} --view agent`),
|
|
@@ -60452,28 +60462,24 @@ function buildAgentCreateWakeReadinessData(profile) {
|
|
|
60452
60462
|
return {
|
|
60453
60463
|
identityCreated: true,
|
|
60454
60464
|
wakeReadinessVerified: false,
|
|
60455
|
-
wakeReadinessNote: "
|
|
60465
|
+
wakeReadinessNote: "Profile creation creates the Space identity. Add it to a Space when the user wants this teammate to participate."
|
|
60456
60466
|
};
|
|
60457
60467
|
}
|
|
60458
60468
|
function buildProfileCreateWakeReadinessRows(input) {
|
|
60459
60469
|
if (input.state !== "created" || input.profile.profileKind !== "agent") return [];
|
|
60460
60470
|
return [{
|
|
60461
|
-
label: "
|
|
60462
|
-
value: "
|
|
60471
|
+
label: "Space identity",
|
|
60472
|
+
value: "Created"
|
|
60463
60473
|
}, {
|
|
60464
60474
|
label: "Next",
|
|
60465
|
-
value:
|
|
60475
|
+
value: "Add this profile to a Space when the user wants this teammate to participate."
|
|
60466
60476
|
}];
|
|
60467
60477
|
}
|
|
60468
60478
|
function buildAgentUpdateNextSteps(profile) {
|
|
60479
|
+
if (profile.profileKind === "agent") return [formatAtsCliCommand(`ats profiles show ${profile.atsProfileId} --view agent`), formatAtsCliCommand(`ats space add-members <space-id> --member ${profile.atsProfileId} --profile <human-profile-id> --view agent`)];
|
|
60469
60480
|
return [
|
|
60470
60481
|
formatAtsCliCommand(`ats profiles show ${profile.atsProfileId} --view agent`),
|
|
60471
60482
|
formatAtsCliCommand(`ats profiles update ${profile.atsProfileId} --name <new-name> --view agent`),
|
|
60472
|
-
formatAtsCliCommand(`ats setup --profile ${profile.atsProfileId} --local-agent <local-agent-id> --view agent`),
|
|
60473
|
-
formatAtsCliCommand(`ats setup --profile ${profile.atsProfileId} --view agent`),
|
|
60474
|
-
formatAtsCliCommand(`ats profiles update ${profile.atsProfileId} --workspace-mode ats-managed --view agent`),
|
|
60475
|
-
formatAtsCliCommand(`ats profiles update ${profile.atsProfileId} --workspace-mode custom --workspace-path /absolute/path --view agent`),
|
|
60476
|
-
formatAtsCliCommand(`ats whoami --profile ${profile.atsProfileId} --view agent`),
|
|
60477
60483
|
formatAtsCliCommand("ats profiles list --view agent")
|
|
60478
60484
|
];
|
|
60479
60485
|
}
|
|
@@ -68222,7 +68228,14 @@ function isAgentProfile(profile) {
|
|
|
68222
68228
|
//#region src/commands/setup.ts
|
|
68223
68229
|
const ROUTE_CATALOG_SYNC_MAX_ATTEMPTS = 8;
|
|
68224
68230
|
const ROUTE_CATALOG_SYNC_RETRY_DELAY_MS = 750;
|
|
68231
|
+
const SETUP_COMMAND_LOCK_PROFILE = "setup";
|
|
68232
|
+
const SETUP_COMMAND_LOCK_KEY = "setup-command";
|
|
68225
68233
|
async function runSetup(input) {
|
|
68234
|
+
return await withSetupCommandLock(input, async () => {
|
|
68235
|
+
await runSetupUnlocked(input);
|
|
68236
|
+
});
|
|
68237
|
+
}
|
|
68238
|
+
async function runSetupUnlocked(input) {
|
|
68226
68239
|
if (shouldUseSetupLocalAgentConnection(input)) {
|
|
68227
68240
|
const setupResult = await runSetupLocalAgentConnection(input);
|
|
68228
68241
|
if (setupResult.status !== "completed") return;
|
|
@@ -68326,6 +68339,33 @@ async function runSetup(input) {
|
|
|
68326
68339
|
view: runtime.resolvedView
|
|
68327
68340
|
});
|
|
68328
68341
|
}
|
|
68342
|
+
async function withSetupCommandLock(input, run) {
|
|
68343
|
+
try {
|
|
68344
|
+
return await runWithHeldLock({
|
|
68345
|
+
lock: await acquireLock({
|
|
68346
|
+
atsProfileId: SETUP_COMMAND_LOCK_PROFILE,
|
|
68347
|
+
key: SETUP_COMMAND_LOCK_KEY,
|
|
68348
|
+
meta: {
|
|
68349
|
+
command: "ats setup",
|
|
68350
|
+
path: shouldUseSetupLocalAgentConnection(input) ? "delegated_or_profile_setup" : "local_setup",
|
|
68351
|
+
view: input.view ?? null
|
|
68352
|
+
}
|
|
68353
|
+
}),
|
|
68354
|
+
run,
|
|
68355
|
+
releaseContext: {
|
|
68356
|
+
atsProfileId: SETUP_COMMAND_LOCK_PROFILE,
|
|
68357
|
+
component: "setup_command",
|
|
68358
|
+
lockKey: SETUP_COMMAND_LOCK_KEY
|
|
68359
|
+
}
|
|
68360
|
+
});
|
|
68361
|
+
} catch (error) {
|
|
68362
|
+
if (isAtsLockError(error)) throw new Error(buildSetupCommandLockMessage(error));
|
|
68363
|
+
throw error;
|
|
68364
|
+
}
|
|
68365
|
+
}
|
|
68366
|
+
function buildSetupCommandLockMessage(error) {
|
|
68367
|
+
return `Another ATS setup is already running on this computer. Wait for it to finish, then run setup again.${error.metaRaw ? ` Existing setup: ${error.metaRaw}` : ""}`;
|
|
68368
|
+
}
|
|
68329
68369
|
function shouldUseSetupLocalAgentConnection(input) {
|
|
68330
68370
|
return Boolean(normalizeOptionalString$5(input.startSession) ?? normalizeOptionalString$5(input.humanProfile) ?? normalizeOptionalString$5(input.profile) ?? (input.agent && input.agent.length > 0 ? "agent" : null));
|
|
68331
68371
|
}
|
|
@@ -69434,7 +69474,7 @@ const STAGES_BY_COMMAND = {
|
|
|
69434
69474
|
"resolve_target",
|
|
69435
69475
|
"read_or_update_guide"
|
|
69436
69476
|
],
|
|
69437
|
-
add_members:
|
|
69477
|
+
add_members: SPACE_ADD_MEMBERS_AGENT_OVERVIEW_STAGES,
|
|
69438
69478
|
remove_members: [
|
|
69439
69479
|
"check_arguments",
|
|
69440
69480
|
"authenticate",
|
|
@@ -83740,13 +83780,13 @@ function handleBlockedSpaceJoinLocalParticipation(input) {
|
|
|
83740
83780
|
if (input.assessmentState === "not_needed") {
|
|
83741
83781
|
input.presenter.line({
|
|
83742
83782
|
code: "space.join.service.not_needed",
|
|
83743
|
-
text: formatInlineAtsCliCommands("ATS will
|
|
83783
|
+
text: formatInlineAtsCliCommands("ATS will join this space. Local agent participation on this device can be checked later with `ats service status`.")
|
|
83744
83784
|
});
|
|
83745
83785
|
return "continue";
|
|
83746
83786
|
}
|
|
83747
83787
|
input.presenter.line({
|
|
83748
83788
|
code: "space.join.service.pending",
|
|
83749
|
-
text: formatInlineAtsCliCommands("ATS will
|
|
83789
|
+
text: formatInlineAtsCliCommands("ATS will join this space. Local agent participation on this device can be checked separately with `ats service status`.")
|
|
83750
83790
|
});
|
|
83751
83791
|
return "continue";
|
|
83752
83792
|
}
|
|
@@ -83759,10 +83799,10 @@ function buildSpaceJoinMembershipOnlyMessage(input) {
|
|
|
83759
83799
|
const profileId = input.atsProfile.atsProfileId;
|
|
83760
83800
|
const reasonCodes = input.reasonCodes;
|
|
83761
83801
|
const statusCommand = formatAtsCliCommand(`ats service status --profile ${profileId}`);
|
|
83762
|
-
if (reasonCodes.includes("profile.unbound")) return `${profileName} will join this space
|
|
83763
|
-
if (reasonCodes.some((reasonCode) => LOCAL_SERVICE_ONLY_JOIN_BLOCK_REASON_CODES.has(reasonCode)) || reasonCodes.includes("dispatch.storage_not_ready") || reasonCodes.includes("service.gateway_chain_unhealthy") || reasonCodes.includes("route.offline") || reasonCodes.includes("route.not_registered")) return formatInlineAtsCliCommands(`${profileName} will join this space
|
|
83802
|
+
if (reasonCodes.includes("profile.unbound")) return `${profileName} will join this space. Choose its local agent in ATS Web when you want it to handle work from this device.`;
|
|
83803
|
+
if (reasonCodes.some((reasonCode) => LOCAL_SERVICE_ONLY_JOIN_BLOCK_REASON_CODES.has(reasonCode)) || reasonCodes.includes("dispatch.storage_not_ready") || reasonCodes.includes("service.gateway_chain_unhealthy") || reasonCodes.includes("route.offline") || reasonCodes.includes("route.not_registered")) return formatInlineAtsCliCommands(`${profileName} will join this space. ATS has not confirmed its local reply path on this device yet. Use \`${statusCommand}\` to check this device.`);
|
|
83764
83804
|
if (reasonCodes.includes("controller.launch.needs_repair") || reasonCodes.includes("controller.launch.choice_required") || reasonCodes.includes("workspace.missing") || reasonCodes.includes("workspace.invalid")) return formatInlineAtsCliCommands(`${profileName} will join this space, but its local agent setup on this device needs attention. Use \`ats agents list\` to find the local agent, then run \`ats agents repair --agent <agent-id>\`.`);
|
|
83765
|
-
return `${profileName} will join this space
|
|
83805
|
+
return `${profileName} will join this space. Check Local Agents in ATS Web when you want it to handle work from this device.`;
|
|
83766
83806
|
}
|
|
83767
83807
|
function buildJoinTargetMissingMessage(input) {
|
|
83768
83808
|
return formatMessage(input.resolvedView, "space.target.missing", { command: "join" });
|
|
@@ -84931,6 +84971,8 @@ const TRAILING_SLASHES_RE = /\/+$/u;
|
|
|
84931
84971
|
const SPACE_CREATE_AUTH_CHECK_TIMEOUT_MS = 8e3;
|
|
84932
84972
|
const SPACE_CREATE_AUTH_CHECK_LOOPBACK_TIMEOUT_MS = 1500;
|
|
84933
84973
|
const SPACE_LOADING_SPINNER_MESSAGE = "Loading spaces...";
|
|
84974
|
+
const SPACE_ADD_MEMBERS_PROJECTION_WAIT_MAX_ATTEMPTS = 3;
|
|
84975
|
+
const SPACE_ADD_MEMBERS_PROJECTION_WAIT_DELAY_MS = 500;
|
|
84934
84976
|
function requireReadableSpaceConfigList(result, operation) {
|
|
84935
84977
|
if (result.kind === "corrupt") throw toSpaceConfigListIntegrityError({
|
|
84936
84978
|
operation,
|
|
@@ -85010,6 +85052,8 @@ const SPACE_MEMBER_PROFILE_RECONNECT_REASON_CODES = new Set([
|
|
|
85010
85052
|
"local_service.identity_mismatch"
|
|
85011
85053
|
]);
|
|
85012
85054
|
const SPACE_MEMBER_SERVICE_STATUS_REASON_CODES = new Set([
|
|
85055
|
+
"agent_profile_binding.local_service_not_connected",
|
|
85056
|
+
"agent_profile_binding.execution_readiness_pending",
|
|
85013
85057
|
"route.offline",
|
|
85014
85058
|
"route.not_registered",
|
|
85015
85059
|
"service.gateway_chain_unhealthy",
|
|
@@ -85133,6 +85177,7 @@ async function runSpaceCreate(input) {
|
|
|
85133
85177
|
guide: typeof parsed.meta?.guide === "string" ? parsed.meta.guide : createInput.value.guide
|
|
85134
85178
|
});
|
|
85135
85179
|
emitSpaceCreateSuccessOutput({
|
|
85180
|
+
baseUrl,
|
|
85136
85181
|
presenter: contextPresenter,
|
|
85137
85182
|
parsed,
|
|
85138
85183
|
outputMode,
|
|
@@ -85151,6 +85196,7 @@ async function runSpaceCreate(input) {
|
|
|
85151
85196
|
const joinNow = isHumanInteractiveSpaceRuntime(contextRuntime) ? Boolean(createInput.value.joinInput) : await resolveJoinAfterCreate(createInput.value.joinInput, contextInteractive);
|
|
85152
85197
|
if (contextRuntime.resolvedView === "agent") {
|
|
85153
85198
|
emitSpaceCreateAgentFollowUp({
|
|
85199
|
+
baseUrl,
|
|
85154
85200
|
presenter: contextPresenter,
|
|
85155
85201
|
profileId: atsProfile.atsProfileId,
|
|
85156
85202
|
spaceId: parsed.spaceId,
|
|
@@ -85186,12 +85232,14 @@ async function runSpaceCreate(input) {
|
|
|
85186
85232
|
}
|
|
85187
85233
|
}
|
|
85188
85234
|
function emitSpaceCreateAgentFollowUp(input) {
|
|
85235
|
+
const spaceUrl = buildSpaceWebUrl(input.baseUrl, input.spaceId);
|
|
85189
85236
|
const historyCommand = formatAtsCliCommand(`ats space history ${input.spaceId} --profile ${input.profileId} --kind text --brief --limit 20 --view agent`);
|
|
85190
85237
|
const sendCommand = formatAtsCliCommand(`ats space send ${input.spaceId} --profile ${input.profileId} "hello" --view agent`);
|
|
85191
85238
|
input.presenter.data({
|
|
85192
85239
|
code: "space.create.next_commands",
|
|
85193
85240
|
payload: {
|
|
85194
85241
|
spaceId: input.spaceId,
|
|
85242
|
+
spaceUrl,
|
|
85195
85243
|
joinRequested: input.joinRequested,
|
|
85196
85244
|
joinedByCreate: true,
|
|
85197
85245
|
note: "Agent View create returns after creating the Space. Use explicit follow-up commands instead of opening a long-running join session.",
|
|
@@ -85278,6 +85326,9 @@ function renderHumanSpaceCreateCard(input) {
|
|
|
85278
85326
|
const rows = [{
|
|
85279
85327
|
label: "🆔 Space ID",
|
|
85280
85328
|
value: input.spaceId
|
|
85329
|
+
}, {
|
|
85330
|
+
label: "🔗 Space URL",
|
|
85331
|
+
value: input.spaceUrl
|
|
85281
85332
|
}];
|
|
85282
85333
|
if (input.passwordProtected) {
|
|
85283
85334
|
rows.push({
|
|
@@ -85563,6 +85614,19 @@ function toAuthEndpoint(baseUrl, pathname) {
|
|
|
85563
85614
|
url.hash = "";
|
|
85564
85615
|
return url.toString();
|
|
85565
85616
|
}
|
|
85617
|
+
function buildSpaceWebUrl(baseUrl, spaceId) {
|
|
85618
|
+
const url = new URL(baseUrl);
|
|
85619
|
+
if (isLoopbackHostname(url.hostname) && url.port === "8080") url.port = "3000";
|
|
85620
|
+
if (url.hostname === "gateway.ats.sh") {
|
|
85621
|
+
url.hostname = "ats.sh";
|
|
85622
|
+
url.port = "";
|
|
85623
|
+
url.protocol = "https:";
|
|
85624
|
+
}
|
|
85625
|
+
url.pathname = `/app/spaces/${encodeURIComponent(spaceId)}`;
|
|
85626
|
+
url.search = "";
|
|
85627
|
+
url.hash = "";
|
|
85628
|
+
return url.toString();
|
|
85629
|
+
}
|
|
85566
85630
|
function resolveSpaceCreateAuthCheckTimeoutMs(endpoint) {
|
|
85567
85631
|
const url = parseUrlOrNull(endpoint);
|
|
85568
85632
|
if (url && isLoopbackHostname(url.hostname)) return SPACE_CREATE_AUTH_CHECK_LOOPBACK_TIMEOUT_MS;
|
|
@@ -85579,10 +85643,14 @@ function isLoopbackHostname(hostname) {
|
|
|
85579
85643
|
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1";
|
|
85580
85644
|
}
|
|
85581
85645
|
function emitSpaceCreateSuccessOutput(input) {
|
|
85646
|
+
const spaceUrl = buildSpaceWebUrl(input.baseUrl, input.parsed.spaceId);
|
|
85582
85647
|
if (input.outputMode === "ndjson") {
|
|
85583
85648
|
input.presenter.data({
|
|
85584
85649
|
code: "space.create.response",
|
|
85585
|
-
payload:
|
|
85650
|
+
payload: {
|
|
85651
|
+
...input.parsed,
|
|
85652
|
+
spaceUrl
|
|
85653
|
+
}
|
|
85586
85654
|
});
|
|
85587
85655
|
return;
|
|
85588
85656
|
}
|
|
@@ -85590,6 +85658,7 @@ function emitSpaceCreateSuccessOutput(input) {
|
|
|
85590
85658
|
renderHumanSpaceCreateCard({
|
|
85591
85659
|
presenter: input.presenter,
|
|
85592
85660
|
spaceId: input.parsed.spaceId,
|
|
85661
|
+
spaceUrl,
|
|
85593
85662
|
passwordProtected: input.passwordProtected
|
|
85594
85663
|
});
|
|
85595
85664
|
return;
|
|
@@ -85599,6 +85668,14 @@ function emitSpaceCreateSuccessOutput(input) {
|
|
|
85599
85668
|
text: formatMessage(input.resolvedView, "space.create.created", { spaceId: input.parsed.spaceId }),
|
|
85600
85669
|
data: { spaceId: input.parsed.spaceId }
|
|
85601
85670
|
});
|
|
85671
|
+
input.presenter.line({
|
|
85672
|
+
code: "space.create.url",
|
|
85673
|
+
text: `Space URL: ${spaceUrl}`,
|
|
85674
|
+
data: {
|
|
85675
|
+
spaceId: input.parsed.spaceId,
|
|
85676
|
+
spaceUrl
|
|
85677
|
+
}
|
|
85678
|
+
});
|
|
85602
85679
|
if (!input.passwordProtected) return;
|
|
85603
85680
|
input.presenter.line({
|
|
85604
85681
|
code: "space.password.warning",
|
|
@@ -86057,7 +86134,7 @@ async function runSpaceAddMembers(input) {
|
|
|
86057
86134
|
resolvedView: runtime.resolvedView,
|
|
86058
86135
|
interactive
|
|
86059
86136
|
});
|
|
86060
|
-
await emitSpaceCommandPreflight({
|
|
86137
|
+
if (shouldRunSpaceAddMembersDiagnosticPreflight(input, explicitMemberIds)) await emitSpaceCommandPreflight({
|
|
86061
86138
|
presenter,
|
|
86062
86139
|
command: "add_members",
|
|
86063
86140
|
profile: atsProfile,
|
|
@@ -86249,6 +86326,12 @@ async function runSpaceLeave(input) {
|
|
|
86249
86326
|
throw error;
|
|
86250
86327
|
}
|
|
86251
86328
|
}
|
|
86329
|
+
function shouldRunSpaceAddMembersDiagnosticPreflight(input, explicitMemberIds) {
|
|
86330
|
+
return input.details === true || input.all === true || explicitMemberIds.length === 0;
|
|
86331
|
+
}
|
|
86332
|
+
function shouldUseFastExplicitSpaceAddMembers(input) {
|
|
86333
|
+
return input.details !== true && input.explicitMemberIds.length > 0;
|
|
86334
|
+
}
|
|
86252
86335
|
async function runSpaceAddMembersForTarget(input) {
|
|
86253
86336
|
const targetBaseUrl = input.hasExplicitBaseUrlInput ? input.baseUrl : input.target.baseUrl ?? input.baseUrl;
|
|
86254
86337
|
const authenticatedGatewayUrl = await ensureSpaceCommandGatewayAuthenticationOrCancel({
|
|
@@ -86266,6 +86349,7 @@ async function runSpaceAddMembersForTarget(input) {
|
|
|
86266
86349
|
};
|
|
86267
86350
|
const explicitMemberIds = normalizeRequestedMemberIds(input.explicitMembers);
|
|
86268
86351
|
const progress = input.details || explicitMemberIds.length === 0 ? addMembersProgress : void 0;
|
|
86352
|
+
const includeLocalParticipation = progress !== void 0 || explicitMemberIds.length === 0;
|
|
86269
86353
|
const candidates = await resolveSpaceMemberCandidatesForAdd({
|
|
86270
86354
|
currentProfile: input.atsProfile,
|
|
86271
86355
|
currentOwnerUserId: input.atsProfile.ownerUserId,
|
|
@@ -86273,7 +86357,12 @@ async function runSpaceAddMembersForTarget(input) {
|
|
|
86273
86357
|
baseUrl: targetBaseUrl,
|
|
86274
86358
|
password: input.password,
|
|
86275
86359
|
explicitMemberIds,
|
|
86276
|
-
progress
|
|
86360
|
+
progress,
|
|
86361
|
+
fastExplicitMembers: shouldUseFastExplicitSpaceAddMembers({
|
|
86362
|
+
details: input.details,
|
|
86363
|
+
explicitMemberIds
|
|
86364
|
+
}),
|
|
86365
|
+
includeLocalParticipation
|
|
86277
86366
|
});
|
|
86278
86367
|
if (candidates.length === 0 && explicitMemberIds.length === 0) {
|
|
86279
86368
|
input.presenter.line({
|
|
@@ -86305,15 +86394,10 @@ async function runSpaceAddMembersForTarget(input) {
|
|
|
86305
86394
|
selectedProfileIds
|
|
86306
86395
|
});
|
|
86307
86396
|
if (selectedCandidates.length === 0) return { status: "completed" };
|
|
86308
|
-
|
|
86309
|
-
stage: "check_local_wake_readiness",
|
|
86310
|
-
phase: "start",
|
|
86311
|
-
summary: "Checking whether selected agent profiles can wake from this computer. Members can still be added if local Wake setup needs attention.",
|
|
86312
|
-
profileIds: selectedCandidates.map((candidate) => candidate.profileId)
|
|
86313
|
-
});
|
|
86314
|
-
const servicePreparationResult = await ensureSpaceMemberCandidatesLocalParticipationReady({
|
|
86397
|
+
const servicePreparationResult = await prepareSpaceAddMembersLocalParticipationIfRequested({
|
|
86315
86398
|
atsProfile: input.atsProfile,
|
|
86316
86399
|
candidates: selectedCandidates,
|
|
86400
|
+
enabled: includeLocalParticipation,
|
|
86317
86401
|
progress,
|
|
86318
86402
|
presenter: input.presenter,
|
|
86319
86403
|
resolvedView: input.runtime.resolvedView,
|
|
@@ -86340,6 +86424,14 @@ async function runSpaceAddMembersForTarget(input) {
|
|
|
86340
86424
|
baseUrl: targetBaseUrl,
|
|
86341
86425
|
password: input.password
|
|
86342
86426
|
});
|
|
86427
|
+
await waitForAddedMembersWakeProjection({
|
|
86428
|
+
actorProfile: input.atsProfile,
|
|
86429
|
+
baseUrl: targetBaseUrl,
|
|
86430
|
+
password: input.password,
|
|
86431
|
+
progress,
|
|
86432
|
+
result,
|
|
86433
|
+
space: input.target.space
|
|
86434
|
+
});
|
|
86343
86435
|
emitSpaceAddMembersProgressIfRequested(progress, {
|
|
86344
86436
|
stage: "record_join_notices",
|
|
86345
86437
|
phase: "write_join_notices",
|
|
@@ -86375,6 +86467,28 @@ async function runSpaceAddMembersForTarget(input) {
|
|
|
86375
86467
|
});
|
|
86376
86468
|
return { status: "completed" };
|
|
86377
86469
|
}
|
|
86470
|
+
async function prepareSpaceAddMembersLocalParticipationIfRequested(input) {
|
|
86471
|
+
if (!input.enabled) return {
|
|
86472
|
+
status: "continue",
|
|
86473
|
+
candidates: input.candidates
|
|
86474
|
+
};
|
|
86475
|
+
emitSpaceAddMembersProgressIfRequested(input.progress, {
|
|
86476
|
+
stage: "check_local_wake_readiness",
|
|
86477
|
+
phase: "start",
|
|
86478
|
+
summary: "Checking whether selected agent profiles can handle work from this computer. Members can still be added if local setup needs attention.",
|
|
86479
|
+
profileIds: input.candidates.map((candidate) => candidate.profileId)
|
|
86480
|
+
});
|
|
86481
|
+
return await ensureSpaceMemberCandidatesLocalParticipationReady({
|
|
86482
|
+
atsProfile: input.atsProfile,
|
|
86483
|
+
candidates: input.candidates,
|
|
86484
|
+
progress: input.progress,
|
|
86485
|
+
presenter: input.presenter,
|
|
86486
|
+
resolvedView: input.resolvedView,
|
|
86487
|
+
allowPrompt: input.allowPrompt,
|
|
86488
|
+
spaceId: input.spaceId,
|
|
86489
|
+
view: input.view
|
|
86490
|
+
});
|
|
86491
|
+
}
|
|
86378
86492
|
function emitSpaceAddMembersProgressIfRequested(progress, input) {
|
|
86379
86493
|
if (!progress) return;
|
|
86380
86494
|
emitAgentSpaceAddMembersProgress({
|
|
@@ -86423,13 +86537,13 @@ function buildSpaceAddMembersLocalWakePlanSummary(plan) {
|
|
|
86423
86537
|
if (assessment.profileKind !== "agent") continue;
|
|
86424
86538
|
counts.set(assessment.localParticipationState, (counts.get(assessment.localParticipationState) ?? 0) + 1);
|
|
86425
86539
|
}
|
|
86426
|
-
return `Local
|
|
86427
|
-
formatLocalWakePlanCount(counts.get("ready") ?? 0, "
|
|
86540
|
+
return `Local agent plan: ${[
|
|
86541
|
+
formatLocalWakePlanCount(counts.get("ready") ?? 0, "can handle work from this device"),
|
|
86428
86542
|
formatLocalWakePlanCount(counts.get("needs_agent_prepare") ?? 0, "need agent preparation"),
|
|
86429
86543
|
formatLocalWakePlanCount(counts.get("needs_ats_service") ?? 0, "need ATS Service"),
|
|
86430
86544
|
formatLocalWakePlanCount(counts.get("membership_only") ?? 0, "will be added as members only"),
|
|
86431
|
-
formatLocalWakePlanCount(counts.get("not_needed") ?? 0, "do not need local
|
|
86432
|
-
].filter((part) => Boolean(part)).join(", ")}. Adding members is separate from
|
|
86545
|
+
formatLocalWakePlanCount(counts.get("not_needed") ?? 0, "do not need local agent setup")
|
|
86546
|
+
].filter((part) => Boolean(part)).join(", ")}. Adding members is separate from local agent participation on this computer.`;
|
|
86433
86547
|
}
|
|
86434
86548
|
function formatLocalWakePlanCount(count, label) {
|
|
86435
86549
|
return count > 0 ? `${String(count)} ${label}` : null;
|
|
@@ -86592,7 +86706,7 @@ async function ensureSpaceMemberCandidatesLocalParticipationReady(input) {
|
|
|
86592
86706
|
candidates: preparedCandidates.map(toActionParticipationCandidateFromSpaceMemberCandidate)
|
|
86593
86707
|
}).shouldOfferServiceGate) input.presenter.line({
|
|
86594
86708
|
code: input.resolvedView === "human" && input.allowPrompt ? "space.add_members.service.declined" : "space.add_members.service.deferred",
|
|
86595
|
-
text: formatInlineAtsCliCommands("ATS will
|
|
86709
|
+
text: formatInlineAtsCliCommands("ATS will add these profiles to the Space. Local agent participation can be checked separately with `ats service status`.")
|
|
86596
86710
|
});
|
|
86597
86711
|
return {
|
|
86598
86712
|
status: "continue",
|
|
@@ -86666,17 +86780,18 @@ function emitSpaceMemberJoinOnlyWarnings(input) {
|
|
|
86666
86780
|
}
|
|
86667
86781
|
function buildSpaceMemberJoinOnlyWarning(candidate) {
|
|
86668
86782
|
if (candidate.profileKind !== "agent") return null;
|
|
86783
|
+
if (candidate.localParticipationChecked !== true) return null;
|
|
86669
86784
|
if (isSpaceMemberCandidateBackgroundReplyReady(candidate)) return null;
|
|
86670
86785
|
const profileLabel = resolveSpaceMemberTerminalProfileLabel(candidate.profileName);
|
|
86671
|
-
if (isSpaceMemberCandidateRepairableLocalParticipationCandidate(candidate)) return `${profileLabel} can join this space now
|
|
86786
|
+
if (isSpaceMemberCandidateRepairableLocalParticipationCandidate(candidate)) return `${profileLabel} can join this space now. ${resolveSpaceMemberTerminalLocalTargetLabel({
|
|
86672
86787
|
displayName: candidate.localTargetDisplayName,
|
|
86673
86788
|
agentId: candidate.localTargetAgentId
|
|
86674
|
-
})} still needs local setup on this device before it can
|
|
86789
|
+
})} still needs local setup on this device before it can handle work from the Space. Use \`${buildSpaceMemberRepairCommand({
|
|
86675
86790
|
agentId: candidate.localTargetAgentId,
|
|
86676
86791
|
profileId: candidate.profileId
|
|
86677
|
-
})}\`
|
|
86792
|
+
})}\` to repair the local agent.`;
|
|
86678
86793
|
const nextAction = resolveSpaceMemberJoinOnlyNextAction(candidate);
|
|
86679
|
-
return `${profileLabel} can join this space now
|
|
86794
|
+
return `${profileLabel} can join this space now. ATS has not confirmed its local reply path on this device yet. ${resolveSpaceMemberJoinOnlyReason(candidate)} ${formatSpaceMemberRecoveryNextAction(nextAction)}`;
|
|
86680
86795
|
}
|
|
86681
86796
|
function resolveSpaceMemberJoinOnlyNextAction(candidate) {
|
|
86682
86797
|
if (candidate.localParticipationReadiness === "not_running") return {
|
|
@@ -86754,6 +86869,7 @@ async function refreshSpaceMemberCandidatesLocalReadiness(candidates, progress,
|
|
|
86754
86869
|
async function enrichSpaceMemberCandidateLocalParticipationReadiness(candidate, progress, options = {}) {
|
|
86755
86870
|
if (candidate.profileKind !== "agent" || !candidate.atsProfile || candidate.controllerEnabled !== true || typeof candidate.controllerRef !== "string" || candidate.controllerRef.trim().length === 0) return {
|
|
86756
86871
|
...candidate,
|
|
86872
|
+
localParticipationChecked: true,
|
|
86757
86873
|
localParticipationReadiness: null,
|
|
86758
86874
|
localParticipationReasonCodes: [],
|
|
86759
86875
|
localParticipationReasonText: null
|
|
@@ -86792,6 +86908,7 @@ async function enrichSpaceMemberCandidateLocalParticipationReadiness(candidate,
|
|
|
86792
86908
|
}
|
|
86793
86909
|
if (!snapshot) return {
|
|
86794
86910
|
...candidate,
|
|
86911
|
+
localParticipationChecked: true,
|
|
86795
86912
|
localParticipationReadiness: null,
|
|
86796
86913
|
localParticipationReasonCodes: [],
|
|
86797
86914
|
localParticipationReasonText: null
|
|
@@ -86803,6 +86920,7 @@ async function enrichSpaceMemberCandidateLocalParticipationReadiness(candidate,
|
|
|
86803
86920
|
});
|
|
86804
86921
|
return {
|
|
86805
86922
|
...candidate,
|
|
86923
|
+
localParticipationChecked: true,
|
|
86806
86924
|
localParticipationReadiness: readinessSummary.serviceReadiness,
|
|
86807
86925
|
localParticipationReasonCodes: [...snapshot.deviceReplyReadiness.reasonCodes],
|
|
86808
86926
|
localParticipationReasonText: snapshot.deviceReplyReadiness.reasonText
|
|
@@ -88079,6 +88197,9 @@ function mapSpaceLeaveFailureToGuideError(input) {
|
|
|
88079
88197
|
return input.error instanceof Error ? input.error : new Error(String(input.error));
|
|
88080
88198
|
}
|
|
88081
88199
|
async function resolveSpaceMemberCandidatesForAdd(input) {
|
|
88200
|
+
const explicitMemberIds = normalizeRequestedMemberIds(input.explicitMemberIds);
|
|
88201
|
+
const includeLocalParticipation = input.includeLocalParticipation !== false;
|
|
88202
|
+
if (input.fastExplicitMembers === true && explicitMemberIds.length > 0) return explicitMemberIds.map(buildFastExplicitSpaceMemberCandidate);
|
|
88082
88203
|
if (input.progress) emitAgentSpaceAddMembersProgress({
|
|
88083
88204
|
...input.progress,
|
|
88084
88205
|
stage: "resolve_candidates",
|
|
@@ -88086,23 +88207,19 @@ async function resolveSpaceMemberCandidatesForAdd(input) {
|
|
|
88086
88207
|
summary: "Reading active local profile identities for this Space."
|
|
88087
88208
|
});
|
|
88088
88209
|
const profiles = await listAtsProfiles();
|
|
88089
|
-
if (input.progress) emitAgentSpaceAddMembersProgress({
|
|
88210
|
+
if (input.progress && includeLocalParticipation) emitAgentSpaceAddMembersProgress({
|
|
88090
88211
|
...input.progress,
|
|
88091
88212
|
stage: "resolve_candidates",
|
|
88092
88213
|
phase: "read_local_targets",
|
|
88093
88214
|
summary: "Reading local agent controller state for candidate profiles before selection."
|
|
88094
88215
|
});
|
|
88095
|
-
const localTargetStates =
|
|
88096
|
-
|
|
88097
|
-
|
|
88098
|
-
|
|
88099
|
-
summary: "Still reading local agent controller state for candidate profiles before selection.",
|
|
88100
|
-
operation: async () => await listAgentTargetStates().catch(() => [])
|
|
88101
|
-
}) : await listAgentTargetStates().catch(() => []);
|
|
88216
|
+
const localTargetStates = await listSpaceAddMembersLocalTargetStatesIfRequested({
|
|
88217
|
+
includeLocalParticipation,
|
|
88218
|
+
progress: input.progress
|
|
88219
|
+
});
|
|
88102
88220
|
const localTargetStateById = new Map(localTargetStates.map((state) => [state.agentId, state]));
|
|
88103
88221
|
const ownerProfileNameByOwnerUserId = buildOwnerProfileNameByOwnerUserId(profiles);
|
|
88104
88222
|
const candidateProfiles = profiles.filter((profile) => profile.status === "active" && isSpaceMembershipProfileKind(profile.profileKind) && profile.atsProfileId !== input.currentProfile.atsProfileId).filter((profile) => {
|
|
88105
|
-
const explicitMemberIds = input.explicitMemberIds ?? [];
|
|
88106
88223
|
if (explicitMemberIds.length > 0 && !explicitMemberIds.includes(profile.atsProfileId)) return false;
|
|
88107
88224
|
return typeof input.currentOwnerUserId !== "string" || input.currentOwnerUserId.trim().length === 0 || profile.ownerUserId === input.currentOwnerUserId;
|
|
88108
88225
|
});
|
|
@@ -88119,29 +88236,58 @@ async function resolveSpaceMemberCandidatesForAdd(input) {
|
|
|
88119
88236
|
...input.password === void 0 ? {} : { spacePassword: input.password }
|
|
88120
88237
|
});
|
|
88121
88238
|
const memberProfileIds = new Set([...membersSnapshot.humans, ...membersSnapshot.agents].map((member) => member.profileId));
|
|
88122
|
-
|
|
88239
|
+
const candidates = (await Promise.all(candidateProfiles.map((profile) => buildSpaceMemberCandidateFromProfile({
|
|
88123
88240
|
baseUrl: input.baseUrl,
|
|
88124
88241
|
profile,
|
|
88125
88242
|
localTargetStateById,
|
|
88126
88243
|
ownerProfileName: ownerProfileNameByOwnerUserId.get(profile.ownerUserId) ?? void 0,
|
|
88127
88244
|
alreadyJoined: memberProfileIds.has(profile.atsProfileId),
|
|
88128
|
-
progress: input.progress
|
|
88245
|
+
progress: input.progress,
|
|
88246
|
+
includeLocalParticipation
|
|
88129
88247
|
})))).sort((left, right) => {
|
|
88130
88248
|
const byName = left.profileName.localeCompare(right.profileName);
|
|
88131
88249
|
if (byName !== 0) return byName;
|
|
88132
88250
|
return left.profileId.localeCompare(right.profileId);
|
|
88133
|
-
})
|
|
88251
|
+
});
|
|
88252
|
+
if (!includeLocalParticipation) return candidates;
|
|
88253
|
+
return await refreshSpaceMemberCandidatesLocalReadiness(candidates, input.progress, { stage: "resolve_candidates" });
|
|
88134
88254
|
}
|
|
88135
|
-
|
|
88136
|
-
|
|
88255
|
+
function buildFastExplicitSpaceMemberCandidate(profileId) {
|
|
88256
|
+
return {
|
|
88257
|
+
profileId,
|
|
88258
|
+
profileName: profileId,
|
|
88259
|
+
profileKind: profileId.startsWith("agt_") ? "agent" : "human",
|
|
88260
|
+
targetMentionLabel: null,
|
|
88261
|
+
localTargetAgentId: null,
|
|
88262
|
+
localTargetDisplayName: null,
|
|
88263
|
+
localTargetLaunchStatus: null,
|
|
88264
|
+
localTargetSelectable: false,
|
|
88265
|
+
localParticipationReadiness: null,
|
|
88266
|
+
localParticipationChecked: false,
|
|
88267
|
+
localParticipationReasonCodes: [],
|
|
88268
|
+
localParticipationReasonText: null,
|
|
88269
|
+
alreadyJoined: false,
|
|
88270
|
+
needsActivation: false
|
|
88271
|
+
};
|
|
88272
|
+
}
|
|
88273
|
+
async function listSpaceAddMembersLocalTargetStatesIfRequested(input) {
|
|
88274
|
+
if (!input.includeLocalParticipation) return [];
|
|
88275
|
+
if (!input.progress) return await listAgentTargetStates().catch(() => []);
|
|
88276
|
+
return await runSpaceAddMembersProgressHeartbeat({
|
|
88137
88277
|
...input.progress,
|
|
88138
88278
|
stage: "resolve_candidates",
|
|
88139
|
-
phase: "
|
|
88140
|
-
summary:
|
|
88141
|
-
|
|
88142
|
-
profileIds: [input.profile.atsProfileId]
|
|
88279
|
+
phase: "read_local_targets_wait",
|
|
88280
|
+
summary: "Still reading local agent controller state for candidate profiles before selection.",
|
|
88281
|
+
operation: async () => await listAgentTargetStates().catch(() => [])
|
|
88143
88282
|
});
|
|
88144
|
-
|
|
88283
|
+
}
|
|
88284
|
+
async function resolveSpaceMemberCandidateRuntimeCapabilityIfRequested(input) {
|
|
88285
|
+
if (!input.includeLocalParticipation) return null;
|
|
88286
|
+
if (!input.progress) return await resolveAgentProfilePrimaryRuntimeCapability({
|
|
88287
|
+
baseUrl: input.baseUrl,
|
|
88288
|
+
profile: input.profile
|
|
88289
|
+
}).catch(() => null);
|
|
88290
|
+
return await runSpaceAddMembersProgressHeartbeat({
|
|
88145
88291
|
...input.progress,
|
|
88146
88292
|
stage: "resolve_candidates",
|
|
88147
88293
|
phase: "read_runtime_capability_wait",
|
|
@@ -88152,10 +88298,24 @@ async function buildSpaceMemberCandidateFromProfile(input) {
|
|
|
88152
88298
|
baseUrl: input.baseUrl,
|
|
88153
88299
|
profile: input.profile
|
|
88154
88300
|
}).catch(() => null)
|
|
88155
|
-
})
|
|
88301
|
+
});
|
|
88302
|
+
}
|
|
88303
|
+
async function buildSpaceMemberCandidateFromProfile(input) {
|
|
88304
|
+
const includeLocalParticipation = input.includeLocalParticipation !== false;
|
|
88305
|
+
if (input.progress && includeLocalParticipation) emitAgentSpaceAddMembersProgress({
|
|
88306
|
+
...input.progress,
|
|
88307
|
+
stage: "resolve_candidates",
|
|
88308
|
+
phase: "read_runtime_capability",
|
|
88309
|
+
summary: `Reading runtime capability projection for ${resolveSpaceMemberTerminalProfileLabel(input.profile.profileName)}.`,
|
|
88310
|
+
profileId: input.profile.atsProfileId,
|
|
88311
|
+
profileIds: [input.profile.atsProfileId]
|
|
88312
|
+
});
|
|
88313
|
+
const runtimeCapability = await resolveSpaceMemberCandidateRuntimeCapabilityIfRequested({
|
|
88156
88314
|
baseUrl: input.baseUrl,
|
|
88157
|
-
|
|
88158
|
-
|
|
88315
|
+
includeLocalParticipation,
|
|
88316
|
+
profile: input.profile,
|
|
88317
|
+
progress: input.progress
|
|
88318
|
+
});
|
|
88159
88319
|
const controllerRef = runtimeCapability?.capabilityRef ?? void 0;
|
|
88160
88320
|
const controllerEnabled = runtimeCapability?.bindingState === "enabled_primary" && runtimeCapability.routable;
|
|
88161
88321
|
const localTargetAgentId = resolveSpaceMemberCandidateLocalTargetAgentId({
|
|
@@ -88180,6 +88340,7 @@ async function buildSpaceMemberCandidateFromProfile(input) {
|
|
|
88180
88340
|
localTargetLaunchStatus: localTargetState?.launchStatus ?? null,
|
|
88181
88341
|
localTargetSelectable: localTargetState?.selectable ?? false,
|
|
88182
88342
|
localParticipationReadiness: null,
|
|
88343
|
+
localParticipationChecked: false,
|
|
88183
88344
|
localParticipationReasonCodes: [],
|
|
88184
88345
|
localParticipationReasonText: null,
|
|
88185
88346
|
alreadyJoined: input.alreadyJoined,
|
|
@@ -88508,14 +88669,19 @@ async function applySpaceAddMembers(input) {
|
|
|
88508
88669
|
}
|
|
88509
88670
|
const addedProfileIds = new Set(response.addedMemberIds);
|
|
88510
88671
|
const alreadyMemberProfileIds = new Set(response.alreadyMemberIds);
|
|
88672
|
+
const responseItemByProfileId = new Map(response.items.map((item) => [item.profileId, item]));
|
|
88511
88673
|
const lastJoinedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
88512
88674
|
const spaceName = normalizeOptionalString$1(input.spaceName);
|
|
88513
88675
|
for (const candidate of selectedCandidates) {
|
|
88676
|
+
const nextCandidate = hydrateSpaceMemberCandidateFromResponseItem({
|
|
88677
|
+
candidate,
|
|
88678
|
+
item: responseItemByProfileId.get(candidate.profileId)
|
|
88679
|
+
});
|
|
88514
88680
|
if (addedProfileIds.has(candidate.profileId)) {
|
|
88515
|
-
result.added.push(
|
|
88681
|
+
result.added.push(nextCandidate);
|
|
88516
88682
|
continue;
|
|
88517
88683
|
}
|
|
88518
|
-
if (alreadyMemberProfileIds.has(candidate.profileId)) result.alreadyJoined.push(
|
|
88684
|
+
if (alreadyMemberProfileIds.has(candidate.profileId)) result.alreadyJoined.push(nextCandidate);
|
|
88519
88685
|
}
|
|
88520
88686
|
for (const candidate of result.added) try {
|
|
88521
88687
|
await upsertProfileSpaceHistory({
|
|
@@ -88542,6 +88708,63 @@ async function applySpaceAddMembers(input) {
|
|
|
88542
88708
|
}
|
|
88543
88709
|
return result;
|
|
88544
88710
|
}
|
|
88711
|
+
function hydrateSpaceMemberCandidateFromResponseItem(input) {
|
|
88712
|
+
if (!input.item) return input.candidate;
|
|
88713
|
+
return {
|
|
88714
|
+
...input.candidate,
|
|
88715
|
+
profileName: input.item.profileName,
|
|
88716
|
+
profileKind: input.item.profileKind,
|
|
88717
|
+
ownerUserId: normalizeOptionalString$1(input.item.ownerUserId) ?? void 0,
|
|
88718
|
+
ownerName: normalizeOptionalString$1(input.item.ownerName) ?? void 0,
|
|
88719
|
+
targetMentionLabel: resolvePrimaryMentionLabelFromSpaceMemberItem(input.item),
|
|
88720
|
+
...input.item.profileKind === "agent" ? { controllerRef: normalizeOptionalString$1(input.item.controllerRef) ?? input.candidate.controllerRef } : {}
|
|
88721
|
+
};
|
|
88722
|
+
}
|
|
88723
|
+
function resolvePrimaryMentionLabelFromSpaceMemberItem(item) {
|
|
88724
|
+
const mentionAlias = normalizeOptionalString$1(item.mentionAlias);
|
|
88725
|
+
if (mentionAlias) return mentionAlias;
|
|
88726
|
+
return resolveSingleSpaceMentionLabels({
|
|
88727
|
+
mentionAlias,
|
|
88728
|
+
profileId: item.profileId,
|
|
88729
|
+
profileName: item.profileName
|
|
88730
|
+
}).primaryMentionLabel;
|
|
88731
|
+
}
|
|
88732
|
+
async function waitForAddedMembersWakeProjection(input) {
|
|
88733
|
+
const expectedWakeableProfileIds = resolveExpectedWakeProjectionProfileIds(input.result);
|
|
88734
|
+
if (expectedWakeableProfileIds.length === 0) return;
|
|
88735
|
+
emitSpaceAddMembersProgressIfRequested(input.progress, {
|
|
88736
|
+
stage: "add_members",
|
|
88737
|
+
phase: "confirm_membership_projection",
|
|
88738
|
+
summary: "Confirming the Space can see newly added wakeable members before returning.",
|
|
88739
|
+
profileIds: expectedWakeableProfileIds
|
|
88740
|
+
});
|
|
88741
|
+
const expected = new Set(expectedWakeableProfileIds);
|
|
88742
|
+
for (let attempt = 0; attempt < SPACE_ADD_MEMBERS_PROJECTION_WAIT_MAX_ATTEMPTS; attempt += 1) {
|
|
88743
|
+
if (attempt > 0) await delay(SPACE_ADD_MEMBERS_PROJECTION_WAIT_DELAY_MS);
|
|
88744
|
+
let membersSnapshot;
|
|
88745
|
+
try {
|
|
88746
|
+
membersSnapshot = await createCliSpaceApi(input.baseUrl).getMembersSnapshot({
|
|
88747
|
+
spaceId: input.space,
|
|
88748
|
+
requestContext: buildAtsRequestContextFromProfile({ atsProfile: input.actorProfile }),
|
|
88749
|
+
...input.password === void 0 ? {} : { spacePassword: input.password }
|
|
88750
|
+
});
|
|
88751
|
+
} catch {
|
|
88752
|
+
return;
|
|
88753
|
+
}
|
|
88754
|
+
if (hasExpectedWakeProjection(membersSnapshot, expected)) return;
|
|
88755
|
+
}
|
|
88756
|
+
}
|
|
88757
|
+
function resolveExpectedWakeProjectionProfileIds(result) {
|
|
88758
|
+
return result.added.filter((candidate) => candidate.profileKind === "agent" && candidate.localParticipationReadiness === "ready").map((candidate) => candidate.profileId);
|
|
88759
|
+
}
|
|
88760
|
+
function hasExpectedWakeProjection(membersSnapshot, expectedProfileIds) {
|
|
88761
|
+
const wakeableProfileIds = new Set(membersSnapshot.agents.filter((member) => member.status === "active" && member.publicReplyPresence?.status === "ready").map((member) => member.profileId));
|
|
88762
|
+
for (const profileId of expectedProfileIds) if (!wakeableProfileIds.has(profileId)) return false;
|
|
88763
|
+
return true;
|
|
88764
|
+
}
|
|
88765
|
+
async function delay(ms) {
|
|
88766
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
88767
|
+
}
|
|
88545
88768
|
function emitSpaceAddMembersResult(input) {
|
|
88546
88769
|
const localParticipationFollowUps = input.result.added.map((candidate) => buildSpaceMemberJoinedFollowUp(candidate)).filter((followUp) => followUp !== null);
|
|
88547
88770
|
if (input.resolvedView === "agent") {
|
|
@@ -88612,6 +88835,7 @@ function emitSpaceAddMembersResult(input) {
|
|
|
88612
88835
|
}
|
|
88613
88836
|
function buildSpaceMemberJoinedFollowUp(candidate) {
|
|
88614
88837
|
if (candidate.profileKind !== "agent") return null;
|
|
88838
|
+
if (candidate.localParticipationChecked !== true) return null;
|
|
88615
88839
|
if (isSpaceMemberCandidateRepairableLocalParticipationCandidate(candidate)) {
|
|
88616
88840
|
const repairCommand = buildSpaceMemberRepairCommand({
|
|
88617
88841
|
agentId: candidate.localTargetAgentId,
|
|
@@ -88625,7 +88849,7 @@ function buildSpaceMemberJoinedFollowUp(candidate) {
|
|
|
88625
88849
|
return {
|
|
88626
88850
|
profileId: candidate.profileId,
|
|
88627
88851
|
reasonCodes: candidate.localParticipationReasonCodes ?? [],
|
|
88628
|
-
text: `${profileLabel} joined this space
|
|
88852
|
+
text: `${profileLabel} joined this space. ${agentLabel} still needs repair on this device before it can handle work from the Space. Use \`${repairCommand}\` to repair the local agent.`
|
|
88629
88853
|
};
|
|
88630
88854
|
}
|
|
88631
88855
|
if (!isSpaceMemberCandidateRunnableLocalParticipationCandidate(candidate)) {
|
|
@@ -88634,7 +88858,7 @@ function buildSpaceMemberJoinedFollowUp(candidate) {
|
|
|
88634
88858
|
return {
|
|
88635
88859
|
profileId: candidate.profileId,
|
|
88636
88860
|
reasonCodes: candidate.localParticipationReasonCodes ?? [],
|
|
88637
|
-
text: `${profileLabel} joined this space
|
|
88861
|
+
text: `${profileLabel} joined this space. ATS has not confirmed its local reply path on this device yet. ${formatSpaceMemberRecoveryNextAction(nextAction)}`
|
|
88638
88862
|
};
|
|
88639
88863
|
}
|
|
88640
88864
|
return null;
|
|
@@ -88869,8 +89093,8 @@ async function persistSpaceAddMembersJoinNotices(input) {
|
|
|
88869
89093
|
failedCount: 0
|
|
88870
89094
|
};
|
|
88871
89095
|
const failures = [];
|
|
88872
|
-
let targetMentionLabelByProfileId;
|
|
88873
|
-
try {
|
|
89096
|
+
let targetMentionLabelByProfileId = buildKnownMentionLabelByProfileId(input.addedMembers);
|
|
89097
|
+
if (!hasMentionLabelsForAllMembers(input.addedMembers, targetMentionLabelByProfileId)) try {
|
|
88874
89098
|
targetMentionLabelByProfileId = buildSpacePrimaryMentionLabelByProfileId(await createCliSpaceApi(input.baseUrl).getMembersSnapshot({
|
|
88875
89099
|
spaceId: input.space,
|
|
88876
89100
|
requestContext: buildAtsRequestContextFromProfile({ atsProfile: input.actorProfile }),
|
|
@@ -88916,6 +89140,17 @@ async function persistSpaceAddMembersJoinNotices(input) {
|
|
|
88916
89140
|
...failures[0] ? { firstFailure: toStructuredGatewayFailure(failures[0].error) } : {}
|
|
88917
89141
|
};
|
|
88918
89142
|
}
|
|
89143
|
+
function buildKnownMentionLabelByProfileId(members) {
|
|
89144
|
+
const labelsByProfileId = /* @__PURE__ */ new Map();
|
|
89145
|
+
for (const member of members) {
|
|
89146
|
+
const targetMentionLabel = normalizeOptionalString$1(member.targetMentionLabel);
|
|
89147
|
+
if (targetMentionLabel) labelsByProfileId.set(member.profileId, targetMentionLabel);
|
|
89148
|
+
}
|
|
89149
|
+
return labelsByProfileId;
|
|
89150
|
+
}
|
|
89151
|
+
function hasMentionLabelsForAllMembers(members, labelsByProfileId) {
|
|
89152
|
+
return members.every((member) => labelsByProfileId.has(member.profileId));
|
|
89153
|
+
}
|
|
88919
89154
|
async function postSpaceAddMemberJoinNotice(input) {
|
|
88920
89155
|
const requestContext = buildAtsRequestContextFromProfile({ atsProfile: input.actorProfile });
|
|
88921
89156
|
await createCliSpaceApi(input.baseUrl).postNormalMessage({
|
|
@@ -89101,8 +89336,9 @@ function resolveSpaceMemberCandidateStatusLabel(candidate) {
|
|
|
89101
89336
|
const TRAILING_PERIOD_RE = /\.$/u;
|
|
89102
89337
|
function resolveSpaceMemberCandidateStatusBadges(candidate) {
|
|
89103
89338
|
if (candidate.profileKind !== "agent") return [];
|
|
89339
|
+
if (candidate.localParticipationChecked !== true) return [];
|
|
89104
89340
|
if (isSpaceMemberCandidateBackgroundReplyReady(candidate)) return ["Local setup connected"];
|
|
89105
|
-
if (isSpaceMemberCandidateRepairableLocalParticipationCandidate(candidate)) return ["Needs repair
|
|
89341
|
+
if (isSpaceMemberCandidateRepairableLocalParticipationCandidate(candidate)) return ["Needs repair"];
|
|
89106
89342
|
return [resolveSpaceMemberJoinOnlyReason(candidate).replace(TRAILING_PERIOD_RE, ""), "Joins only for now"];
|
|
89107
89343
|
}
|
|
89108
89344
|
function isSpaceMemberCandidateBackgroundReplyReady(candidate) {
|
|
@@ -89126,7 +89362,7 @@ function resolveSpaceMemberProfileConnectionAction(candidate) {
|
|
|
89126
89362
|
kind: "instruction"
|
|
89127
89363
|
};
|
|
89128
89364
|
if (candidate.controllerEnabled !== true || typeof candidate.controllerRef !== "string" || candidate.controllerRef.trim().length === 0 || reasonCodes.some((reasonCode) => SPACE_MEMBER_PROFILE_CONNECTION_REASON_CODES.has(reasonCode))) return {
|
|
89129
|
-
instruction: "Open this Agent in ATS Web and choose the local agent that should handle
|
|
89365
|
+
instruction: "Open this Agent in ATS Web and choose the local agent that should handle work from the Space.",
|
|
89130
89366
|
kind: "instruction"
|
|
89131
89367
|
};
|
|
89132
89368
|
if (reasonCodes.includes("controller.binding.disabled")) return {
|
|
@@ -89139,9 +89375,9 @@ function hasSpaceMemberReasonCode(candidate, reasonCodes) {
|
|
|
89139
89375
|
return (candidate.localParticipationReasonCodes ?? []).some((reasonCode) => reasonCodes.has(reasonCode));
|
|
89140
89376
|
}
|
|
89141
89377
|
function formatSpaceMemberRecoveryNextAction(action) {
|
|
89142
|
-
if (action.kind === "instruction") return
|
|
89143
|
-
if (action.command === "ats agents list") return formatInlineAtsCliCommands("Use `ats agents list` to find the local agent that needs repair
|
|
89144
|
-
return `Use \`${formatAtsCliCommand(action.command)}\`
|
|
89378
|
+
if (action.kind === "instruction") return action.instruction;
|
|
89379
|
+
if (action.command === "ats agents list") return formatInlineAtsCliCommands("Use `ats agents list` to find the local agent that needs repair.");
|
|
89380
|
+
return `Use \`${formatAtsCliCommand(action.command)}\` to check the local reply path.`;
|
|
89145
89381
|
}
|
|
89146
89382
|
function resolveSpaceMemberTerminalProfileLabel(profileName) {
|
|
89147
89383
|
return sanitizeSingleLinePromptText(normalizeOptionalString$1(profileName)) || "This agent";
|