primcli 1.74.1 → 3.0.0-preview.1

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.
Files changed (31) hide show
  1. package/README.md +165 -72
  2. package/bin/claude-pending-mail.mjs +1 -1
  3. package/bin/run.js +14 -0
  4. package/dist/{api-command-fKP3NYa7.js → api-command-ctHBqTL5.js} +825 -95
  5. package/dist/{cli-config-C0Y_Ppol.js → cli-config-Ms_0vNjq.js} +66 -28
  6. package/dist/{client.gen-CaaMP86o.js → client.gen-6rZvmHfx.js} +7 -14
  7. package/dist/{json-output-Ce10AsSb.js → json-output-BzSBR-KX.js} +1 -2
  8. package/dist/{listen-background-cD6n8VYO.js → listen-background-C0F9gNDD.js} +2 -3
  9. package/dist/{machine-session-B6V5-grn.js → machine-session-Cp_eQ9t_.js} +164 -99
  10. package/dist/{notify-session-DJAb9SGm.js → notify-session-BN0JTPZ3.js} +341 -31
  11. package/dist/oclif/auto-signal-worker.js +5 -6
  12. package/dist/oclif/auto-signals.js +4 -5
  13. package/dist/oclif/global-org-flag.js +76 -0
  14. package/dist/oclif/help.js +127 -0
  15. package/dist/oclif/index.js +93239 -31954
  16. package/dist/oclif/listen-supervisor.js +1 -1
  17. package/dist/oclif/proxy-auto-detect.js +2 -3
  18. package/dist/oclif/receiver-heal.js +6 -6
  19. package/dist/oclif/root-signup-hint.js +3 -4
  20. package/dist/receiver.d.ts +95 -0
  21. package/dist/receiver.js +569 -0
  22. package/dist/{repeats-BL7ZC-_6-B_ESsWTH.js → repeats-Dj_o6c-X-Bf9G0xds.js} +4617 -1744
  23. package/dist/{scoped-chat-DAiOb622.js → scoped-chat-DZ42V3jq.js} +3 -5
  24. package/dist/{shared-mail-files-CZfm7E2k.js → shared-mail-files-BAQSGxxz.js} +2 -4
  25. package/dist/{shared-mail-watch-DyQB0MK0.js → shared-mail-watch-BAPMsFNv.js} +2 -3
  26. package/dist/{signal-command-Cte4mAL3.js → signal-command-CRUMUCNa.js} +19 -27
  27. package/dist/skills/primitive-connect/references/connect.md +3 -1
  28. package/dist/skills/primitive-connect/references/contacts.md +9 -4
  29. package/dist/skills/primitive-connect.json +4 -4
  30. package/man/primitive.1 +44 -3
  31. package/package.json +65 -15
@@ -1,29 +1,19 @@
1
- import { Et as downloadEmailAttachmentPart, J as parseWebhookEvent, K as isEmailReceivedEvent, c as classifySignalContent, q as isTrustedSender } from "./repeats-BL7ZC-_6-B_ESsWTH.js";
2
- import { _ as acquireListenLock, g as ListenStateError, y as listenIdentity } from "./shared-mail-files-CZfm7E2k.js";
3
- import { B as wakeInteractionSentence, T as wakeReadCommand, w as skillFirstLine } from "./api-command-fKP3NYa7.js";
1
+ import { Et as downloadEmailAttachmentPart, J as parseWebhookEvent, K as isEmailReceivedEvent, c as classifySignalContent, q as isTrustedSender } from "./repeats-Dj_o6c-X-Bf9G0xds.js";
2
+ import { E as wakeReadCommand, T as skillFirstLine, V as wakeInteractionSentence } from "./api-command-ctHBqTL5.js";
3
+ import { _ as acquireListenLock, g as ListenStateError, y as listenIdentity } from "./shared-mail-files-BAQSGxxz.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";
6
6
  import { dirname, isAbsolute, join, normalize, resolve } from "node:path";
7
+ import { spawn } from "node:child_process";
7
8
  import { homedir } from "node:os";
8
9
  import { lstat, realpath } from "node:fs/promises";
9
10
  import { isDeepStrictEqual } from "node:util";
10
11
  import WebSocket from "ws";
11
- //#region src/oclif/connect-skill.ts
12
+ import { request } from "node:http";
13
+ import { request as request$1 } from "node:https";
14
+ import { performance } from "node:perf_hooks";
15
+ // src/oclif/connect-skill.ts
12
16
  const CONNECT_SKILL_NAME = "primitive-connect";
13
- const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
14
- /**
15
- * The runtime whose tool environment names this exact session. A session ID
16
- * that matches neither runtime's variable has no detectable runtime.
17
- */
18
- function detectAgentRuntime(session, env = process.env) {
19
- const wanted = session.toLowerCase();
20
- const claude = env.CLAUDE_CODE_SESSION_ID?.trim().toLowerCase();
21
- const codex = (env.CODEX_THREAD_ID?.trim() || env.CODEX_SESSION_ID?.trim())?.toLowerCase();
22
- if (!UUID.test(wanted)) return null;
23
- if (claude === wanted && codex !== wanted) return "claude";
24
- if (codex === wanted && claude !== wanted) return "codex";
25
- return null;
26
- }
27
17
  function connectSkillTarget(options) {
28
18
  const env = options.env ?? process.env;
29
19
  const cwd = resolve(options.cwd ?? process.cwd());
@@ -288,8 +278,7 @@ function installConnectSkill(options) {
288
278
  };
289
279
  }
290
280
  }
291
- //#endregion
292
- //#region src/oclif/notify-session-errors.ts
281
+ // src/oclif/notify-session-errors.ts
293
282
  var NativeSessionError = class extends ListenStateError {
294
283
  submitted;
295
284
  constructor(message, submitted = false) {
@@ -315,8 +304,7 @@ var NotificationOutcomeUnknownError = class extends NativeSessionError {
315
304
  super(message, true);
316
305
  }
317
306
  };
318
- //#endregion
319
- //#region src/oclif/notify-session-native.ts
307
+ // src/oclif/notify-session-native.ts
320
308
  /** Codex explicitly refused this input before adding it to the turn queue. */
321
309
  var NativeTurnNotSubmittedError = class extends NativeSessionError {
322
310
  constructor() {
@@ -580,8 +568,332 @@ async function connectNativeSession(options) {
580
568
  }
581
569
  };
582
570
  }
583
- //#endregion
584
- //#region src/oclif/notify-session-content.ts
571
+ // src/oclif/listen-handlers.ts
572
+ const HANDLER_TIMEOUT_MS = 3e4;
573
+ const MAX_RESPONSE_BYTES = 1048576;
574
+ const FORWARDED_HEADERS = /* @__PURE__ */ new Set([
575
+ "content-type",
576
+ "user-agent",
577
+ "primitive-signature",
578
+ "mymx-signature",
579
+ "x-webhook-event",
580
+ "x-webhook-id",
581
+ "x-primitive-webhook-delivery-id",
582
+ "x-primitive-email-id",
583
+ "x-primitive-endpoint-id"
584
+ ]);
585
+ function normalizeForwardTarget(target) {
586
+ if (/^\d+$/.test(target)) return `http://localhost:${target}`;
587
+ if (/^(localhost|127\.0\.0\.1|\[::1\])(?::|\/|$)/.test(target)) return `http://${target}`;
588
+ return target;
589
+ }
590
+ function validateListenHandlerOptions(options) {
591
+ if (options.exec !== void 0 && process.platform === "win32") throw new Error("--exec requires a POSIX shell and process groups. On Windows, use --forward-to with a local HTTP handler.");
592
+ if (options.exec !== void 0 && options.forwardTo !== void 0) throw new Error("Choose either --exec or --forward-to.");
593
+ if (options.exec !== void 0 && (!options.exec.trim() || options.exec.includes("\0"))) throw new Error("--exec requires a nonempty shell command.");
594
+ if (options.forwardTo !== void 0) {
595
+ let url;
596
+ try {
597
+ url = new URL(normalizeForwardTarget(options.forwardTo));
598
+ } catch {
599
+ throw new Error("--forward-to requires an HTTP or HTTPS URL.");
600
+ }
601
+ if (!["http:", "https:"].includes(url.protocol) || !url.hostname || url.username || url.password || url.hash) throw new Error("--forward-to requires HTTP or HTTPS without userinfo or a fragment.");
602
+ }
603
+ }
604
+ /** User hooks retain their configuration, but not the CLI's API credentials. */
605
+ function hookEnvironment(delivery) {
606
+ const env = { ...process.env };
607
+ for (const name of Object.keys(env)) if (/^PRIMITIVE_(?:(?:API_|OAUTH_|AUTH_)?(?:KEY|TOKEN|ACCESS_TOKEN|REFRESH_TOKEN)|API_HEADERS|LEASE_TOKEN)$/i.test(name)) delete env[name];
608
+ return {
609
+ ...env,
610
+ PRIMITIVE_EVENT_ID: delivery.event_id,
611
+ PRIMITIVE_DELIVERY_ID: delivery.delivery_id,
612
+ PRIMITIVE_EVENT_TYPE: delivery.event_type
613
+ };
614
+ }
615
+ async function writeChunk(output, chunk, signal) {
616
+ signal.throwIfAborted();
617
+ let onError = () => {};
618
+ let onAbort = () => {};
619
+ let onDrain = () => {};
620
+ let onClose = () => {};
621
+ try {
622
+ await new Promise((resolve, reject) => {
623
+ let callbackDone = false;
624
+ let returned = false;
625
+ let accepted = false;
626
+ let drained = false;
627
+ const finish = () => {
628
+ if (returned && callbackDone && (accepted || drained)) resolve();
629
+ };
630
+ onError = reject;
631
+ onAbort = () => reject(signal.reason);
632
+ onClose = () => reject(/* @__PURE__ */ new Error("Output closed before accepting the event."));
633
+ onDrain = () => {
634
+ drained = true;
635
+ finish();
636
+ };
637
+ output.on("error", onError);
638
+ output.on("close", onClose);
639
+ output.on("drain", onDrain);
640
+ signal.addEventListener("abort", onAbort, { once: true });
641
+ accepted = output.write(chunk, (error) => {
642
+ if (error) reject(error);
643
+ else {
644
+ callbackDone = true;
645
+ finish();
646
+ }
647
+ });
648
+ returned = true;
649
+ finish();
650
+ });
651
+ } finally {
652
+ output.off("error", onError);
653
+ output.off("close", onClose);
654
+ output.off("drain", onDrain);
655
+ signal.removeEventListener("abort", onAbort);
656
+ }
657
+ }
658
+ function stopProcessGroup(child) {
659
+ if (!child.pid) return;
660
+ try {
661
+ process.kill(-child.pid, "SIGKILL");
662
+ } catch {}
663
+ }
664
+ var ChildCleanupError = class extends Error {};
665
+ async function reapChild(child, closed) {
666
+ stopProcessGroup(child);
667
+ child.stdin?.destroy();
668
+ child.stdout?.destroy();
669
+ child.stderr?.destroy();
670
+ let timer;
671
+ try {
672
+ await Promise.race([closed, new Promise((_resolve, reject) => {
673
+ timer = setTimeout(() => reject(new ChildCleanupError("The hook did not close after termination. Its delivery remains uncompleted.")), 1e3);
674
+ })]);
675
+ } finally {
676
+ clearTimeout(timer);
677
+ }
678
+ }
679
+ async function execute(command, delivery, stderr, signal) {
680
+ signal.throwIfAborted();
681
+ const child = spawn(command, {
682
+ shell: true,
683
+ detached: true,
684
+ env: hookEnvironment(delivery),
685
+ stdio: [
686
+ "pipe",
687
+ "pipe",
688
+ "pipe"
689
+ ],
690
+ windowsHide: true
691
+ });
692
+ const closed = new Promise((resolve) => child.once("close", () => resolve()));
693
+ const stop = () => stopProcessGroup(child);
694
+ signal.addEventListener("abort", stop, { once: true });
695
+ const consume = async (stream) => {
696
+ for await (const chunk of stream) await writeChunk(stderr, Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk), signal);
697
+ };
698
+ child.once("exit", stop);
699
+ try {
700
+ const exited = new Promise((resolve, reject) => {
701
+ child.once("error", reject);
702
+ child.once("close", (code) => resolve(code));
703
+ });
704
+ const stdin = writeChunk(child.stdin, Buffer.from(delivery.body, "utf8"), signal).then(() => child.stdin.end());
705
+ const [code] = await Promise.all([
706
+ exited,
707
+ stdin,
708
+ consume(child.stdout),
709
+ consume(child.stderr)
710
+ ]);
711
+ signal.throwIfAborted();
712
+ return code;
713
+ } finally {
714
+ try {
715
+ await reapChild(child, closed);
716
+ } finally {
717
+ signal.removeEventListener("abort", stop);
718
+ }
719
+ }
720
+ }
721
+ function structuredErrorCode(body) {
722
+ try {
723
+ const value = JSON.parse(body);
724
+ if (typeof value !== "object" || value === null) return void 0;
725
+ const object = value;
726
+ const nested = typeof object.error === "object" && object.error !== null ? object.error.code : void 0;
727
+ const code = typeof nested === "string" ? nested : object.code;
728
+ return typeof code === "string" && /^[a-z][a-z0-9_]{0,63}$/.test(code) ? code : void 0;
729
+ } catch {
730
+ return;
731
+ }
732
+ }
733
+ var ForwardFailure = class extends Error {
734
+ statusCode;
735
+ transportError;
736
+ constructor(statusCode, transportError) {
737
+ super("Webhook transport did not complete.");
738
+ this.statusCode = statusCode;
739
+ this.transportError = transportError;
740
+ }
741
+ };
742
+ async function forward(target, delivery, signal) {
743
+ signal.throwIfAborted();
744
+ const url = new URL(normalizeForwardTarget(target));
745
+ const body = Buffer.from(delivery.body, "utf8");
746
+ const headers = {};
747
+ for (const [name, value] of Object.entries(delivery.headers)) if (FORWARDED_HEADERS.has(name.toLowerCase())) headers[name.toLowerCase()] = value;
748
+ headers["content-length"] = String(body.length);
749
+ return new Promise((resolve, reject) => {
750
+ let observedStatus = null;
751
+ let settled = false;
752
+ const fail = (kind = observedStatus === null ? "network" : "io") => {
753
+ if (settled) return;
754
+ settled = true;
755
+ reject(new ForwardFailure(observedStatus, kind));
756
+ };
757
+ const request$2 = (url.protocol === "https:" ? request$1 : request)(url, {
758
+ method: "POST",
759
+ headers,
760
+ signal,
761
+ rejectUnauthorized: true
762
+ }, (response) => {
763
+ observedStatus = response.statusCode ?? null;
764
+ const chunks = [];
765
+ let size = 0;
766
+ response.on("error", () => fail());
767
+ response.on("aborted", () => fail());
768
+ response.on("data", (chunk) => {
769
+ size += chunk.length;
770
+ if (size > MAX_RESPONSE_BYTES) {
771
+ fail("response_too_large");
772
+ request$2.destroy();
773
+ } else chunks.push(chunk);
774
+ });
775
+ response.on("end", () => {
776
+ if (settled) return;
777
+ if (!response.complete || size > MAX_RESPONSE_BYTES) {
778
+ fail(size > MAX_RESPONSE_BYTES ? "response_too_large" : "io");
779
+ return;
780
+ }
781
+ settled = true;
782
+ const status = response.statusCode ?? 0;
783
+ const succeeded = status >= 200 && status < 300;
784
+ resolve({
785
+ status,
786
+ confirmed: succeeded && (response.headers["x-primitive-confirmed"] === "true" || response.headers["x-mymx-confirmed"] === "true"),
787
+ errorCode: succeeded ? void 0 : status >= 300 && status < 400 ? "handler_redirect" : structuredErrorCode(Buffer.concat(chunks).toString("utf8")) ?? (status >= 400 && status < 500 ? "handler_4xx" : status >= 500 ? "handler_5xx" : "unknown_error")
788
+ });
789
+ });
790
+ });
791
+ request$2.on("error", () => fail());
792
+ request$2.end(body);
793
+ });
794
+ }
795
+ function jsonLine(body) {
796
+ try {
797
+ return JSON.stringify(JSON.parse(body));
798
+ } catch {
799
+ throw new Error("Webhook body is not valid JSON.");
800
+ }
801
+ }
802
+ /**
803
+ * The API withholds an event's body from a credential that cannot read the
804
+ * mail it carries. Such an event is never handed on as if it were the event:
805
+ * listening stops with an explanation and the delivery stays uncompleted.
806
+ */
807
+ function readableDelivery(delivery) {
808
+ if (delivery.body === null) throw new ListenStateError("The API withheld this event's content from the listening credential; the delivery remains uncompleted. Listen with a credential that can read this mail.");
809
+ return {
810
+ ...delivery,
811
+ body: delivery.body
812
+ };
813
+ }
814
+ function createListenHandler(options = {}) {
815
+ validateListenHandlerOptions(options);
816
+ return async (received, signal) => {
817
+ signal.throwIfAborted();
818
+ const delivery = readableDelivery(received);
819
+ const start = performance.now();
820
+ const work = new AbortController();
821
+ let timedOut = false;
822
+ const cancel = () => work.abort(signal.reason);
823
+ signal.addEventListener("abort", cancel, { once: true });
824
+ const timer = setTimeout(() => {
825
+ timedOut = true;
826
+ work.abort(/* @__PURE__ */ new Error("Event handler timed out."));
827
+ }, HANDLER_TIMEOUT_MS);
828
+ const duration = () => Math.min(HANDLER_TIMEOUT_MS, Math.max(0, Math.round(performance.now() - start)));
829
+ try {
830
+ if (options.exec !== void 0) {
831
+ const code = await execute(options.exec, delivery, options.stderr ?? process.stderr, work.signal);
832
+ signal.throwIfAborted();
833
+ return {
834
+ succeeded: code === 0,
835
+ outcome: {
836
+ mode: "exec",
837
+ exit_code: code,
838
+ duration_ms: duration()
839
+ }
840
+ };
841
+ }
842
+ if (options.forwardTo !== void 0) {
843
+ const response = await forward(options.forwardTo, delivery, work.signal);
844
+ signal.throwIfAborted();
845
+ return {
846
+ succeeded: response.status >= 200 && response.status < 300,
847
+ outcome: {
848
+ mode: "http",
849
+ status_code: response.status,
850
+ confirmed: response.confirmed,
851
+ duration_ms: duration(),
852
+ ...response.errorCode ? { error_code: response.errorCode } : {}
853
+ }
854
+ };
855
+ }
856
+ await writeChunk(options.stdout ?? process.stdout, Buffer.from(`${jsonLine(delivery.body)}\n`, "utf8"), work.signal);
857
+ signal.throwIfAborted();
858
+ return {
859
+ succeeded: true,
860
+ outcome: {
861
+ mode: "stdout",
862
+ write_succeeded: true,
863
+ duration_ms: duration()
864
+ }
865
+ };
866
+ } catch (error) {
867
+ signal.throwIfAborted();
868
+ if (error instanceof ChildCleanupError) throw error;
869
+ if (options.exec !== void 0) return {
870
+ succeeded: false,
871
+ outcome: {
872
+ mode: "exec",
873
+ exit_code: null,
874
+ transport_error: timedOut ? "timeout" : "io",
875
+ duration_ms: duration()
876
+ }
877
+ };
878
+ if (options.forwardTo !== void 0) return {
879
+ succeeded: false,
880
+ outcome: {
881
+ mode: "http",
882
+ status_code: error instanceof ForwardFailure ? error.statusCode : null,
883
+ confirmed: false,
884
+ transport_error: timedOut ? "timeout" : error instanceof ForwardFailure ? error.transportError : "network",
885
+ duration_ms: duration()
886
+ }
887
+ };
888
+ throw error;
889
+ } finally {
890
+ clearTimeout(timer);
891
+ signal.removeEventListener("abort", cancel);
892
+ work.abort();
893
+ }
894
+ };
895
+ }
896
+ // src/oclif/notify-session-content.ts
585
897
  var NotificationRetryError = class extends ListenStateError {};
586
898
  function notificationPartReader(client) {
587
899
  return async (emailId, partIndex, signal) => {
@@ -683,8 +995,7 @@ async function classifyNotificationContent(email, readPart, signal) {
683
995
  if (classification.classification === "unavailable") throw new NotificationRetryError("Interaction classification is unavailable; retrying through the delivery queue.");
684
996
  return classification;
685
997
  }
686
- //#endregion
687
- //#region src/oclif/notify-session-state.ts
998
+ // src/oclif/notify-session-state.ts
688
999
  const invalid = () => new ListenStateError("Notification receipts are unavailable or inconsistent. Preserve this state to avoid duplicate notifications.");
689
1000
  function uuid(value) {
690
1001
  if (typeof value !== "string" || !SESSION_UUID.test(value)) throw invalid();
@@ -934,8 +1245,7 @@ function notificationReceiptPage(configDir, scope, threadId, options = {}) {
934
1245
  nextCursor: hasMore ? ids.at(-1) ?? null : null
935
1246
  };
936
1247
  }
937
- //#endregion
938
- //#region src/oclif/notify-session.ts
1248
+ // src/oclif/notify-session.ts
939
1249
  function notificationScope(origin, apiKey) {
940
1250
  if (!apiKey?.startsWith("pconn_")) throw new ListenStateError("--notify-session requires a connected-agent credential scoped to its own address.");
941
1251
  return listenIdentity(origin, `connection:${scryptSync(apiKey, "primitive-listener-identity-v1", 32).toString("hex")}`);
@@ -970,9 +1280,10 @@ async function openSessionNotifications(options) {
970
1280
  }
971
1281
  });
972
1282
  if (delivery.event_type !== "email.received") throw new ListenStateError("Notification mode received an unrelated event. It remains uncompleted; use an email.received-only subscription.");
1283
+ const { body } = readableDelivery(delivery);
973
1284
  let event;
974
1285
  try {
975
- event = parseWebhookEvent(JSON.parse(delivery.body), delivery.event_type);
1286
+ event = parseWebhookEvent(JSON.parse(body), delivery.event_type);
976
1287
  } catch {
977
1288
  throw new ListenStateError("Invalid email event; the delivery remains uncompleted.");
978
1289
  }
@@ -1133,5 +1444,4 @@ async function openSessionNotifications(options) {
1133
1444
  }
1134
1445
  var ContactNoticeSuppressed = class extends Error {};
1135
1446
  var ContactNoticeDeferred = class extends Error {};
1136
- //#endregion
1137
- export { detectAgentRuntime as _, NotificationRetryError as a, installedVersion as b, readConversationStatusContent as c, defaultSessionSocket as d, NativeSessionDisconnectedError as f, connectSkillTarget as g, NotificationOutcomeUnknownError as h, notificationReceiptPage as i, SESSION_UUID as l, NativeSessionNotLoadedError as m, notificationSenders as n, isRoutineNotificationContent as o, NativeSessionError as p, openSessionNotifications as r, notificationPartReader as s, notificationScope as t, connectNativeSession as u, installConnectSkill as v, readBundledConnectSkill as x, installedConnectSkillFile as y };
1447
+ export { readBundledConnectSkill as S, NotificationOutcomeUnknownError as _, NotificationRetryError as a, installedConnectSkillFile as b, readConversationStatusContent as c, SESSION_UUID as d, connectNativeSession as f, NativeSessionNotLoadedError as g, NativeSessionError as h, notificationReceiptPage as i, createListenHandler as l, NativeSessionDisconnectedError as m, notificationSenders as n, isRoutineNotificationContent as o, defaultSessionSocket as p, openSessionNotifications as r, notificationPartReader as s, notificationScope as t, readableDelivery as u, connectSkillTarget as v, installedVersion as x, installConnectSkill as y };
@@ -1,11 +1,11 @@
1
- import { Ut as getSentEmail } from "../repeats-BL7ZC-_6-B_ESsWTH.js";
2
- import { _ as acquireListenLock } from "../shared-mail-files-CZfm7E2k.js";
3
- import { b as readThreadContext, kt as createAuthenticatedCliApiClient } from "../api-command-fKP3NYa7.js";
4
- import { t as sendSignal } from "../signal-command-Cte4mAL3.js";
1
+ import { Gt as getSentEmail } from "../repeats-Dj_o6c-X-Bf9G0xds.js";
2
+ import { Mt as createAuthenticatedCliApiClient, x as readThreadContext } from "../api-command-ctHBqTL5.js";
5
3
  import { AUTO_SIGNAL_KIND_ENV, AUTO_WORKING_RENEW_MS, autoSignalsDisabled, clearWorkingSending, markWorkingSending, readAutoClaim, readWorkingLease, recordRenewer, stopWorkingLease, writeWorkingLease } from "./auto-signals.js";
4
+ import { _ as acquireListenLock } from "../shared-mail-files-BAQSGxxz.js";
5
+ import { t as sendSignal } from "../signal-command-CRUMUCNa.js";
6
6
  import { join } from "node:path";
7
7
  import { homedir } from "node:os";
8
- //#region src/oclif/auto-signal-worker.ts
8
+ // src/oclif/auto-signal-worker.ts
9
9
  function configDirectory(env) {
10
10
  if (env.PRIMITIVE_CONFIG_DIR) return env.PRIMITIVE_CONFIG_DIR;
11
11
  return join(env.XDG_CONFIG_HOME || join(homedir(), ".config"), "primitive");
@@ -164,5 +164,4 @@ async function runAutoSignalWorker(env = process.env, deps = {}) {
164
164
  }
165
165
  } catch {}
166
166
  }
167
- //#endregion
168
167
  export { runAutoSignalWorker };
@@ -1,11 +1,11 @@
1
- import { d as readMailJson, h as writeMailJson, i as mailId, l as privateMailDirectory, r as mailAddress } from "../shared-mail-files-CZfm7E2k.js";
2
- import { n as isPlainChatReply, o as scopedChatSenderTrust } from "../scoped-chat-DAiOb622.js";
1
+ import { n as isPlainChatReply, o as scopedChatSenderTrust } from "../scoped-chat-DZ42V3jq.js";
2
+ import { d as readMailJson, h as writeMailJson, i as mailId, l as privateMailDirectory, r as mailAddress } from "../shared-mail-files-BAQSGxxz.js";
3
3
  import { existsSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
4
4
  import { randomUUID } from "node:crypto";
5
5
  import { join } from "node:path";
6
6
  import { spawn } from "node:child_process";
7
7
  import { fileURLToPath } from "node:url";
8
- //#region src/oclif/auto-signals.ts
8
+ // src/oclif/auto-signals.ts
9
9
  /**
10
10
  * Automatic communication signals. When mail from the verified owner or a
11
11
  * verified same-organization member is surfaced to an agent session, the CLI
@@ -63,7 +63,7 @@ function autoSignalEligible(detail, identity, admission) {
63
63
  if (!detail.message_id) return false;
64
64
  const parsed = detail.parsed;
65
65
  const to = parsed?.to_addresses;
66
- if (!Array.isArray(to) || to.length !== 1 || lower(to[0]?.address) !== agent || (parsed.cc?.length ?? 0) > 0 || (parsed.bcc?.length ?? 0) > 0) return false;
66
+ if (!Array.isArray(to) || to.length !== 1 || lower(to[0]?.address) !== agent || (parsed?.cc?.length ?? 0) > 0 || (parsed?.bcc?.length ?? 0) > 0) return false;
67
67
  return isPlainChatReply(detail);
68
68
  } catch {
69
69
  return false;
@@ -612,5 +612,4 @@ function resumeAutoWorking(configDir, options = {}) {
612
612
  return 0;
613
613
  }
614
614
  }
615
- //#endregion
616
615
  export { AUTO_SIGNALS_OPT_OUT_ENV, AUTO_SIGNAL_EMAIL_ENV, AUTO_SIGNAL_KIND_ENV, AUTO_SIGNAL_WORKER_ENV, AUTO_WORKING_CAP_MS, AUTO_WORKING_EXPIRES_SECONDS, AUTO_WORKING_RENEW_MS, activeWorkingLeases, autoSignalEligible, autoSignalEntrypoint, autoSignalsDisabled, claimAutoRead, clearWorkingSending, dispatchAutoRead, dispatchAutoWorking, haltAutoWorking, isSentSignal, markWorkingSending, readAutoClaim, readWorkingLease, recordRenewer, recordSentSignal, releaseStopHold, renewerAlive, restoreAutoWorking, restoreWorkingLease, resumeAutoWorking, spawnAutoSignalWorker, startWorkingLease, stopWorkingLease, writeWorkingLease };
@@ -0,0 +1,76 @@
1
+ // src/oclif/global-org-flag.ts
2
+ /**
3
+ * The global `--org <org>` flag. bin/run.js takes it out of argv before oclif
4
+ * parses the command, so every command accepts it, and passes it on as
5
+ * PRIMITIVE_CLI_ORG. Only a saved `primitive login` made as yourself can switch
6
+ * organizations; every other credential refuses a different organization.
7
+ *
8
+ * No oclif import here: this runs before oclif loads.
9
+ */
10
+ /** Selects the organization for one command. */
11
+ const ORG_SELECTION_ENV = "PRIMITIVE_CLI_ORG";
12
+ /** Split `--org <value>` and `--org=<value>` out of argv, before any `--`. */
13
+ function extractGlobalOrgFlag(argv) {
14
+ const separator = argv.indexOf("--");
15
+ const head = separator === -1 ? [...argv] : argv.slice(0, separator);
16
+ const tail = separator === -1 ? [] : argv.slice(separator);
17
+ const command = head[0] ?? "";
18
+ if (command === "memories" || command.startsWith("memories:")) return {
19
+ ok: true,
20
+ argv: [...argv],
21
+ org: null
22
+ };
23
+ const kept = [];
24
+ let org = null;
25
+ for (let index = 0; index < head.length; index += 1) {
26
+ const arg = head[index];
27
+ if (arg === "--org") {
28
+ const value = head[index + 1];
29
+ if (value === void 0 || value.startsWith("-") || !value.trim()) return {
30
+ ok: false,
31
+ message: "--org needs an organization id or name, for example `--org acme`."
32
+ };
33
+ org = value.trim();
34
+ index += 1;
35
+ continue;
36
+ }
37
+ if (arg.startsWith("--org=")) {
38
+ const value = arg.slice(6).trim();
39
+ if (!value) return {
40
+ ok: false,
41
+ message: "--org needs an organization id or name, for example `--org=acme`."
42
+ };
43
+ org = value;
44
+ continue;
45
+ }
46
+ kept.push(arg);
47
+ }
48
+ return {
49
+ ok: true,
50
+ argv: [...kept, ...tail],
51
+ org
52
+ };
53
+ }
54
+ /**
55
+ * Apply the flag to this process: strip it from `process.argv` and set
56
+ * PRIMITIVE_CLI_ORG. Returns an error message for a malformed flag.
57
+ */
58
+ function applyGlobalOrgFlag(processArgv = process.argv, env = process.env) {
59
+ const parsed = extractGlobalOrgFlag(processArgv.slice(2));
60
+ if (!parsed.ok) return parsed.message;
61
+ if (parsed.org !== null) {
62
+ processArgv.splice(2, processArgv.length - 2, ...parsed.argv);
63
+ env[ORG_SELECTION_ENV] = parsed.org;
64
+ }
65
+ return null;
66
+ }
67
+ /**
68
+ * `env` without an organization selection, for a child that acts as a
69
+ * connected agent profile: the profile acts in its own organization.
70
+ */
71
+ function withoutOrgSelection(env) {
72
+ const next = { ...env };
73
+ delete next[ORG_SELECTION_ENV];
74
+ return next;
75
+ }
76
+ export { ORG_SELECTION_ENV, applyGlobalOrgFlag, extractGlobalOrgFlag, withoutOrgSelection };