@notis_ai/cli 0.2.0-beta.196.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.
Files changed (33) hide show
  1. package/README.md +11 -11
  2. package/config/portal-route-roots.json +0 -1
  3. package/dist/agent-hooks/notis-agent-hook.mjs +760 -473
  4. package/dist/base-skills/notis-apps/SKILL.md +4 -3
  5. package/dist/base-skills/notis-apps/references/sdk.md +3 -1
  6. package/dist/base-skills/notis-apps/references/views.md +1 -1
  7. package/dist/base-skills/notis-cli/SKILL.md +7 -5
  8. package/dist/base-skills/notis-query/references/documents.md +4 -3
  9. package/dist/sdk/src/components/DocumentPage.tsx +6 -3
  10. package/dist/sdk/src/runtime.ts +10 -2
  11. package/dist/skill-sync/index.js +78 -12
  12. package/dist/skill-sync/index.js.map +3 -3
  13. package/dist/skill-sync-worker.mjs +391 -175
  14. package/dist/view-renderer/dist/host.js +86 -86
  15. package/dist/view-renderer/src/host.tsx +4 -2
  16. package/package.json +1 -1
  17. package/skills/notis-apps/cli.md +1 -1
  18. package/skills/notis-cli/AGENT_INSTRUCTIONS.md +1 -1
  19. package/src/command-specs/auth.js +2 -2
  20. package/src/command-specs/handover.js +45 -16
  21. package/src/command-specs/profile.js +42 -1
  22. package/src/command-specs/skills.js +13 -1
  23. package/src/runtime/computer-identity.d.ts +30 -0
  24. package/src/runtime/computer-identity.js +151 -0
  25. package/src/runtime/config-lock.js +135 -0
  26. package/src/runtime/oauth.js +18 -1
  27. package/src/runtime/profiles.js +5 -107
  28. package/src/runtime/skill-sync/index.ts +83 -7
  29. package/src/runtime/skill-sync/local-scanner.ts +7 -4
  30. package/src/runtime/skill-sync/native-plan.ts +14 -3
  31. package/src/runtime/sync-skills.d.ts +3 -1
  32. package/src/runtime/sync-skills.js +10 -2
  33. package/src/skill-sync-worker.js +14 -2
@@ -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
  }
@@ -41494,10 +41747,24 @@ function pushBranch(repository, branch) {
41494
41747
  // src/command-specs/handover.js
41495
41748
  var HAND_OVER_TOOL = "LOCAL_NOTIS_HAND_OVER";
41496
41749
  var SEARCH_THREADS_TOOL = "LOCAL_NOTIS_SEARCH_CODING_AGENT_THREADS";
41497
- var ROUTES = ["notis", "auto", "codex_cloud", "claude_cloud", "codex_local", "claude_local"];
41750
+ var ROUTES = ["auto", "notis", "codex", "claude"];
41751
+ var LEGACY_ROUTES = /* @__PURE__ */ new Map([
41752
+ ["codex_cloud", "codex"],
41753
+ ["codex_local", "codex"],
41754
+ ["claude_cloud", "claude"],
41755
+ ["claude_local", "claude"]
41756
+ ]);
41757
+ var ROUTE_LABELS = { notis: "Notis", codex: "Codex", claude: "Claude" };
41498
41758
  var BRANCH_MODES = ["new", "same"];
41499
41759
  var HANDOVER_TIMEOUT_MS = 12e4;
41500
41760
  var HANDOVER_UNAVAILABLE_CODES = /* @__PURE__ */ new Set(["usage_error", "forbidden"]);
41761
+ function normalizeRoute(route) {
41762
+ return LEGACY_ROUTES.get(route) || route;
41763
+ }
41764
+ function describeRoute(route) {
41765
+ if (route === "auto") return "Notis, which picks the agent";
41766
+ return ROUTE_LABELS[route] || route;
41767
+ }
41501
41768
  function shellSingleQuote(value) {
41502
41769
  return `'${String(value).replace(/'/g, "'\\''")}'`;
41503
41770
  }
@@ -41548,8 +41815,8 @@ async function handoverStartHandler(ctx) {
41548
41815
  if (!BRANCH_MODES.includes(branchMode)) {
41549
41816
  throw usageError(`--branch-mode must be one of: ${BRANCH_MODES.join(", ")}`, { branchMode });
41550
41817
  }
41551
- const route = ctx.options.route || "notis";
41552
- if (!ROUTES.includes(route)) {
41818
+ const route = ctx.options.route || "auto";
41819
+ if (!ROUTES.includes(route) && !LEGACY_ROUTES.has(route)) {
41553
41820
  throw usageError(`--route must be one of: ${ROUTES.join(", ")}`, { route });
41554
41821
  }
41555
41822
  const repository = inspectRepository(ctx.options.cwd || process.cwd());
@@ -41618,7 +41885,10 @@ async function handoverStartHandler(ctx) {
41618
41885
  branchMode,
41619
41886
  repoSlug: ctx.options.repo || null
41620
41887
  });
41621
- ctx.output.emitProgress({ phase: "handover", message: `Handing over to ${route}` });
41888
+ ctx.output.emitProgress({
41889
+ phase: "handover",
41890
+ message: `Handing over to ${describeRoute(normalizeRoute(route))}`
41891
+ });
41622
41892
  const result = await runToolCommand({
41623
41893
  runtime: {
41624
41894
  ...ctx.runtime,
@@ -41646,14 +41916,16 @@ async function handoverStartHandler(ctx) {
41646
41916
  branch_mode: branchMode,
41647
41917
  head: repository.head,
41648
41918
  wip_commit: wipCommit,
41649
- agent_routing: payload.agent_routing || route,
41919
+ // The server answers with auto, notis, codex or claude. An older server
41920
+ // may echo a legacy value back, so map it here too.
41921
+ agent_routing: normalizeRoute(payload.agent_routing || route),
41650
41922
  interaction_id: payload.interaction_id || null,
41651
41923
  thread_id: payload.thread_id || null
41652
41924
  };
41653
41925
  return ctx.output.emitSuccess({
41654
41926
  command: "handover start",
41655
41927
  data,
41656
- humanSummary: `Handed ${data.branch} over to ${data.agent_routing} (${branchMode === "same" ? "continuing the branch" : "new branch from it"}).`,
41928
+ humanSummary: `Handed ${data.branch} over to ${describeRoute(data.agent_routing)} (${branchMode === "same" ? "continuing the branch" : "new branch from it"}).`,
41657
41929
  hints: [
41658
41930
  { command: "notis handover status", reason: "See what the agent is doing" },
41659
41931
  {
@@ -41693,7 +41965,7 @@ var handoverCommandSpecs = [
41693
41965
  {
41694
41966
  command_path: ["handover", "start"],
41695
41967
  summary: "Hand the current branch to a Notis agent and keep working.",
41696
- when_to_use: "Use this when you want Notis to continue work on the branch you are on -- long refactors, test fixing, or anything that should keep running after you close the laptop. Pick the agent with --route.",
41968
+ when_to_use: "Use this when you want Notis to continue work on the branch you are on -- long refactors, test fixing, or anything that should keep running after you close the laptop. Notis picks the agent unless you name one with --route.",
41697
41969
  args_schema: {
41698
41970
  arguments: [{ token: "<task>", description: "What the agent should do, in plain language." }],
41699
41971
  options: [
@@ -41704,7 +41976,7 @@ var handoverCommandSpecs = [
41704
41976
  },
41705
41977
  {
41706
41978
  flags: "--route <target>",
41707
- description: "Which agent runs it: notis (hosted, default), codex_cloud, claude_cloud, codex_local, claude_local, or auto."
41979
+ description: "Which agent runs it: auto (default, Notis picks the agent), notis, codex or claude."
41708
41980
  },
41709
41981
  { flags: "--repo <slug>", description: "Configured repository slug on the cloud computer, when you know it." },
41710
41982
  {
@@ -41715,11 +41987,11 @@ var handoverCommandSpecs = [
41715
41987
  },
41716
41988
  examples: [
41717
41989
  'notis handover start "fix the failing auth tests"',
41718
- 'notis handover start "finish the migration" --branch-mode same --route codex_cloud',
41719
- 'notis handover start "add integration tests" --route claude_cloud',
41720
- 'notis handover start "review and clean up this branch" --route claude_local'
41990
+ 'notis handover start "finish the migration" --branch-mode same --route codex',
41991
+ 'notis handover start "add integration tests" --route claude',
41992
+ 'notis handover start "review and clean up this branch" --route notis'
41721
41993
  ],
41722
- output_schema: "Returns the branch, the resolved routing target, and the interaction/thread ids of the started run.",
41994
+ output_schema: "Returns the branch, the agent routing (auto when Notis picks, otherwise notis, codex or claude), and the interaction/thread ids of the started run.",
41723
41995
  mutates: true,
41724
41996
  idempotent: false,
41725
41997
  require_auth: true,
@@ -41753,98 +42025,98 @@ var handoverCommandSpecs = [
41753
42025
  init_profiles();
41754
42026
 
41755
42027
  // src/runtime/sync-skills.js
41756
- import { createHash as createHash9, randomUUID as randomUUID7 } from "node:crypto";
42028
+ import { createHash as createHash9, randomUUID as randomUUID8 } from "node:crypto";
41757
42029
  import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
41758
- import { homedir as homedir7 } from "node:os";
41759
- 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";
41760
42032
 
41761
42033
  // src/runtime/base-skills.js
41762
42034
  import {
41763
42035
  cpSync as cpSync2,
41764
- existsSync as existsSync12,
42036
+ existsSync as existsSync13,
41765
42037
  lstatSync as lstatSync3,
41766
- mkdirSync as mkdirSync9,
42038
+ mkdirSync as mkdirSync11,
41767
42039
  readlinkSync,
41768
- renameSync as renameSync6,
42040
+ renameSync as renameSync8,
41769
42041
  rmSync as rmSync7,
41770
42042
  symlinkSync
41771
42043
  } from "node:fs";
41772
- import { homedir as homedir6 } from "node:os";
41773
- 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";
41774
42046
  import { fileURLToPath as fileURLToPath9 } from "node:url";
41775
42047
  var BASE_SKILL_NAMES = Object.freeze([
41776
42048
  "notis-apps",
41777
42049
  "notis-query",
41778
42050
  "notis-cli"
41779
42051
  ]);
41780
- var HERE3 = dirname13(fileURLToPath9(import.meta.url));
42052
+ var HERE3 = dirname15(fileURLToPath9(import.meta.url));
41781
42053
  function resolveBundledBaseSkillsRoot({ resourcesPath = process.resourcesPath } = {}) {
41782
- const sourceCheckout = resolve8(HERE3, "../../../../server/skills");
41783
- const packaged = resolve8(HERE3, "../../dist/base-skills");
41784
- 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;
41785
42057
  const desktopPackagerRoot = resourcesPath || null;
41786
42058
  for (const candidate of [sourceCheckout, packaged, desktopResource, desktopPackagerRoot]) {
41787
- 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")))) {
41788
42060
  return candidate;
41789
42061
  }
41790
42062
  }
41791
42063
  return packaged;
41792
42064
  }
41793
- function getBaseSkillPaths({ home = homedir6(), userId = null } = {}) {
41794
- const notisRoot = join14(home, ".notis", "skills");
42065
+ function getBaseSkillPaths({ home = homedir7(), userId = null } = {}) {
42066
+ const notisRoot = join16(home, ".notis", "skills");
41795
42067
  const targetRoots = [
41796
- join14(home, ".agents", "skills"),
41797
- join14(home, ".codex", "skills"),
41798
- join14(home, ".cursor", "skills"),
41799
- join14(home, ".claude", "skills")
42068
+ join16(home, ".agents", "skills"),
42069
+ join16(home, ".codex", "skills"),
42070
+ join16(home, ".cursor", "skills"),
42071
+ join16(home, ".claude", "skills")
41800
42072
  ];
41801
42073
  if (userId) {
41802
- targetRoots.push(join14(notisRoot, "users", userId, "skills"));
42074
+ targetRoots.push(join16(notisRoot, "users", userId, "skills"));
41803
42075
  }
41804
42076
  return {
41805
- baseRoot: join14(notisRoot, "base"),
41806
- backupRoot: join14(notisRoot, "backups"),
42077
+ baseRoot: join16(notisRoot, "base"),
42078
+ backupRoot: join16(notisRoot, "backups"),
41807
42079
  targetRoots
41808
42080
  };
41809
42081
  }
41810
42082
  function sameLinkTarget(linkPath, expectedTarget) {
41811
42083
  try {
41812
42084
  if (!lstatSync3(linkPath).isSymbolicLink()) return false;
41813
- return resolve8(dirname13(linkPath), readlinkSync(linkPath)) === resolve8(expectedTarget);
42085
+ return resolve9(dirname15(linkPath), readlinkSync(linkPath)) === resolve9(expectedTarget);
41814
42086
  } catch {
41815
42087
  return false;
41816
42088
  }
41817
42089
  }
41818
42090
  function backupConflict(linkPath, backupRoot, targetLabel, skillName, now) {
41819
- const backupPath = join14(backupRoot, String(now), targetLabel, skillName);
41820
- mkdirSync9(dirname13(backupPath), { recursive: true, mode: 448 });
41821
- renameSync6(linkPath, backupPath);
42091
+ const backupPath = join16(backupRoot, String(now), targetLabel, skillName);
42092
+ mkdirSync11(dirname15(backupPath), { recursive: true, mode: 448 });
42093
+ renameSync8(linkPath, backupPath);
41822
42094
  return backupPath;
41823
42095
  }
41824
42096
  function replaceDirectory(source, destination) {
41825
- mkdirSync9(dirname13(destination), { recursive: true, mode: 448 });
42097
+ mkdirSync11(dirname15(destination), { recursive: true, mode: 448 });
41826
42098
  const temporary = `${destination}.tmp-${process.pid}-${Date.now()}`;
41827
42099
  const previous = `${destination}.previous-${process.pid}-${Date.now()}`;
41828
42100
  rmSync7(temporary, { recursive: true, force: true });
41829
42101
  cpSync2(source, temporary, { recursive: true });
41830
42102
  let movedPrevious = false;
41831
42103
  try {
41832
- if (existsSync12(destination)) {
41833
- renameSync6(destination, previous);
42104
+ if (existsSync13(destination)) {
42105
+ renameSync8(destination, previous);
41834
42106
  movedPrevious = true;
41835
42107
  }
41836
- renameSync6(temporary, destination);
42108
+ renameSync8(temporary, destination);
41837
42109
  if (movedPrevious) rmSync7(previous, { recursive: true, force: true });
41838
42110
  } catch (error) {
41839
42111
  rmSync7(temporary, { recursive: true, force: true });
41840
- if (movedPrevious && !existsSync12(destination) && existsSync12(previous)) {
41841
- renameSync6(previous, destination);
42112
+ if (movedPrevious && !existsSync13(destination) && existsSync13(previous)) {
42113
+ renameSync8(previous, destination);
41842
42114
  }
41843
42115
  throw error;
41844
42116
  }
41845
42117
  }
41846
42118
  function reconcileBaseSkills({
41847
- home = homedir6(),
42119
+ home = homedir7(),
41848
42120
  userId = null,
41849
42121
  sourceRoot = resolveBundledBaseSkillsRoot(),
41850
42122
  now = Date.now()
@@ -41858,24 +42130,24 @@ function reconcileBaseSkills({
41858
42130
  skills: [...BASE_SKILL_NAMES]
41859
42131
  };
41860
42132
  for (const name of BASE_SKILL_NAMES) {
41861
- const source = join14(sourceRoot, name);
41862
- if (!existsSync12(join14(source, "SKILL.md"))) {
42133
+ const source = join16(sourceRoot, name);
42134
+ if (!existsSync13(join16(source, "SKILL.md"))) {
41863
42135
  throw new Error(`Bundled base skill is missing: ${name}`);
41864
42136
  }
41865
- replaceDirectory(source, join14(paths.baseRoot, name));
42137
+ replaceDirectory(source, join16(paths.baseRoot, name));
41866
42138
  result.installed += 1;
41867
42139
  }
41868
42140
  for (const targetRoot of paths.targetRoots) {
41869
- mkdirSync9(targetRoot, { recursive: true, mode: 448 });
42141
+ mkdirSync11(targetRoot, { recursive: true, mode: 448 });
41870
42142
  const targetLabel = relative5(home, targetRoot).replaceAll("/", "_") || "home";
41871
42143
  for (const name of BASE_SKILL_NAMES) {
41872
- const skillTarget2 = join14(paths.baseRoot, name);
41873
- const linkPath = join14(targetRoot, name);
42144
+ const skillTarget2 = join16(paths.baseRoot, name);
42145
+ const linkPath = join16(targetRoot, name);
41874
42146
  if (sameLinkTarget(linkPath, skillTarget2)) {
41875
42147
  result.unchanged += 1;
41876
42148
  continue;
41877
42149
  }
41878
- if (existsSync12(linkPath) || (() => {
42150
+ if (existsSync13(linkPath) || (() => {
41879
42151
  try {
41880
42152
  lstatSync3(linkPath);
41881
42153
  return true;
@@ -41904,7 +42176,7 @@ var DEFAULT_LOCK_POLL_MS = 50;
41904
42176
  async function lockSnapshot(lockDirectory) {
41905
42177
  try {
41906
42178
  const [raw, metadata] = await Promise.all([
41907
- readFile(join15(lockDirectory, "owner"), "utf8").catch(() => ""),
42179
+ readFile(join17(lockDirectory, "owner"), "utf8").catch(() => ""),
41908
42180
  stat(lockDirectory)
41909
42181
  ]);
41910
42182
  let owner = {};
@@ -41937,14 +42209,14 @@ function processIsAlive2(pid) {
41937
42209
  }
41938
42210
  }
41939
42211
  function delay3(milliseconds) {
41940
- return new Promise((resolve18) => setTimeout(resolve18, milliseconds));
42212
+ return new Promise((resolve19) => setTimeout(resolve19, milliseconds));
41941
42213
  }
41942
42214
  async function quarantineStaleLock(lockDirectory, snapshot) {
41943
- const quarantineRoot = join15(dirname14(lockDirectory), ".stale-operation-locks");
42215
+ const quarantineRoot = join17(dirname16(lockDirectory), ".stale-operation-locks");
41944
42216
  const snapshotToken = createHash9("sha256").update(JSON.stringify(snapshot)).digest("hex");
41945
42217
  await mkdir(quarantineRoot, { recursive: true, mode: 448 });
41946
42218
  try {
41947
- await rename(lockDirectory, join15(quarantineRoot, snapshotToken));
42219
+ await rename(lockDirectory, join17(quarantineRoot, snapshotToken));
41948
42220
  return true;
41949
42221
  } catch (error) {
41950
42222
  if (["EEXIST", "ENOTEMPTY", "ENOENT"].includes(error?.code)) return false;
@@ -41952,16 +42224,16 @@ async function quarantineStaleLock(lockDirectory, snapshot) {
41952
42224
  }
41953
42225
  }
41954
42226
  async function writeLockOwnerAtomically(lockDirectory, owner) {
41955
- const temporaryOwnerPath = join15(lockDirectory, `.owner.${owner.id}.tmp`);
41956
- const ownerPath = join15(lockDirectory, "owner");
42227
+ const temporaryOwnerPath = join17(lockDirectory, `.owner.${owner.id}.tmp`);
42228
+ const ownerPath = join17(lockDirectory, "owner");
41957
42229
  await writeFile(temporaryOwnerPath, JSON.stringify(owner), { mode: 384 });
41958
42230
  await rename(temporaryOwnerPath, ownerPath);
41959
42231
  }
41960
42232
  async function releaseOwnedLock(lockDirectory, ownerId) {
41961
42233
  const owner = await lockSnapshot(lockDirectory);
41962
42234
  if (owner?.id !== ownerId) return;
41963
- const quarantineRoot = join15(dirname14(lockDirectory), ".stale-operation-locks");
41964
- const releasedDirectory = join15(quarantineRoot, `released.${ownerId}`);
42235
+ const quarantineRoot = join17(dirname16(lockDirectory), ".stale-operation-locks");
42236
+ const releasedDirectory = join17(quarantineRoot, `released.${ownerId}`);
41965
42237
  await mkdir(quarantineRoot, { recursive: true, mode: 448 });
41966
42238
  try {
41967
42239
  await rename(lockDirectory, releasedDirectory);
@@ -41972,16 +42244,16 @@ async function releaseOwnedLock(lockDirectory, ownerId) {
41972
42244
  await rm(releasedDirectory, { recursive: true, force: true });
41973
42245
  }
41974
42246
  async function withSkillSyncLock(callback, {
41975
- home = homedir7(),
42247
+ home = homedir8(),
41976
42248
  timeoutMs = DEFAULT_LOCK_TIMEOUT_MS,
41977
42249
  staleMs = DEFAULT_LOCK_STALE_MS,
41978
42250
  pollMs = DEFAULT_LOCK_POLL_MS,
41979
42251
  now = () => Date.now()
41980
42252
  } = {}) {
41981
- const lockDirectory = join15(home, ".notis", "skills", ".operation-lock");
41982
- const ownerId = `${process.pid}.${randomUUID7()}`;
42253
+ const lockDirectory = join17(home, ".notis", "skills", ".operation-lock");
42254
+ const ownerId = `${process.pid}.${randomUUID8()}`;
41983
42255
  const deadline = now() + timeoutMs;
41984
- await mkdir(dirname14(lockDirectory), { recursive: true, mode: 448 });
42256
+ await mkdir(dirname16(lockDirectory), { recursive: true, mode: 448 });
41985
42257
  for (; ; ) {
41986
42258
  try {
41987
42259
  await mkdir(lockDirectory, { mode: 448 });
@@ -42017,7 +42289,7 @@ async function withSkillSyncLock(callback, {
42017
42289
  let heartbeatInFlight = Promise.resolve();
42018
42290
  const refreshHeartbeat = async () => {
42019
42291
  if (heartbeatStopped) return;
42020
- const temporaryOwnerPath = join15(lockDirectory, `.owner.${ownerId}.tmp`);
42292
+ const temporaryOwnerPath = join17(lockDirectory, `.owner.${ownerId}.tmp`);
42021
42293
  await writeFile(
42022
42294
  temporaryOwnerPath,
42023
42295
  JSON.stringify({ id: ownerId, pid: process.pid, at: now() }),
@@ -42028,7 +42300,7 @@ async function withSkillSyncLock(callback, {
42028
42300
  await rm(temporaryOwnerPath, { force: true });
42029
42301
  return;
42030
42302
  }
42031
- await rename(temporaryOwnerPath, join15(lockDirectory, "owner"));
42303
+ await rename(temporaryOwnerPath, join17(lockDirectory, "owner"));
42032
42304
  };
42033
42305
  const heartbeat = setInterval(() => {
42034
42306
  heartbeatInFlight = heartbeatInFlight.then(refreshHeartbeat).catch(() => void 0);
@@ -42051,15 +42323,20 @@ async function reconcileAllSkills({
42051
42323
  home,
42052
42324
  runAccountSync,
42053
42325
  reconcileBase = reconcileBaseSkills,
42054
- lockOptions = {}
42326
+ lockOptions = {},
42327
+ linkAgentFolders = true
42055
42328
  }) {
42056
42329
  return withSkillSyncLock(async () => {
42057
- const base = reconcileBase({ userId, ...home ? { home } : {} });
42330
+ const base = linkAgentFolders ? reconcileBase({ userId, ...home ? { home } : {} }) : { skills: [], installed: 0, linked: 0, unchanged: 0, backups: [] };
42058
42331
  const account = await runAccountSync(
42059
42332
  serverUrl,
42060
42333
  jwt,
42061
42334
  {},
42062
- { honorSyncEnabled, ...home ? { syncHome: home } : {} }
42335
+ {
42336
+ honorSyncEnabled,
42337
+ ...home ? { syncHome: home } : {},
42338
+ ...linkAgentFolders ? {} : { linkAgentFolders: false }
42339
+ }
42063
42340
  );
42064
42341
  return {
42065
42342
  ...account,
@@ -42078,17 +42355,17 @@ init_oauth();
42078
42355
  init_profiles();
42079
42356
  import { spawnSync as spawnSync3 } from "node:child_process";
42080
42357
  import { createHash as createHash11 } from "node:crypto";
42081
- import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync16, renameSync as renameSync7, writeFileSync as writeFileSync9 } from "node:fs";
42082
- import { homedir as homedir8 } from "node:os";
42083
- 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";
42084
42361
  import { fileURLToPath as fileURLToPath10 } from "node:url";
42085
42362
  var SKILL_SYNC_SERVICE_LABEL = "ai.notis.skills-sync";
42086
42363
  var bundlePath = fileURLToPath10(new URL("../../dist/skill-sync-worker.mjs", import.meta.url));
42087
42364
  function atomicWrite2(target, value, mode = 384) {
42088
- mkdirSync10(dirname15(target), { recursive: true, mode: 448 });
42365
+ mkdirSync12(dirname18(target), { recursive: true, mode: 448 });
42089
42366
  const temporary = `${target}.${process.pid}.tmp`;
42090
- writeFileSync9(temporary, value, { mode });
42091
- renameSync7(temporary, target);
42367
+ writeFileSync11(temporary, value, { mode });
42368
+ renameSync9(temporary, target);
42092
42369
  }
42093
42370
  function xml(value) {
42094
42371
  return String(value).replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
@@ -42100,9 +42377,9 @@ async function maybeInstallSkillSyncService(runtime, {
42100
42377
  refresh
42101
42378
  } = {}) {
42102
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;
42103
- const plist = join17(homedir8(), "Library", "LaunchAgents", `${SKILL_SYNC_SERVICE_LABEL}.plist`);
42104
- if (existsSync13(plist)) {
42105
- 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");
42106
42383
  if (runtime.oauthUserId && [runtime.profileName, runtime.apiBase, runtime.oauthUserId].every((value) => saved.includes(`<string>${xml(value)}</string>`))) return install(runtime);
42107
42384
  return;
42108
42385
  }
@@ -42123,7 +42400,7 @@ async function installSkillSyncService(runtime, options = {}) {
42123
42400
  );
42124
42401
  }
42125
42402
  async function installSkillSyncServiceLocked(runtime, {
42126
- home = homedir8(),
42403
+ home = homedir9(),
42127
42404
  platform = process.platform,
42128
42405
  nodePath = process.execPath,
42129
42406
  source = bundlePath,
@@ -42134,11 +42411,11 @@ async function installSkillSyncServiceLocked(runtime, {
42134
42411
  if (runtime.credentialKind !== "oauth" || runtime.envCredentialOverride || !isValidProfileName(runtime.profileName) || !["https://api.notis.ai", "https://api-beta.notis.ai"].includes(runtime.apiBase)) {
42135
42412
  return { status: "skipped_non_personal_profile" };
42136
42413
  }
42137
- const root = join17(home, ".notis", "skills", "service");
42138
- const bundle = readFileSync16(source);
42414
+ const root = join19(home, ".notis", "skills", "service");
42415
+ const bundle = readFileSync18(source);
42139
42416
  const digest = createHash11("sha256").update(bundle).digest("hex");
42140
- const installedBundle = join17(root, "runtime", digest, "worker.mjs");
42141
- 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);
42142
42419
  const args = [nodePath, installedBundle, runtime.profileName, runtime.apiBase, runtime.oauthUserId];
42143
42420
  if (!runtime.oauthUserId) return { status: "skipped_missing_account" };
42144
42421
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
@@ -42151,10 +42428,10 @@ async function installSkillSyncServiceLocked(runtime, {
42151
42428
  <key>ProcessType</key><string>Background</string>
42152
42429
  </dict></plist>
42153
42430
  `;
42154
- const plistPath = join17(home, "Library", "LaunchAgents", `${SKILL_SYNC_SERVICE_LABEL}.plist`);
42431
+ const plistPath = join19(home, "Library", "LaunchAgents", `${SKILL_SYNC_SERVICE_LABEL}.plist`);
42155
42432
  const domain = `gui/${uid}`;
42156
42433
  const target = `${domain}/${SKILL_SYNC_SERVICE_LABEL}`;
42157
- const unchanged = existsSync13(plistPath) && readFileSync16(plistPath, "utf8") === plist;
42434
+ const unchanged = existsSync14(plistPath) && readFileSync18(plistPath, "utf8") === plist;
42158
42435
  const loaded = run("/bin/launchctl", ["print", target], { encoding: "utf8", timeout: 5e3 });
42159
42436
  if (unchanged && loaded.status === 0) return { status: "installed", intervalSeconds: 60, profile: runtime.profileName };
42160
42437
  if (loaded.status === 0) {
@@ -42166,15 +42443,15 @@ async function installSkillSyncServiceLocked(runtime, {
42166
42443
  for (let attempt = 0; attempt < 10; attempt++) {
42167
42444
  started = run("/bin/launchctl", ["bootstrap", domain, plistPath], { encoding: "utf8", timeout: 5e3 });
42168
42445
  if (started.status === 0) break;
42169
- await new Promise((resolve18) => setTimeout(resolve18, 100));
42446
+ await new Promise((resolve19) => setTimeout(resolve19, 100));
42170
42447
  }
42171
42448
  if (started?.status !== 0) throw new Error("Could not register automatic skill sync with macOS");
42172
42449
  return { status: "installed", intervalSeconds: 60, profile: runtime.profileName };
42173
42450
  }
42174
42451
 
42175
42452
  // src/command-specs/skills.js
42176
- import { readFileSync as readFileSync17 } from "node:fs";
42177
- import { resolve as resolve9 } from "node:path";
42453
+ import { readFileSync as readFileSync19 } from "node:fs";
42454
+ import { resolve as resolve10 } from "node:path";
42178
42455
  init_errors();
42179
42456
  async function nativeSkillAuthoring(ctx, body, path3 = "/portal_skills/native-authoring") {
42180
42457
  const spaceTarget = Boolean(body.target?.space_id || body.destination?.space_id || body.links);
@@ -42244,6 +42521,14 @@ function linkEntries(value, option, required, optional = []) {
42244
42521
  async function loadSkillSyncEngine() {
42245
42522
  return Promise.resolve().then(() => (init_skill_sync(), skill_sync_exports));
42246
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
+ }
42247
42532
  async function syncSkillsHandler(ctx, {
42248
42533
  refresh = ensureFreshOAuthCredential,
42249
42534
  loadEngine = loadSkillSyncEngine,
@@ -42259,6 +42544,9 @@ async function syncSkillsHandler(ctx, {
42259
42544
  jwt: ctx.runtime.jwt,
42260
42545
  userId: settings.user_id || userId,
42261
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),
42262
42550
  runAccountSync: (serverUrl, jwt, dependencies, options) => runSkillSync2(
42263
42551
  serverUrl,
42264
42552
  jwt,
@@ -42339,7 +42627,7 @@ var skillsCommandSpecs = [
42339
42627
  require_auth: true,
42340
42628
  backend_call: { type: "http", path: "/portal_skills/native-create" },
42341
42629
  handler(ctx) {
42342
- 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");
42343
42631
  if (!payload || typeof payload !== "object" || Array.isArray(payload) || Object.keys(payload).some((key2) => !["destination", "name", "description", "skill_md", "files"].includes(key2))) {
42344
42632
  throw usageError("Provide a name, complete instructions or files, and an optional current destination; never override ownership.");
42345
42633
  }
@@ -42385,7 +42673,7 @@ var skillsCommandSpecs = [
42385
42673
  require_auth: true,
42386
42674
  backend_call: { type: "http", path: "/portal_skills/native-settings" },
42387
42675
  handler(ctx) {
42388
- 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");
42389
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") {
42390
42678
  throw usageError("Use a current standalone target, settings revision and personal settings patch.");
42391
42679
  }
@@ -42437,7 +42725,7 @@ var skillsCommandSpecs = [
42437
42725
  require_auth: true,
42438
42726
  backend_call: { type: "http", path: "/portal_skills/native-authoring" },
42439
42727
  handler(ctx) {
42440
- 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");
42441
42729
  if (!payload || typeof payload !== "object" || Array.isArray(payload) || Object.keys(payload).some((key2) => !["target", "version", "skill_md", "files", "name", "description", "links"].includes(key2))) {
42442
42730
  throw usageError("Use an exact target, version, skill_md or files, and optional links; never override ownership.");
42443
42731
  }
@@ -42510,15 +42798,14 @@ var skillsCommandSpecs = [
42510
42798
  ];
42511
42799
 
42512
42800
  // src/runtime/space-collection-scaffold.js
42513
- import { writeFileSync as writeFileSync10, mkdirSync as mkdirSync11 } from "node:fs";
42514
- 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";
42515
42803
 
42516
42804
  // src/runtime/space-view-manifest.js
42517
42805
  init_errors();
42518
42806
 
42519
42807
  // config/portal-route-roots.json
42520
42808
  var portal_route_roots_default = [
42521
- ".well-known",
42522
42809
  "api",
42523
42810
  "apps",
42524
42811
  "auth",
@@ -42820,8 +43107,8 @@ async function scaffoldSpaceCollection({ projectDir, name, databaseKey, path: pa
42820
43107
  if (typeof name !== "string" || !name.trim() || typeof titleProperty !== "string" || !titleProperty.trim()) throw usageError("Choose a Space name and title property.");
42821
43108
  validateViewPath(path3);
42822
43109
  await scaffoldProject({ projectDir, appName: name });
42823
- mkdirSync11(join18(projectDir, "spaces", "collection"), { recursive: true });
42824
- 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';
42825
43112
  export default defineSpaces({ spaces: { collection: { definition: 'spaces/collection/space.config.ts' } } });
42826
43113
  `);
42827
43114
  const definition = {
@@ -42845,11 +43132,11 @@ export default defineSpaces({ spaces: { collection: { definition: 'spaces/collec
42845
43132
  properties: { request: { type: "object" } }
42846
43133
  }, arguments: { database_id: { $asset: "items" }, request: { $input: "request" } } } }
42847
43134
  };
42848
- 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';
42849
43136
  export default defineSpace(${JSON.stringify(definition, null, 2)});
42850
43137
  `);
42851
- writeFileSync10(join18(projectDir, "spaces/collection/view.tsx"), COLLECTION_VIEW);
42852
- 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({
42853
43140
  actions: {},
42854
43141
  shown: { items: [{ params: {}, result: { rows: [], has_more: false, schema_revision: 1 } }] }
42855
43142
  }, null, 2) + "\n");
@@ -42889,13 +43176,13 @@ export default function CollectionView() {
42889
43176
  `;
42890
43177
 
42891
43178
  // src/runtime/space-platform.js
42892
- import { existsSync as existsSync14, mkdirSync as mkdirSync12, readFileSync as readFileSync18, symlinkSync as symlinkSync2, writeFileSync as writeFileSync11 } from "node:fs";
42893
- 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";
42894
43181
 
42895
43182
  // src/runtime/space-source.js
42896
43183
  import { createRequire as createRequire3 } from "node:module";
42897
43184
  import { realpathSync as realpathSync2 } from "node:fs";
42898
- 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";
42899
43186
  init_errors();
42900
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]);
42901
43188
  var VIEWER_READ_FAMILIES = Object.freeze(["databases", "skills"]);
@@ -42916,25 +43203,25 @@ var ROOT_CONFIGS = [
42916
43203
  "tailwind.config.mjs"
42917
43204
  ];
42918
43205
  function sourceCompiler(projectDir, files) {
42919
- const require3 = createRequire3(join19(projectDir, "package.json"));
43206
+ const require3 = createRequire3(join21(projectDir, "package.json"));
42920
43207
  let ts;
42921
43208
  try {
42922
43209
  ts = require3("typescript");
42923
43210
  } catch {
42924
43211
  throw usageError("Install this workspace's TypeScript dependency before packaging Space source.");
42925
43212
  }
42926
- 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));
42927
43214
  let source, checker, syntax, close = () => {
42928
43215
  };
42929
43216
  if (typeof ts.createProgram === "function") {
42930
43217
  let options = { moduleResolution: ts.ModuleResolutionKind.Bundler, allowJs: true };
42931
43218
  if (files["tsconfig.json"]) {
42932
- const config = ts.readConfigFile(join19(projectDir, "tsconfig.json"), ts.sys.readFile);
43219
+ const config = ts.readConfigFile(join21(projectDir, "tsconfig.json"), ts.sys.readFile);
42933
43220
  if (config.error) throw usageError("Fix tsconfig.json before building this Space.");
42934
43221
  options = { ...options, ...ts.parseJsonConfigFileContent(config.config, ts.sys, projectDir).options, allowJs: true };
42935
43222
  }
42936
43223
  const program3 = ts.createProgram(codeFiles, options), projectChecker = program3.getTypeChecker();
42937
- source = (file) => program3.getSourceFile(join19(projectDir, file));
43224
+ source = (file) => program3.getSourceFile(join21(projectDir, file));
42938
43225
  checker = () => projectChecker;
42939
43226
  syntax = ts.SyntaxKind;
42940
43227
  } else {
@@ -42943,8 +43230,8 @@ function sourceCompiler(projectDir, files) {
42943
43230
  const api = new API({ cwd: projectDir });
42944
43231
  try {
42945
43232
  const snapshot = api.updateSnapshot({ openFiles: codeFiles });
42946
- const project = (file) => snapshot.getDefaultProjectForFile(join19(projectDir, file));
42947
- 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));
42948
43235
  checker = (file) => project(file)?.checker;
42949
43236
  close = () => {
42950
43237
  try {
@@ -43018,7 +43305,7 @@ async function loadSelectedSpace(projectDir, selectedKey) {
43018
43305
  }
43019
43306
  const resolveDefinitionPath = (value) => {
43020
43307
  if (typeof value !== "string" || !value || value.startsWith("/") || value.includes("\\") || value.includes("\0")) throw usageError("Use a workspace-relative source path.");
43021
- 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("/"));
43022
43309
  };
43023
43310
  const entry = definition.entry ? resolveDefinitionPath(definition.entry) : null;
43024
43311
  const layout = definition.layout ? resolveDefinitionPath(definition.layout) : null;
@@ -43106,7 +43393,7 @@ function collectSelectedSpaceSource(projectDir, selection, { buildInputs = [] }
43106
43393
  if (!specifier.startsWith(".")) return;
43107
43394
  }
43108
43395
  const raw = specifier.split(/[?#]/, 1)[0];
43109
- 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("/");
43110
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));
43111
43398
  if (candidate) {
43112
43399
  add(candidate);
@@ -43212,25 +43499,25 @@ function generateSpaceManifest(selection) {
43212
43499
  function prepareSelectedArtifact(projectDir, selection) {
43213
43500
  validateProjectBoundary(projectDir);
43214
43501
  validateProjectDesign(projectDir);
43215
- const entryPath = join20(projectDir, ".notis/_entry.tsx");
43216
- const manifestPath = join20(projectDir, ".notis/output/manifest.json");
43217
- mkdirSync12(dirname17(entryPath), { recursive: true });
43218
- 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 });
43219
43506
  if (selection.entry) {
43220
- 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("\\", "/"));
43221
43508
  const lines = [`export { default as SpaceView } from ${reference(selection.entry)};`];
43222
43509
  if (selection.layout) lines.push(`export { default as __AppShell } from ${reference(selection.layout)};`);
43223
43510
  if (selection.markdown) lines.push(`export { default as SpaceMarkdown } from ${reference(selection.markdown)};`);
43224
- writeFileSync11(entryPath, lines.join("\n") + "\n");
43511
+ writeFileSync13(entryPath, lines.join("\n") + "\n");
43225
43512
  }
43226
- writeFileSync11(manifestPath, JSON.stringify(generateSpaceManifest(selection), null, 2) + "\n");
43513
+ writeFileSync13(manifestPath, JSON.stringify(generateSpaceManifest(selection), null, 2) + "\n");
43227
43514
  }
43228
43515
  function finalizeSelectedArtifact(projectDir) {
43229
- const manifestPath = join20(projectDir, ".notis/output/manifest.json");
43230
- const manifest = JSON.parse(readFileSync18(manifestPath, "utf8"));
43231
- 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))) {
43232
43519
  delete manifest.bundle.css;
43233
- writeFileSync11(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
43520
+ writeFileSync13(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
43234
43521
  }
43235
43522
  }
43236
43523
  async function buildSpaceRelease(projectDir, selectedKey, { stdio = "inherit", refreshSdk = true, runBuild } = {}) {
@@ -43242,8 +43529,8 @@ async function buildSpaceRelease(projectDir, selectedKey, { stdio = "inherit", r
43242
43529
  const staging = freezeSourceWorkspace(projectDir, sourceFiles);
43243
43530
  let release;
43244
43531
  try {
43245
- if (existsSync14(join20(projectDir, "node_modules"))) {
43246
- 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");
43247
43534
  }
43248
43535
  const frozenSelection = await loadSelectedSpace(staging.projectDir, selectedKey);
43249
43536
  await buildArtifact(staging.projectDir, {
@@ -43297,18 +43584,18 @@ async function prepareSpaceRelease(projectDir, selectedKey) {
43297
43584
 
43298
43585
  // src/runtime/space-verification.js
43299
43586
  import { createHash as createHash13 } from "node:crypto";
43300
- import { existsSync as existsSync15, readFileSync as readFileSync19 } from "node:fs";
43587
+ import { existsSync as existsSync16, readFileSync as readFileSync21 } from "node:fs";
43301
43588
  import { fileURLToPath as fileURLToPath12 } from "node:url";
43302
43589
 
43303
43590
  // src/runtime/space-test-server.js
43304
43591
  import { createHash as createHash12 } from "node:crypto";
43305
43592
  var import__ = __toESM(require__(), 1);
43306
43593
  var import_ajv_formats = __toESM(require_dist(), 1);
43307
- 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";
43308
43595
  import { isDeepStrictEqual } from "node:util";
43309
43596
  import { fileURLToPath as fileURLToPath11 } from "node:url";
43310
43597
  init_errors();
43311
- var ROOT = resolve12(dirname18(fileURLToPath11(import.meta.url)), "../..");
43598
+ var ROOT = resolve13(dirname21(fileURLToPath11(import.meta.url)), "../..");
43312
43599
  function object(value) {
43313
43600
  return value && typeof value === "object" && !Array.isArray(value);
43314
43601
  }
@@ -43602,11 +43889,11 @@ async function loadSpaceVerificationRenderer() {
43602
43889
  const candidates = [new URL("../../dist/view-renderer/", import.meta.url), new URL("../../../view-renderer/", import.meta.url)];
43603
43890
  for (const root of candidates) {
43604
43891
  const entry = new URL("src/index.js", root);
43605
- if (!existsSync15(fileURLToPath12(entry))) continue;
43892
+ if (!existsSync16(fileURLToPath12(entry))) continue;
43606
43893
  const digest = createHash13("sha256");
43607
43894
  for (const file of ["src/renderer.js", "src/dom.js", "src/pool.js", "dist/host.js", "dist/host.css", "dist/theme.css"]) {
43608
43895
  digest.update(file);
43609
- digest.update(readFileSync19(new URL(file, root)));
43896
+ digest.update(readFileSync21(new URL(file, root)));
43610
43897
  }
43611
43898
  return { ...await import(entry.href), rendererDigest: digest.digest("hex") };
43612
43899
  }
@@ -43731,14 +44018,14 @@ async function verifySpaceRelease(release, {
43731
44018
  // src/runtime/space-database-structures.js
43732
44019
  var import_parser = __toESM(require_lib(), 1);
43733
44020
  init_errors();
43734
- import { existsSync as existsSync16, readFileSync as readFileSync20, realpathSync as realpathSync3, writeFileSync as writeFileSync12 } from "node:fs";
43735
- 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";
43736
44023
  var nameOf = (node) => node?.type === "Identifier" ? node.name : node?.type === "StringLiteral" ? node.value : null;
43737
44024
  function refreshSpaceAuthoring(projectDir, localKey, { databaseStructures, authoringOverrides } = {}) {
43738
44025
  let rewritten = /* @__PURE__ */ new Map();
43739
44026
  if (Object.keys(databaseStructures || {}).length) rewritten = planSpaceAuthoring(projectDir, localKey, { databaseStructures }, rewritten);
43740
44027
  if (authoringOverrides) rewritten = planSpaceAuthoring(projectDir, localKey, { authoringOverrides }, rewritten);
43741
- for (const [file, source] of rewritten) writeFileSync12(file, source);
44028
+ for (const [file, source] of rewritten) writeFileSync14(file, source);
43742
44029
  return [...rewritten.keys()].map((file) => relative8(realpathSync3(projectDir), file).split(sep4).join("/"));
43743
44030
  }
43744
44031
  function planSpaceAuthoring(projectDir, localKey, { databaseStructures: structures, authoringOverrides: overrides }, staged) {
@@ -43748,7 +44035,7 @@ function planSpaceAuthoring(projectDir, localKey, { databaseStructures: structur
43748
44035
  file = realpathSync3(file);
43749
44036
  if (!file.startsWith(root + sep4) || file.includes(`${sep4}node_modules${sep4}`)) throw fail();
43750
44037
  if (modules.has(file)) return modules.get(file);
43751
- const source = staged.get(file) ?? readFileSync20(file, "utf8");
44038
+ const source = staged.get(file) ?? readFileSync22(file, "utf8");
43752
44039
  const ast = (0, import_parser.parse)(source, { sourceType: "module", plugins: ["typescript", "jsx"] });
43753
44040
  const unit2 = { file, source, ast, bindings: /* @__PURE__ */ new Map(), exports: /* @__PURE__ */ new Map() };
43754
44041
  modules.set(file, unit2);
@@ -43776,8 +44063,8 @@ function planSpaceAuthoring(projectDir, localKey, { databaseStructures: structur
43776
44063
  }
43777
44064
  function imported(reference) {
43778
44065
  if (!reference.from?.startsWith(".")) throw fail();
43779
- const base = resolve13(dirname19(reference.unit.file), reference.from);
43780
- 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);
43781
44068
  if (!file) throw fail();
43782
44069
  return load(file);
43783
44070
  }
@@ -43822,12 +44109,12 @@ function planSpaceAuthoring(projectDir, localKey, { databaseStructures: structur
43822
44109
  if (value.node?.type !== "StringLiteral") throw fail();
43823
44110
  return value.node.value;
43824
44111
  }
43825
- 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);
43826
44113
  if (!indexFile) throw fail();
43827
44114
  const index = load(indexFile);
43828
44115
  const workspace = index.exports.get("default");
43829
44116
  const definition = scalar(property(property(property(workspace, "spaces"), localKey), "definition"));
43830
- const unit = load(resolve13(root, definition));
44117
+ const unit = load(resolve14(root, definition));
43831
44118
  const resources = property(unit.exports.get("default"), "resources");
43832
44119
  const edits = /* @__PURE__ */ new Map();
43833
44120
  for (const [alias, structure] of Object.entries(structures || {})) {
@@ -43946,9 +44233,9 @@ function planSpaceAuthoring(projectDir, localKey, { databaseStructures: structur
43946
44233
 
43947
44234
  // src/runtime/space-lock.js
43948
44235
  import { createHash as createHash14 } from "node:crypto";
43949
- 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";
43950
- import { randomUUID as randomUUID8 } from "node:crypto";
43951
- 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";
43952
44239
  init_errors();
43953
44240
  var SPACE_LOCK_FILE = "space-lock.json";
43954
44241
  var RESOURCES_FILE = "resources.json";
@@ -44002,12 +44289,12 @@ function writeSpaceLock(projectDir, lock) {
44002
44289
  return writeSpaceStateFile(projectDir, SPACE_LOCK_FILE, lock);
44003
44290
  }
44004
44291
  function readResourceList(projectDir) {
44005
- const path3 = join23(resolve14(projectDir), RESOURCES_FILE);
44006
- if (!existsSync17(path3)) return null;
44292
+ const path3 = join25(resolve15(projectDir), RESOURCES_FILE);
44293
+ if (!existsSync18(path3)) return null;
44007
44294
  if (lstatSync4(path3).isSymbolicLink()) throw usageError(`${RESOURCES_FILE} must be a regular file.`);
44008
44295
  let parsed;
44009
44296
  try {
44010
- parsed = JSON.parse(readFileSync21(path3, "utf8"));
44297
+ parsed = JSON.parse(readFileSync23(path3, "utf8"));
44011
44298
  } catch {
44012
44299
  throw usageError(`${RESOURCES_FILE} must be valid JSON.`);
44013
44300
  }
@@ -44024,11 +44311,11 @@ function readResourceList(projectDir) {
44024
44311
  });
44025
44312
  }
44026
44313
  function writeResourceList(projectDir, entries) {
44027
- const root = resolve14(projectDir);
44028
- const temporary = join23(root, `.${RESOURCES_FILE}-${randomUUID8()}`);
44314
+ const root = resolve15(projectDir);
44315
+ const temporary = join25(root, `.${RESOURCES_FILE}-${randomUUID9()}`);
44029
44316
  try {
44030
- writeFileSync13(temporary, JSON.stringify(entries, null, 2) + "\n", { flag: "wx" });
44031
- renameSync8(temporary, join23(root, RESOURCES_FILE));
44317
+ writeFileSync15(temporary, JSON.stringify(entries, null, 2) + "\n", { flag: "wx" });
44318
+ renameSync10(temporary, join25(root, RESOURCES_FILE));
44032
44319
  } finally {
44033
44320
  rmSync8(temporary, { force: true });
44034
44321
  }
@@ -44037,19 +44324,19 @@ function walkSkillFolder(directory, prefix, files) {
44037
44324
  for (const entry of readdirSync7(directory, { withFileTypes: true })) {
44038
44325
  if (entry.isSymbolicLink() || excluded(entry.name)) continue;
44039
44326
  const path3 = prefix ? `${prefix}/${entry.name}` : entry.name;
44040
- if (entry.isDirectory()) walkSkillFolder(join23(directory, entry.name), path3, files);
44041
- 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");
44042
44329
  }
44043
44330
  }
44044
44331
  function collectSkillFolders(projectDir) {
44045
- const root = join23(resolve14(projectDir), SKILLS_DIR);
44332
+ const root = join25(resolve15(projectDir), SKILLS_DIR);
44046
44333
  const folders = {};
44047
- if (!existsSync17(root) || lstatSync4(root).isSymbolicLink() || !lstatSync4(root).isDirectory()) return folders;
44334
+ if (!existsSync18(root) || lstatSync4(root).isSymbolicLink() || !lstatSync4(root).isDirectory()) return folders;
44048
44335
  for (const entry of readdirSync7(root, { withFileTypes: true })) {
44049
44336
  if (entry.isSymbolicLink() || !entry.isDirectory()) continue;
44050
44337
  if (!ALIAS.test(entry.name)) throw usageError(`${SKILLS_DIR}/${entry.name}: name the folder with the Skill alias (lowercase letters, digits, - or _).`);
44051
44338
  const files = {};
44052
- walkSkillFolder(join23(root, entry.name), "", files);
44339
+ walkSkillFolder(join25(root, entry.name), "", files);
44053
44340
  if (!files["SKILL.md"]) throw usageError(`${SKILLS_DIR}/${entry.name} needs a SKILL.md.`);
44054
44341
  folders[entry.name] = { files, digest: appFilesDigest(files) };
44055
44342
  }
@@ -44060,7 +44347,7 @@ function skillFolderFiles(files) {
44060
44347
  }
44061
44348
  function writeSkillFolder(projectDir, alias, files, { sourceSnapshot } = {}) {
44062
44349
  if (!ALIAS.test(alias)) throw usageError(`Unsafe Skill alias: ${alias}`);
44063
- const root = join23(resolve14(projectDir), SKILLS_DIR, alias);
44350
+ const root = join25(resolve15(projectDir), SKILLS_DIR, alias);
44064
44351
  const entries = Object.entries(files || {}).map(([path3, encoded]) => {
44065
44352
  safeRelativePath(path3, `Skill ${alias}`);
44066
44353
  return [path3, Buffer.from(encoded, "base64")];
@@ -44069,13 +44356,13 @@ function writeSkillFolder(projectDir, alias, files, { sourceSnapshot } = {}) {
44069
44356
  const changed = () => usageError(`${SKILLS_DIR}/${alias} changed while pulling its current Skill. Keep these local files and pull into a new directory.`);
44070
44357
  const readSnapshot = () => {
44071
44358
  const current = {};
44072
- 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();
44073
44360
  const walk = (directory, prefix = "") => {
44074
44361
  for (const entry of readdirSync7(directory, { withFileTypes: true })) {
44075
44362
  if (entry.isSymbolicLink() || excluded(entry.name)) throw changed();
44076
44363
  const path3 = prefix + entry.name;
44077
- if (entry.isDirectory()) walk(join23(directory, entry.name), path3 + "/");
44078
- 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");
44079
44366
  else throw changed();
44080
44367
  }
44081
44368
  };
@@ -44085,23 +44372,23 @@ function writeSkillFolder(projectDir, alias, files, { sourceSnapshot } = {}) {
44085
44372
  const expected = appFilesDigest(sourceSnapshot);
44086
44373
  if (appFilesDigest(readSnapshot()) !== expected) throw changed();
44087
44374
  if (appFilesDigest(files) === expected) return;
44088
- const staging = join23(resolve14(projectDir), ".notis", `skill-pull-${randomUUID8()}`);
44375
+ const staging = join25(resolve15(projectDir), ".notis", `skill-pull-${randomUUID9()}`);
44089
44376
  const backup = `${staging}-previous`;
44090
- mkdirSync13(staging, { recursive: true });
44377
+ mkdirSync15(staging, { recursive: true });
44091
44378
  let displaced = false;
44092
44379
  try {
44093
44380
  for (const [path3, bytes] of entries) {
44094
- const target = join23(staging, path3);
44095
- mkdirSync13(dirname20(target), { recursive: true });
44096
- writeFileSync13(target, bytes, { flag: "wx" });
44381
+ const target = join25(staging, path3);
44382
+ mkdirSync15(dirname23(target), { recursive: true });
44383
+ writeFileSync15(target, bytes, { flag: "wx" });
44097
44384
  }
44098
44385
  if (appFilesDigest(readSnapshot()) !== expected) throw changed();
44099
- renameSync8(root, backup);
44386
+ renameSync10(root, backup);
44100
44387
  displaced = true;
44101
44388
  try {
44102
- renameSync8(staging, root);
44389
+ renameSync10(staging, root);
44103
44390
  } catch (error) {
44104
- renameSync8(backup, root);
44391
+ renameSync10(backup, root);
44105
44392
  displaced = false;
44106
44393
  throw error;
44107
44394
  }
@@ -44114,10 +44401,10 @@ function writeSkillFolder(projectDir, alias, files, { sourceSnapshot } = {}) {
44114
44401
  return;
44115
44402
  }
44116
44403
  for (const [path3, bytes] of entries) {
44117
- const target = join23(root, path3);
44118
- mkdirSync13(dirname20(target), { recursive: true });
44404
+ const target = join25(root, path3);
44405
+ mkdirSync15(dirname23(target), { recursive: true });
44119
44406
  try {
44120
- writeFileSync13(target, bytes, { flag: "wx" });
44407
+ writeFileSync15(target, bytes, { flag: "wx" });
44121
44408
  } catch (error) {
44122
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.`);
44123
44410
  throw error;
@@ -44259,24 +44546,24 @@ function describeAppliedChanges(result) {
44259
44546
 
44260
44547
  // src/command-specs/spaces.js
44261
44548
  init_errors();
44262
- import { readFileSync as readFileSync22 } from "node:fs";
44263
- import { resolve as resolve17 } from "node:path";
44549
+ import { readFileSync as readFileSync24 } from "node:fs";
44550
+ import { resolve as resolve18 } from "node:path";
44264
44551
  import { createHash as createHash15 } from "node:crypto";
44265
44552
 
44266
44553
  // src/command-specs/views.js
44267
44554
  init_errors();
44268
44555
 
44269
44556
  // src/runtime/view-render.js
44270
- import { existsSync as existsSync18 } from "node:fs";
44557
+ import { existsSync as existsSync19 } from "node:fs";
44271
44558
  import { mkdir as mkdir2, writeFile as writeFile2, unlink } from "node:fs/promises";
44272
- import { resolve as resolve15, join as join24 } from "node:path";
44559
+ import { resolve as resolve16, join as join26 } from "node:path";
44273
44560
  import { fileURLToPath as fileURLToPath13 } from "node:url";
44274
44561
  init_errors();
44275
44562
  async function rendererLibrary() {
44276
44563
  const packaged = new URL("../../dist/view-renderer/src/index.js", import.meta.url);
44277
- if (existsSync18(fileURLToPath13(packaged))) return import(packaged.href);
44564
+ if (existsSync19(fileURLToPath13(packaged))) return import(packaged.href);
44278
44565
  const development = new URL("../../../view-renderer/src/index.js", import.meta.url);
44279
- if (existsSync18(fileURLToPath13(development))) return import(development.href);
44566
+ if (existsSync19(fileURLToPath13(development))) return import(development.href);
44280
44567
  throw usageError("The shared view renderer is missing. Rebuild or reinstall this CLI package.");
44281
44568
  }
44282
44569
  async function renderViewWithCliRuntime({
@@ -44316,7 +44603,7 @@ async function renderViewWithCliRuntime({
44316
44603
  throw error;
44317
44604
  }
44318
44605
  if (!directory) return { result, artifacts: null };
44319
- const root = resolve15(directory), created = [], artifacts = {};
44606
+ const root = resolve16(directory), created = [], artifacts = {};
44320
44607
  await mkdir2(root, { recursive: true });
44321
44608
  try {
44322
44609
  for (const [kind, name, bytes] of [
@@ -44324,7 +44611,7 @@ async function renderViewWithCliRuntime({
44324
44611
  ["screenshot", "view.png", result.screenshot ? Buffer.from(result.screenshot.data_base64, "base64") : void 0]
44325
44612
  ]) {
44326
44613
  if (bytes === void 0) continue;
44327
- const path3 = join24(root, name);
44614
+ const path3 = join26(root, name);
44328
44615
  await writeFile2(path3, bytes, { flag: "wx", mode: 384 });
44329
44616
  created.push(path3);
44330
44617
  artifacts[kind] = path3;
@@ -44337,8 +44624,8 @@ async function renderViewWithCliRuntime({
44337
44624
  }
44338
44625
 
44339
44626
  // src/command-specs/views.js
44340
- import { resolve as resolve16 } from "node:path";
44341
- import { randomUUID as randomUUID9 } from "node:crypto";
44627
+ import { resolve as resolve17 } from "node:path";
44628
+ import { randomUUID as randomUUID10 } from "node:crypto";
44342
44629
  function viewRenderCommandSpec({ screenshotOnly = false } = {}) {
44343
44630
  const command_path = screenshotOnly ? ["spaces", "screenshot"] : ["views", "render"];
44344
44631
  return {
@@ -44361,7 +44648,7 @@ function viewRenderCommandSpec({ screenshotOnly = false } = {}) {
44361
44648
  throw usageError("Choose markdown, screenshot, or markdown,screenshot.");
44362
44649
  }
44363
44650
  const width = ctx.options.width === void 0 ? 1440 : Number(ctx.options.width);
44364
- const directory = resolve16(ctx.options.outputDir || `.notis/renders/${randomUUID9()}`);
44651
+ const directory = resolve17(ctx.options.outputDir || `.notis/renders/${randomUUID10()}`);
44365
44652
  const controller = new AbortController(), cancel = () => controller.abort();
44366
44653
  process.once("SIGINT", cancel);
44367
44654
  process.once("SIGTERM", cancel);
@@ -44762,7 +45049,7 @@ var spacesCommandSpecs = [
44762
45049
  const sourceLink = { space_id: ctx.args.spaceId, api_base: ctx.runtime.apiBase.replace(/\/$/, "") };
44763
45050
  let databaseStructures, authoringOverrides;
44764
45051
  const result = await pullAppSource({
44765
- targetDir: resolve17(ctx.args.dir || ctx.args.spaceId),
45052
+ targetDir: resolve18(ctx.args.dir || ctx.args.spaceId),
44766
45053
  force: false,
44767
45054
  sourceKind: "space",
44768
45055
  sourceLink,
@@ -44985,7 +45272,7 @@ var spacesCommandSpecs = [
44985
45272
  return remote(ctx, "grant-authorize", { body: {
44986
45273
  space_id: ctx.args.spaceId,
44987
45274
  request_id: requestId(ctx),
44988
- template: object3(readFileSync22(resolve17(ctx.options.template), "utf8"), "--template"),
45275
+ template: object3(readFileSync24(resolve18(ctx.options.template), "utf8"), "--template"),
44989
45276
  document_id: ctx.options.record,
44990
45277
  dry_run: Boolean(ctx.options.dryRun)
44991
45278
  } });
@@ -45406,8 +45693,8 @@ init_channel();
45406
45693
  init_profiles();
45407
45694
  function readCliVersion() {
45408
45695
  try {
45409
- const manifestPath = join25(dirname21(fileURLToPath14(import.meta.url)), "..", "package.json");
45410
- 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;
45411
45698
  if (typeof version === "string" && version.trim()) {
45412
45699
  return version.trim();
45413
45700
  }