primcli 1.68.0 → 1.69.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.
@@ -5361,7 +5361,7 @@ function savedConnectedProfiles(configDir, exclude) {
5361
5361
  */
5362
5362
  async function otherProfiles(configDir, session, current) {
5363
5363
  if (session) try {
5364
- const { connectedProfilesForSession } = await import("./machine-session-7bISVcRb.js").then((n) => n.s);
5364
+ const { connectedProfilesForSession } = await import("./machine-session-CKmn5bvB.js").then((n) => n.s);
5365
5365
  return {
5366
5366
  inSession: true,
5367
5367
  profiles: connectedProfilesForSession(configDir, session, current)
@@ -1,8 +1,8 @@
1
1
  import { S as __exportAll } from "./repeats-BL7ZC-_6-BZ-MphTV.js";
2
2
  import { B as parseOwnerMemberAddress, F as agentProfilesDirectory, I as connectedAgentIdentity, L as connectedApiBaseUrl, M as AgentConnectionSetupError, N as agentProfileDirectory, P as agentProfileName, R as loadConnectedAgentProfile, U as saveConnectedAgentProfile, V as profileAlreadyConnectedMessage, W as PrimitiveApiClient, j as AGENT_PROFILE_ENV, x as loadCliCredentials, z as parseConnectedAgentProfile } from "./cli-config-DMszFbGn.js";
3
- import { Ct as cliInvocation, Jn as putAgentContactPolicy, Jt as refreshStoredCliCredentials, Pn as listDomains, Tt as defaultConnectionName, Vn as listSentEmails, Yn as putContact, an as deleteAgentContact, ar as sendEmail, jn as listContacts, kn as listAgentContacts, mn as getContact, nr as searchEmails, on as deleteContact, pn as getAgentContactPolicy, qn as putAgentContact, vn as getEmail } from "./api-command-D7DPn2Ro.js";
3
+ import { Ct as cliInvocation, Jn as putAgentContactPolicy, Jt as refreshStoredCliCredentials, Pn as listDomains, Tt as defaultConnectionName, Vn as listSentEmails, Yn as putContact, an as deleteAgentContact, ar as sendEmail, jn as listContacts, kn as listAgentContacts, mn as getContact, nr as searchEmails, on as deleteContact, pn as getAgentContactPolicy, qn as putAgentContact, vn as getEmail } from "./api-command-C58Oh38I.js";
4
4
  import { _ as acquireListenLock, c as mailTime, d as readMailJson, f as removeMailFile, g as ListenStateError, h as writeMailJson, i as mailId, l as privateMailDirectory, o as mailObject, r as mailAddress, s as mailString } from "./shared-mail-files-MwlVE90c.js";
5
- import { _ as detectAgentRuntime, a as NotificationRetryError, d as defaultSessionSocket, f as NativeSessionDisconnectedError, l as SESSION_UUID, t as notificationScope, u as connectNativeSession, v as installConnectSkill, x as readBundledConnectSkill } from "./notify-session-Cp0Kkstb.js";
5
+ import { _ as detectAgentRuntime, a as NotificationRetryError, d as defaultSessionSocket, f as NativeSessionDisconnectedError, l as SESSION_UUID, t as notificationScope, u as connectNativeSession, v as installConnectSkill, x as readBundledConnectSkill } from "./notify-session-CVZtEboh.js";
6
6
  import { a as scopedChatSenderTrust } from "./scoped-chat-Dsark9hm.js";
7
7
  import { l as stopBackgroundListen, r as backgroundListenStatus } from "./listen-background--0peztKE.js";
8
8
  import { t as readSharedMailOwner } from "./shared-mail-watch-DtKpsgg8.js";
@@ -2507,7 +2507,7 @@ async function runAddressNotesRequest(client, request) {
2507
2507
  if (request.ifAbsent) condition = { if_absent: true };
2508
2508
  else if (ifVersion) condition = { if_version: ifVersion };
2509
2509
  else try {
2510
- condition = { if_version: (await getNote(client, address, name)).version };
2510
+ condition = { if_version: (await getNote(client, address, name, request.signal)).version };
2511
2511
  } catch (error) {
2512
2512
  if (!(error instanceof AddressNotesApiError) || error.status !== 404) throw error;
2513
2513
  condition = { if_absent: true };
@@ -2525,10 +2525,11 @@ async function runAddressNotesRequest(client, request) {
2525
2525
  ...request.visibility ? { visibility: request.visibility } : {}
2526
2526
  },
2527
2527
  headers: { "Content-Type": "application/json" },
2528
- responseStyle: "fields"
2528
+ responseStyle: "fields",
2529
+ ...request.signal ? { signal: request.signal } : {}
2529
2530
  })), address, name);
2530
2531
  }
2531
- const version = ifVersion ?? (await getNote(client, address, name)).version;
2532
+ const version = ifVersion ?? (await getNote(client, address, name, request.signal)).version;
2532
2533
  const data = await result(client.delete({
2533
2534
  security,
2534
2535
  url: "/address-notes/{address}/{name}",
@@ -2537,12 +2538,127 @@ async function runAddressNotesRequest(client, request) {
2537
2538
  name
2538
2539
  },
2539
2540
  query: { if_version: version },
2540
- responseStyle: "fields"
2541
+ responseStyle: "fields",
2542
+ ...request.signal ? { signal: request.signal } : {}
2541
2543
  }));
2542
2544
  if (!data || typeof data !== "object" || Array.isArray(data) || typeof data.deleted !== "boolean") throw new Error("The address notes API returned an invalid deletion response.");
2543
2545
  return data;
2544
2546
  }
2545
2547
  //#endregion
2548
+ //#region src/oclif/agent-resume-note.ts
2549
+ /**
2550
+ * The address note holding the command that resumes the coding session an
2551
+ * agent is bound to, so an app can offer to reopen that exact session.
2552
+ */
2553
+ const RESUME_NOTE_NAME = "AGENT_RESUME";
2554
+ /**
2555
+ * Each note request gets this long. The note is best effort and runs inside
2556
+ * registration, connect, disconnect and their hooks, so a stalled request
2557
+ * must never hold them up.
2558
+ */
2559
+ const NOTE_REQUEST_TIMEOUT_MS = 1e4;
2560
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2561
+ /**
2562
+ * The AGENT_RESUME value for a session: `claude --resume <uuid>` for Claude
2563
+ * Code or `codex resume <uuid>` for Codex, with the ID lowercased. Any other
2564
+ * runtime, or an ID that is not a UUID, has no value.
2565
+ */
2566
+ function resumeNoteValue(runtime, sessionId) {
2567
+ const id = sessionId?.trim().toLowerCase() ?? "";
2568
+ if (!UUID.test(id)) return null;
2569
+ if (runtime === "claude") return `claude --resume ${id}`;
2570
+ if (runtime === "codex") return `codex resume ${id}`;
2571
+ return null;
2572
+ }
2573
+ function client(profile, fetchImpl) {
2574
+ return new PrimitiveApiClient({
2575
+ apiKey: profile.api_key,
2576
+ apiBaseUrl: profile.api_base_url,
2577
+ ...fetchImpl ? { fetch: fetchImpl } : {}
2578
+ }).client;
2579
+ }
2580
+ /** The current note, or null when the address has none. */
2581
+ async function currentNote(api, address, timeoutMs) {
2582
+ try {
2583
+ return await runAddressNotesRequest(api, {
2584
+ action: "get",
2585
+ address,
2586
+ name: RESUME_NOTE_NAME,
2587
+ signal: AbortSignal.timeout(timeoutMs)
2588
+ });
2589
+ } catch (error) {
2590
+ if (error instanceof AddressNotesApiError && error.status === 404) return null;
2591
+ throw error;
2592
+ }
2593
+ }
2594
+ /**
2595
+ * Write the AGENT_RESUME note for a connected profile's address. Skips the
2596
+ * write when the note already holds the same value, so a resume hook that
2597
+ * runs on every start does not rewrite it. `rewrite` writes it anyway, so a
2598
+ * new claim leaves the note no older than the connection it belongs to.
2599
+ * Never throws.
2600
+ */
2601
+ async function publishResumeNote(options) {
2602
+ const timeoutMs = options.timeoutMs ?? 1e4;
2603
+ const value = resumeNoteValue(options.runtime, options.sessionId);
2604
+ if (value === null) return "skipped";
2605
+ try {
2606
+ const profile = loadConnectedAgentProfile(options.configDir, options.profileName);
2607
+ if (!profile) return "skipped";
2608
+ const api = client(profile, options.fetch);
2609
+ const address = profile.agent_address;
2610
+ const current = await currentNote(api, address, timeoutMs);
2611
+ if (current?.value === value && !options.rewrite) return "unchanged";
2612
+ await runAddressNotesRequest(api, {
2613
+ action: "set",
2614
+ address,
2615
+ name: RESUME_NOTE_NAME,
2616
+ value,
2617
+ visibility: "private",
2618
+ signal: AbortSignal.timeout(timeoutMs),
2619
+ ...current?.version ? { ifVersion: current.version } : { ifAbsent: true }
2620
+ });
2621
+ return "written";
2622
+ } catch {
2623
+ return "failed";
2624
+ }
2625
+ }
2626
+ /**
2627
+ * Delete the AGENT_RESUME note with this credential, before it is revoked.
2628
+ * Never throws.
2629
+ */
2630
+ async function clearResumeNote(profile, fetchImpl, timeoutMs = NOTE_REQUEST_TIMEOUT_MS) {
2631
+ try {
2632
+ const api = client(profile, fetchImpl);
2633
+ const current = await currentNote(api, profile.agent_address, timeoutMs);
2634
+ if (!current) return "absent";
2635
+ await runAddressNotesRequest(api, {
2636
+ action: "delete",
2637
+ address: profile.agent_address,
2638
+ name: RESUME_NOTE_NAME,
2639
+ signal: AbortSignal.timeout(timeoutMs),
2640
+ ...current.version ? { ifVersion: current.version } : {}
2641
+ });
2642
+ return "cleared";
2643
+ } catch {
2644
+ return "failed";
2645
+ }
2646
+ }
2647
+ /**
2648
+ * Delete the AGENT_RESUME note of a connected profile's address, for a
2649
+ * connection that binds no resumable session, so a command left by an older
2650
+ * session never points at the wrong conversation. Never throws.
2651
+ */
2652
+ async function clearProfileResumeNote(options) {
2653
+ try {
2654
+ const profile = loadConnectedAgentProfile(options.configDir, options.profileName);
2655
+ if (!profile) return "skipped";
2656
+ return await clearResumeNote(profile, options.fetch);
2657
+ } catch {
2658
+ return "failed";
2659
+ }
2660
+ }
2661
+ //#endregion
2546
2662
  //#region src/oclif/agent-disconnect.ts
2547
2663
  var AgentDisconnectError = class extends Error {};
2548
2664
  /** The profile no longer holds the credential the caller expected to revoke. */
@@ -2676,6 +2792,12 @@ async function disconnectAgent(params) {
2676
2792
  }) : null;
2677
2793
  if (receiver && !receiverStopped(receiver)) throw new AgentDisconnectError("The bound receiver has not confirmed stopping. The connection and credential were preserved. Check listener status before retrying.");
2678
2794
  const previous = confirmedLocally(directory, profile);
2795
+ let resumeNote = "skipped";
2796
+ if (!previous) try {
2797
+ resumeNote = await (params.clearResumeNote ?? clearResumeNote)(profile, params.fetch);
2798
+ } catch {
2799
+ resumeNote = "failed";
2800
+ }
2679
2801
  const revocation = previous ? "previously_confirmed" : await revoke(profile, params.fetch);
2680
2802
  if (!previous) try {
2681
2803
  writeMailJson(confirmationPath(directory, profile), {
@@ -2708,7 +2830,8 @@ async function disconnectAgent(params) {
2708
2830
  identity: connectedAgentIdentity(profileName, profile),
2709
2831
  receiver,
2710
2832
  revocation,
2711
- externalHook
2833
+ externalHook,
2834
+ resumeNote
2712
2835
  };
2713
2836
  } catch (error) {
2714
2837
  if (error instanceof AgentDisconnectError) throw error;
@@ -2818,6 +2941,7 @@ async function clearRevokedAddresses(params) {
2818
2941
  stopReceiver: params.stopReceiver,
2819
2942
  now: params.now,
2820
2943
  env: params.env,
2944
+ clearResumeNote: async () => "skipped",
2821
2945
  expected: {
2822
2946
  address: checked.agent_address,
2823
2947
  invitationHash: checked.invitation_hash
@@ -4028,6 +4152,17 @@ function defaults(options) {
4028
4152
  });
4029
4153
  },
4030
4154
  seedAgentInfo: (profileName, value) => seedAgentInfoNote(options.configDir, profileName, value),
4155
+ publishResumeNote: (profileName, runtime, session) => publishResumeNote({
4156
+ configDir: options.configDir,
4157
+ profileName,
4158
+ runtime,
4159
+ sessionId: session,
4160
+ rewrite: true
4161
+ }),
4162
+ clearResumeNote: (profileName) => clearProfileResumeNote({
4163
+ configDir: options.configDir,
4164
+ profileName
4165
+ }),
4031
4166
  refreshOwnerMemberAddress: (profileName) => refreshOwnerMemberAddress({
4032
4167
  configDir: options.configDir,
4033
4168
  profileName
@@ -4224,6 +4359,12 @@ async function runAgentConnect(options) {
4224
4359
  reason: "already_present"
4225
4360
  });
4226
4361
  }
4362
+ let resumeNote = "skipped";
4363
+ if (verified) try {
4364
+ resumeNote = session && runtime ? await dependencies.publishResumeNote(result.identity.profileName, runtime, session) : await dependencies.clearResumeNote(result.identity.profileName);
4365
+ } catch {
4366
+ resumeNote = "failed";
4367
+ }
4227
4368
  const receiving = receiver === "external" ? {
4228
4369
  ...result.receiving,
4229
4370
  state: externalReceivingState(externalHook),
@@ -4279,6 +4420,7 @@ async function runAgentConnect(options) {
4279
4420
  receiving,
4280
4421
  ...result.ownerNotifications ? { ownerNotifications: result.ownerNotifications } : {},
4281
4422
  agentInfo: agentInfoState,
4423
+ resumeNote,
4282
4424
  skipped,
4283
4425
  warnings,
4284
4426
  selectProfile: `PRIMITIVE_AGENT_PROFILE=${result.identity.profileName}`,
@@ -5164,7 +5306,7 @@ async function cleanUpReplacedRegistration(configDir, record, current, deps, env
5164
5306
  await deps.revokeByAddress(configDir, address, fetchImpl);
5165
5307
  } catch {}
5166
5308
  }
5167
- async function disconnectSessionAgent(configDir, record, deps, env, fetchImpl, enrollmentSettled = false) {
5309
+ async function disconnectSessionAgent(configDir, record, deps, env, fetchImpl, enrollmentSettled = false, report = {}) {
5168
5310
  try {
5169
5311
  const current = loadConnectedAgentProfile(configDir, record.profile);
5170
5312
  if (current) {
@@ -5174,7 +5316,7 @@ async function disconnectSessionAgent(configDir, record, deps, env, fetchImpl, e
5174
5316
  };
5175
5317
  if (!holdsRegisteredCredential(configDir, record, current)) return await release(current);
5176
5318
  try {
5177
- await deps.disconnect({
5319
+ const disconnected = await deps.disconnect({
5178
5320
  configDir,
5179
5321
  profileName: record.profile,
5180
5322
  fetch: fetchImpl,
@@ -5184,6 +5326,7 @@ async function disconnectSessionAgent(configDir, record, deps, env, fetchImpl, e
5184
5326
  invitationHash: current.invitation_hash
5185
5327
  }
5186
5328
  });
5329
+ if (disconnected?.resumeNote) report.resumeNote = disconnected.resumeNote;
5187
5330
  } catch (error) {
5188
5331
  if (!(error instanceof AgentCredentialChangedError)) throw error;
5189
5332
  const holder = loadConnectedAgentProfile(configDir, record.profile);
@@ -5203,8 +5346,8 @@ async function disconnectSessionAgent(configDir, record, deps, env, fetchImpl, e
5203
5346
  return "pending";
5204
5347
  }
5205
5348
  }
5206
- async function finishSessionDisconnect(configDir, record, deps, env, fetchImpl, enrollmentSettled = false) {
5207
- const outcome = await disconnectSessionAgent(configDir, record, deps, env, fetchImpl, enrollmentSettled);
5349
+ async function finishSessionDisconnect(configDir, record, deps, env, fetchImpl, enrollmentSettled = false, report = {}) {
5350
+ const outcome = await disconnectSessionAgent(configDir, record, deps, env, fetchImpl, enrollmentSettled, report);
5208
5351
  const saved = await updateSessionRecord(configDir, record.session, (current) => {
5209
5352
  if (current?.createdBy !== "session-register" || current.disconnect === "done") return current;
5210
5353
  if (outcome === "released") return releasedRecord(current, "credential_changed", deps.now());
@@ -5252,6 +5395,13 @@ async function registerSession(options) {
5252
5395
  installClaudeHook: installClaudeWakeHook,
5253
5396
  seedAgentInfo: (configDir, profileName, value) => seedAgentInfoNote(configDir, profileName, value, options.fetch),
5254
5397
  connectionState: (profile) => agentConnectionState(profile, options.fetch),
5398
+ publishResumeNote: (configDir, profileName, runtime, sessionId) => publishResumeNote({
5399
+ configDir,
5400
+ profileName,
5401
+ runtime,
5402
+ sessionId,
5403
+ fetch: options.fetch
5404
+ }),
5255
5405
  ompSession: ompProcessSession,
5256
5406
  ...DISCONNECT_DEFAULTS
5257
5407
  }, options.dependencies);
@@ -5382,6 +5532,14 @@ async function registerSession(options) {
5382
5532
  agentInfo: seeded
5383
5533
  } : current);
5384
5534
  };
5535
+ const finishResumeNote = async () => {
5536
+ if (runtime === "omp") return {};
5537
+ try {
5538
+ return { resumeNote: await deps.publishResumeNote(options.configDir, profileName, runtime, sessionId) };
5539
+ } catch {
5540
+ return { resumeNote: "failed" };
5541
+ }
5542
+ };
5385
5543
  const claudeHook = (agentAddress) => {
5386
5544
  const outcome = deps.installClaudeHook({
5387
5545
  cliPath: options.cliPath,
@@ -5424,10 +5582,12 @@ async function registerSession(options) {
5424
5582
  if (state === "connected") {
5425
5583
  const hooked = installHook(existing);
5426
5584
  await finishAgentInfo();
5585
+ const resumeNote = await finishResumeNote();
5427
5586
  return {
5428
5587
  ...withAddress,
5429
5588
  receiving: RECEIVING[runtime],
5430
5589
  status: "already_registered",
5590
+ ...resumeNote,
5431
5591
  detail: hooked === "installed" ? "This session is already connected." : hooked === "held" ? HELD_DETAIL : "This session is already connected, but its receive hook could not be installed. Run `primitive machine doctor`."
5432
5592
  };
5433
5593
  }
@@ -5495,7 +5655,11 @@ async function registerSession(options) {
5495
5655
  const status = result.connection.status;
5496
5656
  let hooked = "installed";
5497
5657
  if (runtime === "claude" && submitted && status !== "owner_inactive") hooked = claudeHook(address);
5498
- if (status === "connected") await finishAgentInfo();
5658
+ let resumeNote = {};
5659
+ if (status === "connected") {
5660
+ await finishAgentInfo();
5661
+ resumeNote = await finishResumeNote();
5662
+ }
5499
5663
  const withAddress = {
5500
5664
  ...known,
5501
5665
  address,
@@ -5507,6 +5671,7 @@ async function registerSession(options) {
5507
5671
  status: "registered",
5508
5672
  name,
5509
5673
  nameIsDefault: name === record.name,
5674
+ ...resumeNote,
5510
5675
  detail: hooked === "installed" ? `Connected as ${address}.` : hooked === "held" ? `Connected as ${address}. ${HELD_DETAIL}` : `Connected as ${address}, but the receive hook could not be installed. Run \`primitive machine doctor\`.`
5511
5676
  };
5512
5677
  if (status === "revoked" || status === "owner_inactive") return {
@@ -5701,7 +5866,8 @@ async function endSession(options) {
5701
5866
  status: "kept",
5702
5867
  detail: KEPT_DETAIL
5703
5868
  };
5704
- const outcome = await finishSessionDisconnect(options.configDir, record, deps, env, options.fetch);
5869
+ const report = {};
5870
+ const outcome = await finishSessionDisconnect(options.configDir, record, deps, env, options.fetch, false, report);
5705
5871
  if (outcome === "released") return {
5706
5872
  ...known,
5707
5873
  status: "left_connected",
@@ -5710,6 +5876,7 @@ async function endSession(options) {
5710
5876
  return outcome === "done" ? {
5711
5877
  ...known,
5712
5878
  status: "disconnected",
5879
+ ...report.resumeNote ? { resumeNote: report.resumeNote } : {},
5713
5880
  detail: "This session's agent was disconnected."
5714
5881
  } : {
5715
5882
  ...known,
@@ -1,5 +1,5 @@
1
1
  import { b as parseWebhookEvent, c as classifySignalContent, v as isEmailReceivedEvent, y as isTrustedSender } from "./repeats-BL7ZC-_6-BZ-MphTV.js";
2
- import { F as wakeReadCommand, P as skillFirstLine, Y as wakeInteractionSentence, dn as downloadEmailAttachmentPart } from "./api-command-D7DPn2Ro.js";
2
+ import { F as wakeReadCommand, P as skillFirstLine, Y as wakeInteractionSentence, dn as downloadEmailAttachmentPart } from "./api-command-C58Oh38I.js";
3
3
  import { _ as acquireListenLock, g as ListenStateError, y as listenIdentity } from "./shared-mail-files-MwlVE90c.js";
4
4
  import { closeSync, copyFileSync, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, opendirSync, readFileSync, readdirSync, readlinkSync, renameSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
5
5
  import { createHash, randomUUID, scryptSync } from "node:crypto";
@@ -1,6 +1,6 @@
1
- import { A as readThreadContext, En as getSentEmail, Kt as createAuthenticatedCliApiClient } from "../api-command-D7DPn2Ro.js";
1
+ import { A as readThreadContext, En as getSentEmail, Kt as createAuthenticatedCliApiClient } from "../api-command-C58Oh38I.js";
2
2
  import { _ as acquireListenLock } from "../shared-mail-files-MwlVE90c.js";
3
- import { t as sendSignal } from "../signal-command-Bi2U2BR_.js";
3
+ import { t as sendSignal } from "../signal-command-Dy_oub7_.js";
4
4
  import { AUTO_SIGNAL_KIND_ENV, AUTO_WORKING_RENEW_MS, autoSignalsDisabled, clearWorkingSending, markWorkingSending, readAutoClaim, readWorkingLease, recordRenewer, stopWorkingLease, writeWorkingLease } from "./auto-signals.js";
5
5
  import { join } from "node:path";
6
6
  import { homedir } from "node:os";
@@ -1,12 +1,12 @@
1
1
  import { a as REPEAT_IDLE_MAX_MINUTES, b as parseWebhookEvent, d as parseRepeatTick, f as preparePresenceAliveEmail, i as REPEAT_EVERY_MAX_MINUTES, l as parseInteractionEnvelope$1, m as repeatStopCommand, o as REPEAT_MAX_SENDS_MAX, p as prepareSignalEmail, s as buildRepeatStopBody, u as parsePresenceEnvelope, v as isEmailReceivedEvent, x as parseFromHeader } from "../repeats-BL7ZC-_6-BZ-MphTV.js";
2
2
  import { A as saveActiveChatState, C as resolveCliAuth, D as deleteChatState, E as chatStatePath, F as agentProfilesDirectory, H as requireDefaultLoginProfile, M as AgentConnectionSetupError, N as agentProfileDirectory, O as loadActiveChatState, P as agentProfileName, R as loadConnectedAgentProfile, T as saveSignupCredentials, W as PrimitiveApiClient, _ as deleteCliCredentials, a as normalizeCliEnvironmentName, b as hasStoredCliLogin, c as resolveConfigEnvironment, g as credentialsPath, h as credentialsLockPath, i as loadCliConfig, j as AGENT_PROFILE_ENV, k as loadChatConversationByLocalId, l as saveCliConfig, m as cliAccessTokenExpiresAt, n as deleteCliConfig, o as redactCliEnvironment, p as acquireCliCredentialsLock, r as emptyCliConfig, s as removeCliEnvironment, u as upsertCliEnvironment, v as deleteCliCredentialsLock, w as saveCliCredentials, x as loadCliCredentials, y as detectPrimitiveKeyEnvMisname } from "../cli-config-DMszFbGn.js";
3
- import { $ as apiResultHttpStatus, $n as replyToEmail, $t as completeWebhookEvent, A as readThreadContext, An as listAgentNetworks, At as formatAlreadySentNotice, B as pendingMailPath, Bn as listRoutes, Bt as expectedAutomatedVerdicts, C as queryUsesAwaiting, Cn as getMemory, Cr as verifyAgentSignup, Ct as cliInvocation, D as displayAddress, Dn as getThread, Dt as identitySuggestions, E as describeWake, En as getSentEmail, Et as generatedAgentName, F as wakeReadCommand, Fn as listEmails, Ft as AUTOMATED_VALUES, G as interactionNextActions, Gn as pollCliLogin, H as recordPendingMail, Hn as listWakeAuthorizations, Ht as isAutomatedRejectedError, I as wakeRecipientField, In as listEndpoints, It as AutomatedFilterUnsupportedError, J as replyInteractionWarning, Jt as refreshStoredCliCredentials, K as readEmailInteraction, Kn as pullWebhookEvent, Kt as createAuthenticatedCliApiClient, L as wakeRelationship, Ln as listFunctionLogs, Lt as assertAutomatedVerdict, M as serverMuted, Mn as listDefaultNetworkAgents, Mt as withFlagSuggestion, N as serverRelationship, Nn as listDefaultNetworkMembers, Nt as AUTOMATED_FILTER_UNSUPPORTED_CODE, O as formatMailWakeLine, On as getWakeSchedule, Ot as loadSkillLine, Pn as listDomains, Pt as AUTOMATED_FLAG_DESCRIPTION, Q as SEND_OUTCOME_HELP, Qn as reorderRoutes, Qt as cliLogout, R as clearConsumedPendingMail, Rn as listFunctions, Rt as automatedRejectedError, S as isAwaitingRejectedError, Sn as getInboxStatus, Sr as verifyAgentClaim, T as bareAddress, Tn as getRepeatingSend, U as removePendingMail, Un as listWakeDispatches, Ut as queryUsesAutomated, V as readPendingMail, Vn as listSentEmails, Vt as hasAutomatedVerdict, W as interactionHumanLine, Wn as listWakeSchedules, Wt as ConnectedAgentKeyRequiredError, X as IDEMPOTENCY_KEY_FLAG_DESCRIPTION, Xn as redeemCreditCode, Xt as addDefaultNetworkMember, Yt as resolveCliApiRequestConfig, Z as MAX_SEND_WAIT_TIMEOUT_MS, Zn as removeDefaultNetworkMember, Zt as checkDefaultNetworkContactAdmission, _ as awaitingRejectedError, _n as getDefaultNetworkAgent, _r as updateFunction, _t as sendWaitClampNotice, a as extractErrorCode, ar as sendEmail, at as deriveSendIdempotencyKey, b as formatRepliesCell, bn as getFunctionRouting, br as updateWakeAuthorization, bt as successfulSendOutcome, c as readTextFileFlag, cn as deleteRoute, cr as setMemory, ct as formatDeletedEarlierSendNotice, d as writeErrorWithHints, dr as startAgentSignup, dt as formatSendFailureSummary, en as createEndpoint, er as resendAgentSignupVerification, et as assertValidIdempotencyKey, f as AWAITING_FLAG_DESCRIPTION, fn as getAccount, fr as startCliLogin, ft as formatSendRecordFailureSummary, g as assertAwaitingFilterRows, gn as getCreditBalance, gr as updateDefaultNetworkMember, gt as sendOutcomeExitCode, h as ReplyStateUnsupportedError, hn as getConversation, hr as unsetFunctionRoute, ht as sendIdentityFields, i as createOperationCommand, in as createWakeSchedule, ir as semanticSearch, it as classifySendError, j as sentInThread, jt as writeIdempotentReplayBannerIfReplay, k as latestOwnOutbound, kn as listAgentContacts, kt as currentMailSessionKey, l as runWithTiming, ln as deleteWakeAuthorization, lr as simulateRoute, lt as formatPriorRepliesCheckSkipped, m as REPLY_STATE_UNSUPPORTED_CODE, mr as testFunction, mt as reportSendCommandResult, n as API_ERROR_CODES, nn as createRoute, nr as searchEmails, nt as buildThrownSendFailureEnvelope, o as extractErrorPayload, or as setFunctionRoute, ot as excludeSignalReplies, p as AWAITING_VALUES, pn as getAgentContactPolicy, pr as stopRepeatFromEmail, pt as priorRepliesThatWentOut, q as replyExpectation, qt as createCliApiClient, r as TIME_FLAG_DESCRIPTION, rn as createWakeAuthorization, rr as searchMemories, rt as checkPriorReplies, s as formatErrorPayload, sn as deleteMemory, sr as setFunctionSecret, st as followUpCommandPrefix, t as API_BASE_URL_FLAG_DESCRIPTION, tn as createFunction, tr as runWakeSchedule, tt as buildFollowUpCommand, u as surfaceUnauthorizedHint, un as deleteWakeSchedule, ur as startAgentClaim, ut as formatPriorRepliesWarning, v as ensureSearchReportsReplyState, vn as getEmail, vr as updateRepeatingSend, vt as sentHistoryWindowStart, w as explainPendingMailNotFound, wn as getOrgRoutingTopology, wt as connectNextSteps, x as hasReplyState, xn as getFunctionTestRunTrace, xr as updateWakeSchedule, xt as thrownErrorExitCode, y as formatAwaitingCell, yn as getFunction, yr as updateRoute, yt as serializeErrorPayload, z as clearReadPendingMail, zn as listRepeatingSends, zt as ensureSearchReportsAutomated } from "../api-command-D7DPn2Ro.js";
3
+ import { $ as apiResultHttpStatus, $n as replyToEmail, $t as completeWebhookEvent, A as readThreadContext, An as listAgentNetworks, At as formatAlreadySentNotice, B as pendingMailPath, Bn as listRoutes, Bt as expectedAutomatedVerdicts, C as queryUsesAwaiting, Cn as getMemory, Cr as verifyAgentSignup, Ct as cliInvocation, D as displayAddress, Dn as getThread, Dt as identitySuggestions, E as describeWake, En as getSentEmail, Et as generatedAgentName, F as wakeReadCommand, Fn as listEmails, Ft as AUTOMATED_VALUES, G as interactionNextActions, Gn as pollCliLogin, H as recordPendingMail, Hn as listWakeAuthorizations, Ht as isAutomatedRejectedError, I as wakeRecipientField, In as listEndpoints, It as AutomatedFilterUnsupportedError, J as replyInteractionWarning, Jt as refreshStoredCliCredentials, K as readEmailInteraction, Kn as pullWebhookEvent, Kt as createAuthenticatedCliApiClient, L as wakeRelationship, Ln as listFunctionLogs, Lt as assertAutomatedVerdict, M as serverMuted, Mn as listDefaultNetworkAgents, Mt as withFlagSuggestion, N as serverRelationship, Nn as listDefaultNetworkMembers, Nt as AUTOMATED_FILTER_UNSUPPORTED_CODE, O as formatMailWakeLine, On as getWakeSchedule, Ot as loadSkillLine, Pn as listDomains, Pt as AUTOMATED_FLAG_DESCRIPTION, Q as SEND_OUTCOME_HELP, Qn as reorderRoutes, Qt as cliLogout, R as clearConsumedPendingMail, Rn as listFunctions, Rt as automatedRejectedError, S as isAwaitingRejectedError, Sn as getInboxStatus, Sr as verifyAgentClaim, T as bareAddress, Tn as getRepeatingSend, U as removePendingMail, Un as listWakeDispatches, Ut as queryUsesAutomated, V as readPendingMail, Vn as listSentEmails, Vt as hasAutomatedVerdict, W as interactionHumanLine, Wn as listWakeSchedules, Wt as ConnectedAgentKeyRequiredError, X as IDEMPOTENCY_KEY_FLAG_DESCRIPTION, Xn as redeemCreditCode, Xt as addDefaultNetworkMember, Yt as resolveCliApiRequestConfig, Z as MAX_SEND_WAIT_TIMEOUT_MS, Zn as removeDefaultNetworkMember, Zt as checkDefaultNetworkContactAdmission, _ as awaitingRejectedError, _n as getDefaultNetworkAgent, _r as updateFunction, _t as sendWaitClampNotice, a as extractErrorCode, ar as sendEmail, at as deriveSendIdempotencyKey, b as formatRepliesCell, bn as getFunctionRouting, br as updateWakeAuthorization, bt as successfulSendOutcome, c as readTextFileFlag, cn as deleteRoute, cr as setMemory, ct as formatDeletedEarlierSendNotice, d as writeErrorWithHints, dr as startAgentSignup, dt as formatSendFailureSummary, en as createEndpoint, er as resendAgentSignupVerification, et as assertValidIdempotencyKey, f as AWAITING_FLAG_DESCRIPTION, fn as getAccount, fr as startCliLogin, ft as formatSendRecordFailureSummary, g as assertAwaitingFilterRows, gn as getCreditBalance, gr as updateDefaultNetworkMember, gt as sendOutcomeExitCode, h as ReplyStateUnsupportedError, hn as getConversation, hr as unsetFunctionRoute, ht as sendIdentityFields, i as createOperationCommand, in as createWakeSchedule, ir as semanticSearch, it as classifySendError, j as sentInThread, jt as writeIdempotentReplayBannerIfReplay, k as latestOwnOutbound, kn as listAgentContacts, kt as currentMailSessionKey, l as runWithTiming, ln as deleteWakeAuthorization, lr as simulateRoute, lt as formatPriorRepliesCheckSkipped, m as REPLY_STATE_UNSUPPORTED_CODE, mr as testFunction, mt as reportSendCommandResult, n as API_ERROR_CODES, nn as createRoute, nr as searchEmails, nt as buildThrownSendFailureEnvelope, o as extractErrorPayload, or as setFunctionRoute, ot as excludeSignalReplies, p as AWAITING_VALUES, pn as getAgentContactPolicy, pr as stopRepeatFromEmail, pt as priorRepliesThatWentOut, q as replyExpectation, qt as createCliApiClient, r as TIME_FLAG_DESCRIPTION, rn as createWakeAuthorization, rr as searchMemories, rt as checkPriorReplies, s as formatErrorPayload, sn as deleteMemory, sr as setFunctionSecret, st as followUpCommandPrefix, t as API_BASE_URL_FLAG_DESCRIPTION, tn as createFunction, tr as runWakeSchedule, tt as buildFollowUpCommand, u as surfaceUnauthorizedHint, un as deleteWakeSchedule, ur as startAgentClaim, ut as formatPriorRepliesWarning, v as ensureSearchReportsReplyState, vn as getEmail, vr as updateRepeatingSend, vt as sentHistoryWindowStart, w as explainPendingMailNotFound, wn as getOrgRoutingTopology, wt as connectNextSteps, x as hasReplyState, xn as getFunctionTestRunTrace, xr as updateWakeSchedule, xt as thrownErrorExitCode, y as formatAwaitingCell, yn as getFunction, yr as updateRoute, yt as serializeErrorPayload, z as clearReadPendingMail, zn as listRepeatingSends, zt as ensureSearchReportsAutomated } from "../api-command-C58Oh38I.js";
4
4
  import { S as resolveListenSubscription, _ as acquireListenLock, a as mailLockBusy, c as mailTime, d as readMailJson, f as removeMailFile, g as ListenStateError, h as writeMailJson, i as mailId, l as privateMailDirectory, m as withMailLock, o as mailObject, u as privateMailPermissions, x as normalizeListenOrigin, y as listenIdentity } from "../shared-mail-files-MwlVE90c.js";
5
- import { _ as detectAgentRuntime, a as NotificationRetryError, b as installedVersion, c as readConversationStatusContent, d as defaultSessionSocket, f as NativeSessionDisconnectedError, g as connectSkillTarget, h as NotificationOutcomeUnknownError, i as notificationReceiptPage, l as SESSION_UUID$1, m as NativeSessionNotLoadedError, n as notificationSenders, o as isRoutineNotificationContent, p as NativeSessionError, r as openSessionNotifications, s as notificationPartReader, t as notificationScope, v as installConnectSkill, x as readBundledConnectSkill, y as installedConnectSkillFile } from "../notify-session-Cp0Kkstb.js";
6
- import { $ as installClaudeWakeHook, A as evaluateContactPolicy, B as contactAddress, C as RECEIVER_MODES, Ct as withOwnerMemberAddress, D as NETWORK_ADMISSION_PENDING_RETRY_MS, E as ContactPolicyReadRetryError, F as disconnectAgent, G as connectAgent, H as runContactRequest, I as AddressNotesApiError, J as refusalAfterReplacement, K as readAgentInvitation, L as addressNoteTarget, M as AgentDisconnectError, N as claimOverRevokedSetup, O as NetworkAdmissionPendingError, P as clearRevokedAddresses, Q as releaseRegistrationsForProfile, R as runAddressNotesRequest, S as runAgentConnect, St as refreshOwnerMemberAddressPeriodically, T as verificationReplySubmitted, U as agentConnectionStatus, V as contactAgentAddress, W as agentInvitationHash, X as savedReceiver, Y as saveConnectionName, Z as MACHINE_RUNTIMES, _ as enrollmentResumes, _t as jsonIndentation, a as endSession, at as describeSessionHookItem, b as invitationProfileName, bt as writeManagedFile, c as pendingSessionDisconnects, ct as findOnPath, d as registerSession, dt as readClaudeSettings, et as recordHookMailCheck, f as retryPendingDisconnects, ft as repairClaudeHooks, g as enrollAgent, gt as inspectManagedBlock, h as staleSessionAgents, ht as MachineFileError, i as connectedProfilesForSession, it as describeSessionHookChange, j as canonicalContactSelector, k as createNotificationContactPolicy, l as psProcessInfo, lt as hasMachineSessionHooks, m as runDetached, mt as writeClaudeSettings, n as OMP_MAIN, nt as claudeConfigDir, o as headlessClaudeRun, ot as ensureHookLauncher, p as revokeStaleSessionAgents, pt as samePath, q as receiverStatusCommand, r as agentConnectionState, rt as currentCliLocation, st as ephemeralCliReason, t as HOOK_END_GRACE_MS, tt as boundSessionProfiles, u as readClaudeHookInput, ut as inspectClaudeHooks, v as connectWarnings, vt as readManagedFile, w as externalReceivingState, x as pollCheckCommand, xt as readHookLauncherWarning, y as defaultAgentProfileName, yt as upsertManagedBlock, z as ContactsApiError } from "../machine-session-7bISVcRb.js";
5
+ import { _ as detectAgentRuntime, a as NotificationRetryError, b as installedVersion, c as readConversationStatusContent, d as defaultSessionSocket, f as NativeSessionDisconnectedError, g as connectSkillTarget, h as NotificationOutcomeUnknownError, i as notificationReceiptPage, l as SESSION_UUID$1, m as NativeSessionNotLoadedError, n as notificationSenders, o as isRoutineNotificationContent, p as NativeSessionError, r as openSessionNotifications, s as notificationPartReader, t as notificationScope, v as installConnectSkill, x as readBundledConnectSkill, y as installedConnectSkillFile } from "../notify-session-CVZtEboh.js";
6
+ import { $ as installClaudeWakeHook, A as evaluateContactPolicy, B as contactAddress, C as RECEIVER_MODES, Ct as withOwnerMemberAddress, D as NETWORK_ADMISSION_PENDING_RETRY_MS, E as ContactPolicyReadRetryError, F as disconnectAgent, G as connectAgent, H as runContactRequest, I as AddressNotesApiError, J as refusalAfterReplacement, K as readAgentInvitation, L as addressNoteTarget, M as AgentDisconnectError, N as claimOverRevokedSetup, O as NetworkAdmissionPendingError, P as clearRevokedAddresses, Q as releaseRegistrationsForProfile, R as runAddressNotesRequest, S as runAgentConnect, St as refreshOwnerMemberAddressPeriodically, T as verificationReplySubmitted, U as agentConnectionStatus, V as contactAgentAddress, W as agentInvitationHash, X as savedReceiver, Y as saveConnectionName, Z as MACHINE_RUNTIMES, _ as enrollmentResumes, _t as jsonIndentation, a as endSession, at as describeSessionHookItem, b as invitationProfileName, bt as writeManagedFile, c as pendingSessionDisconnects, ct as findOnPath, d as registerSession, dt as readClaudeSettings, et as recordHookMailCheck, f as retryPendingDisconnects, ft as repairClaudeHooks, g as enrollAgent, gt as inspectManagedBlock, h as staleSessionAgents, ht as MachineFileError, i as connectedProfilesForSession, it as describeSessionHookChange, j as canonicalContactSelector, k as createNotificationContactPolicy, l as psProcessInfo, lt as hasMachineSessionHooks, m as runDetached, mt as writeClaudeSettings, n as OMP_MAIN, nt as claudeConfigDir, o as headlessClaudeRun, ot as ensureHookLauncher, p as revokeStaleSessionAgents, pt as samePath, q as receiverStatusCommand, r as agentConnectionState, rt as currentCliLocation, st as ephemeralCliReason, t as HOOK_END_GRACE_MS, tt as boundSessionProfiles, u as readClaudeHookInput, ut as inspectClaudeHooks, v as connectWarnings, vt as readManagedFile, w as externalReceivingState, x as pollCheckCommand, xt as readHookLauncherWarning, y as defaultAgentProfileName, yt as upsertManagedBlock, z as ContactsApiError } from "../machine-session-CKmn5bvB.js";
7
7
  import { a as scopedChatSenderTrust, i as readBeforeDeadline, n as isPlainChatReply, o as presenceDisposition, r as isScopedChatReply, s as readPresenceProjection, t as isConnectedChatCredential } from "../scoped-chat-Dsark9hm.js";
8
8
  import { c as startBackgroundListen, i as backgroundListenToken, l as stopBackgroundListen, o as runBackgroundListen, r as backgroundListenStatus, u as verifyBackgroundListenTarget } from "../listen-background--0peztKE.js";
9
- import { a as ensureSharedMailSubscription, c as isConnectedAgentKey, d as reserveSharedMailSubscription, f as followEmailConversation, g as EventReceiverError, h as EventConnection, i as sharedMailScope, l as createSharedMailWaiter, m as otherParticipants, n as reconcileChatSend, p as readConversationFollow, r as openSharedMailReceiver, s as AGENT_CONNECTION_REQUIRED_MESSAGE, t as sendSignal, u as openSharedMailStore } from "../signal-command-Bi2U2BR_.js";
9
+ import { a as ensureSharedMailSubscription, c as isConnectedAgentKey, d as reserveSharedMailSubscription, f as followEmailConversation, g as EventReceiverError, h as EventConnection, i as sharedMailScope, l as createSharedMailWaiter, m as otherParticipants, n as reconcileChatSend, p as readConversationFollow, r as openSharedMailReceiver, s as AGENT_CONNECTION_REQUIRED_MESSAGE, t as sendSignal, u as openSharedMailStore } from "../signal-command-Dy_oub7_.js";
10
10
  import { autoSignalEligible, dispatchAutoRead, dispatchAutoWorking, haltAutoWorking, isSentSignal, readWorkingLease, restoreAutoWorking } from "./auto-signals.js";
11
11
  import { t as guardJsonOutputCommands } from "../json-output-CEskSQJi.js";
12
12
  import { Args, Command, Errors, Flags, ux } from "@oclif/core";
@@ -36477,7 +36477,7 @@ function withClearedNote(message, cleared) {
36477
36477
  return `${message} Before that, this run cleared ${cleared.map((row) => `${row.address} (profile ${row.profile})`).join(", ")} on this machine because Primitive confirmed ${cleared.length === 1 ? "its credential was" : "their credentials were"} already revoked; ${cleared.length === 1 ? "it stays" : "they stay"} disconnected.`;
36478
36478
  }
36479
36479
  var AgentConnectCommand = class AgentConnectCommand extends Command {
36480
- static description = `Connect this coding session to Primitive in one call. With --session, the command checks this CLI's capabilities, installs or refreshes the matching primitive-connect skill for the detected runtime (Claude Code or Codex) from files bundled in this CLI, claims the owner's private setup invitation from piped stdin, answers one authenticated setup challenge, enables owner notifications, starts receiving, seeds a private AGENT_INFO note from --name and --info when absent, and prints one JSON result. The receiver defaults to external hooks in Claude Code and the native background listener elsewhere. When the native default cannot work because this machine has no local session socket (for example Codex older than 0.158.0), the command connects with poll receiving instead and reports receiving.fallbackReason and receiving.fallbackDetail. Without a session (no --session, or an empty one) the receiver is poll: for runtimes with no local session ID or hooks, such as a cloud-hosted conversation whose commands run in a separate sandbox, the invitation is claimed and verified the same way, nothing is installed, and the result's receiving.checkCommand is the command the agent runs to check for new mail at the start of each turn and after it sends. Native receiving starts or reuses a supervised background listener and waits briefly for its first successful mail check; external receiving installs the exact Claude session's fail-open Stop hook and resume SessionStart hook after the verification reply; a real idle mail event must still verify wake. The profile defaults to session-<session>, or to connection-<invitation hash prefix> without a session. --resume continues saved progress without reading stdin or replaying a claim or uncertain verification send. After the reply is submitted it waits up to a minute for the server to confirm the connection and reports verification.state verified, or reply_submitted while confirmation is still pending. Verification is separate from receiver health. Both official production (https://api.primitive.dev/v1) and staging (https://api.primitive-staging-1.com/v1) invitations pin their API origin. Never pass an invitation as a command argument. One address per session: an address whose credential Primitive confirms was already revoked (for example, revoked in the app before the owner reconnected it) no longer counts; it is disconnected locally, reported in clearedRevoked, and its saved setup is moved aside so the new invitation can be claimed into the same profile. Otherwise, if this session already has a connected Primitive address, including one saved in the profile being connected, the command claims nothing, leaves stdin unread, and exits 3 with status already_connected. Its detail names how to continue that profile's own connection when that is the only one: --resume for a setup with saved progress, or --keep-existing to refresh a claim-only profile from the same invitation. Otherwise ask the user whether to keep the existing address or disconnect it first, then rerun with --keep-existing or --replace-existing. Never choose for the user. Select the saved identity with PRIMITIVE_AGENT_PROFILE. Use --status --json with --profile, with PRIMITIVE_AGENT_PROFILE set, or with --session (the address connected for that session) to inspect saved identity and local receiver health offline; it exits 1 when nothing is configured. A status check before connecting is optional: connect itself claims nothing and exits 3 when the session already has an address. A completed connection's result carries nextSteps, in order: report to the owner in two short sentences, make one offer to rename a generated name and record where the agent runs, and load the primitive-connect skill before handling mail. When the claim reported one, the result also carries the connection's name and nameIsDefault.`;
36480
+ static description = `Connect this coding session to Primitive in one call. With --session, the command checks this CLI's capabilities, installs or refreshes the matching primitive-connect skill for the detected runtime (Claude Code or Codex) from files bundled in this CLI, claims the owner's private setup invitation from piped stdin, answers one authenticated setup challenge, enables owner notifications, starts receiving, seeds a private AGENT_INFO note from --name and --info when absent, writes a private AGENT_RESUME note holding the command that resumes the bound session ("claude --resume <session>" or "codex resume <session>") once verified (or deletes an existing one when no resumable session is bound), and prints one JSON result. The receiver defaults to external hooks in Claude Code and the native background listener elsewhere. When the native default cannot work because this machine has no local session socket (for example Codex older than 0.158.0), the command connects with poll receiving instead and reports receiving.fallbackReason and receiving.fallbackDetail. Without a session (no --session, or an empty one) the receiver is poll: for runtimes with no local session ID or hooks, such as a cloud-hosted conversation whose commands run in a separate sandbox, the invitation is claimed and verified the same way, nothing is installed, and the result's receiving.checkCommand is the command the agent runs to check for new mail at the start of each turn and after it sends. Native receiving starts or reuses a supervised background listener and waits briefly for its first successful mail check; external receiving installs the exact Claude session's fail-open Stop hook and resume SessionStart hook after the verification reply; a real idle mail event must still verify wake. The profile defaults to session-<session>, or to connection-<invitation hash prefix> without a session. --resume continues saved progress without reading stdin or replaying a claim or uncertain verification send. After the reply is submitted it waits up to a minute for the server to confirm the connection and reports verification.state verified, or reply_submitted while confirmation is still pending. Verification is separate from receiver health. Both official production (https://api.primitive.dev/v1) and staging (https://api.primitive-staging-1.com/v1) invitations pin their API origin. Never pass an invitation as a command argument. One address per session: an address whose credential Primitive confirms was already revoked (for example, revoked in the app before the owner reconnected it) no longer counts; it is disconnected locally, reported in clearedRevoked, and its saved setup is moved aside so the new invitation can be claimed into the same profile. Otherwise, if this session already has a connected Primitive address, including one saved in the profile being connected, the command claims nothing, leaves stdin unread, and exits 3 with status already_connected. Its detail names how to continue that profile's own connection when that is the only one: --resume for a setup with saved progress, or --keep-existing to refresh a claim-only profile from the same invitation. Otherwise ask the user whether to keep the existing address or disconnect it first, then rerun with --keep-existing or --replace-existing. Never choose for the user. Select the saved identity with PRIMITIVE_AGENT_PROFILE. Use --status --json with --profile, with PRIMITIVE_AGENT_PROFILE set, or with --session (the address connected for that session) to inspect saved identity and local receiver health offline; it exits 1 when nothing is configured. A status check before connecting is optional: connect itself claims nothing and exits 3 when the session already has an address. A completed connection's result carries nextSteps, in order: report to the owner in two short sentences, make one offer to rename a generated name and record where the agent runs, and load the primitive-connect skill before handling mail. When the claim reported one, the result also carries the connection's name and nameIsDefault.`;
36481
36481
  static summary = "Connect and verify an agent address";
36482
36482
  static examples = [
36483
36483
  "<%= config.bin %> agent connect --session \"$CODEX_THREAD_ID\" --name Research --info \"Reviews pull requests\" --json < private-invitation.txt",
@@ -36699,6 +36699,7 @@ var AgentConnectCommand = class AgentConnectCommand extends Command {
36699
36699
  this.log(`Agent ${output.address}: verification ${output.verification.state}; receiving ${output.receiving.state}; skill ${output.skill.state}.`);
36700
36700
  this.log(`Select it with ${output.selectProfile}.`);
36701
36701
  for (const warning of output.warnings) this.log(warning.message);
36702
+ if (output.resumeNote === "failed") this.warn("The AGENT_RESUME note could not be updated. The connection is unaffected.");
36702
36703
  if (output.ownerNotifications === "silenced") this.log("Owner notifications remain silenced by the existing preference or policy.");
36703
36704
  if (external && verificationReplySubmitted(output.verification.state)) this.log(output.externalHook === "installed_unverified" ? "External receive hook installed. Idle wake still needs a live mail check." : "External receive hook is unavailable. Pairing may complete, but this session will not wake automatically.");
36704
36705
  if (poll && "fallbackDetail" in output.receiving) this.log(String(output.receiving.fallbackDetail));
@@ -37600,7 +37601,7 @@ var AgentRuntimeGetCommand = class AgentRuntimeGetCommand extends Command {
37600
37601
  //#region src/oclif/commands/agent-session-end.ts
37601
37602
  var AgentSessionEndCommand = class AgentSessionEndCommand extends Command {
37602
37603
  static summary = "Record that a registered session ended";
37603
- static description = "Marks this session ended and removes its exact-session receive hooks. The agent that `primitive agent session-register` created for the session stays connected, with its credential and profile, so resuming the session (for example `claude --resume`) re-verifies it and reinstalls the hooks at the same address. Its presence lapses on its own once the session stops running. An agent whose session has not started again for 30 days is disconnected by `primitive machine doctor --fix` or the next `agent session-register` on this machine. --revoke disconnects the agent now instead. Agents connected any other way are never disconnected, including an agent later connected into the same profile with `primitive agent connect`. Never blocks or fails a session: every outcome exits 0 with a status. --hook reads Claude's SessionEnd hook input from stdin and finishes in the background after a grace period: Claude reports the same end for a restart, a switch to another session and a real exit, so a start of the same session within the grace period cancels the end.";
37604
+ static description = "Marks this session ended and removes its exact-session receive hooks. The agent that `primitive agent session-register` created for the session stays connected, with its credential and profile, so resuming the session (for example `claude --resume`) re-verifies it and reinstalls the hooks at the same address. Its presence lapses on its own once the session stops running. An agent whose session has not started again for 30 days is disconnected by `primitive machine doctor --fix` or the next `agent session-register` on this machine. --revoke disconnects the agent now instead, first deleting its AGENT_RESUME note (reported as resumeNote; a failed deletion is a warning and never stops the disconnect). Agents connected any other way are never disconnected, including an agent later connected into the same profile with `primitive agent connect`. Never blocks or fails a session: every outcome exits 0 with a status. --hook reads Claude's SessionEnd hook input from stdin and finishes in the background after a grace period: Claude reports the same end for a restart, a switch to another session and a real exit, so a start of the same session within the grace period cancels the end.";
37604
37605
  static examples = [
37605
37606
  "<%= config.bin %> agent session-end --runtime claude --json",
37606
37607
  "<%= config.bin %> agent session-end --runtime codex --session 11111111-1111-4111-8111-111111111111",
@@ -37664,7 +37665,10 @@ var AgentSessionEndCommand = class AgentSessionEndCommand extends Command {
37664
37665
  status,
37665
37666
  ...rest
37666
37667
  }));
37667
- else if (!flags.quiet) this.log(`${result.status}: ${result.detail}`);
37668
+ else if (!flags.quiet) {
37669
+ this.log(`${result.status}: ${result.detail}`);
37670
+ if (result.resumeNote === "failed") this.warn("The AGENT_RESUME note could not be deleted before the agent was disconnected.");
37671
+ }
37668
37672
  }
37669
37673
  };
37670
37674
  //#endregion
@@ -37673,7 +37677,7 @@ var AgentSessionEndCommand = class AgentSessionEndCommand extends Command {
37673
37677
  const HOOK_BUDGET_MS = 3e3;
37674
37678
  var AgentSessionRegisterCommand = class AgentSessionRegisterCommand extends Command {
37675
37679
  static summary = "Register this coding session with Primitive, once";
37676
- static description = "Gives the current Claude Code, Codex or omp session an address in your organization using the saved member login, without a browser. Safe to run on every start and resume: a session that already has a profile is only re-verified, and a session that ended and starts again (for example `claude --resume`) keeps its agent and address, and a session whose agent was disconnected or removed never gets a second address. Each run also disconnects the agents of sessions on this machine that ended more than 30 days ago without starting again, only while their profile still holds the credential this command created. The session ID comes from CLAUDE_CODE_SESSION_ID (Claude), CODEX_THREAD_ID or CODEX_SESSION_ID (Codex), or --session. omp does not expose a session ID to commands, so omp sessions use one generated ID per running omp process, and receiving mail is not supported for them. The agent is named <runtime>-<repository> and gets a private AGENT_INFO note naming the runtime and repository when it has none. Claude sessions receive mail through exact-session hooks; Codex through the native receiver. Non-interactive Claude runs (claude -p and SDK hosts, by CLAUDE_CODE_ENTRYPOINT) are skipped with status skipped_headless. Never blocks a session: every outcome, including no login or no network, exits 0 with a status. --hook reads Claude's or Codex's SessionStart hook input from stdin, returns within a few seconds and finishes slower work in the background.";
37680
+ static description = "Gives the current Claude Code, Codex or omp session an address in your organization using the saved member login, without a browser. Safe to run on every start and resume: a session that already has a profile is only re-verified, and a session that ended and starts again (for example `claude --resume`) keeps its agent and address, and a session whose agent was disconnected or removed never gets a second address. Each run also disconnects the agents of sessions on this machine that ended more than 30 days ago without starting again, only while their profile still holds the credential this command created. The session ID comes from CLAUDE_CODE_SESSION_ID (Claude), CODEX_THREAD_ID or CODEX_SESSION_ID (Codex), or --session. omp does not expose a session ID to commands, so omp sessions use one generated ID per running omp process, and receiving mail is not supported for them. The agent is named <runtime>-<repository> and gets a private AGENT_INFO note naming the runtime and repository when it has none. A connected Claude Code or Codex session also gets a private AGENT_RESUME note holding the one-line command that resumes it (`claude --resume <session>` or `codex resume <session>`), rewritten only when it changes; a failure to write it is reported as a warning and never fails the registration. Claude sessions receive mail through exact-session hooks; Codex through the native receiver. Non-interactive Claude runs (claude -p and SDK hosts, by CLAUDE_CODE_ENTRYPOINT) are skipped with status skipped_headless. Never blocks a session: every outcome, including no login or no network, exits 0 with a status. --hook reads Claude's or Codex's SessionStart hook input from stdin, returns within a few seconds and finishes slower work in the background.";
37677
37681
  static examples = [
37678
37682
  "<%= config.bin %> agent session-register --runtime codex --quiet",
37679
37683
  "<%= config.bin %> agent session-register --runtime claude --json",
@@ -37738,7 +37742,10 @@ var AgentSessionRegisterCommand = class AgentSessionRegisterCommand extends Comm
37738
37742
  ...rest,
37739
37743
  ...identity
37740
37744
  }));
37741
- else if (!flags.quiet) this.log(`${result.status}: ${result.detail}`);
37745
+ else if (!flags.quiet) {
37746
+ this.log(`${result.status}: ${result.detail}`);
37747
+ if (result.resumeNote === "failed") this.warn("The AGENT_RESUME note could not be written. The session is registered; the next start retries it.");
37748
+ }
37742
37749
  try {
37743
37750
  await revokeStaleSessionAgents(this.config.configDir, { exclude: result.session });
37744
37751
  } catch {}
@@ -44949,7 +44956,7 @@ const PRIMITIVE_TEAM_AUTHOR = {
44949
44956
  url: "https://primitive.dev"
44950
44957
  };
44951
44958
  const SDK_VERSION_RANGE = "^2.0.0";
44952
- const CLI_VERSION_RANGE = "^1.68.0";
44959
+ const CLI_VERSION_RANGE = "^1.69.0";
44953
44960
  const ESBUILD_VERSION_RANGE = "^0.27.0";
44954
44961
  function renderHandler() {
44955
44962
  return `// env.PRIMITIVE_API_KEY, env.PRIMITIVE_WEBHOOK_SECRET, and
@@ -1,6 +1,6 @@
1
1
  import { N as agentProfileDirectory, P as agentProfileName, R as loadConnectedAgentProfile, j as AGENT_PROFILE_ENV } from "../cli-config-DMszFbGn.js";
2
2
  import { d as readMailJson } from "../shared-mail-files-MwlVE90c.js";
3
- import { _ as detectAgentRuntime, l as SESSION_UUID, t as notificationScope } from "../notify-session-Cp0Kkstb.js";
3
+ import { _ as detectAgentRuntime, l as SESSION_UUID, t as notificationScope } from "../notify-session-CVZtEboh.js";
4
4
  import { a as claimBackgroundListenRestart, n as backgroundListenRestartable, r as backgroundListenStatus } from "../listen-background--0peztKE.js";
5
5
  import { join } from "node:path";
6
6
  import { spawn } from "node:child_process";
@@ -1,5 +1,5 @@
1
1
  import { h as sendPreparedSignal, p as prepareSignalEmail } from "./repeats-BL7ZC-_6-BZ-MphTV.js";
2
- import { T as bareAddress, Vn as listSentEmails, ar as sendEmail, bt as successfulSendOutcome, en as createEndpoint, it as classifySendError, o as extractErrorPayload, vn as getEmail } from "./api-command-D7DPn2Ro.js";
2
+ import { T as bareAddress, Vn as listSentEmails, ar as sendEmail, bt as successfulSendOutcome, en as createEndpoint, it as classifySendError, o as extractErrorPayload, vn as getEmail } from "./api-command-C58Oh38I.js";
3
3
  import { _ as acquireListenLock, b as listenProcessIdentity, c as mailTime, d as readMailJson, f as removeMailFile, h as writeMailJson, i as mailId, l as privateMailDirectory, m as withMailLock, n as invalidSharedMail, o as mailObject, p as syncMailDirectory, r as mailAddress, s as mailString, t as SharedMailStateError, v as compareListenProcessIdentity, y as listenIdentity } from "./shared-mail-files-MwlVE90c.js";
4
4
  import { a as scopedChatSenderTrust, i as readBeforeDeadline, n as isPlainChatReply } from "./scoped-chat-Dsark9hm.js";
5
5
  import { n as tryOwnSharedMail, r as waitForSharedMailChange, t as readSharedMailOwner } from "./shared-mail-watch-DtKpsgg8.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "primcli",
3
- "version": "1.68.0",
3
+ "version": "1.69.0",
4
4
  "description": "Official Primitive CLI: deploy Primitive Functions, send and inspect mail, manage endpoints, all from the terminal. Wraps the @primitivedotdev/sdk runtime client with one-shot commands.",
5
5
  "type": "module",
6
6
  "sideEffects": false,