@notis_ai/cli 0.2.0-beta.197.1 → 0.2.0-beta.198.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.
@@ -100,6 +100,114 @@ var init_errors = __esm({
100
100
  }
101
101
  });
102
102
 
103
+ // src/runtime/config-lock.js
104
+ import { randomUUID as randomUUID2 } from "node:crypto";
105
+ import {
106
+ existsSync as existsSync7,
107
+ mkdirSync as mkdirSync4,
108
+ readFileSync as readFileSync7,
109
+ renameSync as renameSync2,
110
+ rmSync as rmSync3,
111
+ statSync as statSync4,
112
+ writeFileSync as writeFileSync4
113
+ } from "node:fs";
114
+ import { homedir as homedir2 } from "node:os";
115
+ import { dirname as dirname6, join as join7, resolve as resolve6 } from "node:path";
116
+ function resolveCliConfigFile() {
117
+ const envConfigFile = process.env.NOTIS_CLI_CONFIG_FILE;
118
+ if (envConfigFile) {
119
+ return resolve6(envConfigFile);
120
+ }
121
+ return join7(homedir2(), ".notis", "config.json");
122
+ }
123
+ function readLockOwner(lockDirectory) {
124
+ try {
125
+ return JSON.parse(readFileSync7(join7(lockDirectory, "owner"), "utf-8"));
126
+ } catch {
127
+ return null;
128
+ }
129
+ }
130
+ function lockDirectoryMtime(lockDirectory) {
131
+ try {
132
+ return statSync4(lockDirectory).mtimeMs;
133
+ } catch {
134
+ return null;
135
+ }
136
+ }
137
+ function publishConfigWriteLock(lockDirectory, ownerId) {
138
+ const candidateDirectory = `${lockDirectory}.candidate-${ownerId}`;
139
+ try {
140
+ mkdirSync4(candidateDirectory);
141
+ writeFileSync4(
142
+ join7(candidateDirectory, "owner"),
143
+ JSON.stringify({ id: ownerId, at: Date.now() }),
144
+ { mode: 384 }
145
+ );
146
+ try {
147
+ renameSync2(candidateDirectory, lockDirectory);
148
+ return true;
149
+ } catch (error) {
150
+ if (!existsSync7(lockDirectory)) throw error;
151
+ return false;
152
+ }
153
+ } finally {
154
+ rmSync3(candidateDirectory, { recursive: true, force: true });
155
+ }
156
+ }
157
+ function withConfigFileWriteLock(configFile, callback) {
158
+ const lockDirectory = `${configFile}.write-lock`;
159
+ const ownerId = `${process.pid}.${randomUUID2()}`;
160
+ const deadline = Date.now() + CONFIG_WRITE_LOCK_TIMEOUT_MS;
161
+ mkdirSync4(dirname6(configFile), { recursive: true });
162
+ for (; ; ) {
163
+ if (!existsSync7(lockDirectory) && publishConfigWriteLock(lockDirectory, ownerId)) {
164
+ break;
165
+ }
166
+ const owner = readLockOwner(lockDirectory);
167
+ const observedMtime = lockDirectoryMtime(lockDirectory);
168
+ const ownerIsStale = owner?.id && Date.now() - Number(owner.at) > CONFIG_WRITE_LOCK_STALE_MS;
169
+ const ownerlessIsStale = !owner && observedMtime !== null && Date.now() - observedMtime > CONFIG_WRITE_LOCK_STALE_MS;
170
+ if (ownerIsStale || ownerlessIsStale) {
171
+ try {
172
+ const currentOwner = readLockOwner(lockDirectory);
173
+ const ownerUnchanged = owner?.id ? currentOwner?.id === owner.id : !currentOwner && lockDirectoryMtime(lockDirectory) === observedMtime;
174
+ if (ownerUnchanged) {
175
+ rmSync3(lockDirectory, { recursive: true, force: true });
176
+ continue;
177
+ }
178
+ } catch {
179
+ }
180
+ }
181
+ if (Date.now() >= deadline) {
182
+ throw new Error(`Timed out waiting to update ${configFile}`);
183
+ }
184
+ Atomics.wait(
185
+ new Int32Array(new SharedArrayBuffer(4)),
186
+ 0,
187
+ 0,
188
+ CONFIG_WRITE_LOCK_POLL_MS
189
+ );
190
+ }
191
+ try {
192
+ return callback(configFile);
193
+ } finally {
194
+ try {
195
+ if (readLockOwner(lockDirectory)?.id === ownerId) {
196
+ rmSync3(lockDirectory, { recursive: true, force: true });
197
+ }
198
+ } catch {
199
+ }
200
+ }
201
+ }
202
+ var CONFIG_WRITE_LOCK_TIMEOUT_MS, CONFIG_WRITE_LOCK_STALE_MS, CONFIG_WRITE_LOCK_POLL_MS;
203
+ var init_config_lock = __esm({
204
+ "src/runtime/config-lock.js"() {
205
+ CONFIG_WRITE_LOCK_TIMEOUT_MS = 5e3;
206
+ CONFIG_WRITE_LOCK_STALE_MS = 2e3;
207
+ CONFIG_WRITE_LOCK_POLL_MS = 10;
208
+ }
209
+ });
210
+
103
211
  // src/runtime/channel.js
104
212
  function isReleaseChannel(value) {
105
213
  return RELEASE_CHANNELS.includes(value);
@@ -279,18 +387,15 @@ var init_auth_recovery = __esm({
279
387
  });
280
388
 
281
389
  // src/runtime/profiles.js
282
- import { randomUUID as randomUUID2 } from "node:crypto";
283
390
  import {
284
- existsSync as existsSync7,
285
- mkdirSync as mkdirSync4,
286
- readFileSync as readFileSync7,
287
- renameSync as renameSync2,
288
- rmSync as rmSync3,
289
- statSync as statSync4,
290
- writeFileSync as writeFileSync4
391
+ existsSync as existsSync8,
392
+ mkdirSync as mkdirSync5,
393
+ readFileSync as readFileSync8,
394
+ renameSync as renameSync3,
395
+ writeFileSync as writeFileSync5
291
396
  } from "node:fs";
292
- import { homedir as homedir2 } from "node:os";
293
- import { dirname as dirname6, join as join7, parse, resolve as resolve6 } from "node:path";
397
+ import { homedir as homedir3 } from "node:os";
398
+ import { dirname as dirname7, join as join8, parse, resolve as resolve7 } from "node:path";
294
399
  function clone(value) {
295
400
  return JSON.parse(JSON.stringify(value));
296
401
  }
@@ -390,23 +495,23 @@ function listProfiles(config) {
390
495
  }
391
496
  function readJsonFile2(path3) {
392
497
  try {
393
- return JSON.parse(readFileSync7(path3, "utf-8"));
498
+ return JSON.parse(readFileSync8(path3, "utf-8"));
394
499
  } catch {
395
500
  return null;
396
501
  }
397
502
  }
398
503
  function findUp(filename, startDir = process.cwd()) {
399
- let current = resolve6(startDir);
504
+ let current = resolve7(startDir);
400
505
  const root = parse(current).root;
401
506
  while (true) {
402
- const candidate = join7(current, filename);
403
- if (existsSync7(candidate)) {
507
+ const candidate = join8(current, filename);
508
+ if (existsSync8(candidate)) {
404
509
  return candidate;
405
510
  }
406
511
  if (current === root) {
407
512
  return null;
408
513
  }
409
- current = dirname6(current);
514
+ current = dirname7(current);
410
515
  }
411
516
  }
412
517
  function processIsAlive(pid) {
@@ -477,17 +582,17 @@ function resolveWorktreeRuntime(startDir = process.cwd()) {
477
582
  function resolveConfigFile() {
478
583
  const envConfigFile = process.env.NOTIS_CLI_CONFIG_FILE;
479
584
  if (envConfigFile) {
480
- return resolve6(envConfigFile);
585
+ return resolve7(envConfigFile);
481
586
  }
482
587
  return CONFIG_FILE;
483
588
  }
484
589
  function loadConfig() {
485
590
  const configFile = resolveConfigFile();
486
- if (!existsSync7(configFile)) {
591
+ if (!existsSync8(configFile)) {
487
592
  return normalizeConfig({});
488
593
  }
489
594
  try {
490
- return normalizeConfig(JSON.parse(readFileSync7(configFile, "utf-8")));
595
+ return normalizeConfig(JSON.parse(readFileSync8(configFile, "utf-8")));
491
596
  } catch {
492
597
  return normalizeConfig({});
493
598
  }
@@ -495,7 +600,7 @@ function loadConfig() {
495
600
  function writeConfig(configFile, config) {
496
601
  let rawConfig = null;
497
602
  try {
498
- rawConfig = JSON.parse(readFileSync7(configFile, "utf-8"));
603
+ rawConfig = JSON.parse(readFileSync8(configFile, "utf-8"));
499
604
  } catch {
500
605
  }
501
606
  const normalized = normalizeConfig(config);
@@ -513,90 +618,13 @@ function writeConfig(configFile, config) {
513
618
  writeRawConfig(configFile, persisted);
514
619
  }
515
620
  function writeRawConfig(configFile, config) {
516
- mkdirSync4(dirname6(configFile), { recursive: true });
621
+ mkdirSync5(dirname7(configFile), { recursive: true });
517
622
  const temporaryFile = `${configFile}.${process.pid}.${Date.now()}.tmp`;
518
- writeFileSync4(temporaryFile, JSON.stringify(config, null, 2), { mode: 384 });
519
- renameSync2(temporaryFile, configFile);
520
- }
521
- function readLockOwner(lockDirectory) {
522
- try {
523
- return JSON.parse(readFileSync7(join7(lockDirectory, "owner"), "utf-8"));
524
- } catch {
525
- return null;
526
- }
527
- }
528
- function lockDirectoryMtime(lockDirectory) {
529
- try {
530
- return statSync4(lockDirectory).mtimeMs;
531
- } catch {
532
- return null;
533
- }
534
- }
535
- function publishConfigWriteLock(lockDirectory, ownerId) {
536
- const candidateDirectory = `${lockDirectory}.candidate-${ownerId}`;
537
- try {
538
- mkdirSync4(candidateDirectory);
539
- writeFileSync4(
540
- join7(candidateDirectory, "owner"),
541
- JSON.stringify({ id: ownerId, at: Date.now() }),
542
- { mode: 384 }
543
- );
544
- try {
545
- renameSync2(candidateDirectory, lockDirectory);
546
- return true;
547
- } catch (error) {
548
- if (!existsSync7(lockDirectory)) throw error;
549
- return false;
550
- }
551
- } finally {
552
- rmSync3(candidateDirectory, { recursive: true, force: true });
553
- }
623
+ writeFileSync5(temporaryFile, JSON.stringify(config, null, 2), { mode: 384 });
624
+ renameSync3(temporaryFile, configFile);
554
625
  }
555
626
  function withConfigWriteLock(callback) {
556
- const configFile = resolveConfigFile();
557
- const lockDirectory = `${configFile}.write-lock`;
558
- const ownerId = `${process.pid}.${randomUUID2()}`;
559
- const deadline = Date.now() + CONFIG_WRITE_LOCK_TIMEOUT_MS;
560
- mkdirSync4(dirname6(configFile), { recursive: true });
561
- for (; ; ) {
562
- if (!existsSync7(lockDirectory) && publishConfigWriteLock(lockDirectory, ownerId)) {
563
- break;
564
- }
565
- const owner = readLockOwner(lockDirectory);
566
- const observedMtime = lockDirectoryMtime(lockDirectory);
567
- const ownerIsStale = owner?.id && Date.now() - Number(owner.at) > CONFIG_WRITE_LOCK_STALE_MS;
568
- const ownerlessIsStale = !owner && observedMtime !== null && Date.now() - observedMtime > CONFIG_WRITE_LOCK_STALE_MS;
569
- if (ownerIsStale || ownerlessIsStale) {
570
- try {
571
- const currentOwner = readLockOwner(lockDirectory);
572
- const ownerUnchanged = owner?.id ? currentOwner?.id === owner.id : !currentOwner && lockDirectoryMtime(lockDirectory) === observedMtime;
573
- if (ownerUnchanged) {
574
- rmSync3(lockDirectory, { recursive: true, force: true });
575
- continue;
576
- }
577
- } catch {
578
- }
579
- }
580
- if (Date.now() >= deadline) {
581
- throw new Error(`Timed out waiting to update ${configFile}`);
582
- }
583
- Atomics.wait(
584
- new Int32Array(new SharedArrayBuffer(4)),
585
- 0,
586
- 0,
587
- CONFIG_WRITE_LOCK_POLL_MS
588
- );
589
- }
590
- try {
591
- return callback(configFile);
592
- } finally {
593
- try {
594
- if (readLockOwner(lockDirectory)?.id === ownerId) {
595
- rmSync3(lockDirectory, { recursive: true, force: true });
596
- }
597
- } catch {
598
- }
599
- }
627
+ return withConfigFileWriteLock(resolveConfigFile(), callback);
600
628
  }
601
629
  function updateConfig(updater) {
602
630
  return withConfigWriteLock((configFile) => {
@@ -611,6 +639,13 @@ function getProfile(config, profileName) {
611
639
  const normalized = normalizeConfig(config);
612
640
  return Object.hasOwn(normalized.profiles, profileName) ? normalized.profiles[profileName] : {};
613
641
  }
642
+ function getCurrentProfileName(config, preferredName) {
643
+ const normalized = normalizeConfig(config);
644
+ if (preferredName && Object.hasOwn(normalized.profiles, preferredName)) {
645
+ return preferredName;
646
+ }
647
+ return normalized.current_profile || DEFAULT_PROFILE;
648
+ }
614
649
  function resolveProfileSelection(globalOptions = {}, worktreeRuntime = null, config, { allowUnknownProfile = false } = {}) {
615
650
  const normalized = normalizeConfig(config);
616
651
  const requested = globalOptions.profile || process.env.NOTIS_PROFILE || "";
@@ -989,17 +1024,18 @@ function credentialIsExpired(runtime, profile = {}, nowSeconds = Math.floor(Date
989
1024
  }
990
1025
  }
991
1026
  function workspacePath(appId) {
992
- return join7(WORKSPACE_DIR, appId);
1027
+ return join8(WORKSPACE_DIR, appId);
993
1028
  }
994
- var CONFIG_DIR, CONFIG_FILE, WORKSPACE_DIR, DEFAULT_API_BASE, BETA_API_BASE, DEFAULT_PROFILE, PROFILE_NAME_PATTERN, LEGACY_DESKTOP_PROFILE_KEYS, WORKTREE_RUNTIME_FILENAME, WORKTREE_ROUTING_FILENAME, LOCAL_API_HOSTS, LIVE_API_HOSTS, CONFIG_WRITE_LOCK_TIMEOUT_MS, CONFIG_WRITE_LOCK_STALE_MS, CONFIG_WRITE_LOCK_POLL_MS;
1029
+ var CONFIG_DIR, CONFIG_FILE, WORKSPACE_DIR, DEFAULT_API_BASE, BETA_API_BASE, DEFAULT_PROFILE, PROFILE_NAME_PATTERN, LEGACY_DESKTOP_PROFILE_KEYS, WORKTREE_RUNTIME_FILENAME, WORKTREE_ROUTING_FILENAME, LOCAL_API_HOSTS, LIVE_API_HOSTS;
995
1030
  var init_profiles = __esm({
996
1031
  "src/runtime/profiles.js"() {
997
1032
  init_errors();
1033
+ init_config_lock();
998
1034
  init_auth_recovery();
999
1035
  init_channel();
1000
- CONFIG_DIR = join7(homedir2(), ".notis");
1001
- CONFIG_FILE = join7(CONFIG_DIR, "config.json");
1002
- WORKSPACE_DIR = join7(CONFIG_DIR, "workspace");
1036
+ CONFIG_DIR = join8(homedir3(), ".notis");
1037
+ CONFIG_FILE = join8(CONFIG_DIR, "config.json");
1038
+ WORKSPACE_DIR = join8(CONFIG_DIR, "workspace");
1003
1039
  DEFAULT_API_BASE = "https://api.notis.ai";
1004
1040
  BETA_API_BASE = "https://api-beta.notis.ai";
1005
1041
  DEFAULT_PROFILE = "default";
@@ -1013,13 +1049,120 @@ var init_profiles = __esm({
1013
1049
  "desktop_app_name",
1014
1050
  "desktop_pid"
1015
1051
  ];
1016
- WORKTREE_RUNTIME_FILENAME = join7(".context", "notis-runtime.json");
1017
- WORKTREE_ROUTING_FILENAME = join7(".context", "notis-routing.json");
1052
+ WORKTREE_RUNTIME_FILENAME = join8(".context", "notis-runtime.json");
1053
+ WORKTREE_ROUTING_FILENAME = join8(".context", "notis-routing.json");
1018
1054
  LOCAL_API_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
1019
1055
  LIVE_API_HOSTS = /* @__PURE__ */ new Set(["api.notis.ai", "api-beta.notis.ai"]);
1020
- CONFIG_WRITE_LOCK_TIMEOUT_MS = 5e3;
1021
- CONFIG_WRITE_LOCK_STALE_MS = 2e3;
1022
- CONFIG_WRITE_LOCK_POLL_MS = 10;
1056
+ }
1057
+ });
1058
+
1059
+ // src/runtime/computer-identity.js
1060
+ import { randomUUID as randomUUID3 } from "node:crypto";
1061
+ import { execFileSync } from "node:child_process";
1062
+ import { mkdirSync as mkdirSync6, readFileSync as readFileSync9, renameSync as renameSync4, writeFileSync as writeFileSync6 } from "node:fs";
1063
+ import { hostname as osHostname } from "node:os";
1064
+ import { dirname as dirname8, join as join9 } from "node:path";
1065
+ function computerIdentityFile(configFile = resolveCliConfigFile()) {
1066
+ return join9(dirname8(configFile), "computer.json");
1067
+ }
1068
+ function normalizeComputerName(value) {
1069
+ if (typeof value !== "string") return null;
1070
+ const collapsed = value.replace(/\s+/gu, " ").trim();
1071
+ if (!collapsed) return null;
1072
+ const characters = Array.from(collapsed);
1073
+ if (characters.length <= COMPUTER_NAME_MAX_LENGTH) return collapsed;
1074
+ return characters.slice(0, COMPUTER_NAME_MAX_LENGTH).join("").trim();
1075
+ }
1076
+ function readMacComputerName() {
1077
+ try {
1078
+ return execFileSync("/usr/sbin/scutil", ["--get", "ComputerName"], {
1079
+ encoding: "utf8",
1080
+ stdio: ["ignore", "pipe", "ignore"],
1081
+ timeout: 2e3
1082
+ });
1083
+ } catch {
1084
+ return null;
1085
+ }
1086
+ }
1087
+ function defaultComputerName(options = {}) {
1088
+ const platform = options.platform ?? process.platform;
1089
+ if (platform === "darwin") {
1090
+ const macName = normalizeComputerName((options.readMacComputerName ?? readMacComputerName)());
1091
+ if (macName) return macName;
1092
+ }
1093
+ let host = "";
1094
+ try {
1095
+ host = String((options.hostname ?? osHostname)() || "");
1096
+ } catch {
1097
+ host = "";
1098
+ }
1099
+ return normalizeComputerName(host.replace(/\.local\.?$/iu, "")) || FALLBACK_COMPUTER_NAME;
1100
+ }
1101
+ function parseIdentityFile(file) {
1102
+ let raw;
1103
+ try {
1104
+ raw = JSON.parse(readFileSync9(file, "utf8"));
1105
+ } catch {
1106
+ return null;
1107
+ }
1108
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
1109
+ return raw;
1110
+ }
1111
+ function validStored(raw) {
1112
+ if (!raw || raw.version !== COMPUTER_IDENTITY_VERSION) return null;
1113
+ if (typeof raw.computer_id !== "string" || !COMPUTER_ID_PATTERN.test(raw.computer_id)) return null;
1114
+ return {
1115
+ computerId: raw.computer_id.toLowerCase(),
1116
+ name: normalizeComputerName(raw.name)
1117
+ };
1118
+ }
1119
+ function writeIdentityFile(file, stored) {
1120
+ mkdirSync6(dirname8(file), { recursive: true });
1121
+ const contents = {
1122
+ version: COMPUTER_IDENTITY_VERSION,
1123
+ computer_id: stored.computerId,
1124
+ ...stored.name ? { name: stored.name } : {}
1125
+ };
1126
+ const temporaryFile = `${file}.${process.pid}.${Date.now()}.tmp`;
1127
+ writeFileSync6(temporaryFile, `${JSON.stringify(contents, null, 2)}
1128
+ `, { mode: 384 });
1129
+ renameSync4(temporaryFile, file);
1130
+ }
1131
+ function withIdentity(stored, options) {
1132
+ const defaultName = defaultComputerName(options);
1133
+ return {
1134
+ computerId: stored.computerId,
1135
+ name: stored.name,
1136
+ defaultName,
1137
+ displayName: stored.name ?? defaultName
1138
+ };
1139
+ }
1140
+ function readOrCreateLocked(configFile, file) {
1141
+ const raw = parseIdentityFile(file);
1142
+ const existing = validStored(raw);
1143
+ if (existing) return existing;
1144
+ const created = {
1145
+ computerId: randomUUID3(),
1146
+ // A file with a broken id keeps the name the user chose.
1147
+ name: normalizeComputerName(raw?.name)
1148
+ };
1149
+ writeIdentityFile(file, created);
1150
+ return created;
1151
+ }
1152
+ function readComputerIdentity(options = {}) {
1153
+ const configFile = options.configFile ?? resolveCliConfigFile();
1154
+ const file = computerIdentityFile(configFile);
1155
+ const stored = validStored(parseIdentityFile(file)) ?? withConfigFileWriteLock(configFile, () => readOrCreateLocked(configFile, file));
1156
+ return withIdentity(stored, options);
1157
+ }
1158
+ var COMPUTER_IDENTITY_VERSION, COMPUTER_NAME_MAX_LENGTH, COMPUTER_ID_PATTERN, FALLBACK_COMPUTER_NAME;
1159
+ var init_computer_identity = __esm({
1160
+ "src/runtime/computer-identity.js"() {
1161
+ init_config_lock();
1162
+ COMPUTER_IDENTITY_VERSION = 1;
1163
+ COMPUTER_NAME_MAX_LENGTH = 64;
1164
+ COMPUTER_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
1165
+ FALLBACK_COMPUTER_NAME = "Computer";
1023
1166
  }
1024
1167
  });
1025
1168
 
@@ -1029,6 +1172,7 @@ __export(oauth_exports, {
1029
1172
  DEFAULT_CLI_OAUTH_SCOPES: () => DEFAULT_CLI_OAUTH_SCOPES,
1030
1173
  acquireListenerGlobalLock: () => acquireListenerGlobalLock,
1031
1174
  browserOpenCommand: () => browserOpenCommand,
1175
+ buildAuthorizeUrl: () => buildAuthorizeUrl,
1032
1176
  clearListenerState: () => clearListenerState,
1033
1177
  createLoopbackReceiver: () => createLoopbackReceiver,
1034
1178
  createPkce: () => createPkce,
@@ -1050,20 +1194,20 @@ import {
1050
1194
  timingSafeEqual
1051
1195
  } from "node:crypto";
1052
1196
  import {
1053
- mkdirSync as mkdirSync5,
1197
+ mkdirSync as mkdirSync7,
1054
1198
  readdirSync as readdirSync4,
1055
- readFileSync as readFileSync8,
1056
- renameSync as renameSync3,
1199
+ readFileSync as readFileSync10,
1200
+ renameSync as renameSync5,
1057
1201
  rmdirSync as rmdirSync2,
1058
1202
  rmSync as rmSync4,
1059
1203
  statSync as statSync5,
1060
- writeFileSync as writeFileSync5
1204
+ writeFileSync as writeFileSync7
1061
1205
  } from "node:fs";
1062
1206
  import { createServer as createServer3 } from "node:http";
1063
- import { homedir as homedir3 } from "node:os";
1064
- import { basename as basename2, dirname as dirname7, join as join8 } from "node:path";
1207
+ import { homedir as homedir4 } from "node:os";
1208
+ import { basename as basename2, dirname as dirname9, join as join10 } from "node:path";
1065
1209
  import { fileURLToPath as fileURLToPath5 } from "node:url";
1066
- import { execFileSync, spawn as spawn3 } from "node:child_process";
1210
+ import { execFileSync as execFileSync2, spawn as spawn3 } from "node:child_process";
1067
1211
  import { createInterface } from "node:readline/promises";
1068
1212
  function oauthError(code, message, hints = null, details = {}) {
1069
1213
  return new CliError({
@@ -1453,13 +1597,13 @@ async function createLoopbackReceiver({
1453
1597
  let pendingResponse = null;
1454
1598
  const sockets = /* @__PURE__ */ new Set();
1455
1599
  let responseFlushed = Promise.resolve();
1456
- const result = new Promise((resolve18, reject) => {
1457
- resolveCode = resolve18;
1600
+ const result = new Promise((resolve19, reject) => {
1601
+ resolveCode = resolve19;
1458
1602
  rejectCode = reject;
1459
1603
  });
1460
1604
  const endResponse = (response, body) => {
1461
- responseFlushed = new Promise((resolve18) => {
1462
- response.end(body, resolve18);
1605
+ responseFlushed = new Promise((resolve19) => {
1606
+ response.end(body, resolve19);
1463
1607
  });
1464
1608
  };
1465
1609
  const server = createServer3((request, response) => {
@@ -1508,11 +1652,11 @@ async function createLoopbackReceiver({
1508
1652
  sockets.add(socket);
1509
1653
  socket.on("close", () => sockets.delete(socket));
1510
1654
  });
1511
- await new Promise((resolve18, reject) => {
1655
+ await new Promise((resolve19, reject) => {
1512
1656
  server.once("error", reject);
1513
1657
  server.listen(0, "127.0.0.1", () => {
1514
1658
  server.off("error", reject);
1515
- resolve18();
1659
+ resolve19();
1516
1660
  });
1517
1661
  });
1518
1662
  const address = server.address();
@@ -1536,14 +1680,14 @@ async function createLoopbackReceiver({
1536
1680
  }
1537
1681
  await Promise.race([
1538
1682
  responseFlushed,
1539
- new Promise((resolve18) => {
1540
- setTimeout(resolve18, RESPONSE_FLUSH_GRACE_MS).unref?.();
1683
+ new Promise((resolve19) => {
1684
+ setTimeout(resolve19, RESPONSE_FLUSH_GRACE_MS).unref?.();
1541
1685
  })
1542
1686
  ]);
1543
1687
  for (const socket of sockets) socket.destroy();
1544
1688
  sockets.clear();
1545
1689
  if (!server.listening) return;
1546
- await new Promise((resolve18) => server.close(resolve18));
1690
+ await new Promise((resolve19) => server.close(resolve19));
1547
1691
  };
1548
1692
  return {
1549
1693
  port,
@@ -1611,6 +1755,14 @@ function storedOAuthMetadata(runtime, profile) {
1611
1755
  revocationEndpoint: `${issuer}/oauth/revoke`
1612
1756
  };
1613
1757
  }
1758
+ function cliDeviceParams() {
1759
+ try {
1760
+ const identity = readComputerIdentity({ configFile: resolveConfigFile() });
1761
+ return { device_id: identity.computerId, device_name: identity.displayName };
1762
+ } catch {
1763
+ return {};
1764
+ }
1765
+ }
1614
1766
  function buildAuthorizeUrl(metadata, {
1615
1767
  redirectUri,
1616
1768
  challenge,
@@ -1626,6 +1778,9 @@ function buildAuthorizeUrl(metadata, {
1626
1778
  url.searchParams.set("code_challenge", challenge);
1627
1779
  url.searchParams.set("code_challenge_method", "S256");
1628
1780
  url.searchParams.set("state", state);
1781
+ for (const [key2, value] of Object.entries(cliDeviceParams())) {
1782
+ url.searchParams.set(key2, value);
1783
+ }
1629
1784
  return url.toString();
1630
1785
  }
1631
1786
  async function exchangeCode(metadata, {
@@ -1701,8 +1856,8 @@ function legacyPendingAuthorizationFile(runtime) {
1701
1856
  }
1702
1857
  function savePendingAuthorization(runtime, pending) {
1703
1858
  const file = pendingAuthorizationFile(runtime);
1704
- mkdirSync5(dirname7(file), { recursive: true });
1705
- writeFileSync5(file, JSON.stringify(pending, null, 2), { mode: 384 });
1859
+ mkdirSync7(dirname9(file), { recursive: true });
1860
+ writeFileSync7(file, JSON.stringify(pending, null, 2), { mode: 384 });
1706
1861
  }
1707
1862
  function readPendingAuthorization(runtime, { includeExpired = false } = {}) {
1708
1863
  for (const file of [
@@ -1711,7 +1866,7 @@ function readPendingAuthorization(runtime, { includeExpired = false } = {}) {
1711
1866
  ]) {
1712
1867
  let pending;
1713
1868
  try {
1714
- pending = JSON.parse(readFileSync8(file, "utf-8"));
1869
+ pending = JSON.parse(readFileSync10(file, "utf-8"));
1715
1870
  } catch {
1716
1871
  continue;
1717
1872
  }
@@ -1732,7 +1887,7 @@ function clearPendingAuthorizations(runtime) {
1732
1887
  clearPendingAuthorization(runtime);
1733
1888
  const legacyFile = legacyPendingAuthorizationFile(runtime);
1734
1889
  try {
1735
- const pending = JSON.parse(readFileSync8(legacyFile, "utf-8"));
1890
+ const pending = JSON.parse(readFileSync10(legacyFile, "utf-8"));
1736
1891
  if (pending?.profile === runtime.profileName) rmSync4(legacyFile);
1737
1892
  } catch {
1738
1893
  }
@@ -1780,11 +1935,11 @@ function listenerGlobalLockDir() {
1780
1935
  return `${resolveConfigFile()}.oauth-listener-global.lock`;
1781
1936
  }
1782
1937
  function listenerGlobalLockOwnerFile(lockDir) {
1783
- return join8(lockDir, "owner.json");
1938
+ return join10(lockDir, "owner.json");
1784
1939
  }
1785
1940
  function readListenerGlobalLockOwner(lockDir) {
1786
1941
  try {
1787
- return JSON.parse(readFileSync8(listenerGlobalLockOwnerFile(lockDir), "utf-8"));
1942
+ return JSON.parse(readFileSync10(listenerGlobalLockOwnerFile(lockDir), "utf-8"));
1788
1943
  } catch {
1789
1944
  return null;
1790
1945
  }
@@ -1792,7 +1947,7 @@ function readListenerGlobalLockOwner(lockDir) {
1792
1947
  function writeListenerGlobalLockOwner(lock) {
1793
1948
  const current = readListenerGlobalLockOwner(lock.lockDir);
1794
1949
  if (current && current.owner_token !== lock.ownerToken) return false;
1795
- writeFileSync5(listenerGlobalLockOwnerFile(lock.lockDir), JSON.stringify({
1950
+ writeFileSync7(listenerGlobalLockOwnerFile(lock.lockDir), JSON.stringify({
1796
1951
  owner_token: lock.ownerToken,
1797
1952
  owner_pid: process.pid,
1798
1953
  updated_at: Date.now()
@@ -1813,7 +1968,7 @@ function listenerGlobalLockIsStale(lockDir, staleMs) {
1813
1968
  function retireStaleListenerGlobalLock(lockDir) {
1814
1969
  const retiredDir = `${lockDir}.stale-${process.pid}-${base64url(randomBytes(8))}`;
1815
1970
  try {
1816
- renameSync3(lockDir, retiredDir);
1971
+ renameSync5(lockDir, retiredDir);
1817
1972
  } catch {
1818
1973
  return false;
1819
1974
  }
@@ -1822,11 +1977,11 @@ function retireStaleListenerGlobalLock(lockDir) {
1822
1977
  }
1823
1978
  async function acquireListenerStartLock(runtime) {
1824
1979
  const lockDir = listenerStartLockDir(runtime);
1825
- mkdirSync5(dirname7(lockDir), { recursive: true });
1980
+ mkdirSync7(dirname9(lockDir), { recursive: true });
1826
1981
  const deadline = Date.now() + LISTENER_START_LOCK_STALE_MS * 2;
1827
1982
  for (; ; ) {
1828
1983
  try {
1829
- mkdirSync5(lockDir);
1984
+ mkdirSync7(lockDir);
1830
1985
  return lockDir;
1831
1986
  } catch (error) {
1832
1987
  if (error?.code !== "EEXIST") throw error;
@@ -1843,7 +1998,7 @@ async function acquireListenerStartLock(runtime) {
1843
1998
  "Timed out waiting for another CLI process to start browser authorization."
1844
1999
  );
1845
2000
  }
1846
- await new Promise((resolve18) => setTimeout(resolve18, 50));
2001
+ await new Promise((resolve19) => setTimeout(resolve19, 50));
1847
2002
  }
1848
2003
  }
1849
2004
  }
@@ -1860,11 +2015,11 @@ async function acquireListenerGlobalLock({
1860
2015
  heartbeatMs = LISTENER_GLOBAL_LOCK_HEARTBEAT_MS
1861
2016
  } = {}) {
1862
2017
  const lockDir = listenerGlobalLockDir();
1863
- mkdirSync5(dirname7(lockDir), { recursive: true });
2018
+ mkdirSync7(dirname9(lockDir), { recursive: true });
1864
2019
  const deadline = Date.now() + waitMs;
1865
2020
  for (; ; ) {
1866
2021
  try {
1867
- mkdirSync5(lockDir);
2022
+ mkdirSync7(lockDir);
1868
2023
  const lock = {
1869
2024
  lockDir,
1870
2025
  ownerToken: base64url(randomBytes(24)),
@@ -1890,7 +2045,7 @@ async function acquireListenerGlobalLock({
1890
2045
  "Timed out waiting for another CLI process to finish OAuth account changes."
1891
2046
  );
1892
2047
  }
1893
- await new Promise((resolve18) => setTimeout(resolve18, 50));
2048
+ await new Promise((resolve19) => setTimeout(resolve19, 50));
1894
2049
  }
1895
2050
  }
1896
2051
  }
@@ -1901,14 +2056,14 @@ function releaseListenerGlobalLock(lock) {
1901
2056
  if (owner?.owner_token !== lock.ownerToken) return;
1902
2057
  const releasedDir = `${lock.lockDir}.released-${process.pid}-${lock.ownerToken}`;
1903
2058
  try {
1904
- renameSync3(lock.lockDir, releasedDir);
2059
+ renameSync5(lock.lockDir, releasedDir);
1905
2060
  } catch {
1906
2061
  return;
1907
2062
  }
1908
2063
  const movedOwner = readListenerGlobalLockOwner(releasedDir);
1909
2064
  if (movedOwner?.owner_token !== lock.ownerToken) {
1910
2065
  try {
1911
- renameSync3(releasedDir, lock.lockDir);
2066
+ renameSync5(releasedDir, lock.lockDir);
1912
2067
  } catch {
1913
2068
  }
1914
2069
  return;
@@ -1917,12 +2072,12 @@ function releaseListenerGlobalLock(lock) {
1917
2072
  }
1918
2073
  function saveListenerState(runtime, state) {
1919
2074
  const file = listenerStateFile(runtime);
1920
- mkdirSync5(dirname7(file), { recursive: true });
1921
- writeFileSync5(file, JSON.stringify(state, null, 2), { mode: 384 });
2075
+ mkdirSync7(dirname9(file), { recursive: true });
2076
+ writeFileSync7(file, JSON.stringify(state, null, 2), { mode: 384 });
1922
2077
  }
1923
2078
  function readListenerState(runtime) {
1924
2079
  try {
1925
- const state = JSON.parse(readFileSync8(listenerStateFile(runtime), "utf-8"));
2080
+ const state = JSON.parse(readFileSync10(listenerStateFile(runtime), "utf-8"));
1926
2081
  return state?.profile === runtime.profileName ? state : null;
1927
2082
  } catch {
1928
2083
  return null;
@@ -1937,7 +2092,7 @@ function listenerStateAllowsPersistence(runtime, ownerPid) {
1937
2092
  function clearListenerState(runtime, { ownerPid = null } = {}) {
1938
2093
  if (ownerPid !== null) {
1939
2094
  try {
1940
- const state = JSON.parse(readFileSync8(listenerStateFile(runtime), "utf-8"));
2095
+ const state = JSON.parse(readFileSync10(listenerStateFile(runtime), "utf-8"));
1941
2096
  if (Number(state?.pid) !== Number(ownerPid)) return;
1942
2097
  } catch {
1943
2098
  return;
@@ -1962,7 +2117,7 @@ function readLiveListener(runtime, { sameApiBase = true } = {}) {
1962
2117
  }
1963
2118
  function listenerProcessIsAlive(pid, {
1964
2119
  platform = process.platform,
1965
- run = execFileSync,
2120
+ run = execFileSync2,
1966
2121
  signal = process.kill.bind(process),
1967
2122
  expectedIdentity = null,
1968
2123
  expectedScriptPath = null
@@ -2035,8 +2190,8 @@ async function startDetachedLoopbackListener(runtime, {
2035
2190
  const identityToken = randomBytes(24).toString("base64url");
2036
2191
  const payloadFile = `${listenerStateFile(runtime)}.payload.${process.pid}.${randomBytes(8).toString("hex")}`;
2037
2192
  try {
2038
- mkdirSync5(dirname7(payloadFile), { recursive: true });
2039
- writeFileSync5(payloadFile, JSON.stringify({
2193
+ mkdirSync7(dirname9(payloadFile), { recursive: true });
2194
+ writeFileSync7(payloadFile, JSON.stringify({
2040
2195
  profile: runtime.profileName,
2041
2196
  api_base: runtime.apiBase,
2042
2197
  verifier,
@@ -2067,7 +2222,7 @@ async function startDetachedLoopbackListener(runtime, {
2067
2222
  }
2068
2223
  return null;
2069
2224
  }
2070
- const port = await new Promise((resolve18) => {
2225
+ const port = await new Promise((resolve19) => {
2071
2226
  let settled = false;
2072
2227
  const finish = (value) => {
2073
2228
  if (settled) return;
@@ -2076,7 +2231,7 @@ async function startDetachedLoopbackListener(runtime, {
2076
2231
  child.off("message", onMessage);
2077
2232
  child.off("error", onFailure);
2078
2233
  child.off("exit", onFailure);
2079
- resolve18(value);
2234
+ resolve19(value);
2080
2235
  };
2081
2236
  const onMessage = (message) => finish(Number(message?.port) || null);
2082
2237
  const onFailure = () => finish(null);
@@ -2128,7 +2283,7 @@ async function revokeCancelledToken(metadata, tokenResponse, fetchImpl) {
2128
2283
  async function runDetachedLoginListener(payloadFile, fetchImpl = fetch, identityToken = process.argv[3] || null) {
2129
2284
  let payload;
2130
2285
  try {
2131
- payload = JSON.parse(readFileSync8(payloadFile, "utf-8"));
2286
+ payload = JSON.parse(readFileSync10(payloadFile, "utf-8"));
2132
2287
  } catch {
2133
2288
  return 1;
2134
2289
  }
@@ -2835,7 +2990,7 @@ function pendingListenerProfiles() {
2835
2990
  const prefix = `${basename2(configFile)}.login-listener.`;
2836
2991
  let entries;
2837
2992
  try {
2838
- entries = readdirSync4(dirname7(configFile));
2993
+ entries = readdirSync4(dirname9(configFile));
2839
2994
  } catch {
2840
2995
  return [];
2841
2996
  }
@@ -2843,7 +2998,7 @@ function pendingListenerProfiles() {
2843
2998
  for (const entry of entries) {
2844
2999
  if (!entry.startsWith(prefix) || entry.includes(".payload") || entry.endsWith(".lock")) continue;
2845
3000
  try {
2846
- const state = JSON.parse(readFileSync8(join8(dirname7(configFile), entry), "utf-8"));
3001
+ const state = JSON.parse(readFileSync10(join10(dirname9(configFile), entry), "utf-8"));
2847
3002
  if (typeof state?.profile === "string" && state.profile) profiles.add(state.profile);
2848
3003
  } catch {
2849
3004
  }
@@ -2857,7 +3012,7 @@ function pendingAuthorizationProfiles() {
2857
3012
  const legacyName = `${configName}.pending-login`;
2858
3013
  let entries;
2859
3014
  try {
2860
- entries = readdirSync4(dirname7(configFile));
3015
+ entries = readdirSync4(dirname9(configFile));
2861
3016
  } catch {
2862
3017
  return [];
2863
3018
  }
@@ -2865,7 +3020,7 @@ function pendingAuthorizationProfiles() {
2865
3020
  for (const entry of entries) {
2866
3021
  if (entry !== legacyName && !entry.startsWith(prefix)) continue;
2867
3022
  try {
2868
- const pending = JSON.parse(readFileSync8(join8(dirname7(configFile), entry), "utf-8"));
3023
+ const pending = JSON.parse(readFileSync10(join10(dirname9(configFile), entry), "utf-8"));
2869
3024
  if (typeof pending?.profile === "string" && pending.profile) profiles.add(pending.profile);
2870
3025
  } catch {
2871
3026
  }
@@ -2880,11 +3035,11 @@ function lockIsStale() {
2880
3035
  }
2881
3036
  }
2882
3037
  async function acquireRefreshLock(runtime, waitMs = 6e4) {
2883
- mkdirSync5(join8(homedir3(), ".notis"), { recursive: true });
3038
+ mkdirSync7(join10(homedir4(), ".notis"), { recursive: true });
2884
3039
  const deadline = Date.now() + waitMs;
2885
3040
  for (; ; ) {
2886
3041
  try {
2887
- mkdirSync5(OAUTH_LOCK_DIR);
3042
+ mkdirSync7(OAUTH_LOCK_DIR);
2888
3043
  return true;
2889
3044
  } catch (error) {
2890
3045
  if (error?.code !== "EEXIST") throw error;
@@ -2903,7 +3058,7 @@ async function acquireRefreshLock(runtime, waitMs = 6e4) {
2903
3058
  if (Date.now() >= deadline) {
2904
3059
  throw oauthError("oauth_refresh_lock_timeout", "Timed out waiting for another CLI process to refresh OAuth.");
2905
3060
  }
2906
- await new Promise((resolve18) => setTimeout(resolve18, 100));
3061
+ await new Promise((resolve19) => setTimeout(resolve19, 100));
2907
3062
  }
2908
3063
  }
2909
3064
  }
@@ -2938,7 +3093,8 @@ async function refreshOAuthCredential(runtime, fetchImpl = fetch) {
2938
3093
  grant_type: "refresh_token",
2939
3094
  refresh_token: profile.oauth_refresh_token,
2940
3095
  client_id: profile.oauth_client_id,
2941
- resource: metadata.resource
3096
+ resource: metadata.resource,
3097
+ ...cliDeviceParams()
2942
3098
  })
2943
3099
  },
2944
3100
  fetchImpl
@@ -3065,6 +3221,7 @@ var DEFAULT_CLI_OAUTH_SCOPES, OAUTH_LOCK_DIR, DEFAULT_LOGIN_TIMEOUT_MS, DEFAULT_
3065
3221
  var init_oauth = __esm({
3066
3222
  "src/runtime/oauth.js"() {
3067
3223
  init_errors();
3224
+ init_computer_identity();
3068
3225
  init_auth_recovery();
3069
3226
  init_channel();
3070
3227
  init_profiles();
@@ -3074,7 +3231,7 @@ var init_oauth = __esm({
3074
3231
  "notis:connections",
3075
3232
  "notis:apps"
3076
3233
  ];
3077
- OAUTH_LOCK_DIR = join8(homedir3(), ".notis", "oauth.lock");
3234
+ OAUTH_LOCK_DIR = join10(homedir4(), ".notis", "oauth.lock");
3078
3235
  DEFAULT_LOGIN_TIMEOUT_MS = 3e5;
3079
3236
  DEFAULT_REFRESH_EXPIRES_IN = 30 * 24 * 60 * 60;
3080
3237
  PENDING_LOGIN_TTL_SECONDS = 30 * 60;
@@ -3122,7 +3279,8 @@ __export(skill_sync_exports, {
3122
3279
  shouldWriteCloudSkill: () => shouldWriteCloudSkill
3123
3280
  });
3124
3281
  import { createHash as createHash42 } from "node:crypto";
3125
- import { join as join16 } from "node:path";
3282
+ import { promises as fs3 } from "node:fs";
3283
+ import { dirname as dirname17, join as join18 } from "node:path";
3126
3284
  import { createHash as createHash10 } from "node:crypto";
3127
3285
  import { createHash as createHash22 } from "crypto";
3128
3286
  import { execFile } from "child_process";
@@ -3231,8 +3389,16 @@ function previousNativeState(state, skill) {
3231
3389
  function nativeLocalReady(skill, local) {
3232
3390
  return Boolean(local?.nativeFilesCurrent && local.folderHash === local.nativeBaseFolderHash && local.cloudId === skill.id && local.nativeScope === skill.native_scope && sameNativeReference(local.nativeReference, skill.native_reference));
3233
3391
  }
3234
- function nativeLinkRows(response, locals) {
3235
- return response.skills.map((skill) => isNativeSkill(skill) && !nativeLocalReady(skill, locals.find((row) => row.name === skill.name)) ? { ...skill, status: "disabled" } : skill);
3392
+ function pendingLegacyUpgrade(skill, local, state) {
3393
+ if (!isNativeSkill(skill) || !local || local.nativeReference || local.cloudId) return false;
3394
+ const previous = previousNativeState(state, skill);
3395
+ return Boolean(previous && !previous.nativeReference);
3396
+ }
3397
+ function nativeLinkRows(response, locals, state) {
3398
+ return response.skills.map((skill) => {
3399
+ const local = locals.find((row) => row.name === skill.name);
3400
+ return isNativeSkill(skill) && !nativeLocalReady(skill, local) && !(state && pendingLegacyUpgrade(skill, local, state)) ? { ...skill, status: "disabled" } : skill;
3401
+ });
3236
3402
  }
3237
3403
  function retainMissingNativeState(previous, next) {
3238
3404
  const present = new Set(Object.values(next.skills).map((row) => row.cloudId));
@@ -3960,7 +4126,12 @@ async function replaceSkillDirectoryAtomically(skillDir, populateDir, preserve)
3960
4126
  }
3961
4127
  await populateDir(stagingDir);
3962
4128
  if (preserve && await pathExists(skillDir)) {
3963
- await preserveUnmanagedFiles(skillDir, stagingDir, preserve.previouslyApplied, preserve.native);
4129
+ await preserveUnmanagedFiles(
4130
+ skillDir,
4131
+ stagingDir,
4132
+ preserve.previouslyApplied,
4133
+ preserve.native && !preserve.legacyBaseline
4134
+ );
3964
4135
  }
3965
4136
  if (preserve?.native) {
3966
4137
  const markerPath = path2.join(stagingDir, NATIVE_IDENTITY_FILE);
@@ -4057,7 +4228,9 @@ async function writeCloudSkillToDisk(skill, bundleBytes, paths = DEFAULT_SYNC_PA
4057
4228
  const preserve = {
4058
4229
  previouslyApplied: options.previouslyApplied,
4059
4230
  expectedFolderHash: options.expectedFolderHash,
4060
- native: isNativeSkill(skill)
4231
+ native: isNativeSkill(skill),
4232
+ // An unchanged legacy folder upgrading in place: shared files take the cloud version.
4233
+ legacyBaseline: isNativeSkill(skill) && options.legacyBaseline === true && options.expectedFolderHash !== void 0
4061
4234
  };
4062
4235
  if (bundleBytes?.length) {
4063
4236
  const bundlePath2 = path2.join(
@@ -4578,17 +4751,50 @@ function withoutBaseSkillState(state) {
4578
4751
  )
4579
4752
  };
4580
4753
  }
4754
+ async function forgetOtherAccountsAgentLinks(paths) {
4755
+ const usersDir = dirname17(dirname17(paths.syncStatePath));
4756
+ let entries;
4757
+ try {
4758
+ entries = await fs3.readdir(usersDir, { withFileTypes: true });
4759
+ } catch {
4760
+ return;
4761
+ }
4762
+ for (const entry of entries) {
4763
+ if (!entry.isDirectory()) continue;
4764
+ const statePath2 = join18(usersDir, entry.name, ".notis-sync.json");
4765
+ if (statePath2 === paths.syncStatePath) continue;
4766
+ let state = null;
4767
+ try {
4768
+ state = JSON.parse(await fs3.readFile(statePath2, "utf8"));
4769
+ } catch {
4770
+ continue;
4771
+ }
4772
+ if (!state || typeof state !== "object" || !state.skills || typeof state.skills !== "object") continue;
4773
+ let changed = false;
4774
+ for (const skill of Object.values(state.skills)) {
4775
+ if (skill && typeof skill === "object" && "verifiedAgentLinks" in skill) {
4776
+ delete skill.verifiedAgentLinks;
4777
+ changed = true;
4778
+ }
4779
+ }
4780
+ if (!changed) continue;
4781
+ const temporaryPath = `${statePath2}.${process.pid}.${Date.now()}.tmp`;
4782
+ await fs3.writeFile(temporaryPath, `${JSON.stringify(state, null, 2)}
4783
+ `, "utf8");
4784
+ await fs3.rename(temporaryPath, statePath2);
4785
+ }
4786
+ }
4581
4787
  function isolatedLinkOptions(paths) {
4582
4788
  if (!paths.isolatedNamespace && !paths.homeDir) return void 0;
4583
- const root = paths.isolatedNamespace ? join16(paths.syncRoot, "environments", paths.isolatedNamespace, "agents") : paths.homeDir;
4789
+ const root = paths.isolatedNamespace ? join18(paths.syncRoot, "environments", paths.isolatedNamespace, "agents") : paths.homeDir;
4584
4790
  return {
4585
4791
  agentSkillDirs: {
4586
4792
  notis: paths.skillsDir,
4587
- claude_code: join16(root, ".claude", "skills"),
4588
- cursor: join16(root, ".cursor", "skills"),
4589
- codex: join16(root, ".codex", "skills")
4793
+ claude_code: join18(root, ".claude", "skills"),
4794
+ cursor: join18(root, ".cursor", "skills"),
4795
+ codex: join18(root, ".codex", "skills")
4590
4796
  },
4591
- legacyGlobalSkillsDir: join16(root, ".agents", "skills")
4797
+ legacyGlobalSkillsDir: join18(root, ".agents", "skills")
4592
4798
  };
4593
4799
  }
4594
4800
  function assertSyncEnvironment(pull, settings) {
@@ -4665,6 +4871,10 @@ function buildSyncState(pullResponse, localSkills, lastSyncedAt, verifiedAgentLi
4665
4871
  const localSkill = localSkillMap.get(skill.name);
4666
4872
  const appliedCloudFolderHash = appliedRevisions[skill.name];
4667
4873
  const appliedFileList = appliedFiles[skill.name];
4874
+ if (pendingLegacyUpgrade(skill, localSkill, previousState)) {
4875
+ const { nativeUnavailable: _unavailable, ...previous } = previousNativeState(previousState, skill);
4876
+ return [skill.name, { ...previous, verifiedAgentLinks: verifiedAgentLinks[skill.name] ?? {} }];
4877
+ }
4668
4878
  if (isNativeSkill(skill) && !nativeLocalReady(skill, localSkill)) {
4669
4879
  const previous = previousNativeState(previousState, skill);
4670
4880
  return [skill.name, { ...previous || {
@@ -4728,7 +4938,7 @@ function buildLocalSymlinkCandidates(pullResponse, localSkills, previousState) {
4728
4938
  status: "active"
4729
4939
  };
4730
4940
  });
4731
- return [...nativeLinkRows(pullResponse, localSkills), ...localOnlySkills];
4941
+ return [...nativeLinkRows(pullResponse, localSkills, previousState), ...localOnlySkills];
4732
4942
  }
4733
4943
  function isEmptySyncState(state) {
4734
4944
  return state.lastSyncedAt === null && Object.keys(state.skills).length === 0;
@@ -4764,6 +4974,7 @@ async function writePulledSkillsToScopedMirror(pullResponse, localSkills, previo
4764
4974
  for (const cloudSkill of selectCloudSkillsToApply(pullResponse.skills)) {
4765
4975
  const local = localSkillMap.get(cloudSkill.name);
4766
4976
  const acknowledged = isNativeSkill(cloudSkill) && local && acknowledgedNative.get(cloudSkill.id) === local.folderHash;
4977
+ const legacyBaseline = Boolean(local && pendingLegacyUpgrade(cloudSkill, local, previousState) && previousNativeState(previousState, cloudSkill)?.folderHash === local.folderHash);
4767
4978
  if (!acknowledged && !shouldWriteCloudSkill(cloudSkill, localSkillMap, previousState)) {
4768
4979
  if (isNativeSkill(cloudSkill) && !nativeLocalReady(cloudSkill, local)) {
4769
4980
  failures.push({ name: cloudSkill.name, error: "Local native Skill changes were retained; resolve the version or identity conflict before using them." });
@@ -4776,7 +4987,8 @@ async function writePulledSkillsToScopedMirror(pullResponse, localSkills, previo
4776
4987
  // What the last write put there. Everything else in the folder was
4777
4988
  // produced locally and survives this one.
4778
4989
  previouslyApplied: previousNativeState(previousState, skill)?.appliedFiles,
4779
- ...isNativeSkill(skill) && local ? { expectedFolderHash: local.folderHash } : {}
4990
+ ...isNativeSkill(skill) && local ? { expectedFolderHash: local.folderHash } : {},
4991
+ ...legacyBaseline ? { legacyBaseline } : {}
4780
4992
  }),
4781
4993
  onWarning: warnSkillSync
4782
4994
  });
@@ -4845,7 +5057,7 @@ async function materializeCloudSkillsForLocalShell(serverUrl, jwt, dependencies
4845
5057
  }
4846
5058
  if (relinkSkillNames.size > 0) {
4847
5059
  const relinked = await deps.syncSymlinks(
4848
- nativeLinkRows(pullResponse, finalLocalSkills).filter((skill) => relinkSkillNames.has(skill.name)),
5060
+ nativeLinkRows(pullResponse, finalLocalSkills, previousState).filter((skill) => relinkSkillNames.has(skill.name)),
4849
5061
  syncPaths.skillsDir,
4850
5062
  { ...isolatedLinkOptions(syncPaths), removeUndesired: false }
4851
5063
  );
@@ -4882,7 +5094,8 @@ async function materializeCloudSkillsForLocalShell(serverUrl, jwt, dependencies
4882
5094
  for (const [name, previous] of Object.entries(previousState.skills)) {
4883
5095
  if (!previous.nativeReference && !previous.nativeUnavailable) continue;
4884
5096
  const current = pullResponse.skills.find((skill) => skill.id === previous.cloudId);
4885
- if (!current || !nativeLocalReady(current, finalLocalSkills.find((local) => local.name === current.name))) {
5097
+ const local = current && finalLocalSkills.find((row) => row.name === current.name);
5098
+ if (!current || !nativeLocalReady(current, local) && !pendingLegacyUpgrade(current, local, previousState)) {
4886
5099
  removed += await deps.removeAllSymlinksForSkill(name, syncPaths.skillsDir, isolatedLinkOptions(syncPaths));
4887
5100
  }
4888
5101
  }
@@ -4968,9 +5181,11 @@ async function deactivateDeletedAgentSkills(serverUrl, jwt, pullResponse, previo
4968
5181
  return deactivated;
4969
5182
  }
4970
5183
  async function runSkillSync(serverUrl, jwt, dependencies = {}, options = {}) {
5184
+ const linkAgentFolders = options.linkAgentFolders !== false;
4971
5185
  const deps = {
4972
5186
  ...DEFAULT_RUN_SKILL_SYNC_DEPS,
4973
- ...dependencies
5187
+ ...dependencies,
5188
+ ...linkAgentFolders ? {} : MIRROR_ONLY_DEPS
4974
5189
  };
4975
5190
  const syncSettings = await deps.fetchSyncSettings(
4976
5191
  serverUrl,
@@ -5009,13 +5224,16 @@ async function runSkillSync(serverUrl, jwt, dependencies = {}, options = {}) {
5009
5224
  syncPaths.skillsDir,
5010
5225
  isolatedLinkOptions(syncPaths)
5011
5226
  );
5227
+ if (linkAgentFolders && !syncPaths.isolatedNamespace) {
5228
+ await forgetOtherAccountsAgentLinks(syncPaths);
5229
+ }
5012
5230
  const cloudCuratedSkillNames = new Set(
5013
5231
  pullResponse.skills.filter((skill) => skill.source === "curated").map((skill) => skill.name)
5014
5232
  );
5015
5233
  const protectedSkillNames = /* @__PURE__ */ new Set([...cloudCuratedSkillNames, ...BASE_SKILL_NAMES2]);
5016
5234
  const scopedState = withoutBaseSkillState(await deps.readSyncState(syncPaths));
5017
5235
  const assignmentFailures = [];
5018
- const deactivated = !syncPaths.isolatedNamespace && syncSettings.agent_targets_conditional_updates === true ? await deactivateDeletedAgentSkills(
5236
+ const deactivated = linkAgentFolders && !syncPaths.isolatedNamespace && syncSettings.agent_targets_conditional_updates === true ? await deactivateDeletedAgentSkills(
5019
5237
  serverUrl,
5020
5238
  jwt,
5021
5239
  pullResponse,
@@ -5037,7 +5255,7 @@ async function runSkillSync(serverUrl, jwt, dependencies = {}, options = {}) {
5037
5255
  protectedSkillNames
5038
5256
  });
5039
5257
  }
5040
- if (!syncPaths.isolatedNamespace) {
5258
+ if (linkAgentFolders && !syncPaths.isolatedNamespace) {
5041
5259
  await deps.gatherTopLevelLocalSkills(syncPaths, { protectedSkillNames });
5042
5260
  }
5043
5261
  const localSkills = (await deps.scanLocalSkills(syncPaths)).filter((skill) => !BASE_SKILL_NAMES2.has(skill.name));
@@ -5151,7 +5369,7 @@ async function runSkillSync(serverUrl, jwt, dependencies = {}, options = {}) {
5151
5369
  failedPushes
5152
5370
  };
5153
5371
  }
5154
- var DEFAULT_AGENT_TARGETS, NATIVE_IDENTITY_FILE, UUID, HOME_DIR, execFileAsync, NativeSkillIdentityError, AGENTS_DIR, LEGACY_AGENTS_SKILLS_DIR, NOTIS_SKILL_SYNC_ROOT, LEGACY_NOTIS_SYNC_STATE_PATH, AGENTS_SKILLS_DIR, SKILL_LOCK_PATH, DEFAULT_SYNC_STATE, EXCLUDED_TOP_LEVEL_ROOT_NAMES, DEFAULT_SYNC_PATHS, IGNORED_SKILL_DIRECTORIES, HOME_DIR2, EXTERNAL_AGENT_SKILL_DIRS, EXTERNAL_AGENTS, AGENT_FAILURE_LABELS, BASE_SKILL_NAMES2, DEFAULT_RUN_SKILL_SYNC_DEPS;
5372
+ var DEFAULT_AGENT_TARGETS, NATIVE_IDENTITY_FILE, UUID, HOME_DIR, execFileAsync, NativeSkillIdentityError, AGENTS_DIR, LEGACY_AGENTS_SKILLS_DIR, NOTIS_SKILL_SYNC_ROOT, LEGACY_NOTIS_SYNC_STATE_PATH, AGENTS_SKILLS_DIR, SKILL_LOCK_PATH, DEFAULT_SYNC_STATE, EXCLUDED_TOP_LEVEL_ROOT_NAMES, DEFAULT_SYNC_PATHS, IGNORED_SKILL_DIRECTORIES, HOME_DIR2, EXTERNAL_AGENT_SKILL_DIRS, EXTERNAL_AGENTS, AGENT_FAILURE_LABELS, BASE_SKILL_NAMES2, DEFAULT_RUN_SKILL_SYNC_DEPS, MIRROR_ONLY_DEPS;
5155
5373
  var init_skill_sync = __esm({
5156
5374
  "dist/skill-sync/index.js"() {
5157
5375
  DEFAULT_AGENT_TARGETS = {
@@ -5240,6 +5458,11 @@ var init_skill_sync = __esm({
5240
5458
  removeForeignAccountSymlinks,
5241
5459
  updateAgentTargets
5242
5460
  };
5461
+ MIRROR_ONLY_DEPS = {
5462
+ removeForeignAccountSymlinks: async () => 0,
5463
+ removeAllSymlinksForSkill: async () => 0,
5464
+ syncSymlinks: async () => ({ linked: 0, removed: 0, skipped: 0, verifiedAgentLinks: {} })
5465
+ };
5243
5466
  }
5244
5467
  });
5245
5468
 
@@ -8194,7 +8417,7 @@ var require_compile = __commonJS({
8194
8417
  const schOrFunc = root.refs[ref];
8195
8418
  if (schOrFunc)
8196
8419
  return schOrFunc;
8197
- let _sch = resolve18.call(this, root, ref);
8420
+ let _sch = resolve19.call(this, root, ref);
8198
8421
  if (_sch === void 0) {
8199
8422
  const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
8200
8423
  const { schemaId } = this.opts;
@@ -8221,7 +8444,7 @@ var require_compile = __commonJS({
8221
8444
  function sameSchemaEnv(s1, s2) {
8222
8445
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
8223
8446
  }
8224
- function resolve18(root, ref) {
8447
+ function resolve19(root, ref) {
8225
8448
  let sch;
8226
8449
  while (typeof (sch = this.refs[ref]) == "string")
8227
8450
  ref = sch;
@@ -9051,7 +9274,7 @@ var require_fast_uri = __commonJS({
9051
9274
  }
9052
9275
  return uri;
9053
9276
  }
9054
- function resolve18(baseURI, relativeURI, options) {
9277
+ function resolve19(baseURI, relativeURI, options) {
9055
9278
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
9056
9279
  const {
9057
9280
  parsed: baseParsed,
@@ -9420,7 +9643,7 @@ var require_fast_uri = __commonJS({
9420
9643
  var fastUri = {
9421
9644
  SCHEMES,
9422
9645
  normalize,
9423
- resolve: resolve18,
9646
+ resolve: resolve19,
9424
9647
  resolveComponent,
9425
9648
  equal,
9426
9649
  serialize,
@@ -13220,12 +13443,12 @@ var require_dist = __commonJS({
13220
13443
  throw new Error(`Unknown format "${name}"`);
13221
13444
  return f;
13222
13445
  };
13223
- function addFormats2(ajv, list, fs3, exportName) {
13446
+ function addFormats2(ajv, list, fs4, exportName) {
13224
13447
  var _a;
13225
13448
  var _b;
13226
13449
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
13227
13450
  for (const f of list)
13228
- ajv.addFormat(f, fs3[f]);
13451
+ ajv.addFormat(f, fs4[f]);
13229
13452
  }
13230
13453
  module.exports = exports = formatsPlugin;
13231
13454
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -27826,8 +28049,8 @@ var require_lib = __commonJS({
27826
28049
  });
27827
28050
 
27828
28051
  // src/cli.js
27829
- import { readFileSync as readFileSync23 } from "node:fs";
27830
- import { dirname as dirname21, join as join25 } from "node:path";
28052
+ import { readFileSync as readFileSync25 } from "node:fs";
28053
+ import { dirname as dirname24, join as join27 } from "node:path";
27831
28054
  import { fileURLToPath as fileURLToPath14 } from "node:url";
27832
28055
 
27833
28056
  // node_modules/commander/lib/error.js
@@ -31200,9 +31423,9 @@ var program = new Command();
31200
31423
 
31201
31424
  // src/command-specs/apps.js
31202
31425
  init_errors();
31203
- import { mkdirSync as mkdirSync6, mkdtempSync as mkdtempSync3, readdirSync as readdirSync5, rmSync as rmSync5 } from "node:fs";
31426
+ import { mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync3, readdirSync as readdirSync5, rmSync as rmSync5 } from "node:fs";
31204
31427
  import { tmpdir as tmpdir2 } from "node:os";
31205
- import { basename as basename3, join as join9, relative as relative3 } from "node:path";
31428
+ import { basename as basename3, join as join11, relative as relative3 } from "node:path";
31206
31429
 
31207
31430
  // src/runtime/output.js
31208
31431
  init_errors();
@@ -35899,9 +36122,9 @@ async function composeStoreScreenshot({
35899
36122
 
35900
36123
  // src/runtime/transport.js
35901
36124
  init_errors();
35902
- import { randomUUID as randomUUID3 } from "node:crypto";
36125
+ import { randomUUID as randomUUID4 } from "node:crypto";
35903
36126
  import { createReadStream } from "node:fs";
35904
- import { dirname as dirname8 } from "node:path";
36127
+ import { dirname as dirname10 } from "node:path";
35905
36128
 
35906
36129
  // src/runtime/delegated-context.js
35907
36130
  init_errors();
@@ -35982,7 +36205,7 @@ async function* multipartFileBody(boundary, payload, bindingMetadata, fileBindin
35982
36205
  `);
35983
36206
  }
35984
36207
  function createMultipartFileUpload(payload, bindingMetadata, fileBindings) {
35985
- const boundary = `----notis-cli-${randomUUID3().replace(/-/g, "")}`;
36208
+ const boundary = `----notis-cli-${randomUUID4().replace(/-/g, "")}`;
35986
36209
  const textParts = [
35987
36210
  multipartTextPart(boundary, "payload", JSON.stringify(payload)),
35988
36211
  multipartTextPart(boundary, "file_bindings", JSON.stringify(bindingMetadata))
@@ -36078,7 +36301,7 @@ function reloadDevJwt(runtime, loadedProfile = null) {
36078
36301
  const expectedUserId = runtime.worktreeRuntime?.expected_user_id;
36079
36302
  const runtimePath = runtime.worktreeRuntime?.runtime_path;
36080
36303
  if (runtimePath) {
36081
- const refreshedRuntime = resolveWorktreeRuntime(dirname8(runtimePath));
36304
+ const refreshedRuntime = resolveWorktreeRuntime(dirname10(runtimePath));
36082
36305
  if (refreshedRuntime && !refreshedRuntime.unavailable && refreshedRuntime.runtime_path === runtimePath && refreshedRuntime.profile === runtime.profileName && refreshedRuntime.api_base === runtime.apiBase) {
36083
36306
  if (expectedUserId && refreshedRuntime.expected_user_id !== expectedUserId) {
36084
36307
  throw new CliError({
@@ -36157,7 +36380,7 @@ async function httpRequest({
36157
36380
  }
36158
36381
  let controller = new AbortController();
36159
36382
  let timeout = setTimeout(() => controller.abort(), runtime.timeoutMs);
36160
- const requestId2 = `req_${randomUUID3().replace(/-/g, "")}`;
36383
+ const requestId2 = `req_${randomUUID4().replace(/-/g, "")}`;
36161
36384
  const resetTimeout = () => {
36162
36385
  clearTimeout(timeout);
36163
36386
  controller = new AbortController();
@@ -36283,7 +36506,7 @@ async function callTool({
36283
36506
  idempotencyKey,
36284
36507
  fileBindings = []
36285
36508
  }) {
36286
- const requestId2 = idempotencyKey || (runtime.mutating ? randomUUID3() : null);
36509
+ const requestId2 = idempotencyKey || (runtime.mutating ? randomUUID4() : null);
36287
36510
  const payload = {
36288
36511
  tool_name: toolName,
36289
36512
  arguments: argumentsPayload,
@@ -36329,7 +36552,7 @@ init_oauth();
36329
36552
 
36330
36553
  // src/command-specs/helpers.js
36331
36554
  init_errors();
36332
- import { randomUUID as randomUUID4 } from "node:crypto";
36555
+ import { randomUUID as randomUUID5 } from "node:crypto";
36333
36556
  var COMPOSIO_SEARCH_TOOLS = "COMPOSIO_SEARCH_TOOLS";
36334
36557
  var COMPOSIO_GET_TOOL_SCHEMAS = "COMPOSIO_GET_TOOL_SCHEMAS";
36335
36558
  var COMPOSIO_MULTI_EXECUTE_TOOL = "COMPOSIO_MULTI_EXECUTE_TOOL";
@@ -36367,7 +36590,7 @@ function parseMaybeJson(value, label) {
36367
36590
  return parseJson(value, label);
36368
36591
  }
36369
36592
  function nextIdempotencyKey(globalOptions) {
36370
- return globalOptions.idempotencyKey || randomUUID4();
36593
+ return globalOptions.idempotencyKey || randomUUID5();
36371
36594
  }
36372
36595
  async function runToolCommand({
36373
36596
  runtime,
@@ -36591,7 +36814,7 @@ function pruneStaleScreenshotFiles(outputDir, keepCount) {
36591
36814
  if (!entry.isFile()) continue;
36592
36815
  const match = /^screenshot-(\d+)\.png$/i.exec(entry.name);
36593
36816
  if (match && Number.parseInt(match[1], 10) > keepCount) {
36594
- rmSync5(join9(outputDir, entry.name), { force: true });
36817
+ rmSync5(join11(outputDir, entry.name), { force: true });
36595
36818
  }
36596
36819
  }
36597
36820
  }
@@ -37076,7 +37299,7 @@ ${listing.errors.map((error) => ` - ${error}`).join("\n")}`);
37076
37299
  browserTouched = true;
37077
37300
  results = [];
37078
37301
  for (const { route, url } of urls) {
37079
- const snapshotPath = join9(projectDir, ".notis", "output", ".harness", `${route.slug}.snapshot.txt`);
37302
+ const snapshotPath = join11(projectDir, ".notis", "output", ".harness", `${route.slug}.snapshot.txt`);
37080
37303
  const result = await runHarnessRoute({
37081
37304
  url,
37082
37305
  sessionName: browserSessionName,
@@ -37204,7 +37427,7 @@ ${problems.map((p) => ` - ${p}`).join("\n")}`);
37204
37427
  }
37205
37428
  const width = parsePositiveInt(ctx.options.width) || 2e3;
37206
37429
  const height = parsePositiveInt(ctx.options.height) || 1250;
37207
- const outputDir = ctx.options.outputDir ? resolveProjectDir(ctx.options.outputDir) : join9(projectDir, "metadata");
37430
+ const outputDir = ctx.options.outputDir ? resolveProjectDir(ctx.options.outputDir) : join11(projectDir, "metadata");
37208
37431
  const port = parsePort(ctx.options.port) || await getAvailablePort();
37209
37432
  const appSlug = slugify(appConfig.name || manifest.app?.name || "app") || "app";
37210
37433
  const baseUrl = `http://127.0.0.1:${port}/a/${appSlug}`;
@@ -37235,7 +37458,7 @@ ${problems.map((p) => ` - ${p}`).join("\n")}`);
37235
37458
  theme: "light",
37236
37459
  fileName: `screenshot-${screenshotSlots.get(route.slug) || index + 1}.png`
37237
37460
  }));
37238
- const rawOutputDir = ctx.options.raw ? null : mkdtempSync3(join9(tmpdir2(), "notis-store-screenshots-"));
37461
+ const rawOutputDir = ctx.options.raw ? null : mkdtempSync3(join11(tmpdir2(), "notis-store-screenshots-"));
37239
37462
  let testServer = null;
37240
37463
  let browserTouched = false;
37241
37464
  let cleanupPromise;
@@ -37260,12 +37483,12 @@ ${problems.map((p) => ` - ${p}`).join("\n")}`);
37260
37483
  `)
37261
37484
  });
37262
37485
  browserTouched = true;
37263
- mkdirSync6(outputDir, { recursive: true });
37486
+ mkdirSync8(outputDir, { recursive: true });
37264
37487
  const results = [];
37265
37488
  for (const capture of captures) {
37266
37489
  const { route, scenario, focus, theme, fileName } = capture;
37267
- const screenshotPath = join9(outputDir, fileName);
37268
- const browserScreenshotPath = rawOutputDir ? join9(rawOutputDir, fileName) : screenshotPath;
37490
+ const screenshotPath = join11(outputDir, fileName);
37491
+ const browserScreenshotPath = rawOutputDir ? join11(rawOutputDir, fileName) : screenshotPath;
37269
37492
  const scenarioParam = scenario ? `&scenario=${encodeURIComponent(scenario)}` : "";
37270
37493
  const themeParam = `&theme=${encodeURIComponent(theme || "light")}`;
37271
37494
  const captureSessionName = `${browserSessionName}-${results.length + 1}`;
@@ -38050,7 +38273,7 @@ var appsCommandSpecs = [
38050
38273
 
38051
38274
  // src/command-specs/tools.js
38052
38275
  init_errors();
38053
- import { accessSync, constants as fsConstants2, createReadStream as createReadStream2, existsSync as existsSync8, readFileSync as readFileSync9, statSync as statSync6 } from "node:fs";
38276
+ import { accessSync, constants as fsConstants2, createReadStream as createReadStream2, existsSync as existsSync9, readFileSync as readFileSync11, statSync as statSync6 } from "node:fs";
38054
38277
  import { createHash as createHash3 } from "node:crypto";
38055
38278
  import { basename as basename4 } from "node:path";
38056
38279
  async function resolveJsonInput(value, label) {
@@ -38064,10 +38287,10 @@ async function resolveJsonInput(value, label) {
38064
38287
  }
38065
38288
  if (value.startsWith("@")) {
38066
38289
  const filePath = value.slice(1);
38067
- if (!existsSync8(filePath)) {
38290
+ if (!existsSync9(filePath)) {
38068
38291
  throw usageError(`File not found: ${filePath}`);
38069
38292
  }
38070
- return parseJson(readFileSync9(filePath, "utf-8"), label);
38293
+ return parseJson(readFileSync11(filePath, "utf-8"), label);
38071
38294
  }
38072
38295
  return parseJson(value, label);
38073
38296
  }
@@ -38265,7 +38488,7 @@ async function parseFileBindingSpec(spec, index) {
38265
38488
  if (!localPath2) {
38266
38489
  throw usageError("--file local path is required");
38267
38490
  }
38268
- if (!existsSync8(localPath2)) {
38491
+ if (!existsSync9(localPath2)) {
38269
38492
  throw usageError(`File not found: ${localPath2}`);
38270
38493
  }
38271
38494
  let stats;
@@ -38669,7 +38892,7 @@ var toolsCommandSpecs = [
38669
38892
  ];
38670
38893
 
38671
38894
  // src/command-specs/meta.js
38672
- import { dirname as dirname9 } from "node:path";
38895
+ import { dirname as dirname11 } from "node:path";
38673
38896
  import { fileURLToPath as fileURLToPath6 } from "node:url";
38674
38897
 
38675
38898
  // src/runtime/help.js
@@ -38738,7 +38961,7 @@ function doctorToolRoundtripRuntime(runtime) {
38738
38961
  timeoutMs: Math.max(runtime.timeoutMs || 0, DOCTOR_TOOL_ROUNDTRIP_TIMEOUT_MS)
38739
38962
  };
38740
38963
  }
38741
- function doctorChannelSummary(runtime, moduleDirectory = dirname9(fileURLToPath6(import.meta.url))) {
38964
+ function doctorChannelSummary(runtime, moduleDirectory = dirname11(fileURLToPath6(import.meta.url))) {
38742
38965
  const decision = resolveChannelSwitch({
38743
38966
  runningVersion: runtime.cliVersion,
38744
38967
  profile: {
@@ -38955,8 +39178,8 @@ init_errors();
38955
39178
  init_auth_recovery();
38956
39179
  init_profiles();
38957
39180
  init_oauth();
38958
- import { readFileSync as readFileSync12 } from "node:fs";
38959
- import { dirname as dirname12, join as join12 } from "node:path";
39181
+ import { readFileSync as readFileSync14 } from "node:fs";
39182
+ import { dirname as dirname14, join as join14 } from "node:path";
38960
39183
  import { fileURLToPath as fileURLToPath8 } from "node:url";
38961
39184
 
38962
39185
  // src/command-specs/auth.js
@@ -38969,20 +39192,20 @@ import { basename as basename5 } from "node:path";
38969
39192
  // src/runtime/agent-setup.js
38970
39193
  import {
38971
39194
  chmodSync,
38972
- existsSync as existsSync9,
38973
- mkdirSync as mkdirSync7,
38974
- readFileSync as readFileSync10,
39195
+ existsSync as existsSync10,
39196
+ mkdirSync as mkdirSync9,
39197
+ readFileSync as readFileSync12,
38975
39198
  readdirSync as readdirSync6,
38976
- renameSync as renameSync4,
38977
- writeFileSync as writeFileSync6
39199
+ renameSync as renameSync6,
39200
+ writeFileSync as writeFileSync8
38978
39201
  } from "node:fs";
38979
39202
  import { createHash as createHash4 } from "node:crypto";
38980
- import { homedir as homedir4 } from "node:os";
38981
- import { dirname as dirname10, join as join10 } from "node:path";
39203
+ import { homedir as homedir5 } from "node:os";
39204
+ import { dirname as dirname12, join as join12 } from "node:path";
38982
39205
  import { fileURLToPath as fileURLToPath7 } from "node:url";
38983
- var HERE = dirname10(fileURLToPath7(import.meta.url));
38984
- var INSTRUCTIONS_PATH = join10(HERE, "..", "..", "skills", "notis-cli", "AGENT_INSTRUCTIONS.md");
38985
- var HOOK_BUNDLE_PATH = join10(HERE, "..", "..", "dist", "agent-hooks", "notis-agent-hook.mjs");
39206
+ var HERE = dirname12(fileURLToPath7(import.meta.url));
39207
+ var INSTRUCTIONS_PATH = join12(HERE, "..", "..", "skills", "notis-cli", "AGENT_INSTRUCTIONS.md");
39208
+ var HOOK_BUNDLE_PATH = join12(HERE, "..", "..", "dist", "agent-hooks", "notis-agent-hook.mjs");
38986
39209
  var START_MARKER = "<!-- notis-cli:instructions:start -->";
38987
39210
  var END_MARKER = "<!-- notis-cli:instructions:end -->";
38988
39211
  var LEGACY_SENTINEL = "Use the Notis CLI (`npx --package @notis_ai/cli@latest -- notis ...`)";
@@ -38990,20 +39213,20 @@ var MANAGED_HOOK_MARKER = "--notis-managed-agent-hook";
38990
39213
  var LEGACY_MANAGED_HOOK_MARKER = "NOTIS_MANAGED_AGENT_HOOK=1";
38991
39214
  var AGENT_IDS = Object.freeze(["codex", "claude-code"]);
38992
39215
  function atomicWrite(filePath, contents, mode = 384) {
38993
- mkdirSync7(dirname10(filePath), { recursive: true, mode: 448 });
39216
+ mkdirSync9(dirname12(filePath), { recursive: true, mode: 448 });
38994
39217
  const temporaryPath = `${filePath}.notis-${process.pid}-${Date.now()}.tmp`;
38995
- writeFileSync6(temporaryPath, contents, { mode });
38996
- renameSync4(temporaryPath, filePath);
39218
+ writeFileSync8(temporaryPath, contents, { mode });
39219
+ renameSync6(temporaryPath, filePath);
38997
39220
  }
38998
39221
  function readText(filePath) {
38999
- return existsSync9(filePath) ? readFileSync10(filePath, "utf-8") : "";
39222
+ return existsSync10(filePath) ? readFileSync12(filePath, "utf-8") : "";
39000
39223
  }
39001
39224
  function activeCodexInstructionsPath(home) {
39002
- const overridePath = join10(home, ".codex", "AGENTS.override.md");
39003
- if (existsSync9(overridePath) && readText(overridePath).trim()) {
39225
+ const overridePath = join12(home, ".codex", "AGENTS.override.md");
39226
+ if (existsSync10(overridePath) && readText(overridePath).trim()) {
39004
39227
  return overridePath;
39005
39228
  }
39006
- return join10(home, ".codex", "AGENTS.md");
39229
+ return join12(home, ".codex", "AGENTS.md");
39007
39230
  }
39008
39231
  function upsertInstructionBlock(filePath, block) {
39009
39232
  const existing = readText(filePath);
@@ -39038,8 +39261,8 @@ function upsertInstructionBlock(filePath, block) {
39038
39261
  return { path: filePath, status };
39039
39262
  }
39040
39263
  function readJsonObject(filePath) {
39041
- if (!existsSync9(filePath)) return {};
39042
- const raw = readFileSync10(filePath, "utf-8");
39264
+ if (!existsSync10(filePath)) return {};
39265
+ const raw = readFileSync12(filePath, "utf-8");
39043
39266
  try {
39044
39267
  const parsed = JSON.parse(raw);
39045
39268
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
@@ -39086,14 +39309,14 @@ function shellQuote(value) {
39086
39309
  return `'${String(value).replaceAll("'", `'"'"'`)}'`;
39087
39310
  }
39088
39311
  function installManagedHookRuntime({
39089
- home = homedir4(),
39312
+ home = homedir5(),
39090
39313
  bundlePath: bundlePath2 = HOOK_BUNDLE_PATH,
39091
39314
  nodePath = process.execPath,
39092
39315
  platform = process.platform
39093
39316
  } = {}) {
39094
- const bundle = readFileSync10(bundlePath2);
39317
+ const bundle = readFileSync12(bundlePath2);
39095
39318
  const digest = createHash4("sha256").update(bundle).digest("hex");
39096
- const runtimePath = join10(
39319
+ const runtimePath = join12(
39097
39320
  home,
39098
39321
  ".notis",
39099
39322
  "agent-hooks",
@@ -39101,10 +39324,10 @@ function installManagedHookRuntime({
39101
39324
  digest,
39102
39325
  "notis-agent-hook.mjs"
39103
39326
  );
39104
- const existingDigest = existsSync9(runtimePath) ? createHash4("sha256").update(readFileSync10(runtimePath)).digest("hex") : null;
39327
+ const existingDigest = existsSync10(runtimePath) ? createHash4("sha256").update(readFileSync12(runtimePath)).digest("hex") : null;
39105
39328
  if (existingDigest !== digest) atomicWrite(runtimePath, bundle, 320);
39106
39329
  chmodSync(runtimePath, 320);
39107
- const launcherPath = join10(
39330
+ const launcherPath = join12(
39108
39331
  home,
39109
39332
  ".notis",
39110
39333
  "agent-hooks",
@@ -39129,7 +39352,7 @@ function installManagedHookRuntime({
39129
39352
  ""
39130
39353
  ].join("\n");
39131
39354
  if (readText(launcherPath) !== launcher) {
39132
- if (platform === "win32" && existsSync9(launcherPath)) {
39355
+ if (platform === "win32" && existsSync10(launcherPath)) {
39133
39356
  chmodSync(launcherPath, 448);
39134
39357
  }
39135
39358
  atomicWrite(launcherPath, launcher, 320);
@@ -39182,30 +39405,30 @@ function upsertPromptHooks(filePath, agentId, profileName, enabled, launcherPath
39182
39405
  atomicWrite(filePath, serialized);
39183
39406
  return {
39184
39407
  path: filePath,
39185
- status: enabled ? existsSync9(filePath) && existing ? "updated" : "installed" : "removed"
39408
+ status: enabled ? existsSync10(filePath) && existing ? "updated" : "installed" : "removed"
39186
39409
  };
39187
39410
  }
39188
39411
  function agentPaths(agentId, home) {
39189
39412
  if (agentId === "codex") {
39190
39413
  return {
39191
- root: join10(home, ".codex"),
39414
+ root: join12(home, ".codex"),
39192
39415
  instructions: activeCodexInstructionsPath(home),
39193
- hooks: join10(home, ".codex", "hooks.json")
39416
+ hooks: join12(home, ".codex", "hooks.json")
39194
39417
  };
39195
39418
  }
39196
39419
  if (agentId === "claude-code") {
39197
39420
  return {
39198
- root: join10(home, ".claude"),
39199
- instructions: join10(home, ".claude", "CLAUDE.md"),
39200
- hooks: join10(home, ".claude", "settings.json")
39421
+ root: join12(home, ".claude"),
39422
+ instructions: join12(home, ".claude", "CLAUDE.md"),
39423
+ hooks: join12(home, ".claude", "settings.json")
39201
39424
  };
39202
39425
  }
39203
39426
  throw new Error(`Unsupported agent: ${agentId}`);
39204
39427
  }
39205
- function shouldInstallLocalAgentSetup(env = process.env, home = homedir4()) {
39428
+ function shouldInstallLocalAgentSetup(env = process.env, home = homedir5()) {
39206
39429
  if (env.NOTIS_JWT || env.NOTIS_AGENT === "1" || env.NOTIS_DELEGATED_CONTEXT === "1") return false;
39207
39430
  if (env.CONDUCTOR_IS_LOCAL === "0") return false;
39208
- if (existsSync9("/vercel/sandbox")) return false;
39431
+ if (existsSync10("/vercel/sandbox")) return false;
39209
39432
  return Boolean(home);
39210
39433
  }
39211
39434
  function installAgentSetup({
@@ -39214,19 +39437,19 @@ function installAgentSetup({
39214
39437
  memoryHooks = true,
39215
39438
  onlyExisting = false,
39216
39439
  detectedAgents = null,
39217
- home = homedir4(),
39440
+ home = homedir5(),
39218
39441
  platform = process.platform
39219
39442
  } = {}) {
39220
39443
  if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(String(profileName || ""))) {
39221
39444
  throw new Error("A valid authenticated Notis profile is required for agent setup");
39222
39445
  }
39223
- const instructions = readFileSync10(INSTRUCTIONS_PATH, "utf-8").trim();
39446
+ const instructions = readFileSync12(INSTRUCTIONS_PATH, "utf-8").trim();
39224
39447
  const results = [];
39225
39448
  const shouldRepairManagedHooks = memoryHooks === true || memoryHooks === null && agents.some((agentId) => fileHasManagedNotisHook(agentPaths(agentId, home).hooks));
39226
39449
  const hookRuntime = shouldRepairManagedHooks ? installManagedHookRuntime({ home, platform }) : null;
39227
39450
  for (const agentId of agents) {
39228
39451
  const paths = agentPaths(agentId, home);
39229
- const detected = Array.isArray(detectedAgents) ? detectedAgents.includes(agentId) : existsSync9(paths.root);
39452
+ const detected = Array.isArray(detectedAgents) ? detectedAgents.includes(agentId) : existsSync10(paths.root);
39230
39453
  if (onlyExisting && !detected) {
39231
39454
  results.push({ agent: agentId, status: "not_detected" });
39232
39455
  continue;
@@ -39264,28 +39487,28 @@ function installAgentSetup({
39264
39487
  // src/runtime/agent-memory-state.js
39265
39488
  import { createHash as createHash5 } from "node:crypto";
39266
39489
  import {
39267
- existsSync as existsSync10,
39268
- mkdirSync as mkdirSync8,
39269
- readFileSync as readFileSync11,
39270
- renameSync as renameSync5,
39271
- writeFileSync as writeFileSync7
39490
+ existsSync as existsSync11,
39491
+ mkdirSync as mkdirSync10,
39492
+ readFileSync as readFileSync13,
39493
+ renameSync as renameSync7,
39494
+ writeFileSync as writeFileSync9
39272
39495
  } from "node:fs";
39273
- import { homedir as homedir5 } from "node:os";
39274
- import { dirname as dirname11, join as join11 } from "node:path";
39496
+ import { homedir as homedir6 } from "node:os";
39497
+ import { dirname as dirname13, join as join13 } from "node:path";
39275
39498
  var MAX_SEEN_HASHES = 500;
39276
39499
  var MAX_PROMPT_CHARS = 12e3;
39277
39500
  function hash(value) {
39278
39501
  return createHash5("sha256").update(String(value || "")).digest("hex").slice(0, 24);
39279
39502
  }
39280
- function statePath(sessionId, home = homedir5()) {
39503
+ function statePath(sessionId, home = homedir6()) {
39281
39504
  if (!sessionId) return null;
39282
- return join11(home, ".notis", "agent-memory-hooks", `${hash(sessionId)}.json`);
39505
+ return join13(home, ".notis", "agent-memory-hooks", `${hash(sessionId)}.json`);
39283
39506
  }
39284
39507
  function readState(sessionId, home) {
39285
39508
  const filePath = statePath(sessionId, home);
39286
- if (!filePath || !existsSync10(filePath)) return { seen: [], pending: null };
39509
+ if (!filePath || !existsSync11(filePath)) return { seen: [], pending: null };
39287
39510
  try {
39288
- const parsed = JSON.parse(readFileSync11(filePath, "utf-8"));
39511
+ const parsed = JSON.parse(readFileSync13(filePath, "utf-8"));
39289
39512
  return parsed && typeof parsed === "object" ? {
39290
39513
  seen: Array.isArray(parsed.seen) ? parsed.seen.filter((item) => typeof item === "string") : [],
39291
39514
  pending: parsed.pending && typeof parsed.pending === "object" ? parsed.pending : null,
@@ -39315,13 +39538,13 @@ function stateForInput(sessionId, input, home) {
39315
39538
  function writeState(sessionId, state, home) {
39316
39539
  const filePath = statePath(sessionId, home);
39317
39540
  if (!filePath) return;
39318
- mkdirSync8(dirname11(filePath), { recursive: true, mode: 448 });
39541
+ mkdirSync10(dirname13(filePath), { recursive: true, mode: 448 });
39319
39542
  const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
39320
- writeFileSync7(temporaryPath, `${JSON.stringify(state)}
39543
+ writeFileSync9(temporaryPath, `${JSON.stringify(state)}
39321
39544
  `, { mode: 384 });
39322
- renameSync5(temporaryPath, filePath);
39545
+ renameSync7(temporaryPath, filePath);
39323
39546
  }
39324
- function rememberPendingTurn(input, home = homedir5()) {
39547
+ function rememberPendingTurn(input, home = homedir6()) {
39325
39548
  const sessionId = input?.session_id;
39326
39549
  const prompt = typeof input?.prompt === "string" ? input.prompt.trim() : "";
39327
39550
  if (!sessionId || !prompt || ["/", "!", "#"].includes(prompt[0])) return;
@@ -39334,7 +39557,7 @@ function rememberPendingTurn(input, home = homedir5()) {
39334
39557
  };
39335
39558
  writeState(sessionId, state, home);
39336
39559
  }
39337
- function pendingTurn(input, home = homedir5()) {
39560
+ function pendingTurn(input, home = homedir6()) {
39338
39561
  const sessionId = input?.session_id;
39339
39562
  const state = readState(sessionId, home);
39340
39563
  const identity = inputIdentity(input);
@@ -39346,17 +39569,17 @@ function pendingTurn(input, home = homedir5()) {
39346
39569
  if (state.pending.turn_id && input?.turn_id && state.pending.turn_id !== input.turn_id) return null;
39347
39570
  return state.pending;
39348
39571
  }
39349
- function completePendingTurn(input, home = homedir5()) {
39572
+ function completePendingTurn(input, home = homedir6()) {
39350
39573
  const sessionId = input?.session_id;
39351
39574
  if (!sessionId) return;
39352
39575
  const filePath = statePath(sessionId, home);
39353
- if (!filePath || !existsSync10(filePath)) return;
39576
+ if (!filePath || !existsSync11(filePath)) return;
39354
39577
  const state = readState(sessionId, home);
39355
39578
  if (!state.pending) return;
39356
39579
  state.pending = null;
39357
39580
  writeState(sessionId, state, home);
39358
39581
  }
39359
- function freshRecallItems(input, items, home = homedir5()) {
39582
+ function freshRecallItems(input, items, home = homedir6()) {
39360
39583
  const sessionId = input?.session_id;
39361
39584
  if (!sessionId) return items;
39362
39585
  const state = stateForInput(sessionId, input, home);
@@ -39799,8 +40022,8 @@ var authCommandSpecs = [
39799
40022
  },
39800
40023
  {
39801
40024
  command_path: ["logout"],
39802
- summary: "Revoke and remove the OAuth credential for one CLI profile.",
39803
- when_to_use: "Use this to disconnect a single account. Other profiles keep their credentials unless you pass --all-profiles.",
40025
+ summary: "Sign this computer out of one CLI profile: revoke and remove its OAuth credential.",
40026
+ when_to_use: "Use this to disconnect a single account on this computer. Its sign-ins on other computers stay, and other profiles keep their credentials unless you pass --all-profiles.",
39804
40027
  args_schema: {
39805
40028
  arguments: [],
39806
40029
  options: [
@@ -39820,8 +40043,8 @@ var authCommandSpecs = [
39820
40043
  ];
39821
40044
 
39822
40045
  // src/command-specs/onboarding.js
39823
- var HERE2 = dirname12(fileURLToPath8(import.meta.url));
39824
- var BUNDLED_BRIEF_PATH = join12(HERE2, "..", "..", "skills", "notis-onboarding", "BRIEF.md");
40046
+ var HERE2 = dirname14(fileURLToPath8(import.meta.url));
40047
+ var BUNDLED_BRIEF_PATH = join14(HERE2, "..", "..", "skills", "notis-onboarding", "BRIEF.md");
39825
40048
  async function fetchOnboardingState(runtime) {
39826
40049
  try {
39827
40050
  const { payload } = await runToolCommand({
@@ -39862,7 +40085,7 @@ async function fetchBrief(apiBase, timeoutMs) {
39862
40085
  } catch {
39863
40086
  }
39864
40087
  try {
39865
- return { markdown: readFileSync12(BUNDLED_BRIEF_PATH, "utf-8"), source: "bundled" };
40088
+ return { markdown: readFileSync14(BUNDLED_BRIEF_PATH, "utf-8"), source: "bundled" };
39866
40089
  } catch {
39867
40090
  return { markdown: null, source: null };
39868
40091
  }
@@ -40030,8 +40253,8 @@ var onboardingCommandSpecs = [
40030
40253
 
40031
40254
  // src/command-specs/diagnostics.js
40032
40255
  init_errors();
40033
- import { createHash as createHash7, randomUUID as randomUUID5 } from "node:crypto";
40034
- import { existsSync as existsSync11, readFileSync as readFileSync13 } from "node:fs";
40256
+ import { createHash as createHash7, randomUUID as randomUUID6 } from "node:crypto";
40257
+ import { existsSync as existsSync12, readFileSync as readFileSync15 } from "node:fs";
40035
40258
  var ENTITLEMENT_FIELDS = [
40036
40259
  "created_at",
40037
40260
  "included_credit_seat_count",
@@ -40160,7 +40383,7 @@ async function executeReadOnlySql(ctx, query, phase) {
40160
40383
  // Always a fresh key, never the operator's --idempotency-key: a diagnostic
40161
40384
  // must observe current state rather than replay a cached response, and two
40162
40385
  // different queries under one reused key would collide on the request hash.
40163
- idempotencyKey: randomUUID5(),
40386
+ idempotencyKey: randomUUID6(),
40164
40387
  sendIdempotencyKeyWhenReading: true
40165
40388
  });
40166
40389
  if (result.payload?.successful === false || result.payload?.error) {
@@ -40441,8 +40664,8 @@ ORDER BY i.created_at ASC;`;
40441
40664
  }
40442
40665
  function traceFileDiagnostics(path3) {
40443
40666
  if (!path3) return null;
40444
- if (!existsSync11(path3)) throw usageError(`Trace file not found: ${path3}`);
40445
- const trace = JSON.parse(readFileSync13(path3, "utf-8"));
40667
+ if (!existsSync12(path3)) throw usageError(`Trace file not found: ${path3}`);
40668
+ const trace = JSON.parse(readFileSync15(path3, "utf-8"));
40446
40669
  const text2 = JSON.stringify(trace).toLowerCase();
40447
40670
  const modelCounts = {};
40448
40671
  const generationIds = /* @__PURE__ */ new Set();
@@ -40673,15 +40896,15 @@ var diagnosticCommandSpecs = [
40673
40896
 
40674
40897
  // src/command-specs/smoke.js
40675
40898
  init_errors();
40676
- import { createHash as createHash8, randomUUID as randomUUID6 } from "node:crypto";
40899
+ import { createHash as createHash8, randomUUID as randomUUID7 } from "node:crypto";
40677
40900
  import {
40678
40901
  mkdtempSync as mkdtempSync4,
40679
- readFileSync as readFileSync14,
40902
+ readFileSync as readFileSync16,
40680
40903
  rmSync as rmSync6,
40681
- writeFileSync as writeFileSync8
40904
+ writeFileSync as writeFileSync10
40682
40905
  } from "node:fs";
40683
40906
  import { tmpdir as tmpdir3 } from "node:os";
40684
- import { basename as basename6, join as join13 } from "node:path";
40907
+ import { basename as basename6, join as join15 } from "node:path";
40685
40908
  import { setTimeout as delay2 } from "node:timers/promises";
40686
40909
  function discoveryNames(payload) {
40687
40910
  return [...new Set(
@@ -40762,12 +40985,12 @@ function remotePath(folder, name) {
40762
40985
  return `${normalizedFolder}/${name}`;
40763
40986
  }
40764
40987
  async function smokeFileUploadHandler(ctx) {
40765
- const tempDir = mkdtempSync4(join13(tmpdir3(), "notis-smoke-file-upload-"));
40766
- const marker = `${(/* @__PURE__ */ new Date()).toISOString().replaceAll(/[-:.]/g, "")}-${randomUUID6().slice(0, 8)}`;
40988
+ const tempDir = mkdtempSync4(join15(tmpdir3(), "notis-smoke-file-upload-"));
40989
+ const marker = `${(/* @__PURE__ */ new Date()).toISOString().replaceAll(/[-:.]/g, "")}-${randomUUID7().slice(0, 8)}`;
40767
40990
  const generatedFixture = !ctx.options.sourceFile;
40768
- const fixturePath = ctx.options.sourceFile || join13(tempDir, `notis-file-upload-${marker}.txt`);
40991
+ const fixturePath = ctx.options.sourceFile || join15(tempDir, `notis-file-upload-${marker}.txt`);
40769
40992
  if (generatedFixture) {
40770
- writeFileSync8(
40993
+ writeFileSync10(
40771
40994
  fixturePath,
40772
40995
  `Notis Dropbox file-upload smoke
40773
40996
  marker=${marker}
@@ -40777,7 +41000,7 @@ unicode=\xE9t\xE9 Z\xFCrich \u6771\u4EAC
40777
41000
  );
40778
41001
  }
40779
41002
  const localHash = await hashFileSha256(fixturePath);
40780
- const localBytes = readFileSync14(fixturePath);
41003
+ const localBytes = readFileSync16(fixturePath);
40781
41004
  const destination = remotePath(
40782
41005
  ctx.options.remoteFolder,
40783
41006
  `notis-file-upload-${marker}-${basename6(fixturePath)}`
@@ -41020,9 +41243,11 @@ var smokeCommandSpecs = [
41020
41243
  ];
41021
41244
 
41022
41245
  // src/command-specs/profile.js
41246
+ init_channel();
41023
41247
  init_errors();
41024
41248
  init_auth_recovery();
41025
41249
  init_profiles();
41250
+ import { spawn as spawn4 } from "node:child_process";
41026
41251
  function describeProfile(config, name, worktreeRuntime) {
41027
41252
  const entry = listProfiles(config).find((candidate) => candidate.name === name);
41028
41253
  if (worktreeRuntime?.profile === name) {
@@ -41099,6 +41324,33 @@ async function listHandler(ctx) {
41099
41324
  ]
41100
41325
  });
41101
41326
  }
41327
+ var SKILL_SYNC_API_BASE_PATTERN = /^https:\/\/api(?:-beta)?\.notis\.ai\/?$/;
41328
+ var RELINK_DROPPED_ENV = ["NOTIS_JWT", "NOTIS_API_BASE", "NOTIS_PROFILE", CHANNEL_SWITCH_ENV];
41329
+ function relinkSkillsInBackground(name, profile, {
41330
+ env = process.env,
41331
+ argv = process.argv,
41332
+ execPath = process.execPath,
41333
+ spawnImpl = spawn4
41334
+ } = {}) {
41335
+ if (env.NODE_ENV === "test" || env.NODE_TEST_CONTEXT || !argv[1]) return false;
41336
+ if (!profile?.oauth_access_token && !profile?.oauth_refresh_token) return false;
41337
+ if (!SKILL_SYNC_API_BASE_PATTERN.test(String(profile.api_base || ""))) return false;
41338
+ const childEnv = { ...env };
41339
+ for (const key2 of RELINK_DROPPED_ENV) delete childEnv[key2];
41340
+ try {
41341
+ const child = spawnImpl(
41342
+ execPath,
41343
+ [argv[1], "skills", "sync", "--json", "--profile", name],
41344
+ { detached: true, stdio: "ignore", env: childEnv }
41345
+ );
41346
+ child.on("error", () => {
41347
+ });
41348
+ child.unref();
41349
+ return true;
41350
+ } catch {
41351
+ return false;
41352
+ }
41353
+ }
41102
41354
  async function useHandler(ctx) {
41103
41355
  const requested = ctx.args.name;
41104
41356
  const config = loadConfig();
@@ -41114,6 +41366,7 @@ async function useHandler(ctx) {
41114
41366
  const worktreeOverride = Boolean(worktreeRuntime);
41115
41367
  const worktreeBlocked = Boolean(worktreeUnavailable);
41116
41368
  const authenticated = profileHasCredential(profile);
41369
+ if (authenticated) relinkSkillsInBackground(requested, profile);
41117
41370
  return ctx.output.emitSuccess({
41118
41371
  command: ctx.spec.command_path.join(" "),
41119
41372
  data: {
@@ -41242,7 +41495,7 @@ var profileCommandSpecs = [
41242
41495
  {
41243
41496
  command_path: ["profile", "use"],
41244
41497
  summary: "Switch the default profile without signing any profile out.",
41245
- when_to_use: "Use this to change which account and API subsequent commands target. Every other profile keeps its credential.",
41498
+ when_to_use: "Use this to change which account and API subsequent commands target. Every other profile keeps its credential. Its skills replace the previous default's in the agent folders (Claude Code, Codex, Cursor) straight away.",
41246
41499
  args_schema: {
41247
41500
  arguments: [{ token: "<name>", key: "name", description: "Profile to make active." }],
41248
41501
  options: []
@@ -41305,8 +41558,8 @@ init_errors();
41305
41558
  // src/runtime/git.js
41306
41559
  init_errors();
41307
41560
  import { spawnSync as spawnSync2 } from "node:child_process";
41308
- import { lstatSync as lstatSync2, readFileSync as readFileSync15 } from "node:fs";
41309
- import { basename as basename7, relative as relative4, resolve as resolve7, sep as sep2 } from "node:path";
41561
+ import { lstatSync as lstatSync2, readFileSync as readFileSync17 } from "node:fs";
41562
+ import { basename as basename7, relative as relative4, resolve as resolve8, sep as sep2 } from "node:path";
41310
41563
  var GIT_TIMEOUT_MS = 12e4;
41311
41564
  var MAX_SECRET_SCAN_BYTES = 1e6;
41312
41565
  var SAFE_ENV_TEMPLATES = /^\.env\.(?:example|sample|template)$/i;
@@ -41360,10 +41613,10 @@ function filesToAutoCommit(repository) {
41360
41613
  ])];
41361
41614
  }
41362
41615
  function sensitiveAutoCommitFiles(repository) {
41363
- const root = resolve7(repository.toplevel);
41616
+ const root = resolve8(repository.toplevel);
41364
41617
  const sensitive = [];
41365
41618
  for (const path3 of filesToAutoCommit(repository)) {
41366
- const absolute = resolve7(root, path3);
41619
+ const absolute = resolve8(root, path3);
41367
41620
  const insideRoot = relative4(root, absolute);
41368
41621
  if (insideRoot === ".." || insideRoot.startsWith(`..${sep2}`) || insideRoot === "") continue;
41369
41622
  const name = basename7(path3);
@@ -41374,7 +41627,7 @@ function sensitiveAutoCommitFiles(repository) {
41374
41627
  try {
41375
41628
  const stat2 = lstatSync2(absolute);
41376
41629
  if (!stat2.isFile() || stat2.size > MAX_SECRET_SCAN_BYTES) continue;
41377
- const content = readFileSync15(absolute, "utf8");
41630
+ const content = readFileSync17(absolute, "utf8");
41378
41631
  if (SENSITIVE_CONTENT.some((pattern) => pattern.test(content))) sensitive.push(path3);
41379
41632
  } catch {
41380
41633
  }
@@ -41772,98 +42025,98 @@ var handoverCommandSpecs = [
41772
42025
  init_profiles();
41773
42026
 
41774
42027
  // src/runtime/sync-skills.js
41775
- import { createHash as createHash9, randomUUID as randomUUID7 } from "node:crypto";
42028
+ import { createHash as createHash9, randomUUID as randomUUID8 } from "node:crypto";
41776
42029
  import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
41777
- import { homedir as homedir7 } from "node:os";
41778
- import { dirname as dirname14, join as join15 } from "node:path";
42030
+ import { homedir as homedir8 } from "node:os";
42031
+ import { dirname as dirname16, join as join17 } from "node:path";
41779
42032
 
41780
42033
  // src/runtime/base-skills.js
41781
42034
  import {
41782
42035
  cpSync as cpSync2,
41783
- existsSync as existsSync12,
42036
+ existsSync as existsSync13,
41784
42037
  lstatSync as lstatSync3,
41785
- mkdirSync as mkdirSync9,
42038
+ mkdirSync as mkdirSync11,
41786
42039
  readlinkSync,
41787
- renameSync as renameSync6,
42040
+ renameSync as renameSync8,
41788
42041
  rmSync as rmSync7,
41789
42042
  symlinkSync
41790
42043
  } from "node:fs";
41791
- import { homedir as homedir6 } from "node:os";
41792
- import { dirname as dirname13, join as join14, relative as relative5, resolve as resolve8 } from "node:path";
42044
+ import { homedir as homedir7 } from "node:os";
42045
+ import { dirname as dirname15, join as join16, relative as relative5, resolve as resolve9 } from "node:path";
41793
42046
  import { fileURLToPath as fileURLToPath9 } from "node:url";
41794
42047
  var BASE_SKILL_NAMES = Object.freeze([
41795
42048
  "notis-apps",
41796
42049
  "notis-query",
41797
42050
  "notis-cli"
41798
42051
  ]);
41799
- var HERE3 = dirname13(fileURLToPath9(import.meta.url));
42052
+ var HERE3 = dirname15(fileURLToPath9(import.meta.url));
41800
42053
  function resolveBundledBaseSkillsRoot({ resourcesPath = process.resourcesPath } = {}) {
41801
- const sourceCheckout = resolve8(HERE3, "../../../../server/skills");
41802
- const packaged = resolve8(HERE3, "../../dist/base-skills");
41803
- const desktopResource = resourcesPath ? join14(resourcesPath, "base-skills") : null;
42054
+ const sourceCheckout = resolve9(HERE3, "../../../../server/skills");
42055
+ const packaged = resolve9(HERE3, "../../dist/base-skills");
42056
+ const desktopResource = resourcesPath ? join16(resourcesPath, "base-skills") : null;
41804
42057
  const desktopPackagerRoot = resourcesPath || null;
41805
42058
  for (const candidate of [sourceCheckout, packaged, desktopResource, desktopPackagerRoot]) {
41806
- if (candidate && BASE_SKILL_NAMES.every((name) => existsSync12(join14(candidate, name, "SKILL.md")))) {
42059
+ if (candidate && BASE_SKILL_NAMES.every((name) => existsSync13(join16(candidate, name, "SKILL.md")))) {
41807
42060
  return candidate;
41808
42061
  }
41809
42062
  }
41810
42063
  return packaged;
41811
42064
  }
41812
- function getBaseSkillPaths({ home = homedir6(), userId = null } = {}) {
41813
- const notisRoot = join14(home, ".notis", "skills");
42065
+ function getBaseSkillPaths({ home = homedir7(), userId = null } = {}) {
42066
+ const notisRoot = join16(home, ".notis", "skills");
41814
42067
  const targetRoots = [
41815
- join14(home, ".agents", "skills"),
41816
- join14(home, ".codex", "skills"),
41817
- join14(home, ".cursor", "skills"),
41818
- join14(home, ".claude", "skills")
42068
+ join16(home, ".agents", "skills"),
42069
+ join16(home, ".codex", "skills"),
42070
+ join16(home, ".cursor", "skills"),
42071
+ join16(home, ".claude", "skills")
41819
42072
  ];
41820
42073
  if (userId) {
41821
- targetRoots.push(join14(notisRoot, "users", userId, "skills"));
42074
+ targetRoots.push(join16(notisRoot, "users", userId, "skills"));
41822
42075
  }
41823
42076
  return {
41824
- baseRoot: join14(notisRoot, "base"),
41825
- backupRoot: join14(notisRoot, "backups"),
42077
+ baseRoot: join16(notisRoot, "base"),
42078
+ backupRoot: join16(notisRoot, "backups"),
41826
42079
  targetRoots
41827
42080
  };
41828
42081
  }
41829
42082
  function sameLinkTarget(linkPath, expectedTarget) {
41830
42083
  try {
41831
42084
  if (!lstatSync3(linkPath).isSymbolicLink()) return false;
41832
- return resolve8(dirname13(linkPath), readlinkSync(linkPath)) === resolve8(expectedTarget);
42085
+ return resolve9(dirname15(linkPath), readlinkSync(linkPath)) === resolve9(expectedTarget);
41833
42086
  } catch {
41834
42087
  return false;
41835
42088
  }
41836
42089
  }
41837
42090
  function backupConflict(linkPath, backupRoot, targetLabel, skillName, now) {
41838
- const backupPath = join14(backupRoot, String(now), targetLabel, skillName);
41839
- mkdirSync9(dirname13(backupPath), { recursive: true, mode: 448 });
41840
- renameSync6(linkPath, backupPath);
42091
+ const backupPath = join16(backupRoot, String(now), targetLabel, skillName);
42092
+ mkdirSync11(dirname15(backupPath), { recursive: true, mode: 448 });
42093
+ renameSync8(linkPath, backupPath);
41841
42094
  return backupPath;
41842
42095
  }
41843
42096
  function replaceDirectory(source, destination) {
41844
- mkdirSync9(dirname13(destination), { recursive: true, mode: 448 });
42097
+ mkdirSync11(dirname15(destination), { recursive: true, mode: 448 });
41845
42098
  const temporary = `${destination}.tmp-${process.pid}-${Date.now()}`;
41846
42099
  const previous = `${destination}.previous-${process.pid}-${Date.now()}`;
41847
42100
  rmSync7(temporary, { recursive: true, force: true });
41848
42101
  cpSync2(source, temporary, { recursive: true });
41849
42102
  let movedPrevious = false;
41850
42103
  try {
41851
- if (existsSync12(destination)) {
41852
- renameSync6(destination, previous);
42104
+ if (existsSync13(destination)) {
42105
+ renameSync8(destination, previous);
41853
42106
  movedPrevious = true;
41854
42107
  }
41855
- renameSync6(temporary, destination);
42108
+ renameSync8(temporary, destination);
41856
42109
  if (movedPrevious) rmSync7(previous, { recursive: true, force: true });
41857
42110
  } catch (error) {
41858
42111
  rmSync7(temporary, { recursive: true, force: true });
41859
- if (movedPrevious && !existsSync12(destination) && existsSync12(previous)) {
41860
- renameSync6(previous, destination);
42112
+ if (movedPrevious && !existsSync13(destination) && existsSync13(previous)) {
42113
+ renameSync8(previous, destination);
41861
42114
  }
41862
42115
  throw error;
41863
42116
  }
41864
42117
  }
41865
42118
  function reconcileBaseSkills({
41866
- home = homedir6(),
42119
+ home = homedir7(),
41867
42120
  userId = null,
41868
42121
  sourceRoot = resolveBundledBaseSkillsRoot(),
41869
42122
  now = Date.now()
@@ -41877,24 +42130,24 @@ function reconcileBaseSkills({
41877
42130
  skills: [...BASE_SKILL_NAMES]
41878
42131
  };
41879
42132
  for (const name of BASE_SKILL_NAMES) {
41880
- const source = join14(sourceRoot, name);
41881
- if (!existsSync12(join14(source, "SKILL.md"))) {
42133
+ const source = join16(sourceRoot, name);
42134
+ if (!existsSync13(join16(source, "SKILL.md"))) {
41882
42135
  throw new Error(`Bundled base skill is missing: ${name}`);
41883
42136
  }
41884
- replaceDirectory(source, join14(paths.baseRoot, name));
42137
+ replaceDirectory(source, join16(paths.baseRoot, name));
41885
42138
  result.installed += 1;
41886
42139
  }
41887
42140
  for (const targetRoot of paths.targetRoots) {
41888
- mkdirSync9(targetRoot, { recursive: true, mode: 448 });
42141
+ mkdirSync11(targetRoot, { recursive: true, mode: 448 });
41889
42142
  const targetLabel = relative5(home, targetRoot).replaceAll("/", "_") || "home";
41890
42143
  for (const name of BASE_SKILL_NAMES) {
41891
- const skillTarget2 = join14(paths.baseRoot, name);
41892
- const linkPath = join14(targetRoot, name);
42144
+ const skillTarget2 = join16(paths.baseRoot, name);
42145
+ const linkPath = join16(targetRoot, name);
41893
42146
  if (sameLinkTarget(linkPath, skillTarget2)) {
41894
42147
  result.unchanged += 1;
41895
42148
  continue;
41896
42149
  }
41897
- if (existsSync12(linkPath) || (() => {
42150
+ if (existsSync13(linkPath) || (() => {
41898
42151
  try {
41899
42152
  lstatSync3(linkPath);
41900
42153
  return true;
@@ -41923,7 +42176,7 @@ var DEFAULT_LOCK_POLL_MS = 50;
41923
42176
  async function lockSnapshot(lockDirectory) {
41924
42177
  try {
41925
42178
  const [raw, metadata] = await Promise.all([
41926
- readFile(join15(lockDirectory, "owner"), "utf8").catch(() => ""),
42179
+ readFile(join17(lockDirectory, "owner"), "utf8").catch(() => ""),
41927
42180
  stat(lockDirectory)
41928
42181
  ]);
41929
42182
  let owner = {};
@@ -41956,14 +42209,14 @@ function processIsAlive2(pid) {
41956
42209
  }
41957
42210
  }
41958
42211
  function delay3(milliseconds) {
41959
- return new Promise((resolve18) => setTimeout(resolve18, milliseconds));
42212
+ return new Promise((resolve19) => setTimeout(resolve19, milliseconds));
41960
42213
  }
41961
42214
  async function quarantineStaleLock(lockDirectory, snapshot) {
41962
- const quarantineRoot = join15(dirname14(lockDirectory), ".stale-operation-locks");
42215
+ const quarantineRoot = join17(dirname16(lockDirectory), ".stale-operation-locks");
41963
42216
  const snapshotToken = createHash9("sha256").update(JSON.stringify(snapshot)).digest("hex");
41964
42217
  await mkdir(quarantineRoot, { recursive: true, mode: 448 });
41965
42218
  try {
41966
- await rename(lockDirectory, join15(quarantineRoot, snapshotToken));
42219
+ await rename(lockDirectory, join17(quarantineRoot, snapshotToken));
41967
42220
  return true;
41968
42221
  } catch (error) {
41969
42222
  if (["EEXIST", "ENOTEMPTY", "ENOENT"].includes(error?.code)) return false;
@@ -41971,16 +42224,16 @@ async function quarantineStaleLock(lockDirectory, snapshot) {
41971
42224
  }
41972
42225
  }
41973
42226
  async function writeLockOwnerAtomically(lockDirectory, owner) {
41974
- const temporaryOwnerPath = join15(lockDirectory, `.owner.${owner.id}.tmp`);
41975
- const ownerPath = join15(lockDirectory, "owner");
42227
+ const temporaryOwnerPath = join17(lockDirectory, `.owner.${owner.id}.tmp`);
42228
+ const ownerPath = join17(lockDirectory, "owner");
41976
42229
  await writeFile(temporaryOwnerPath, JSON.stringify(owner), { mode: 384 });
41977
42230
  await rename(temporaryOwnerPath, ownerPath);
41978
42231
  }
41979
42232
  async function releaseOwnedLock(lockDirectory, ownerId) {
41980
42233
  const owner = await lockSnapshot(lockDirectory);
41981
42234
  if (owner?.id !== ownerId) return;
41982
- const quarantineRoot = join15(dirname14(lockDirectory), ".stale-operation-locks");
41983
- const releasedDirectory = join15(quarantineRoot, `released.${ownerId}`);
42235
+ const quarantineRoot = join17(dirname16(lockDirectory), ".stale-operation-locks");
42236
+ const releasedDirectory = join17(quarantineRoot, `released.${ownerId}`);
41984
42237
  await mkdir(quarantineRoot, { recursive: true, mode: 448 });
41985
42238
  try {
41986
42239
  await rename(lockDirectory, releasedDirectory);
@@ -41991,16 +42244,16 @@ async function releaseOwnedLock(lockDirectory, ownerId) {
41991
42244
  await rm(releasedDirectory, { recursive: true, force: true });
41992
42245
  }
41993
42246
  async function withSkillSyncLock(callback, {
41994
- home = homedir7(),
42247
+ home = homedir8(),
41995
42248
  timeoutMs = DEFAULT_LOCK_TIMEOUT_MS,
41996
42249
  staleMs = DEFAULT_LOCK_STALE_MS,
41997
42250
  pollMs = DEFAULT_LOCK_POLL_MS,
41998
42251
  now = () => Date.now()
41999
42252
  } = {}) {
42000
- const lockDirectory = join15(home, ".notis", "skills", ".operation-lock");
42001
- const ownerId = `${process.pid}.${randomUUID7()}`;
42253
+ const lockDirectory = join17(home, ".notis", "skills", ".operation-lock");
42254
+ const ownerId = `${process.pid}.${randomUUID8()}`;
42002
42255
  const deadline = now() + timeoutMs;
42003
- await mkdir(dirname14(lockDirectory), { recursive: true, mode: 448 });
42256
+ await mkdir(dirname16(lockDirectory), { recursive: true, mode: 448 });
42004
42257
  for (; ; ) {
42005
42258
  try {
42006
42259
  await mkdir(lockDirectory, { mode: 448 });
@@ -42036,7 +42289,7 @@ async function withSkillSyncLock(callback, {
42036
42289
  let heartbeatInFlight = Promise.resolve();
42037
42290
  const refreshHeartbeat = async () => {
42038
42291
  if (heartbeatStopped) return;
42039
- const temporaryOwnerPath = join15(lockDirectory, `.owner.${ownerId}.tmp`);
42292
+ const temporaryOwnerPath = join17(lockDirectory, `.owner.${ownerId}.tmp`);
42040
42293
  await writeFile(
42041
42294
  temporaryOwnerPath,
42042
42295
  JSON.stringify({ id: ownerId, pid: process.pid, at: now() }),
@@ -42047,7 +42300,7 @@ async function withSkillSyncLock(callback, {
42047
42300
  await rm(temporaryOwnerPath, { force: true });
42048
42301
  return;
42049
42302
  }
42050
- await rename(temporaryOwnerPath, join15(lockDirectory, "owner"));
42303
+ await rename(temporaryOwnerPath, join17(lockDirectory, "owner"));
42051
42304
  };
42052
42305
  const heartbeat = setInterval(() => {
42053
42306
  heartbeatInFlight = heartbeatInFlight.then(refreshHeartbeat).catch(() => void 0);
@@ -42070,15 +42323,20 @@ async function reconcileAllSkills({
42070
42323
  home,
42071
42324
  runAccountSync,
42072
42325
  reconcileBase = reconcileBaseSkills,
42073
- lockOptions = {}
42326
+ lockOptions = {},
42327
+ linkAgentFolders = true
42074
42328
  }) {
42075
42329
  return withSkillSyncLock(async () => {
42076
- const base = reconcileBase({ userId, ...home ? { home } : {} });
42330
+ const base = linkAgentFolders ? reconcileBase({ userId, ...home ? { home } : {} }) : { skills: [], installed: 0, linked: 0, unchanged: 0, backups: [] };
42077
42331
  const account = await runAccountSync(
42078
42332
  serverUrl,
42079
42333
  jwt,
42080
42334
  {},
42081
- { honorSyncEnabled, ...home ? { syncHome: home } : {} }
42335
+ {
42336
+ honorSyncEnabled,
42337
+ ...home ? { syncHome: home } : {},
42338
+ ...linkAgentFolders ? {} : { linkAgentFolders: false }
42339
+ }
42082
42340
  );
42083
42341
  return {
42084
42342
  ...account,
@@ -42097,17 +42355,17 @@ init_oauth();
42097
42355
  init_profiles();
42098
42356
  import { spawnSync as spawnSync3 } from "node:child_process";
42099
42357
  import { createHash as createHash11 } from "node:crypto";
42100
- import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync16, renameSync as renameSync7, writeFileSync as writeFileSync9 } from "node:fs";
42101
- import { homedir as homedir8 } from "node:os";
42102
- import { dirname as dirname15, join as join17 } from "node:path";
42358
+ import { existsSync as existsSync14, mkdirSync as mkdirSync12, readFileSync as readFileSync18, renameSync as renameSync9, writeFileSync as writeFileSync11 } from "node:fs";
42359
+ import { homedir as homedir9 } from "node:os";
42360
+ import { dirname as dirname18, join as join19 } from "node:path";
42103
42361
  import { fileURLToPath as fileURLToPath10 } from "node:url";
42104
42362
  var SKILL_SYNC_SERVICE_LABEL = "ai.notis.skills-sync";
42105
42363
  var bundlePath = fileURLToPath10(new URL("../../dist/skill-sync-worker.mjs", import.meta.url));
42106
42364
  function atomicWrite2(target, value, mode = 384) {
42107
- mkdirSync10(dirname15(target), { recursive: true, mode: 448 });
42365
+ mkdirSync12(dirname18(target), { recursive: true, mode: 448 });
42108
42366
  const temporary = `${target}.${process.pid}.tmp`;
42109
- writeFileSync9(temporary, value, { mode });
42110
- renameSync7(temporary, target);
42367
+ writeFileSync11(temporary, value, { mode });
42368
+ renameSync9(temporary, target);
42111
42369
  }
42112
42370
  function xml(value) {
42113
42371
  return String(value).replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
@@ -42119,9 +42377,9 @@ async function maybeInstallSkillSyncService(runtime, {
42119
42377
  refresh
42120
42378
  } = {}) {
42121
42379
  if (process.platform !== "darwin" || runtime.credentialKind !== "oauth" || config.current_profile !== runtime.profileName || !["https://api.notis.ai", "https://api-beta.notis.ai"].includes(runtime.apiBase)) return;
42122
- const plist = join17(homedir8(), "Library", "LaunchAgents", `${SKILL_SYNC_SERVICE_LABEL}.plist`);
42123
- if (existsSync13(plist)) {
42124
- const saved = readFileSync16(plist, "utf8");
42380
+ const plist = join19(homedir9(), "Library", "LaunchAgents", `${SKILL_SYNC_SERVICE_LABEL}.plist`);
42381
+ if (existsSync14(plist)) {
42382
+ const saved = readFileSync18(plist, "utf8");
42125
42383
  if (runtime.oauthUserId && [runtime.profileName, runtime.apiBase, runtime.oauthUserId].every((value) => saved.includes(`<string>${xml(value)}</string>`))) return install(runtime);
42126
42384
  return;
42127
42385
  }
@@ -42142,7 +42400,7 @@ async function installSkillSyncService(runtime, options = {}) {
42142
42400
  );
42143
42401
  }
42144
42402
  async function installSkillSyncServiceLocked(runtime, {
42145
- home = homedir8(),
42403
+ home = homedir9(),
42146
42404
  platform = process.platform,
42147
42405
  nodePath = process.execPath,
42148
42406
  source = bundlePath,
@@ -42153,11 +42411,11 @@ async function installSkillSyncServiceLocked(runtime, {
42153
42411
  if (runtime.credentialKind !== "oauth" || runtime.envCredentialOverride || !isValidProfileName(runtime.profileName) || !["https://api.notis.ai", "https://api-beta.notis.ai"].includes(runtime.apiBase)) {
42154
42412
  return { status: "skipped_non_personal_profile" };
42155
42413
  }
42156
- const root = join17(home, ".notis", "skills", "service");
42157
- const bundle = readFileSync16(source);
42414
+ const root = join19(home, ".notis", "skills", "service");
42415
+ const bundle = readFileSync18(source);
42158
42416
  const digest = createHash11("sha256").update(bundle).digest("hex");
42159
- const installedBundle = join17(root, "runtime", digest, "worker.mjs");
42160
- if (!existsSync13(installedBundle) || !readFileSync16(installedBundle).equals(bundle)) atomicWrite2(installedBundle, bundle, 320);
42417
+ const installedBundle = join19(root, "runtime", digest, "worker.mjs");
42418
+ if (!existsSync14(installedBundle) || !readFileSync18(installedBundle).equals(bundle)) atomicWrite2(installedBundle, bundle, 320);
42161
42419
  const args = [nodePath, installedBundle, runtime.profileName, runtime.apiBase, runtime.oauthUserId];
42162
42420
  if (!runtime.oauthUserId) return { status: "skipped_missing_account" };
42163
42421
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
@@ -42170,10 +42428,10 @@ async function installSkillSyncServiceLocked(runtime, {
42170
42428
  <key>ProcessType</key><string>Background</string>
42171
42429
  </dict></plist>
42172
42430
  `;
42173
- const plistPath = join17(home, "Library", "LaunchAgents", `${SKILL_SYNC_SERVICE_LABEL}.plist`);
42431
+ const plistPath = join19(home, "Library", "LaunchAgents", `${SKILL_SYNC_SERVICE_LABEL}.plist`);
42174
42432
  const domain = `gui/${uid}`;
42175
42433
  const target = `${domain}/${SKILL_SYNC_SERVICE_LABEL}`;
42176
- const unchanged = existsSync13(plistPath) && readFileSync16(plistPath, "utf8") === plist;
42434
+ const unchanged = existsSync14(plistPath) && readFileSync18(plistPath, "utf8") === plist;
42177
42435
  const loaded = run("/bin/launchctl", ["print", target], { encoding: "utf8", timeout: 5e3 });
42178
42436
  if (unchanged && loaded.status === 0) return { status: "installed", intervalSeconds: 60, profile: runtime.profileName };
42179
42437
  if (loaded.status === 0) {
@@ -42185,15 +42443,15 @@ async function installSkillSyncServiceLocked(runtime, {
42185
42443
  for (let attempt = 0; attempt < 10; attempt++) {
42186
42444
  started = run("/bin/launchctl", ["bootstrap", domain, plistPath], { encoding: "utf8", timeout: 5e3 });
42187
42445
  if (started.status === 0) break;
42188
- await new Promise((resolve18) => setTimeout(resolve18, 100));
42446
+ await new Promise((resolve19) => setTimeout(resolve19, 100));
42189
42447
  }
42190
42448
  if (started?.status !== 0) throw new Error("Could not register automatic skill sync with macOS");
42191
42449
  return { status: "installed", intervalSeconds: 60, profile: runtime.profileName };
42192
42450
  }
42193
42451
 
42194
42452
  // src/command-specs/skills.js
42195
- import { readFileSync as readFileSync17 } from "node:fs";
42196
- import { resolve as resolve9 } from "node:path";
42453
+ import { readFileSync as readFileSync19 } from "node:fs";
42454
+ import { resolve as resolve10 } from "node:path";
42197
42455
  init_errors();
42198
42456
  async function nativeSkillAuthoring(ctx, body, path3 = "/portal_skills/native-authoring") {
42199
42457
  const spaceTarget = Boolean(body.target?.space_id || body.destination?.space_id || body.links);
@@ -42263,6 +42521,14 @@ function linkEntries(value, option, required, optional = []) {
42263
42521
  async function loadSkillSyncEngine() {
42264
42522
  return Promise.resolve().then(() => (init_skill_sync(), skill_sync_exports));
42265
42523
  }
42524
+ function cliDefaultOwnsAgentFolders(runtime) {
42525
+ if (runtime.profileSource !== "explicit" || !runtime.profileName) return true;
42526
+ try {
42527
+ return runtime.profileName === getCurrentProfileName(loadConfig());
42528
+ } catch {
42529
+ return true;
42530
+ }
42531
+ }
42266
42532
  async function syncSkillsHandler(ctx, {
42267
42533
  refresh = ensureFreshOAuthCredential,
42268
42534
  loadEngine = loadSkillSyncEngine,
@@ -42278,6 +42544,9 @@ async function syncSkillsHandler(ctx, {
42278
42544
  jwt: ctx.runtime.jwt,
42279
42545
  userId: settings.user_id || userId,
42280
42546
  honorSyncEnabled: Boolean(ctx.options.electronRepeat),
42547
+ // Only the CLI default's skills go into the agent folders; another profile
42548
+ // syncs its own folder.
42549
+ linkAgentFolders: cliDefaultOwnsAgentFolders(ctx.runtime),
42281
42550
  runAccountSync: (serverUrl, jwt, dependencies, options) => runSkillSync2(
42282
42551
  serverUrl,
42283
42552
  jwt,
@@ -42358,7 +42627,7 @@ var skillsCommandSpecs = [
42358
42627
  require_auth: true,
42359
42628
  backend_call: { type: "http", path: "/portal_skills/native-create" },
42360
42629
  handler(ctx) {
42361
- const payload = parseJson(readFileSync17(resolve9(ctx.args.file), "utf8"), "Skill creation file");
42630
+ const payload = parseJson(readFileSync19(resolve10(ctx.args.file), "utf8"), "Skill creation file");
42362
42631
  if (!payload || typeof payload !== "object" || Array.isArray(payload) || Object.keys(payload).some((key2) => !["destination", "name", "description", "skill_md", "files"].includes(key2))) {
42363
42632
  throw usageError("Provide a name, complete instructions or files, and an optional current destination; never override ownership.");
42364
42633
  }
@@ -42404,7 +42673,7 @@ var skillsCommandSpecs = [
42404
42673
  require_auth: true,
42405
42674
  backend_call: { type: "http", path: "/portal_skills/native-settings" },
42406
42675
  handler(ctx) {
42407
- const payload = parseJson(readFileSync17(resolve9(ctx.args.file), "utf8"), "Skill settings file");
42676
+ const payload = parseJson(readFileSync19(resolve10(ctx.args.file), "utf8"), "Skill settings file");
42408
42677
  if (!payload || typeof payload !== "object" || Array.isArray(payload) || Object.keys(payload).sort().join(",") !== "patch,revision,target" || !payload.target || Object.keys(payload.target).sort().join(",") !== "access_revision,skill_id") {
42409
42678
  throw usageError("Use a current standalone target, settings revision and personal settings patch.");
42410
42679
  }
@@ -42456,7 +42725,7 @@ var skillsCommandSpecs = [
42456
42725
  require_auth: true,
42457
42726
  backend_call: { type: "http", path: "/portal_skills/native-authoring" },
42458
42727
  handler(ctx) {
42459
- const payload = parseJson(readFileSync17(resolve9(ctx.args.file), "utf8"), "Skill edit file");
42728
+ const payload = parseJson(readFileSync19(resolve10(ctx.args.file), "utf8"), "Skill edit file");
42460
42729
  if (!payload || typeof payload !== "object" || Array.isArray(payload) || Object.keys(payload).some((key2) => !["target", "version", "skill_md", "files", "name", "description", "links"].includes(key2))) {
42461
42730
  throw usageError("Use an exact target, version, skill_md or files, and optional links; never override ownership.");
42462
42731
  }
@@ -42529,8 +42798,8 @@ var skillsCommandSpecs = [
42529
42798
  ];
42530
42799
 
42531
42800
  // src/runtime/space-collection-scaffold.js
42532
- import { writeFileSync as writeFileSync10, mkdirSync as mkdirSync11 } from "node:fs";
42533
- import { join as join18 } from "node:path";
42801
+ import { writeFileSync as writeFileSync12, mkdirSync as mkdirSync13 } from "node:fs";
42802
+ import { join as join20 } from "node:path";
42534
42803
 
42535
42804
  // src/runtime/space-view-manifest.js
42536
42805
  init_errors();
@@ -42838,8 +43107,8 @@ async function scaffoldSpaceCollection({ projectDir, name, databaseKey, path: pa
42838
43107
  if (typeof name !== "string" || !name.trim() || typeof titleProperty !== "string" || !titleProperty.trim()) throw usageError("Choose a Space name and title property.");
42839
43108
  validateViewPath(path3);
42840
43109
  await scaffoldProject({ projectDir, appName: name });
42841
- mkdirSync11(join18(projectDir, "spaces", "collection"), { recursive: true });
42842
- writeFileSync10(join18(projectDir, "notis.config.ts"), `import { defineSpaces } from '@notis/sdk/config';
43110
+ mkdirSync13(join20(projectDir, "spaces", "collection"), { recursive: true });
43111
+ writeFileSync12(join20(projectDir, "notis.config.ts"), `import { defineSpaces } from '@notis/sdk/config';
42843
43112
  export default defineSpaces({ spaces: { collection: { definition: 'spaces/collection/space.config.ts' } } });
42844
43113
  `);
42845
43114
  const definition = {
@@ -42863,11 +43132,11 @@ export default defineSpaces({ spaces: { collection: { definition: 'spaces/collec
42863
43132
  properties: { request: { type: "object" } }
42864
43133
  }, arguments: { database_id: { $asset: "items" }, request: { $input: "request" } } } }
42865
43134
  };
42866
- writeFileSync10(join18(projectDir, "spaces/collection/space.config.ts"), `import { defineSpace } from '@notis/sdk/config';
43135
+ writeFileSync12(join20(projectDir, "spaces/collection/space.config.ts"), `import { defineSpace } from '@notis/sdk/config';
42867
43136
  export default defineSpace(${JSON.stringify(definition, null, 2)});
42868
43137
  `);
42869
- writeFileSync10(join18(projectDir, "spaces/collection/view.tsx"), COLLECTION_VIEW);
42870
- writeFileSync10(join18(projectDir, "spaces/collection/verification.json"), JSON.stringify({
43138
+ writeFileSync12(join20(projectDir, "spaces/collection/view.tsx"), COLLECTION_VIEW);
43139
+ writeFileSync12(join20(projectDir, "spaces/collection/verification.json"), JSON.stringify({
42871
43140
  actions: {},
42872
43141
  shown: { items: [{ params: {}, result: { rows: [], has_more: false, schema_revision: 1 } }] }
42873
43142
  }, null, 2) + "\n");
@@ -42907,13 +43176,13 @@ export default function CollectionView() {
42907
43176
  `;
42908
43177
 
42909
43178
  // src/runtime/space-platform.js
42910
- import { existsSync as existsSync14, mkdirSync as mkdirSync12, readFileSync as readFileSync18, symlinkSync as symlinkSync2, writeFileSync as writeFileSync11 } from "node:fs";
42911
- import { dirname as dirname17, join as join20, relative as relative7, resolve as resolve11 } from "node:path";
43179
+ import { existsSync as existsSync15, mkdirSync as mkdirSync14, readFileSync as readFileSync20, symlinkSync as symlinkSync2, writeFileSync as writeFileSync13 } from "node:fs";
43180
+ import { dirname as dirname20, join as join22, relative as relative7, resolve as resolve12 } from "node:path";
42912
43181
 
42913
43182
  // src/runtime/space-source.js
42914
43183
  import { createRequire as createRequire3 } from "node:module";
42915
43184
  import { realpathSync as realpathSync2 } from "node:fs";
42916
- import { dirname as dirname16, extname as extname2, join as join19, relative as relative6, resolve as resolve10, sep as sep3 } from "node:path";
43185
+ import { dirname as dirname19, extname as extname2, join as join21, relative as relative6, resolve as resolve11, sep as sep3 } from "node:path";
42917
43186
  init_errors();
42918
43187
  var CONFIG_FIELDS = /* @__PURE__ */ new Set(["name", "description", "icon", "accent", "entry", "layout", "readableContext", "resources", "actions", "navigation", "viewerReads", "cloudComputer", "collection", "sourceIncludes", "verificationFixtures", ...VIEW_DEFINITION_FIELDS]);
42919
43188
  var VIEWER_READ_FAMILIES = Object.freeze(["databases", "skills"]);
@@ -42934,25 +43203,25 @@ var ROOT_CONFIGS = [
42934
43203
  "tailwind.config.mjs"
42935
43204
  ];
42936
43205
  function sourceCompiler(projectDir, files) {
42937
- const require3 = createRequire3(join19(projectDir, "package.json"));
43206
+ const require3 = createRequire3(join21(projectDir, "package.json"));
42938
43207
  let ts;
42939
43208
  try {
42940
43209
  ts = require3("typescript");
42941
43210
  } catch {
42942
43211
  throw usageError("Install this workspace's TypeScript dependency before packaging Space source.");
42943
43212
  }
42944
- const codeFiles = Object.keys(files).filter((path3) => /\.[cm]?[jt]sx?$/.test(path3)).map((path3) => join19(projectDir, path3));
43213
+ const codeFiles = Object.keys(files).filter((path3) => /\.[cm]?[jt]sx?$/.test(path3)).map((path3) => join21(projectDir, path3));
42945
43214
  let source, checker, syntax, close = () => {
42946
43215
  };
42947
43216
  if (typeof ts.createProgram === "function") {
42948
43217
  let options = { moduleResolution: ts.ModuleResolutionKind.Bundler, allowJs: true };
42949
43218
  if (files["tsconfig.json"]) {
42950
- const config = ts.readConfigFile(join19(projectDir, "tsconfig.json"), ts.sys.readFile);
43219
+ const config = ts.readConfigFile(join21(projectDir, "tsconfig.json"), ts.sys.readFile);
42951
43220
  if (config.error) throw usageError("Fix tsconfig.json before building this Space.");
42952
43221
  options = { ...options, ...ts.parseJsonConfigFileContent(config.config, ts.sys, projectDir).options, allowJs: true };
42953
43222
  }
42954
43223
  const program3 = ts.createProgram(codeFiles, options), projectChecker = program3.getTypeChecker();
42955
- source = (file) => program3.getSourceFile(join19(projectDir, file));
43224
+ source = (file) => program3.getSourceFile(join21(projectDir, file));
42956
43225
  checker = () => projectChecker;
42957
43226
  syntax = ts.SyntaxKind;
42958
43227
  } else {
@@ -42961,8 +43230,8 @@ function sourceCompiler(projectDir, files) {
42961
43230
  const api = new API({ cwd: projectDir });
42962
43231
  try {
42963
43232
  const snapshot = api.updateSnapshot({ openFiles: codeFiles });
42964
- const project = (file) => snapshot.getDefaultProjectForFile(join19(projectDir, file));
42965
- source = (file) => project(file)?.program.getSourceFile(join19(projectDir, file));
43233
+ const project = (file) => snapshot.getDefaultProjectForFile(join21(projectDir, file));
43234
+ source = (file) => project(file)?.program.getSourceFile(join21(projectDir, file));
42966
43235
  checker = (file) => project(file)?.checker;
42967
43236
  close = () => {
42968
43237
  try {
@@ -43036,7 +43305,7 @@ async function loadSelectedSpace(projectDir, selectedKey) {
43036
43305
  }
43037
43306
  const resolveDefinitionPath = (value) => {
43038
43307
  if (typeof value !== "string" || !value || value.startsWith("/") || value.includes("\\") || value.includes("\0")) throw usageError("Use a workspace-relative source path.");
43039
- return localPath(relative6(projectDir, resolve10(projectDir, dirname16(definitionPath), value)).split(sep3).join("/"));
43308
+ return localPath(relative6(projectDir, resolve11(projectDir, dirname19(definitionPath), value)).split(sep3).join("/"));
43040
43309
  };
43041
43310
  const entry = definition.entry ? resolveDefinitionPath(definition.entry) : null;
43042
43311
  const layout = definition.layout ? resolveDefinitionPath(definition.layout) : null;
@@ -43124,7 +43393,7 @@ function collectSelectedSpaceSource(projectDir, selection, { buildInputs = [] }
43124
43393
  if (!specifier.startsWith(".")) return;
43125
43394
  }
43126
43395
  const raw = specifier.split(/[?#]/, 1)[0];
43127
- const path3 = relative6(projectDir, resolve10(dirname16(join19(projectDir, importer)), raw)).split(sep3).join("/");
43396
+ const path3 = relative6(projectDir, resolve11(dirname19(join21(projectDir, importer)), raw)).split(sep3).join("/");
43128
43397
  const candidate = [path3, ...[".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".d.ts", "/index.ts", "/index.tsx", "/index.js"].map((suffix) => path3 + suffix)].find((name) => Object.hasOwn(files, name));
43129
43398
  if (candidate) {
43130
43399
  add(candidate);
@@ -43230,25 +43499,25 @@ function generateSpaceManifest(selection) {
43230
43499
  function prepareSelectedArtifact(projectDir, selection) {
43231
43500
  validateProjectBoundary(projectDir);
43232
43501
  validateProjectDesign(projectDir);
43233
- const entryPath = join20(projectDir, ".notis/_entry.tsx");
43234
- const manifestPath = join20(projectDir, ".notis/output/manifest.json");
43235
- mkdirSync12(dirname17(entryPath), { recursive: true });
43236
- mkdirSync12(dirname17(manifestPath), { recursive: true });
43502
+ const entryPath = join22(projectDir, ".notis/_entry.tsx");
43503
+ const manifestPath = join22(projectDir, ".notis/output/manifest.json");
43504
+ mkdirSync14(dirname20(entryPath), { recursive: true });
43505
+ mkdirSync14(dirname20(manifestPath), { recursive: true });
43237
43506
  if (selection.entry) {
43238
- const reference = (path3) => JSON.stringify("./" + relative7(dirname17(entryPath), join20(projectDir, path3)).replaceAll("\\", "/"));
43507
+ const reference = (path3) => JSON.stringify("./" + relative7(dirname20(entryPath), join22(projectDir, path3)).replaceAll("\\", "/"));
43239
43508
  const lines = [`export { default as SpaceView } from ${reference(selection.entry)};`];
43240
43509
  if (selection.layout) lines.push(`export { default as __AppShell } from ${reference(selection.layout)};`);
43241
43510
  if (selection.markdown) lines.push(`export { default as SpaceMarkdown } from ${reference(selection.markdown)};`);
43242
- writeFileSync11(entryPath, lines.join("\n") + "\n");
43511
+ writeFileSync13(entryPath, lines.join("\n") + "\n");
43243
43512
  }
43244
- writeFileSync11(manifestPath, JSON.stringify(generateSpaceManifest(selection), null, 2) + "\n");
43513
+ writeFileSync13(manifestPath, JSON.stringify(generateSpaceManifest(selection), null, 2) + "\n");
43245
43514
  }
43246
43515
  function finalizeSelectedArtifact(projectDir) {
43247
- const manifestPath = join20(projectDir, ".notis/output/manifest.json");
43248
- const manifest = JSON.parse(readFileSync18(manifestPath, "utf8"));
43249
- if (manifest.bundle?.css && !existsSync14(join20(projectDir, ".notis/output", manifest.bundle.css))) {
43516
+ const manifestPath = join22(projectDir, ".notis/output/manifest.json");
43517
+ const manifest = JSON.parse(readFileSync20(manifestPath, "utf8"));
43518
+ if (manifest.bundle?.css && !existsSync15(join22(projectDir, ".notis/output", manifest.bundle.css))) {
43250
43519
  delete manifest.bundle.css;
43251
- writeFileSync11(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
43520
+ writeFileSync13(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
43252
43521
  }
43253
43522
  }
43254
43523
  async function buildSpaceRelease(projectDir, selectedKey, { stdio = "inherit", refreshSdk = true, runBuild } = {}) {
@@ -43260,8 +43529,8 @@ async function buildSpaceRelease(projectDir, selectedKey, { stdio = "inherit", r
43260
43529
  const staging = freezeSourceWorkspace(projectDir, sourceFiles);
43261
43530
  let release;
43262
43531
  try {
43263
- if (existsSync14(join20(projectDir, "node_modules"))) {
43264
- symlinkSync2(join20(projectDir, "node_modules"), join20(staging.projectDir, "node_modules"), process.platform === "win32" ? "junction" : "dir");
43532
+ if (existsSync15(join22(projectDir, "node_modules"))) {
43533
+ symlinkSync2(join22(projectDir, "node_modules"), join22(staging.projectDir, "node_modules"), process.platform === "win32" ? "junction" : "dir");
43265
43534
  }
43266
43535
  const frozenSelection = await loadSelectedSpace(staging.projectDir, selectedKey);
43267
43536
  await buildArtifact(staging.projectDir, {
@@ -43315,18 +43584,18 @@ async function prepareSpaceRelease(projectDir, selectedKey) {
43315
43584
 
43316
43585
  // src/runtime/space-verification.js
43317
43586
  import { createHash as createHash13 } from "node:crypto";
43318
- import { existsSync as existsSync15, readFileSync as readFileSync19 } from "node:fs";
43587
+ import { existsSync as existsSync16, readFileSync as readFileSync21 } from "node:fs";
43319
43588
  import { fileURLToPath as fileURLToPath12 } from "node:url";
43320
43589
 
43321
43590
  // src/runtime/space-test-server.js
43322
43591
  import { createHash as createHash12 } from "node:crypto";
43323
43592
  var import__ = __toESM(require__(), 1);
43324
43593
  var import_ajv_formats = __toESM(require_dist(), 1);
43325
- import { dirname as dirname18, join as join21, resolve as resolve12 } from "node:path";
43594
+ import { dirname as dirname21, join as join23, resolve as resolve13 } from "node:path";
43326
43595
  import { isDeepStrictEqual } from "node:util";
43327
43596
  import { fileURLToPath as fileURLToPath11 } from "node:url";
43328
43597
  init_errors();
43329
- var ROOT = resolve12(dirname18(fileURLToPath11(import.meta.url)), "../..");
43598
+ var ROOT = resolve13(dirname21(fileURLToPath11(import.meta.url)), "../..");
43330
43599
  function object(value) {
43331
43600
  return value && typeof value === "object" && !Array.isArray(value);
43332
43601
  }
@@ -43620,11 +43889,11 @@ async function loadSpaceVerificationRenderer() {
43620
43889
  const candidates = [new URL("../../dist/view-renderer/", import.meta.url), new URL("../../../view-renderer/", import.meta.url)];
43621
43890
  for (const root of candidates) {
43622
43891
  const entry = new URL("src/index.js", root);
43623
- if (!existsSync15(fileURLToPath12(entry))) continue;
43892
+ if (!existsSync16(fileURLToPath12(entry))) continue;
43624
43893
  const digest = createHash13("sha256");
43625
43894
  for (const file of ["src/renderer.js", "src/dom.js", "src/pool.js", "dist/host.js", "dist/host.css", "dist/theme.css"]) {
43626
43895
  digest.update(file);
43627
- digest.update(readFileSync19(new URL(file, root)));
43896
+ digest.update(readFileSync21(new URL(file, root)));
43628
43897
  }
43629
43898
  return { ...await import(entry.href), rendererDigest: digest.digest("hex") };
43630
43899
  }
@@ -43749,14 +44018,14 @@ async function verifySpaceRelease(release, {
43749
44018
  // src/runtime/space-database-structures.js
43750
44019
  var import_parser = __toESM(require_lib(), 1);
43751
44020
  init_errors();
43752
- import { existsSync as existsSync16, readFileSync as readFileSync20, realpathSync as realpathSync3, writeFileSync as writeFileSync12 } from "node:fs";
43753
- import { dirname as dirname19, join as join22, relative as relative8, resolve as resolve13, sep as sep4 } from "node:path";
44021
+ import { existsSync as existsSync17, readFileSync as readFileSync22, realpathSync as realpathSync3, writeFileSync as writeFileSync14 } from "node:fs";
44022
+ import { dirname as dirname22, join as join24, relative as relative8, resolve as resolve14, sep as sep4 } from "node:path";
43754
44023
  var nameOf = (node) => node?.type === "Identifier" ? node.name : node?.type === "StringLiteral" ? node.value : null;
43755
44024
  function refreshSpaceAuthoring(projectDir, localKey, { databaseStructures, authoringOverrides } = {}) {
43756
44025
  let rewritten = /* @__PURE__ */ new Map();
43757
44026
  if (Object.keys(databaseStructures || {}).length) rewritten = planSpaceAuthoring(projectDir, localKey, { databaseStructures }, rewritten);
43758
44027
  if (authoringOverrides) rewritten = planSpaceAuthoring(projectDir, localKey, { authoringOverrides }, rewritten);
43759
- for (const [file, source] of rewritten) writeFileSync12(file, source);
44028
+ for (const [file, source] of rewritten) writeFileSync14(file, source);
43760
44029
  return [...rewritten.keys()].map((file) => relative8(realpathSync3(projectDir), file).split(sep4).join("/"));
43761
44030
  }
43762
44031
  function planSpaceAuthoring(projectDir, localKey, { databaseStructures: structures, authoringOverrides: overrides }, staged) {
@@ -43766,7 +44035,7 @@ function planSpaceAuthoring(projectDir, localKey, { databaseStructures: structur
43766
44035
  file = realpathSync3(file);
43767
44036
  if (!file.startsWith(root + sep4) || file.includes(`${sep4}node_modules${sep4}`)) throw fail();
43768
44037
  if (modules.has(file)) return modules.get(file);
43769
- const source = staged.get(file) ?? readFileSync20(file, "utf8");
44038
+ const source = staged.get(file) ?? readFileSync22(file, "utf8");
43770
44039
  const ast = (0, import_parser.parse)(source, { sourceType: "module", plugins: ["typescript", "jsx"] });
43771
44040
  const unit2 = { file, source, ast, bindings: /* @__PURE__ */ new Map(), exports: /* @__PURE__ */ new Map() };
43772
44041
  modules.set(file, unit2);
@@ -43794,8 +44063,8 @@ function planSpaceAuthoring(projectDir, localKey, { databaseStructures: structur
43794
44063
  }
43795
44064
  function imported(reference) {
43796
44065
  if (!reference.from?.startsWith(".")) throw fail();
43797
- const base = resolve13(dirname19(reference.unit.file), reference.from);
43798
- const file = ["", ".ts", ".tsx", ".js", ".mjs", "/index.ts", "/index.js"].map((suffix) => base + suffix).find(existsSync16);
44066
+ const base = resolve14(dirname22(reference.unit.file), reference.from);
44067
+ const file = ["", ".ts", ".tsx", ".js", ".mjs", "/index.ts", "/index.js"].map((suffix) => base + suffix).find(existsSync17);
43799
44068
  if (!file) throw fail();
43800
44069
  return load(file);
43801
44070
  }
@@ -43840,12 +44109,12 @@ function planSpaceAuthoring(projectDir, localKey, { databaseStructures: structur
43840
44109
  if (value.node?.type !== "StringLiteral") throw fail();
43841
44110
  return value.node.value;
43842
44111
  }
43843
- const indexFile = ["notis.config.ts", "notis.config.js", "notis.config.mjs"].map((file) => join22(root, file)).find(existsSync16);
44112
+ const indexFile = ["notis.config.ts", "notis.config.js", "notis.config.mjs"].map((file) => join24(root, file)).find(existsSync17);
43844
44113
  if (!indexFile) throw fail();
43845
44114
  const index = load(indexFile);
43846
44115
  const workspace = index.exports.get("default");
43847
44116
  const definition = scalar(property(property(property(workspace, "spaces"), localKey), "definition"));
43848
- const unit = load(resolve13(root, definition));
44117
+ const unit = load(resolve14(root, definition));
43849
44118
  const resources = property(unit.exports.get("default"), "resources");
43850
44119
  const edits = /* @__PURE__ */ new Map();
43851
44120
  for (const [alias, structure] of Object.entries(structures || {})) {
@@ -43964,9 +44233,9 @@ function planSpaceAuthoring(projectDir, localKey, { databaseStructures: structur
43964
44233
 
43965
44234
  // src/runtime/space-lock.js
43966
44235
  import { createHash as createHash14 } from "node:crypto";
43967
- import { existsSync as existsSync17, lstatSync as lstatSync4, mkdirSync as mkdirSync13, readdirSync as readdirSync7, readFileSync as readFileSync21, renameSync as renameSync8, rmSync as rmSync8, writeFileSync as writeFileSync13 } from "node:fs";
43968
- import { randomUUID as randomUUID8 } from "node:crypto";
43969
- import { dirname as dirname20, join as join23, resolve as resolve14 } from "node:path";
44236
+ import { existsSync as existsSync18, lstatSync as lstatSync4, mkdirSync as mkdirSync15, readdirSync as readdirSync7, readFileSync as readFileSync23, renameSync as renameSync10, rmSync as rmSync8, writeFileSync as writeFileSync15 } from "node:fs";
44237
+ import { randomUUID as randomUUID9 } from "node:crypto";
44238
+ import { dirname as dirname23, join as join25, resolve as resolve15 } from "node:path";
43970
44239
  init_errors();
43971
44240
  var SPACE_LOCK_FILE = "space-lock.json";
43972
44241
  var RESOURCES_FILE = "resources.json";
@@ -44020,12 +44289,12 @@ function writeSpaceLock(projectDir, lock) {
44020
44289
  return writeSpaceStateFile(projectDir, SPACE_LOCK_FILE, lock);
44021
44290
  }
44022
44291
  function readResourceList(projectDir) {
44023
- const path3 = join23(resolve14(projectDir), RESOURCES_FILE);
44024
- if (!existsSync17(path3)) return null;
44292
+ const path3 = join25(resolve15(projectDir), RESOURCES_FILE);
44293
+ if (!existsSync18(path3)) return null;
44025
44294
  if (lstatSync4(path3).isSymbolicLink()) throw usageError(`${RESOURCES_FILE} must be a regular file.`);
44026
44295
  let parsed;
44027
44296
  try {
44028
- parsed = JSON.parse(readFileSync21(path3, "utf8"));
44297
+ parsed = JSON.parse(readFileSync23(path3, "utf8"));
44029
44298
  } catch {
44030
44299
  throw usageError(`${RESOURCES_FILE} must be valid JSON.`);
44031
44300
  }
@@ -44042,11 +44311,11 @@ function readResourceList(projectDir) {
44042
44311
  });
44043
44312
  }
44044
44313
  function writeResourceList(projectDir, entries) {
44045
- const root = resolve14(projectDir);
44046
- const temporary = join23(root, `.${RESOURCES_FILE}-${randomUUID8()}`);
44314
+ const root = resolve15(projectDir);
44315
+ const temporary = join25(root, `.${RESOURCES_FILE}-${randomUUID9()}`);
44047
44316
  try {
44048
- writeFileSync13(temporary, JSON.stringify(entries, null, 2) + "\n", { flag: "wx" });
44049
- renameSync8(temporary, join23(root, RESOURCES_FILE));
44317
+ writeFileSync15(temporary, JSON.stringify(entries, null, 2) + "\n", { flag: "wx" });
44318
+ renameSync10(temporary, join25(root, RESOURCES_FILE));
44050
44319
  } finally {
44051
44320
  rmSync8(temporary, { force: true });
44052
44321
  }
@@ -44055,19 +44324,19 @@ function walkSkillFolder(directory, prefix, files) {
44055
44324
  for (const entry of readdirSync7(directory, { withFileTypes: true })) {
44056
44325
  if (entry.isSymbolicLink() || excluded(entry.name)) continue;
44057
44326
  const path3 = prefix ? `${prefix}/${entry.name}` : entry.name;
44058
- if (entry.isDirectory()) walkSkillFolder(join23(directory, entry.name), path3, files);
44059
- else if (entry.isFile()) files[path3] = readFileSync21(join23(directory, entry.name)).toString("base64");
44327
+ if (entry.isDirectory()) walkSkillFolder(join25(directory, entry.name), path3, files);
44328
+ else if (entry.isFile()) files[path3] = readFileSync23(join25(directory, entry.name)).toString("base64");
44060
44329
  }
44061
44330
  }
44062
44331
  function collectSkillFolders(projectDir) {
44063
- const root = join23(resolve14(projectDir), SKILLS_DIR);
44332
+ const root = join25(resolve15(projectDir), SKILLS_DIR);
44064
44333
  const folders = {};
44065
- if (!existsSync17(root) || lstatSync4(root).isSymbolicLink() || !lstatSync4(root).isDirectory()) return folders;
44334
+ if (!existsSync18(root) || lstatSync4(root).isSymbolicLink() || !lstatSync4(root).isDirectory()) return folders;
44066
44335
  for (const entry of readdirSync7(root, { withFileTypes: true })) {
44067
44336
  if (entry.isSymbolicLink() || !entry.isDirectory()) continue;
44068
44337
  if (!ALIAS.test(entry.name)) throw usageError(`${SKILLS_DIR}/${entry.name}: name the folder with the Skill alias (lowercase letters, digits, - or _).`);
44069
44338
  const files = {};
44070
- walkSkillFolder(join23(root, entry.name), "", files);
44339
+ walkSkillFolder(join25(root, entry.name), "", files);
44071
44340
  if (!files["SKILL.md"]) throw usageError(`${SKILLS_DIR}/${entry.name} needs a SKILL.md.`);
44072
44341
  folders[entry.name] = { files, digest: appFilesDigest(files) };
44073
44342
  }
@@ -44078,7 +44347,7 @@ function skillFolderFiles(files) {
44078
44347
  }
44079
44348
  function writeSkillFolder(projectDir, alias, files, { sourceSnapshot } = {}) {
44080
44349
  if (!ALIAS.test(alias)) throw usageError(`Unsafe Skill alias: ${alias}`);
44081
- const root = join23(resolve14(projectDir), SKILLS_DIR, alias);
44350
+ const root = join25(resolve15(projectDir), SKILLS_DIR, alias);
44082
44351
  const entries = Object.entries(files || {}).map(([path3, encoded]) => {
44083
44352
  safeRelativePath(path3, `Skill ${alias}`);
44084
44353
  return [path3, Buffer.from(encoded, "base64")];
@@ -44087,13 +44356,13 @@ function writeSkillFolder(projectDir, alias, files, { sourceSnapshot } = {}) {
44087
44356
  const changed = () => usageError(`${SKILLS_DIR}/${alias} changed while pulling its current Skill. Keep these local files and pull into a new directory.`);
44088
44357
  const readSnapshot = () => {
44089
44358
  const current = {};
44090
- if (!existsSync17(root) || lstatSync4(root).isSymbolicLink() || !lstatSync4(root).isDirectory() || lstatSync4(dirname20(root)).isSymbolicLink()) throw changed();
44359
+ if (!existsSync18(root) || lstatSync4(root).isSymbolicLink() || !lstatSync4(root).isDirectory() || lstatSync4(dirname23(root)).isSymbolicLink()) throw changed();
44091
44360
  const walk = (directory, prefix = "") => {
44092
44361
  for (const entry of readdirSync7(directory, { withFileTypes: true })) {
44093
44362
  if (entry.isSymbolicLink() || excluded(entry.name)) throw changed();
44094
44363
  const path3 = prefix + entry.name;
44095
- if (entry.isDirectory()) walk(join23(directory, entry.name), path3 + "/");
44096
- else if (entry.isFile()) current[path3] = readFileSync21(join23(directory, entry.name)).toString("base64");
44364
+ if (entry.isDirectory()) walk(join25(directory, entry.name), path3 + "/");
44365
+ else if (entry.isFile()) current[path3] = readFileSync23(join25(directory, entry.name)).toString("base64");
44097
44366
  else throw changed();
44098
44367
  }
44099
44368
  };
@@ -44103,23 +44372,23 @@ function writeSkillFolder(projectDir, alias, files, { sourceSnapshot } = {}) {
44103
44372
  const expected = appFilesDigest(sourceSnapshot);
44104
44373
  if (appFilesDigest(readSnapshot()) !== expected) throw changed();
44105
44374
  if (appFilesDigest(files) === expected) return;
44106
- const staging = join23(resolve14(projectDir), ".notis", `skill-pull-${randomUUID8()}`);
44375
+ const staging = join25(resolve15(projectDir), ".notis", `skill-pull-${randomUUID9()}`);
44107
44376
  const backup = `${staging}-previous`;
44108
- mkdirSync13(staging, { recursive: true });
44377
+ mkdirSync15(staging, { recursive: true });
44109
44378
  let displaced = false;
44110
44379
  try {
44111
44380
  for (const [path3, bytes] of entries) {
44112
- const target = join23(staging, path3);
44113
- mkdirSync13(dirname20(target), { recursive: true });
44114
- writeFileSync13(target, bytes, { flag: "wx" });
44381
+ const target = join25(staging, path3);
44382
+ mkdirSync15(dirname23(target), { recursive: true });
44383
+ writeFileSync15(target, bytes, { flag: "wx" });
44115
44384
  }
44116
44385
  if (appFilesDigest(readSnapshot()) !== expected) throw changed();
44117
- renameSync8(root, backup);
44386
+ renameSync10(root, backup);
44118
44387
  displaced = true;
44119
44388
  try {
44120
- renameSync8(staging, root);
44389
+ renameSync10(staging, root);
44121
44390
  } catch (error) {
44122
- renameSync8(backup, root);
44391
+ renameSync10(backup, root);
44123
44392
  displaced = false;
44124
44393
  throw error;
44125
44394
  }
@@ -44132,10 +44401,10 @@ function writeSkillFolder(projectDir, alias, files, { sourceSnapshot } = {}) {
44132
44401
  return;
44133
44402
  }
44134
44403
  for (const [path3, bytes] of entries) {
44135
- const target = join23(root, path3);
44136
- mkdirSync13(dirname20(target), { recursive: true });
44404
+ const target = join25(root, path3);
44405
+ mkdirSync15(dirname23(target), { recursive: true });
44137
44406
  try {
44138
- writeFileSync13(target, bytes, { flag: "wx" });
44407
+ writeFileSync15(target, bytes, { flag: "wx" });
44139
44408
  } catch (error) {
44140
44409
  if (error?.code === "EEXIST") throw usageError(`${SKILLS_DIR}/${alias}/${path3} already exists in the pulled source; the Skill folder cannot be written over it.`);
44141
44410
  throw error;
@@ -44277,24 +44546,24 @@ function describeAppliedChanges(result) {
44277
44546
 
44278
44547
  // src/command-specs/spaces.js
44279
44548
  init_errors();
44280
- import { readFileSync as readFileSync22 } from "node:fs";
44281
- import { resolve as resolve17 } from "node:path";
44549
+ import { readFileSync as readFileSync24 } from "node:fs";
44550
+ import { resolve as resolve18 } from "node:path";
44282
44551
  import { createHash as createHash15 } from "node:crypto";
44283
44552
 
44284
44553
  // src/command-specs/views.js
44285
44554
  init_errors();
44286
44555
 
44287
44556
  // src/runtime/view-render.js
44288
- import { existsSync as existsSync18 } from "node:fs";
44557
+ import { existsSync as existsSync19 } from "node:fs";
44289
44558
  import { mkdir as mkdir2, writeFile as writeFile2, unlink } from "node:fs/promises";
44290
- import { resolve as resolve15, join as join24 } from "node:path";
44559
+ import { resolve as resolve16, join as join26 } from "node:path";
44291
44560
  import { fileURLToPath as fileURLToPath13 } from "node:url";
44292
44561
  init_errors();
44293
44562
  async function rendererLibrary() {
44294
44563
  const packaged = new URL("../../dist/view-renderer/src/index.js", import.meta.url);
44295
- if (existsSync18(fileURLToPath13(packaged))) return import(packaged.href);
44564
+ if (existsSync19(fileURLToPath13(packaged))) return import(packaged.href);
44296
44565
  const development = new URL("../../../view-renderer/src/index.js", import.meta.url);
44297
- if (existsSync18(fileURLToPath13(development))) return import(development.href);
44566
+ if (existsSync19(fileURLToPath13(development))) return import(development.href);
44298
44567
  throw usageError("The shared view renderer is missing. Rebuild or reinstall this CLI package.");
44299
44568
  }
44300
44569
  async function renderViewWithCliRuntime({
@@ -44334,7 +44603,7 @@ async function renderViewWithCliRuntime({
44334
44603
  throw error;
44335
44604
  }
44336
44605
  if (!directory) return { result, artifacts: null };
44337
- const root = resolve15(directory), created = [], artifacts = {};
44606
+ const root = resolve16(directory), created = [], artifacts = {};
44338
44607
  await mkdir2(root, { recursive: true });
44339
44608
  try {
44340
44609
  for (const [kind, name, bytes] of [
@@ -44342,7 +44611,7 @@ async function renderViewWithCliRuntime({
44342
44611
  ["screenshot", "view.png", result.screenshot ? Buffer.from(result.screenshot.data_base64, "base64") : void 0]
44343
44612
  ]) {
44344
44613
  if (bytes === void 0) continue;
44345
- const path3 = join24(root, name);
44614
+ const path3 = join26(root, name);
44346
44615
  await writeFile2(path3, bytes, { flag: "wx", mode: 384 });
44347
44616
  created.push(path3);
44348
44617
  artifacts[kind] = path3;
@@ -44355,8 +44624,8 @@ async function renderViewWithCliRuntime({
44355
44624
  }
44356
44625
 
44357
44626
  // src/command-specs/views.js
44358
- import { resolve as resolve16 } from "node:path";
44359
- import { randomUUID as randomUUID9 } from "node:crypto";
44627
+ import { resolve as resolve17 } from "node:path";
44628
+ import { randomUUID as randomUUID10 } from "node:crypto";
44360
44629
  function viewRenderCommandSpec({ screenshotOnly = false } = {}) {
44361
44630
  const command_path = screenshotOnly ? ["spaces", "screenshot"] : ["views", "render"];
44362
44631
  return {
@@ -44379,7 +44648,7 @@ function viewRenderCommandSpec({ screenshotOnly = false } = {}) {
44379
44648
  throw usageError("Choose markdown, screenshot, or markdown,screenshot.");
44380
44649
  }
44381
44650
  const width = ctx.options.width === void 0 ? 1440 : Number(ctx.options.width);
44382
- const directory = resolve16(ctx.options.outputDir || `.notis/renders/${randomUUID9()}`);
44651
+ const directory = resolve17(ctx.options.outputDir || `.notis/renders/${randomUUID10()}`);
44383
44652
  const controller = new AbortController(), cancel = () => controller.abort();
44384
44653
  process.once("SIGINT", cancel);
44385
44654
  process.once("SIGTERM", cancel);
@@ -44780,7 +45049,7 @@ var spacesCommandSpecs = [
44780
45049
  const sourceLink = { space_id: ctx.args.spaceId, api_base: ctx.runtime.apiBase.replace(/\/$/, "") };
44781
45050
  let databaseStructures, authoringOverrides;
44782
45051
  const result = await pullAppSource({
44783
- targetDir: resolve17(ctx.args.dir || ctx.args.spaceId),
45052
+ targetDir: resolve18(ctx.args.dir || ctx.args.spaceId),
44784
45053
  force: false,
44785
45054
  sourceKind: "space",
44786
45055
  sourceLink,
@@ -45003,7 +45272,7 @@ var spacesCommandSpecs = [
45003
45272
  return remote(ctx, "grant-authorize", { body: {
45004
45273
  space_id: ctx.args.spaceId,
45005
45274
  request_id: requestId(ctx),
45006
- template: object3(readFileSync22(resolve17(ctx.options.template), "utf8"), "--template"),
45275
+ template: object3(readFileSync24(resolve18(ctx.options.template), "utf8"), "--template"),
45007
45276
  document_id: ctx.options.record,
45008
45277
  dry_run: Boolean(ctx.options.dryRun)
45009
45278
  } });
@@ -45424,8 +45693,8 @@ init_channel();
45424
45693
  init_profiles();
45425
45694
  function readCliVersion() {
45426
45695
  try {
45427
- const manifestPath = join25(dirname21(fileURLToPath14(import.meta.url)), "..", "package.json");
45428
- const version = JSON.parse(readFileSync23(manifestPath, "utf-8")).version;
45696
+ const manifestPath = join27(dirname24(fileURLToPath14(import.meta.url)), "..", "package.json");
45697
+ const version = JSON.parse(readFileSync25(manifestPath, "utf-8")).version;
45429
45698
  if (typeof version === "string" && version.trim()) {
45430
45699
  return version.trim();
45431
45700
  }