youmd 0.12.0 → 0.13.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.
Files changed (80) hide show
  1. package/dist/commands/brain.d.ts.map +1 -1
  2. package/dist/commands/brain.js +12 -4
  3. package/dist/commands/brain.js.map +1 -1
  4. package/dist/commands/connect.d.ts +113 -0
  5. package/dist/commands/connect.d.ts.map +1 -0
  6. package/dist/commands/connect.js +849 -0
  7. package/dist/commands/connect.js.map +1 -0
  8. package/dist/commands/founder.d.ts +3 -0
  9. package/dist/commands/founder.d.ts.map +1 -1
  10. package/dist/commands/founder.js +258 -1
  11. package/dist/commands/founder.js.map +1 -1
  12. package/dist/generated/capability-registry.d.ts +291 -83
  13. package/dist/generated/capability-registry.d.ts.map +1 -1
  14. package/dist/generated/capability-registry.js +320 -83
  15. package/dist/generated/capability-registry.js.map +1 -1
  16. package/dist/index.js +31 -4
  17. package/dist/index.js.map +1 -1
  18. package/dist/lib/api.d.ts +76 -0
  19. package/dist/lib/api.d.ts.map +1 -1
  20. package/dist/lib/api.js +40 -0
  21. package/dist/lib/api.js.map +1 -1
  22. package/dist/lib/brain/adapters.d.ts +2 -0
  23. package/dist/lib/brain/adapters.d.ts.map +1 -1
  24. package/dist/lib/brain/adapters.js +71 -0
  25. package/dist/lib/brain/adapters.js.map +1 -1
  26. package/dist/lib/brain/content.d.ts +3 -1
  27. package/dist/lib/brain/content.d.ts.map +1 -1
  28. package/dist/lib/brain/content.js +92 -24
  29. package/dist/lib/brain/content.js.map +1 -1
  30. package/dist/lib/brain/discovery.d.ts.map +1 -1
  31. package/dist/lib/brain/discovery.js +2 -1
  32. package/dist/lib/brain/discovery.js.map +1 -1
  33. package/dist/lib/brain/index.d.ts +1 -0
  34. package/dist/lib/brain/index.d.ts.map +1 -1
  35. package/dist/lib/brain/index.js +7 -2
  36. package/dist/lib/brain/index.js.map +1 -1
  37. package/dist/lib/brain/vision.d.ts +35 -0
  38. package/dist/lib/brain/vision.d.ts.map +1 -0
  39. package/dist/lib/brain/vision.js +65 -0
  40. package/dist/lib/brain/vision.js.map +1 -0
  41. package/dist/lib/businessScaffold.d.ts +42 -0
  42. package/dist/lib/businessScaffold.d.ts.map +1 -0
  43. package/dist/lib/businessScaffold.js +150 -0
  44. package/dist/lib/businessScaffold.js.map +1 -0
  45. package/dist/lib/codex-device-auth.d.ts +94 -0
  46. package/dist/lib/codex-device-auth.d.ts.map +1 -0
  47. package/dist/lib/codex-device-auth.js +295 -0
  48. package/dist/lib/codex-device-auth.js.map +1 -0
  49. package/dist/lib/codex-job-control-plane.d.ts +67 -0
  50. package/dist/lib/codex-job-control-plane.d.ts.map +1 -0
  51. package/dist/lib/codex-job-control-plane.js +105 -0
  52. package/dist/lib/codex-job-control-plane.js.map +1 -0
  53. package/dist/lib/codex-readonly-job.d.ts +76 -0
  54. package/dist/lib/codex-readonly-job.d.ts.map +1 -0
  55. package/dist/lib/codex-readonly-job.js +196 -0
  56. package/dist/lib/codex-readonly-job.js.map +1 -0
  57. package/dist/lib/connected-access-native.d.ts +111 -0
  58. package/dist/lib/connected-access-native.d.ts.map +1 -0
  59. package/dist/lib/connected-access-native.js +403 -0
  60. package/dist/lib/connected-access-native.js.map +1 -0
  61. package/dist/lib/connected-context.d.ts +82 -0
  62. package/dist/lib/connected-context.d.ts.map +1 -0
  63. package/dist/lib/connected-context.js +610 -0
  64. package/dist/lib/connected-context.js.map +1 -0
  65. package/dist/lib/redact.d.ts.map +1 -1
  66. package/dist/lib/redact.js +9 -1
  67. package/dist/lib/redact.js.map +1 -1
  68. package/dist/mcp/registry.d.ts +4 -1
  69. package/dist/mcp/registry.d.ts.map +1 -1
  70. package/dist/mcp/registry.js +120 -1
  71. package/dist/mcp/registry.js.map +1 -1
  72. package/dist/mcp/server.d.ts +1 -1
  73. package/dist/mcp/server.d.ts.map +1 -1
  74. package/dist/mcp/server.js +18 -9
  75. package/dist/mcp/server.js.map +1 -1
  76. package/native/prebuilds/darwin-universal/youmd_safe_open.node +0 -0
  77. package/package.json +1 -1
  78. package/scripts/env-vault/README.md +16 -20
  79. package/scripts/env-vault/backup.sh +22 -57
  80. package/scripts/env-vault/restore.sh +18 -96
@@ -0,0 +1,849 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.issueCodexStatusReceipt = issueCodexStatusReceipt;
40
+ exports.listAgentAccessDeviceKeys = listAgentAccessDeviceKeys;
41
+ exports.enrollAgentAccessDeviceKey = enrollAgentAccessDeviceKey;
42
+ exports.revokeAgentAccessDeviceKey = revokeAgentAccessDeviceKey;
43
+ exports.listAgentAccessApplications = listAgentAccessApplications;
44
+ exports.registerAgentAccessApplication = registerAgentAccessApplication;
45
+ exports.updateAgentAccessApplication = updateAgentAccessApplication;
46
+ exports.revokeAgentAccessApplication = revokeAgentAccessApplication;
47
+ exports.proveChatGPTConnectedAccess = proveChatGPTConnectedAccess;
48
+ exports.listAgentAccessReceipts = listAgentAccessReceipts;
49
+ exports.verifyAgentAccessReceipt = verifyAgentAccessReceipt;
50
+ exports.revokeAgentAccessReceipt = revokeAgentAccessReceipt;
51
+ exports.normalizeLocalHandoffBase = normalizeLocalHandoffBase;
52
+ exports.normalizeHandoffAuthorizationUrl = normalizeHandoffAuthorizationUrl;
53
+ exports.startLocalBrowserHandoff = startLocalBrowserHandoff;
54
+ exports.connectCommand = connectCommand;
55
+ const child_process_1 = require("child_process");
56
+ const crypto = __importStar(require("crypto"));
57
+ const chalk_1 = __importDefault(require("chalk"));
58
+ const render_1 = require("../lib/render");
59
+ const config_1 = require("../lib/config");
60
+ const machine_identity_1 = require("../lib/machine-identity");
61
+ const connected_access_native_1 = require("../lib/connected-access-native");
62
+ const codex_device_auth_1 = require("../lib/codex-device-auth");
63
+ const fs = __importStar(require("fs"));
64
+ const path = __importStar(require("path"));
65
+ const codex_job_control_plane_1 = require("../lib/codex-job-control-plane");
66
+ const codex_readonly_job_1 = require("../lib/codex-readonly-job");
67
+ const connected_context_1 = require("../lib/connected-context");
68
+ const ACCENT = chalk_1.default.hex("#C46A3A");
69
+ const HANDOFF_START_PATH = "/api/local/browser-session/start";
70
+ const HANDOFF_AUTHORIZE_PATH = "/local-handoff/authorize";
71
+ /**
72
+ * The local store needs stable manifest/artifact correlators to enforce
73
+ * rollback and perform an exact revoke. They are not a CLI receipt contract.
74
+ * Keep every routine bootstrap operation on this deliberately small shape so
75
+ * shell history, logs, and MCP-adjacent wrappers cannot collect them.
76
+ */
77
+ function publicConnectedContextStatus(result) {
78
+ const receipt = {
79
+ connected: result.connected,
80
+ state: result.state,
81
+ authorityGranted: false,
82
+ secretValuesExposed: false,
83
+ };
84
+ if (typeof result.generation === "number")
85
+ receipt.generation = result.generation;
86
+ if (typeof result.expiresAt === "string")
87
+ receipt.expiresAt = result.expiresAt;
88
+ if (result.recovered === true)
89
+ receipt.recovered = true;
90
+ return receipt;
91
+ }
92
+ const CONNECTED_ACCESS = "/api/v1/me/agent-access";
93
+ const CONNECTED_ACCESS_APPLICATION_ID = "app:youmd-connected-access-extension";
94
+ const CODEX_ADAPTER_APPLICATION_ID = "app:youmd-local-codex-adapter";
95
+ function declaredInputFiles(files) {
96
+ if (!files?.length)
97
+ throw new Error("codex_audit_file_required");
98
+ if (files.length > 64 || new Set(files).size !== files.length)
99
+ throw new Error("codex_audit_files_invalid");
100
+ return files.map((relative) => {
101
+ if (!/^(?!\/)(?!.*(?:^|\/)\.\.(?:\/|$))[A-Za-z0-9._/-]{1,512}$/.test(relative))
102
+ throw new Error("codex_audit_files_invalid");
103
+ const parts = relative.toLowerCase().split("/");
104
+ if (parts.some((part) => /^(\.env(?:\..*)?|\.codex|\.claude|\.cursor|\.ssh|\.gnupg|\.git|node_modules|auth\.json|.*(?:credential|secret|token|cookie).*|keychains|chrome|application support)$/.test(part)))
105
+ throw new Error("codex_audit_files_invalid");
106
+ const target = path.resolve(process.cwd(), relative);
107
+ const stat = fs.lstatSync(target);
108
+ if (stat.isSymbolicLink() || !stat.isFile() || stat.size > 64 * 1024)
109
+ throw new Error("codex_audit_files_invalid");
110
+ const bytes = fs.readFileSync(target);
111
+ return { path: relative, digest: `sha256:${crypto.createHash("sha256").update(bytes).digest("hex")}` };
112
+ });
113
+ }
114
+ function codexAdapterRegistration() {
115
+ return { applicationId: CODEX_ADAPTER_APPLICATION_ID, runtime: "native_helper", runtimeBinding: "com.youmd.local-codex-adapter", allowedOrigins: ["https://www.you.md"] };
116
+ }
117
+ async function ensureCodexAdapterKeyAndApplication(nativeHostDeps) {
118
+ const key = await (0, connected_access_native_1.ensureNativeDevicePublicKey)(undefined, nativeHostDeps);
119
+ const deviceId = currentConnectedAccessDeviceId();
120
+ const enrolled = await ownerReceiptRequest(`${CONNECTED_ACCESS}/device-keys/enroll`, { method: "POST", body: JSON.stringify({ deviceId, publicJwk: key.publicJwk }) });
121
+ if (!enrolled.ok || typeof enrolled.data.deviceKey?.keyId !== "string")
122
+ throw new Error(`device_key_enroll_failed:${enrolled.status}`);
123
+ const application = await ownerReceiptRequest(`${CONNECTED_ACCESS}/applications/register`, { method: "POST", body: JSON.stringify(codexAdapterRegistration()) });
124
+ if (!application.ok || application.data.application?.applicationId !== CODEX_ADAPTER_APPLICATION_ID)
125
+ throw new Error(`application_register_failed:${application.status}`);
126
+ return { keyId: enrolled.data.deviceKey.keyId, publicKey: key.publicKey };
127
+ }
128
+ async function ownerReceiptRequest(path, init = {}) {
129
+ const token = (0, config_1.getAuthToken)();
130
+ if (!token)
131
+ throw new Error("authentication_required");
132
+ const response = await fetch(`${(0, config_1.getConvexSiteUrl)()}${path}`, {
133
+ ...init,
134
+ headers: { Accept: "application/json", "Content-Type": "application/json", Authorization: `Bearer ${token}`, ...(init.headers ?? {}) },
135
+ signal: AbortSignal.timeout(15000),
136
+ });
137
+ let data;
138
+ try {
139
+ data = await response.json();
140
+ }
141
+ catch {
142
+ data = {};
143
+ }
144
+ return { ok: response.ok, status: response.status, data };
145
+ }
146
+ function asNonAuthoritative(value) {
147
+ return { ...value, authorityGranted: false, secretValuesExposed: false };
148
+ }
149
+ function currentConnectedAccessDeviceId() {
150
+ const machineKey = (0, machine_identity_1.getPhysicalMachineKey)();
151
+ if (!/^[A-Za-z0-9._-]{3,128}$/.test(machineKey))
152
+ throw new Error("invalid_local_machine_identity");
153
+ return `device:${machineKey}`;
154
+ }
155
+ function localWorkspaceRef(deviceId) {
156
+ // A deterministic opaque workspace ref avoids uploading a hostname or path.
157
+ return `workspace:${crypto.createHash("sha256").update(`youmd-connected-access/v1:${deviceId}`).digest("hex")}`;
158
+ }
159
+ function canonicalizeStatusReport(value) {
160
+ if (value === null || typeof value === "boolean" || typeof value === "string" || typeof value === "number")
161
+ return JSON.stringify(value);
162
+ if (Array.isArray(value))
163
+ return `[${value.map(canonicalizeStatusReport).join(",")}]`;
164
+ if (!value || typeof value !== "object")
165
+ throw new Error("invalid_status_report");
166
+ const record = value;
167
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${canonicalizeStatusReport(record[key])}`).join(",")}}`;
168
+ }
169
+ function codexStatusProvenanceHash(status) {
170
+ return `sha256:${crypto.createHash("sha256").update(canonicalizeStatusReport(status)).digest("hex")}`;
171
+ }
172
+ /** Issue M1 evidence from an already-redacted, local Codex status enum only. */
173
+ async function issueCodexStatusReceipt(status, providerStateChanged) {
174
+ // An API-key-local Codex session is a different authentication mode. Never
175
+ // relabel it as a ChatGPT-connected receipt or upload it as such.
176
+ if (status.authenticationKind !== "chatgpt")
177
+ throw new Error("codex_chatgpt_sign_in_required");
178
+ const deviceId = currentConnectedAccessDeviceId();
179
+ const challenge = await ownerReceiptRequest(`${CONNECTED_ACCESS}/challenges`, {
180
+ method: "POST",
181
+ body: JSON.stringify({
182
+ deviceId,
183
+ applicationId: CODEX_ADAPTER_APPLICATION_ID,
184
+ target: "openai_codex",
185
+ origin: "https://chatgpt.com",
186
+ audience: "youmd:personal",
187
+ workspaceRef: localWorkspaceRef(deviceId),
188
+ }),
189
+ });
190
+ if (!challenge.ok || typeof challenge.data.challenge !== "string")
191
+ throw new Error(`codex_challenge_failed:${challenge.status}`);
192
+ const confirmation = await ownerReceiptRequest(`${CONNECTED_ACCESS}/receipts/confirm`, {
193
+ method: "POST",
194
+ body: JSON.stringify({
195
+ challenge: challenge.data.challenge,
196
+ provenanceHash: codexStatusProvenanceHash(status),
197
+ observedAt: new Date().toISOString(),
198
+ expiresInMs: 60 * 60 * 1000,
199
+ }),
200
+ });
201
+ if (!confirmation.ok || !confirmation.data.receipt)
202
+ throw new Error(`codex_receipt_failed:${confirmation.status}`);
203
+ return asNonAuthoritative({
204
+ ...confirmation.data.receipt,
205
+ localStatus: status,
206
+ providerStateChanged: providerStateChanged === true,
207
+ providerCredentialsRead: false,
208
+ deviceCodeCaptured: false,
209
+ });
210
+ }
211
+ function hashFromApi(value) {
212
+ if (typeof value !== "string")
213
+ throw new Error("invalid_proof_hash");
214
+ const normalized = value.replace(/^sha256:/, "");
215
+ if (!/^[a-f0-9]{64}$/.test(normalized))
216
+ throw new Error("invalid_proof_hash");
217
+ return normalized;
218
+ }
219
+ function expiresAtMs(value) {
220
+ if (typeof value !== "string")
221
+ throw new Error("invalid_proof_expiry");
222
+ const timestamp = Date.parse(value);
223
+ if (!Number.isFinite(timestamp) || timestamp <= Date.now())
224
+ throw new Error("proof_expired");
225
+ return timestamp;
226
+ }
227
+ async function listAgentAccessDeviceKeys(includeInactive = false) {
228
+ const result = await ownerReceiptRequest(`${CONNECTED_ACCESS}/device-keys${includeInactive ? "?includeInactive=1" : ""}`);
229
+ if (!result.ok || !Array.isArray(result.data.deviceKeys))
230
+ throw new Error(`device_key_list_failed:${result.status}`);
231
+ return result.data.deviceKeys.map((row) => asNonAuthoritative(row));
232
+ }
233
+ async function enrollAgentAccessDeviceKey(nativeHostDeps) {
234
+ const loaded = (0, connected_access_native_1.loadNativeHostConfig)(nativeHostDeps);
235
+ const key = await (0, connected_access_native_1.ensureNativeDevicePublicKey)(loaded, nativeHostDeps);
236
+ const result = await ownerReceiptRequest(`${CONNECTED_ACCESS}/device-keys/enroll`, {
237
+ method: "POST",
238
+ body: JSON.stringify({ deviceId: currentConnectedAccessDeviceId(), publicJwk: key.publicJwk }),
239
+ });
240
+ if (!result.ok || !result.data.deviceKey || typeof result.data.deviceKey.keyId !== "string")
241
+ throw new Error(`device_key_enroll_failed:${result.status}`);
242
+ return asNonAuthoritative({ ...result.data.deviceKey, deviceId: currentConnectedAccessDeviceId(), bindingClass: loaded.config.bindingClass });
243
+ }
244
+ async function revokeAgentAccessDeviceKey(keyId) {
245
+ const result = await ownerReceiptRequest(`${CONNECTED_ACCESS}/device-keys/revoke`, {
246
+ method: "POST", body: JSON.stringify({ keyId }),
247
+ });
248
+ if (!result.ok || !result.data.deviceKey)
249
+ throw new Error(`device_key_revoke_failed:${result.status}`);
250
+ return asNonAuthoritative(result.data.deviceKey);
251
+ }
252
+ async function listAgentAccessApplications(includeInactive = false) {
253
+ const result = await ownerReceiptRequest(`${CONNECTED_ACCESS}/applications${includeInactive ? "?includeInactive=1" : ""}`);
254
+ if (!result.ok || !Array.isArray(result.data.applications))
255
+ throw new Error(`application_list_failed:${result.status}`);
256
+ return result.data.applications.map((row) => asNonAuthoritative(row));
257
+ }
258
+ function officialDevelopmentExtensionRegistration(extensionId) {
259
+ return {
260
+ applicationId: CONNECTED_ACCESS_APPLICATION_ID,
261
+ runtime: "chrome_extension",
262
+ runtimeBinding: extensionId,
263
+ allowedOrigins: ["https://chatgpt.com"],
264
+ };
265
+ }
266
+ async function registerAgentAccessApplication(nativeHostDeps) {
267
+ const loaded = (0, connected_access_native_1.loadNativeHostConfig)(nativeHostDeps);
268
+ const browser = (0, connected_access_native_1.requireBrowserNativeHostConfig)(loaded.config);
269
+ const result = await ownerReceiptRequest(`${CONNECTED_ACCESS}/applications/register`, {
270
+ method: "POST",
271
+ body: JSON.stringify(officialDevelopmentExtensionRegistration(browser.extensionId)),
272
+ });
273
+ if (!result.ok || !result.data.application || typeof result.data.application.applicationId !== "string")
274
+ throw new Error(`application_register_failed:${result.status}`);
275
+ return asNonAuthoritative({ ...result.data.application, bindingClass: loaded.config.bindingClass });
276
+ }
277
+ /**
278
+ * Rotate the exact local extension binding only when the owner invokes this
279
+ * command. Register/prove are deliberately idempotent and never auto-update:
280
+ * changing a binding invalidates outstanding signed evidence server-side.
281
+ */
282
+ async function updateAgentAccessApplication(nativeHostDeps) {
283
+ const loaded = (0, connected_access_native_1.loadNativeHostConfig)(nativeHostDeps);
284
+ const browser = (0, connected_access_native_1.requireBrowserNativeHostConfig)(loaded.config);
285
+ const result = await ownerReceiptRequest(`${CONNECTED_ACCESS}/applications/update`, {
286
+ method: "POST",
287
+ body: JSON.stringify(officialDevelopmentExtensionRegistration(browser.extensionId)),
288
+ });
289
+ if (!result.ok || !result.data.application || typeof result.data.application.applicationId !== "string")
290
+ throw new Error(`application_update_failed:${result.status}`);
291
+ return asNonAuthoritative({ ...result.data.application, bindingClass: loaded.config.bindingClass });
292
+ }
293
+ async function revokeAgentAccessApplication(applicationId) {
294
+ const result = await ownerReceiptRequest(`${CONNECTED_ACCESS}/applications/revoke`, {
295
+ method: "POST", body: JSON.stringify({ applicationId }),
296
+ });
297
+ if (!result.ok || !result.data.application)
298
+ throw new Error(`application_revoke_failed:${result.status}`);
299
+ return asNonAuthoritative(result.data.application);
300
+ }
301
+ /**
302
+ * Complete a bounded signed observation proof. This reads a pre-existing,
303
+ * short-lived sanitized observation only; it never opens Chrome, installs an
304
+ * extension, reads provider storage, or copies a provider credential.
305
+ */
306
+ async function proveChatGPTConnectedAccess(nativeHostDeps) {
307
+ const loaded = (0, connected_access_native_1.loadNativeHostConfig)(nativeHostDeps);
308
+ const browser = (0, connected_access_native_1.requireBrowserNativeHostConfig)(loaded.config);
309
+ const deviceId = currentConnectedAccessDeviceId();
310
+ const key = await (0, connected_access_native_1.ensureNativeDevicePublicKey)(loaded, nativeHostDeps);
311
+ const keyEnrollment = await ownerReceiptRequest(`${CONNECTED_ACCESS}/device-keys/enroll`, {
312
+ method: "POST", body: JSON.stringify({ deviceId, publicJwk: key.publicJwk }),
313
+ });
314
+ if (!keyEnrollment.ok || !keyEnrollment.data.deviceKey || typeof keyEnrollment.data.deviceKey.keyId !== "string")
315
+ throw new Error(`device_key_enroll_failed:${keyEnrollment.status}`);
316
+ const appRegistration = await ownerReceiptRequest(`${CONNECTED_ACCESS}/applications/register`, {
317
+ method: "POST",
318
+ body: JSON.stringify(officialDevelopmentExtensionRegistration(browser.extensionId)),
319
+ });
320
+ if (!appRegistration.ok || !appRegistration.data.application)
321
+ throw new Error(`application_register_failed:${appRegistration.status}`);
322
+ const observation = await (0, connected_access_native_1.readCachedNativeObservation)(loaded, nativeHostDeps);
323
+ if (observation.publicKey !== key.publicKey)
324
+ throw new Error("native_host_observation_key_mismatch");
325
+ const preparedResponse = await ownerReceiptRequest(`${CONNECTED_ACCESS}/proofs/prepare`, {
326
+ method: "POST",
327
+ body: JSON.stringify({
328
+ keyId: keyEnrollment.data.deviceKey.keyId,
329
+ deviceId,
330
+ applicationId: CONNECTED_ACCESS_APPLICATION_ID,
331
+ target: "chatgpt",
332
+ origin: "https://chatgpt.com",
333
+ audience: "youmd:personal",
334
+ workspaceRef: localWorkspaceRef(deviceId),
335
+ expiresInMs: 60 * 60 * 1000,
336
+ cachedObservationEnvelope: observation.envelope,
337
+ cachedObservationSignature: observation.signature,
338
+ cachedObservationPublicKey: observation.publicKey,
339
+ }),
340
+ });
341
+ if (!preparedResponse.ok || !preparedResponse.data.proof)
342
+ throw new Error(`proof_prepare_failed:${preparedResponse.status}`);
343
+ const prepared = preparedResponse.data.proof;
344
+ if (typeof prepared.proofDraftId !== "string" || typeof prepared.preparedCanonicalPayload !== "string")
345
+ throw new Error("invalid_prepared_proof");
346
+ const preparedPayload = Buffer.from(prepared.preparedCanonicalPayload, "base64url");
347
+ if (preparedPayload.length === 0 || (0, connected_access_native_1.sha256Hex)(preparedPayload) !== hashFromApi(prepared.payloadHash)
348
+ || hashFromApi(prepared.observationHash) !== observation.observationHash) {
349
+ throw new Error("prepared_proof_hash_mismatch");
350
+ }
351
+ const signed = await (0, connected_access_native_1.signPreparedNativeProof)({
352
+ preparedCanonicalPayload: prepared.preparedCanonicalPayload,
353
+ observationHash: observation.observationHash,
354
+ expiresAt: expiresAtMs(prepared.expiresAt),
355
+ expectedPublicKey: key.publicKey,
356
+ }, loaded, nativeHostDeps);
357
+ if (signed.payloadHash !== hashFromApi(prepared.payloadHash))
358
+ throw new Error("native_host_payload_hash_mismatch");
359
+ const complete = await ownerReceiptRequest(`${CONNECTED_ACCESS}/proofs/complete`, {
360
+ method: "POST", body: JSON.stringify({ proofDraftId: prepared.proofDraftId, signature: signed.signature }),
361
+ });
362
+ if (!complete.ok || !complete.data.receipt)
363
+ throw new Error(`proof_complete_failed:${complete.status}`);
364
+ return asNonAuthoritative({
365
+ ...complete.data.receipt,
366
+ target: "chatgpt",
367
+ assurance: "local_auth_ui_observed",
368
+ bindingClass: loaded.config.bindingClass,
369
+ providerCredentialsRead: false,
370
+ extensionInstalled: false,
371
+ chromeWebStoreClaimed: false,
372
+ });
373
+ }
374
+ async function listAgentAccessReceipts(includeInactive = false) {
375
+ const result = await ownerReceiptRequest(`/api/v1/me/agent-access/receipts${includeInactive ? "?includeInactive=1" : ""}`);
376
+ if (!result.ok || !Array.isArray(result.data.receipts))
377
+ throw new Error(`receipt_list_failed:${result.status}`);
378
+ return result.data.receipts;
379
+ }
380
+ async function verifyAgentAccessReceipt(receiptId) {
381
+ const rows = await listAgentAccessReceipts(true);
382
+ const receipt = rows.find((row) => row.receiptId === receiptId);
383
+ if (!receipt)
384
+ return { ok: false, reason: "receipt_not_found", authorityGranted: false };
385
+ const result = await ownerReceiptRequest("/api/v1/me/agent-access/receipts/verify", {
386
+ method: "POST",
387
+ body: JSON.stringify({ receiptId, deviceId: receipt.deviceId, applicationId: receipt.applicationId, audience: receipt.audience }),
388
+ });
389
+ if (!result.ok)
390
+ throw new Error(`receipt_verify_failed:${result.status}`);
391
+ return { ...result.data, authorityGranted: false };
392
+ }
393
+ async function revokeAgentAccessReceipt(receiptId) {
394
+ const result = await ownerReceiptRequest("/api/v1/me/agent-access/receipts/revoke", {
395
+ method: "POST", body: JSON.stringify({ receiptId }),
396
+ });
397
+ if (!result.ok)
398
+ throw new Error(`receipt_revoke_failed:${result.status}`);
399
+ return { ...result.data, providerLogoutPerformed: false };
400
+ }
401
+ /** Only IP-literal loopback is eligible. `localhost` is intentionally excluded. */
402
+ function normalizeLocalHandoffBase(value) {
403
+ if (!value?.trim())
404
+ return null;
405
+ try {
406
+ const url = new URL(value.trim());
407
+ if (url.protocol !== "http:" || (url.hostname !== "127.0.0.1" && url.hostname !== "[::1]" && url.hostname !== "::1"))
408
+ return null;
409
+ if (!url.port || !/^[1-9]\d{0,4}$/.test(url.port))
410
+ return null;
411
+ const port = Number(url.port);
412
+ if (port > 65535 || url.username || url.password || url.search || url.hash)
413
+ return null;
414
+ if (url.pathname !== "/" && url.pathname !== "")
415
+ return null;
416
+ return url.origin;
417
+ }
418
+ catch {
419
+ return null;
420
+ }
421
+ }
422
+ /** Never open a URL supplied by the local listener unless it is You.md's handoff UI. */
423
+ function normalizeHandoffAuthorizationUrl(value) {
424
+ if (typeof value !== "string")
425
+ return null;
426
+ try {
427
+ const url = new URL(value);
428
+ const host = url.hostname.toLowerCase();
429
+ if (url.protocol !== "https:" || host !== "www.you.md")
430
+ return null;
431
+ if (url.username || url.password || url.pathname !== HANDOFF_AUTHORIZE_PATH || url.hash)
432
+ return null;
433
+ return url.toString();
434
+ }
435
+ catch {
436
+ return null;
437
+ }
438
+ }
439
+ function openExternalUrl(url) {
440
+ const [command, args] = process.platform === "darwin"
441
+ ? ["open", [url]]
442
+ : process.platform === "win32"
443
+ ? ["cmd", ["/c", "start", "", url]]
444
+ : ["xdg-open", [url]];
445
+ (0, child_process_1.execFile)(command, args, { windowsHide: true }, () => {
446
+ // The URL is printed as a reliable manual fallback.
447
+ });
448
+ }
449
+ function resultForError(status, localOrigin) {
450
+ return { ok: false, status, localOrigin, secretValuesExposed: false };
451
+ }
452
+ /**
453
+ * Start a confirmed local browser handoff. This intentionally carries neither
454
+ * the You.md CLI token nor an API origin: the fixed loopback listener derives
455
+ * the exact current port, callback audience, and registered local identity.
456
+ */
457
+ async function startLocalBrowserHandoff(options, deps = {}) {
458
+ const localOrigin = normalizeLocalHandoffBase(options.localBase);
459
+ if (!localOrigin)
460
+ return resultForError("unavailable");
461
+ const request = deps.fetch ?? fetch;
462
+ let response;
463
+ try {
464
+ response = await request(`${localOrigin}${HANDOFF_START_PATH}`, {
465
+ method: "POST",
466
+ headers: { Accept: "application/json", "Cache-Control": "no-store" },
467
+ redirect: "error",
468
+ });
469
+ }
470
+ catch {
471
+ return resultForError("unavailable", localOrigin);
472
+ }
473
+ if (response.status === 404 || response.status === 405 || response.status === 501) {
474
+ return resultForError("unsupported", localOrigin);
475
+ }
476
+ if (!response.ok)
477
+ return resultForError("rejected", localOrigin);
478
+ let payload;
479
+ try {
480
+ payload = await response.json();
481
+ }
482
+ catch {
483
+ return resultForError("rejected", localOrigin);
484
+ }
485
+ const authorizationUrl = normalizeHandoffAuthorizationUrl(payload.authorizationUrl);
486
+ const expiresAt = typeof payload.expiresAt === "number" && Number.isFinite(payload.expiresAt) && payload.expiresAt > Date.now()
487
+ ? payload.expiresAt
488
+ : null;
489
+ if (payload.ok !== true || !authorizationUrl || !expiresAt)
490
+ return resultForError("rejected", localOrigin);
491
+ return {
492
+ ok: true,
493
+ status: "started",
494
+ localOrigin,
495
+ authorizationUrl,
496
+ expiresAt,
497
+ secretValuesExposed: false,
498
+ };
499
+ }
500
+ async function connectCommand(action, value, argument, options = {}) {
501
+ const nestedAction = value?.toLowerCase();
502
+ const nestedArgument = argument;
503
+ const connectedDeps = options.connectedContextDeps ?? {
504
+ fetch,
505
+ native: (0, connected_context_1.createNativeConnectedContext)(options.nativeHostDeps),
506
+ authToken: config_1.getAuthToken,
507
+ apiUrl: config_1.getConvexSiteUrl,
508
+ };
509
+ const output = (result, label) => {
510
+ const safe = asNonAuthoritative(result);
511
+ if (options.json)
512
+ console.log(JSON.stringify(safe, null, 2));
513
+ else {
514
+ console.log(` ${JSON.stringify(safe, null, 2).split("\n").join("\n ")}`);
515
+ const providerStateCopy = safe.providerStateChanged === true
516
+ ? "Provider sign-in state may have changed through the provider's own interactive UI; no provider credential was read or copied."
517
+ : "No provider authority, credentials, or login state were changed.";
518
+ console.log(chalk_1.default.dim(` ${label} ${providerStateCopy}`));
519
+ }
520
+ };
521
+ if (action === "bootstrap") {
522
+ const operation = nestedAction ?? "start";
523
+ const spinner = options.json ? null : new render_1.BrailleSpinner(operation === "start" ? "verifying and syncing your signed private context..." : `${operation}ing the local signed context snapshot...`);
524
+ spinner?.start();
525
+ try {
526
+ let result;
527
+ if (operation === "start") {
528
+ if (nestedArgument)
529
+ throw new Error("bootstrap_usage");
530
+ result = await (0, connected_context_1.bootstrapConnectedContext)(connectedDeps, { trustCurrentGeneration: options.trustCurrentGeneration });
531
+ }
532
+ else if (operation === "status") {
533
+ if (nestedArgument)
534
+ throw new Error("bootstrap_usage");
535
+ result = (0, connected_context_1.getConnectedContextStatus)(connectedDeps);
536
+ }
537
+ else if (operation === "verify") {
538
+ if (nestedArgument)
539
+ throw new Error("bootstrap_usage");
540
+ result = await (0, connected_context_1.verifyConnectedContext)(connectedDeps);
541
+ }
542
+ else if (operation === "revoke") {
543
+ result = await (0, connected_context_1.revokeConnectedContext)(connectedDeps, { manifestId: nestedArgument, revokeApplication: options.revokeApplication, revokeKey: options.revokeKey });
544
+ }
545
+ else
546
+ throw new Error("bootstrap_usage");
547
+ spinner?.stop(operation === "start" ? "signed private context is ready for local agents" : `connected context ${result.state}`);
548
+ const receipt = publicConnectedContextStatus(result);
549
+ if (options.json)
550
+ console.log(JSON.stringify(receipt, null, 2));
551
+ else {
552
+ console.log(` ${JSON.stringify(receipt, null, 2).split("\n").join("\n ")}`);
553
+ console.log(chalk_1.default.dim(" The owner key and short-lived DPoP token were not stored or exposed to agents."));
554
+ }
555
+ return;
556
+ }
557
+ catch (error) {
558
+ spinner?.stop("connected context stopped safely");
559
+ const code = error instanceof Error ? error.message : "connected_context_failed";
560
+ if (options.json)
561
+ console.log(JSON.stringify({ ok: false, error: code, authorityGranted: false, secretValuesExposed: false }, null, 2));
562
+ else
563
+ console.error(ACCENT(` ${code.replaceAll("_", " ")}; no credential or partial snapshot was exposed`));
564
+ process.exitCode = 1;
565
+ return;
566
+ }
567
+ }
568
+ if (action === "codex") {
569
+ const spinner = options.json ? null : new render_1.BrailleSpinner("checking the local Codex sign-in state without reading credentials...");
570
+ spinner?.start();
571
+ try {
572
+ if (nestedAction === "status") {
573
+ const status = await (0, codex_device_auth_1.getCodexAuthenticationStatus)(options.codexDeps);
574
+ spinner?.stop(status.authenticated ? "local Codex authentication observed" : "local Codex authentication is not confirmed");
575
+ output({
576
+ localStatus: status,
577
+ providerStateChanged: false,
578
+ providerCredentialsRead: false,
579
+ deviceCodeCaptured: false,
580
+ }, "Only a strict local status enum was read.");
581
+ }
582
+ else if (nestedAction === "login") {
583
+ // Device auth prints the provider URL/code directly to the terminal.
584
+ // A JSON response cannot coexist safely with that inherited stream.
585
+ const before = await (0, codex_device_auth_1.getCodexAuthenticationStatus)(options.codexDeps);
586
+ if (options.json && before.authenticationKind !== "chatgpt")
587
+ throw new Error("interactive_login_requires_tty");
588
+ const outcome = await (0, codex_device_auth_1.ensureCodexAuthentication)(options.codexDeps);
589
+ const receipt = await issueCodexStatusReceipt(outcome.status, outcome.providerStateChanged);
590
+ spinner?.stop(outcome.loginChildRan ? "Codex sign-in confirmed; non-authoritative receipt issued" : "existing Codex sign-in confirmed; non-authoritative receipt issued");
591
+ output(receipt, "The receipt is first-party client-reported evidence only; it cannot run a Codex job.");
592
+ }
593
+ else if (nestedAction === "audit") {
594
+ if (nestedArgument)
595
+ throw new Error("codex_audit_usage");
596
+ const files = declaredInputFiles(options.files);
597
+ const bound = await (options.codexAuditBinding ?? (() => ensureCodexAdapterKeyAndApplication(options.nativeHostDeps)))();
598
+ const deviceId = currentConnectedAccessDeviceId();
599
+ const jobDeps = options.codexJobDeps ?? { fetch, openApproval: openExternalUrl, sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)), token: config_1.getAuthToken };
600
+ const job = await (0, codex_job_control_plane_1.prepareAndAwaitOwnerApproval)({ keyId: bound.keyId, workspaceRef: localWorkspaceRef(deviceId), deviceId, files, deadlineSeconds: 300 }, jobDeps, { waitForApproval: options.json !== true });
601
+ if (options.json) {
602
+ spinner?.stop("audit is waiting for owner approval");
603
+ output({ jobId: job.jobId, hostedApprovalUrl: job.hostedApprovalUrl, approvalState: "pending", contextDigest: codex_readonly_job_1.CODEX_READONLY_JOB_CONTEXT_DIGEST, declaredInputCount: files.length, authorityGranted: false, providerCredentialsRead: false, providerStateChanged: false, providerExecutionStarted: false }, "Approval is pending. Open hostedApprovalUrl in a signed-in browser, then rerun without --json.");
604
+ return;
605
+ }
606
+ const lifecycle = options.codexAuditLifecycle ?? { run: async (claim, grant) => {
607
+ const localGrant = { ...claim, ...grant, approvalState: grant.approvalState, approvalRef: grant.approvalRef, approvalExpiresAt: grant.approvalExpiresAt, keyId: grant.keyId, keyGeneration: grant.keyGeneration, applicationGeneration: grant.applicationGeneration };
608
+ const executed = await (0, codex_readonly_job_1.executeApprovedReadonlyLocalCodexJob)(localGrant, process.cwd(), () => { });
609
+ return { outcome: executed.status === "completed" ? "succeeded" : "failed", resultDigest: executed.resultHash, contextLoaded: executed.contextLoaded, modelStarted: executed.modelStarted };
610
+ } };
611
+ const outcome = await (0, codex_job_control_plane_1.claimAndRunApprovedLocalCodexJob)(job, { ...jobDeps, ...lifecycle, publicKey: bound.publicKey });
612
+ spinner?.stop(`approved local audit ${outcome.outcome}`);
613
+ const lifecycleCopy = outcome.contextLoaded
614
+ ? outcome.modelStarted
615
+ ? "The declared snapshot was the working input. Codex read-only sandbox blocks writes and configured agent tools/network; this is not OS-level read isolation, and OpenAI handled provider inference transport."
616
+ : "The declared snapshot was prepared, but Codex never started; no provider inference was attempted."
617
+ : "The declared snapshot was not prepared and Codex never started; no provider inference was attempted.";
618
+ output({ jobId: job.jobId, outcome: outcome.outcome, declaredInputCount: files.length, authorityGranted: false, providerCredentialsRead: false, providerStateChanged: false, providerExecutionStarted: outcome.modelStarted }, lifecycleCopy);
619
+ }
620
+ else {
621
+ spinner?.stop("Codex command needs an action");
622
+ throw new Error("codex_usage");
623
+ }
624
+ return;
625
+ }
626
+ catch (error) {
627
+ spinner?.stop("Codex connection stopped safely");
628
+ const code = error instanceof Error ? error.message : "codex_connection_failed";
629
+ if (options.json)
630
+ console.log(JSON.stringify({ ok: false, error: code, authorityGranted: false, providerCredentialsRead: false, deviceCodeCaptured: false }, null, 2));
631
+ else
632
+ console.error(ACCENT(` ${code.replaceAll("_", " ")}; no provider credential was read or copied`));
633
+ process.exitCode = 1;
634
+ return;
635
+ }
636
+ }
637
+ if (action === "key") {
638
+ const spinner = options.json ? null : new render_1.BrailleSpinner("checking the local signed-helper key...");
639
+ spinner?.start();
640
+ try {
641
+ if (nestedAction === "list") {
642
+ const keys = await listAgentAccessDeviceKeys(options.includeInactive === true);
643
+ spinner?.stop(`${keys.length} device key${keys.length === 1 ? "" : "s"} found`);
644
+ output({ deviceKeys: keys }, "Device keys are public-key records only.");
645
+ }
646
+ else if (nestedAction === "enroll") {
647
+ const result = await enrollAgentAccessDeviceKey(options.nativeHostDeps);
648
+ spinner?.stop("dedicated public signing key enrolled");
649
+ output(result, "The private Ed25519 key remains in the local Keychain-backed helper.");
650
+ }
651
+ else if (nestedAction === "revoke" && nestedArgument) {
652
+ const result = await revokeAgentAccessDeviceKey(nestedArgument);
653
+ spinner?.stop("device key revoked");
654
+ output(result, "Existing signed evidence may now be invalidated.");
655
+ }
656
+ else {
657
+ spinner?.stop("key command needs an action");
658
+ throw new Error("key_usage");
659
+ }
660
+ return;
661
+ }
662
+ catch (error) {
663
+ spinner?.stop("key operation stopped safely");
664
+ const code = error instanceof Error ? error.message : "device_key_failed";
665
+ if (options.json)
666
+ console.log(JSON.stringify({ ok: false, error: code, authorityGranted: false, secretValuesExposed: false }, null, 2));
667
+ else
668
+ console.error(ACCENT(` ${code.replaceAll("_", " ")}; no provider state changed`));
669
+ process.exitCode = 1;
670
+ return;
671
+ }
672
+ }
673
+ if (action === "app") {
674
+ const spinner = options.json ? null : new render_1.BrailleSpinner("checking the exact local extension binding...");
675
+ spinner?.start();
676
+ try {
677
+ if (nestedAction === "list") {
678
+ const applications = await listAgentAccessApplications(options.includeInactive === true);
679
+ spinner?.stop(`${applications.length} application${applications.length === 1 ? "" : "s"} found`);
680
+ output({ applications }, "Application records bind local runtime metadata only.");
681
+ }
682
+ else if (nestedAction === "register") {
683
+ const result = await registerAgentAccessApplication(options.nativeHostDeps);
684
+ spinner?.stop("development extension binding registered");
685
+ output(result, "This is owner-registered development provenance, not a Chrome Web Store claim.");
686
+ }
687
+ else if (nestedAction === "update") {
688
+ const result = await updateAgentAccessApplication(options.nativeHostDeps);
689
+ spinner?.stop("development extension binding rotated explicitly");
690
+ output(result, "Binding rotation was explicit; register and prove never rotate it automatically.");
691
+ }
692
+ else if (nestedAction === "revoke" && nestedArgument) {
693
+ const result = await revokeAgentAccessApplication(nestedArgument);
694
+ spinner?.stop("application binding revoked");
695
+ output(result, "No Chrome extension or provider login was removed.");
696
+ }
697
+ else {
698
+ spinner?.stop("app command needs an action");
699
+ throw new Error("app_usage");
700
+ }
701
+ return;
702
+ }
703
+ catch (error) {
704
+ spinner?.stop("application operation stopped safely");
705
+ const code = error instanceof Error ? error.message : "application_failed";
706
+ if (options.json)
707
+ console.log(JSON.stringify({ ok: false, error: code, authorityGranted: false, secretValuesExposed: false }, null, 2));
708
+ else
709
+ console.error(ACCENT(` ${code.replaceAll("_", " ")}; no provider state changed`));
710
+ process.exitCode = 1;
711
+ return;
712
+ }
713
+ }
714
+ if (action === "prove") {
715
+ const spinner = options.json ? null : new render_1.BrailleSpinner("verifying a short-lived local ChatGPT UI observation...");
716
+ spinner?.start();
717
+ try {
718
+ if (value?.toLowerCase() !== "chatgpt" || argument)
719
+ throw new Error("prove_usage");
720
+ const result = await proveChatGPTConnectedAccess(options.nativeHostDeps);
721
+ spinner?.stop("signed local observation receipt issued");
722
+ output(result, "This is local UI evidence only; it cannot run a provider job or access an account.");
723
+ return;
724
+ }
725
+ catch (error) {
726
+ spinner?.stop("proof stopped safely");
727
+ const code = error instanceof Error ? error.message : "proof_failed";
728
+ if (options.json)
729
+ console.log(JSON.stringify({ ok: false, error: code, authorityGranted: false, secretValuesExposed: false }, null, 2));
730
+ else
731
+ console.error(ACCENT(` ${code.replaceAll("_", " ")}; no provider state changed`));
732
+ process.exitCode = 1;
733
+ return;
734
+ }
735
+ }
736
+ if (action === "status") {
737
+ const spinner = options.json ? null : new render_1.BrailleSpinner("checking non-secret connection receipts...");
738
+ spinner?.start();
739
+ try {
740
+ const receipts = await listAgentAccessReceipts(options.includeInactive === true);
741
+ spinner?.stop(`${receipts.length} receipt${receipts.length === 1 ? "" : "s"} found`);
742
+ if (options.json) {
743
+ console.log(JSON.stringify({ receipts, authorityGranted: false }, null, 2));
744
+ return;
745
+ }
746
+ if (receipts.length === 0) {
747
+ console.log(chalk_1.default.dim(" no active connection receipts"));
748
+ return;
749
+ }
750
+ for (const receipt of receipts) {
751
+ console.log(` ${ACCENT(receipt.status.padEnd(7))} ${chalk_1.default.white(receipt.target.padEnd(18))} ${chalk_1.default.dim(receipt.assurance)}`);
752
+ console.log(chalk_1.default.dim(` ${receipt.receiptId} · expires ${receipt.expiresAt}`));
753
+ }
754
+ console.log(chalk_1.default.dim(" receipts are evidence only; they cannot run an agent job"));
755
+ return;
756
+ }
757
+ catch (error) {
758
+ spinner?.stop("receipt status unavailable");
759
+ const message = error instanceof Error && error.message === "authentication_required" ? "run `you login` before reading private receipts" : "could not read connection receipts";
760
+ if (options.json)
761
+ console.log(JSON.stringify({ ok: false, error: message, authorityGranted: false }, null, 2));
762
+ else
763
+ console.error(ACCENT(` ${message}`));
764
+ process.exitCode = 1;
765
+ return;
766
+ }
767
+ }
768
+ if ((action === "verify" || action === "revoke") && value) {
769
+ const spinner = options.json ? null : new render_1.BrailleSpinner(action === "verify" ? "verifying exact receipt bindings..." : "revoking receipt evidence only...");
770
+ spinner?.start();
771
+ try {
772
+ const result = action === "verify" ? await verifyAgentAccessReceipt(value) : await revokeAgentAccessReceipt(value);
773
+ spinner?.stop(action === "verify" ? "receipt verification complete" : "receipt revoked; provider login unchanged");
774
+ if (options.json)
775
+ console.log(JSON.stringify(result, null, 2));
776
+ else {
777
+ console.log(` ${JSON.stringify(result, null, 2).split("\n").join("\n ")}`);
778
+ console.log(chalk_1.default.dim(action === "verify" ? " no execution authority was granted" : " provider login state was not changed"));
779
+ }
780
+ return;
781
+ }
782
+ catch {
783
+ spinner?.stop(`receipt ${action} failed`);
784
+ if (options.json)
785
+ console.log(JSON.stringify({ ok: false, error: `receipt_${action}_failed`, authorityGranted: false }, null, 2));
786
+ else
787
+ console.error(ACCENT(` receipt ${action} failed; no provider state was changed`));
788
+ process.exitCode = 1;
789
+ return;
790
+ }
791
+ }
792
+ if (action !== "browser") {
793
+ console.log("usage: you connect browser --local-base http://127.0.0.1:<port>");
794
+ console.log(" you connect status [--all] [--json]");
795
+ console.log(" you connect verify <receipt-id> [--json]");
796
+ console.log(" you connect revoke <receipt-id> [--json]");
797
+ console.log(" you connect key enroll|list [--all] [--json]");
798
+ console.log(" you connect key revoke <key-id> [--json]");
799
+ console.log(" you connect app register|update|list [--all] [--json]");
800
+ console.log(" you connect app revoke <application-id> [--json]");
801
+ console.log(" you connect prove chatgpt [--json]");
802
+ console.log(" you connect codex status|login [--json]");
803
+ console.log(" you connect codex audit --file <relative-path> [--file <relative-path> ...] [--json]");
804
+ console.log(" you connect bootstrap [status|verify|revoke [manifest-id]] [--trust-current-generation] [--revoke-app] [--revoke-key] [--json]");
805
+ console.log(" connection receipts are non-secret evidence; they never authorize an agent job");
806
+ return;
807
+ }
808
+ const localOrigin = normalizeLocalHandoffBase(options.localBase);
809
+ if (!localOrigin) {
810
+ const message = "a literal loopback local broker is required (for example http://127.0.0.1:49152)";
811
+ if (options.json)
812
+ console.log(JSON.stringify({ ...resultForError("unavailable"), error: message }, null, 2));
813
+ else {
814
+ console.error(ACCENT(` ${message}`));
815
+ console.error(chalk_1.default.dim(" Start the registered local You.md desktop/web listener, then rerun with its current port."));
816
+ }
817
+ process.exitCode = 1;
818
+ return;
819
+ }
820
+ const spinner = options.json ? null : new render_1.BrailleSpinner("requesting a one-time local browser handoff...");
821
+ spinner?.start();
822
+ const result = await startLocalBrowserHandoff({ ...options, localBase: localOrigin });
823
+ spinner?.stop(result.ok ? "local handoff ready for your approval" : "local handoff was not started");
824
+ if (!result.ok) {
825
+ const message = result.status === "unsupported"
826
+ ? "this local You.md listener does not support confirmed browser handoff yet"
827
+ : result.status === "rejected"
828
+ ? "the local listener rejected this handoff; no browser session was created"
829
+ : "the local listener is unavailable; no browser session was created";
830
+ if (options.json)
831
+ console.log(JSON.stringify({ ...result, error: message }, null, 2));
832
+ else {
833
+ console.error(ACCENT(` ${message}`));
834
+ console.error(chalk_1.default.dim(" No CLI token, provider credential, or browser session was sent or created."));
835
+ }
836
+ process.exitCode = 1;
837
+ return;
838
+ }
839
+ if (options.json) {
840
+ console.log(JSON.stringify(result, null, 2));
841
+ }
842
+ else {
843
+ console.log(` approval URL: ${chalk_1.default.cyan(result.authorizationUrl)}`);
844
+ console.log(chalk_1.default.dim(" Review the exact request in your signed-in You.md browser before authorizing it."));
845
+ }
846
+ if (!options.json)
847
+ openExternalUrl(result.authorizationUrl);
848
+ }
849
+ //# sourceMappingURL=connect.js.map