@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.
- package/README.md +11 -11
- package/config/portal-route-roots.json +0 -1
- package/dist/agent-hooks/notis-agent-hook.mjs +760 -473
- package/dist/base-skills/notis-apps/SKILL.md +4 -3
- package/dist/base-skills/notis-apps/references/sdk.md +3 -1
- package/dist/base-skills/notis-apps/references/views.md +1 -1
- package/dist/base-skills/notis-cli/SKILL.md +7 -5
- package/dist/base-skills/notis-query/references/documents.md +4 -3
- package/dist/sdk/src/components/DocumentPage.tsx +6 -3
- package/dist/sdk/src/runtime.ts +10 -2
- package/dist/skill-sync/index.js +78 -12
- package/dist/skill-sync/index.js.map +3 -3
- package/dist/skill-sync-worker.mjs +391 -175
- package/dist/view-renderer/dist/host.js +86 -86
- package/dist/view-renderer/src/host.tsx +4 -2
- package/package.json +1 -1
- package/skills/notis-apps/cli.md +1 -1
- package/skills/notis-cli/AGENT_INSTRUCTIONS.md +1 -1
- package/src/command-specs/auth.js +2 -2
- package/src/command-specs/handover.js +45 -16
- package/src/command-specs/profile.js +42 -1
- package/src/command-specs/skills.js +13 -1
- package/src/runtime/computer-identity.d.ts +30 -0
- package/src/runtime/computer-identity.js +151 -0
- package/src/runtime/config-lock.js +135 -0
- package/src/runtime/oauth.js +18 -1
- package/src/runtime/profiles.js +5 -107
- package/src/runtime/skill-sync/index.ts +83 -7
- package/src/runtime/skill-sync/local-scanner.ts +7 -4
- package/src/runtime/skill-sync/native-plan.ts +14 -3
- package/src/runtime/sync-skills.d.ts +3 -1
- package/src/runtime/sync-skills.js +10 -2
- 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
|
|
285
|
-
mkdirSync as
|
|
286
|
-
readFileSync as
|
|
287
|
-
renameSync as
|
|
288
|
-
|
|
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
|
|
293
|
-
import { dirname as
|
|
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(
|
|
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 =
|
|
504
|
+
let current = resolve7(startDir);
|
|
400
505
|
const root = parse(current).root;
|
|
401
506
|
while (true) {
|
|
402
|
-
const candidate =
|
|
403
|
-
if (
|
|
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 =
|
|
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
|
|
585
|
+
return resolve7(envConfigFile);
|
|
481
586
|
}
|
|
482
587
|
return CONFIG_FILE;
|
|
483
588
|
}
|
|
484
589
|
function loadConfig() {
|
|
485
590
|
const configFile = resolveConfigFile();
|
|
486
|
-
if (!
|
|
591
|
+
if (!existsSync8(configFile)) {
|
|
487
592
|
return normalizeConfig({});
|
|
488
593
|
}
|
|
489
594
|
try {
|
|
490
|
-
return normalizeConfig(JSON.parse(
|
|
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(
|
|
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
|
-
|
|
621
|
+
mkdirSync5(dirname7(configFile), { recursive: true });
|
|
517
622
|
const temporaryFile = `${configFile}.${process.pid}.${Date.now()}.tmp`;
|
|
518
|
-
|
|
519
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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 =
|
|
1001
|
-
CONFIG_FILE =
|
|
1002
|
-
WORKSPACE_DIR =
|
|
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 =
|
|
1017
|
-
WORKTREE_ROUTING_FILENAME =
|
|
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
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
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
|
|
1197
|
+
mkdirSync as mkdirSync7,
|
|
1054
1198
|
readdirSync as readdirSync4,
|
|
1055
|
-
readFileSync as
|
|
1056
|
-
renameSync as
|
|
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
|
|
1204
|
+
writeFileSync as writeFileSync7
|
|
1061
1205
|
} from "node:fs";
|
|
1062
1206
|
import { createServer as createServer3 } from "node:http";
|
|
1063
|
-
import { homedir as
|
|
1064
|
-
import { basename as basename2, dirname as
|
|
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((
|
|
1457
|
-
resolveCode =
|
|
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((
|
|
1462
|
-
response.end(body,
|
|
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((
|
|
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
|
-
|
|
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((
|
|
1540
|
-
setTimeout(
|
|
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((
|
|
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
|
-
|
|
1705
|
-
|
|
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(
|
|
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(
|
|
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
|
|
1938
|
+
return join10(lockDir, "owner.json");
|
|
1784
1939
|
}
|
|
1785
1940
|
function readListenerGlobalLockOwner(lockDir) {
|
|
1786
1941
|
try {
|
|
1787
|
-
return JSON.parse(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
2018
|
+
mkdirSync7(dirname9(lockDir), { recursive: true });
|
|
1864
2019
|
const deadline = Date.now() + waitMs;
|
|
1865
2020
|
for (; ; ) {
|
|
1866
2021
|
try {
|
|
1867
|
-
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1921
|
-
|
|
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(
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
2039
|
-
|
|
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((
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
3038
|
+
mkdirSync7(join10(homedir4(), ".notis"), { recursive: true });
|
|
2884
3039
|
const deadline = Date.now() + waitMs;
|
|
2885
3040
|
for (; ; ) {
|
|
2886
3041
|
try {
|
|
2887
|
-
|
|
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((
|
|
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 =
|
|
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 {
|
|
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
|
|
3235
|
-
|
|
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(
|
|
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 ?
|
|
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:
|
|
4588
|
-
cursor:
|
|
4589
|
-
codex:
|
|
4793
|
+
claude_code: join18(root, ".claude", "skills"),
|
|
4794
|
+
cursor: join18(root, ".cursor", "skills"),
|
|
4795
|
+
codex: join18(root, ".codex", "skills")
|
|
4590
4796
|
},
|
|
4591
|
-
legacyGlobalSkillsDir:
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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:
|
|
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,
|
|
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,
|
|
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
|
|
27830
|
-
import { dirname as
|
|
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
|
|
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
|
|
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
|
|
36125
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
35903
36126
|
import { createReadStream } from "node:fs";
|
|
35904
|
-
import { dirname as
|
|
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-${
|
|
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(
|
|
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_${
|
|
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 ?
|
|
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
|
|
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 ||
|
|
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(
|
|
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 =
|
|
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) :
|
|
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(
|
|
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
|
-
|
|
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 =
|
|
37268
|
-
const browserScreenshotPath = rawOutputDir ?
|
|
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
|
|
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 (!
|
|
38290
|
+
if (!existsSync9(filePath)) {
|
|
38068
38291
|
throw usageError(`File not found: ${filePath}`);
|
|
38069
38292
|
}
|
|
38070
|
-
return parseJson(
|
|
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 (!
|
|
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
|
|
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 =
|
|
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
|
|
38959
|
-
import { dirname as
|
|
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
|
|
38973
|
-
mkdirSync as
|
|
38974
|
-
readFileSync as
|
|
39195
|
+
existsSync as existsSync10,
|
|
39196
|
+
mkdirSync as mkdirSync9,
|
|
39197
|
+
readFileSync as readFileSync12,
|
|
38975
39198
|
readdirSync as readdirSync6,
|
|
38976
|
-
renameSync as
|
|
38977
|
-
writeFileSync as
|
|
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
|
|
38981
|
-
import { dirname as
|
|
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 =
|
|
38984
|
-
var INSTRUCTIONS_PATH =
|
|
38985
|
-
var HOOK_BUNDLE_PATH =
|
|
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
|
-
|
|
39216
|
+
mkdirSync9(dirname12(filePath), { recursive: true, mode: 448 });
|
|
38994
39217
|
const temporaryPath = `${filePath}.notis-${process.pid}-${Date.now()}.tmp`;
|
|
38995
|
-
|
|
38996
|
-
|
|
39218
|
+
writeFileSync8(temporaryPath, contents, { mode });
|
|
39219
|
+
renameSync6(temporaryPath, filePath);
|
|
38997
39220
|
}
|
|
38998
39221
|
function readText(filePath) {
|
|
38999
|
-
return
|
|
39222
|
+
return existsSync10(filePath) ? readFileSync12(filePath, "utf-8") : "";
|
|
39000
39223
|
}
|
|
39001
39224
|
function activeCodexInstructionsPath(home) {
|
|
39002
|
-
const overridePath =
|
|
39003
|
-
if (
|
|
39225
|
+
const overridePath = join12(home, ".codex", "AGENTS.override.md");
|
|
39226
|
+
if (existsSync10(overridePath) && readText(overridePath).trim()) {
|
|
39004
39227
|
return overridePath;
|
|
39005
39228
|
}
|
|
39006
|
-
return
|
|
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 (!
|
|
39042
|
-
const raw =
|
|
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 =
|
|
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 =
|
|
39317
|
+
const bundle = readFileSync12(bundlePath2);
|
|
39095
39318
|
const digest = createHash4("sha256").update(bundle).digest("hex");
|
|
39096
|
-
const runtimePath =
|
|
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 =
|
|
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 =
|
|
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" &&
|
|
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 ?
|
|
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:
|
|
39414
|
+
root: join12(home, ".codex"),
|
|
39192
39415
|
instructions: activeCodexInstructionsPath(home),
|
|
39193
|
-
hooks:
|
|
39416
|
+
hooks: join12(home, ".codex", "hooks.json")
|
|
39194
39417
|
};
|
|
39195
39418
|
}
|
|
39196
39419
|
if (agentId === "claude-code") {
|
|
39197
39420
|
return {
|
|
39198
|
-
root:
|
|
39199
|
-
instructions:
|
|
39200
|
-
hooks:
|
|
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 =
|
|
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 (
|
|
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 =
|
|
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 =
|
|
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) :
|
|
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
|
|
39268
|
-
mkdirSync as
|
|
39269
|
-
readFileSync as
|
|
39270
|
-
renameSync as
|
|
39271
|
-
writeFileSync as
|
|
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
|
|
39274
|
-
import { dirname as
|
|
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 =
|
|
39503
|
+
function statePath(sessionId, home = homedir6()) {
|
|
39281
39504
|
if (!sessionId) return null;
|
|
39282
|
-
return
|
|
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 || !
|
|
39509
|
+
if (!filePath || !existsSync11(filePath)) return { seen: [], pending: null };
|
|
39287
39510
|
try {
|
|
39288
|
-
const parsed = JSON.parse(
|
|
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
|
-
|
|
39541
|
+
mkdirSync10(dirname13(filePath), { recursive: true, mode: 448 });
|
|
39319
39542
|
const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
39320
|
-
|
|
39543
|
+
writeFileSync9(temporaryPath, `${JSON.stringify(state)}
|
|
39321
39544
|
`, { mode: 384 });
|
|
39322
|
-
|
|
39545
|
+
renameSync7(temporaryPath, filePath);
|
|
39323
39546
|
}
|
|
39324
|
-
function rememberPendingTurn(input, home =
|
|
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 =
|
|
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 =
|
|
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 || !
|
|
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 =
|
|
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: "
|
|
39803
|
-
when_to_use: "Use this to disconnect a single account.
|
|
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 =
|
|
39824
|
-
var BUNDLED_BRIEF_PATH =
|
|
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:
|
|
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
|
|
40034
|
-
import { existsSync as
|
|
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:
|
|
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 (!
|
|
40445
|
-
const trace = JSON.parse(
|
|
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
|
|
40899
|
+
import { createHash as createHash8, randomUUID as randomUUID7 } from "node:crypto";
|
|
40677
40900
|
import {
|
|
40678
40901
|
mkdtempSync as mkdtempSync4,
|
|
40679
|
-
readFileSync as
|
|
40902
|
+
readFileSync as readFileSync16,
|
|
40680
40903
|
rmSync as rmSync6,
|
|
40681
|
-
writeFileSync as
|
|
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
|
|
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(
|
|
40766
|
-
const marker = `${(/* @__PURE__ */ new Date()).toISOString().replaceAll(/[-:.]/g, "")}-${
|
|
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 ||
|
|
40991
|
+
const fixturePath = ctx.options.sourceFile || join15(tempDir, `notis-file-upload-${marker}.txt`);
|
|
40769
40992
|
if (generatedFixture) {
|
|
40770
|
-
|
|
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 =
|
|
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
|
|
41309
|
-
import { basename as basename7, relative as relative4, resolve as
|
|
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 =
|
|
41616
|
+
const root = resolve8(repository.toplevel);
|
|
41364
41617
|
const sensitive = [];
|
|
41365
41618
|
for (const path3 of filesToAutoCommit(repository)) {
|
|
41366
|
-
const absolute =
|
|
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 =
|
|
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 = ["
|
|
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 || "
|
|
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({
|
|
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
|
-
|
|
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.
|
|
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:
|
|
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
|
|
41719
|
-
'notis handover start "add integration tests" --route
|
|
41720
|
-
'notis handover start "review and clean up this branch" --route
|
|
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
|
|
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
|
|
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
|
|
41759
|
-
import { dirname as
|
|
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
|
|
42036
|
+
existsSync as existsSync13,
|
|
41765
42037
|
lstatSync as lstatSync3,
|
|
41766
|
-
mkdirSync as
|
|
42038
|
+
mkdirSync as mkdirSync11,
|
|
41767
42039
|
readlinkSync,
|
|
41768
|
-
renameSync as
|
|
42040
|
+
renameSync as renameSync8,
|
|
41769
42041
|
rmSync as rmSync7,
|
|
41770
42042
|
symlinkSync
|
|
41771
42043
|
} from "node:fs";
|
|
41772
|
-
import { homedir as
|
|
41773
|
-
import { dirname as
|
|
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 =
|
|
42052
|
+
var HERE3 = dirname15(fileURLToPath9(import.meta.url));
|
|
41781
42053
|
function resolveBundledBaseSkillsRoot({ resourcesPath = process.resourcesPath } = {}) {
|
|
41782
|
-
const sourceCheckout =
|
|
41783
|
-
const packaged =
|
|
41784
|
-
const desktopResource = resourcesPath ?
|
|
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) =>
|
|
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 =
|
|
41794
|
-
const notisRoot =
|
|
42065
|
+
function getBaseSkillPaths({ home = homedir7(), userId = null } = {}) {
|
|
42066
|
+
const notisRoot = join16(home, ".notis", "skills");
|
|
41795
42067
|
const targetRoots = [
|
|
41796
|
-
|
|
41797
|
-
|
|
41798
|
-
|
|
41799
|
-
|
|
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(
|
|
42074
|
+
targetRoots.push(join16(notisRoot, "users", userId, "skills"));
|
|
41803
42075
|
}
|
|
41804
42076
|
return {
|
|
41805
|
-
baseRoot:
|
|
41806
|
-
backupRoot:
|
|
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
|
|
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 =
|
|
41820
|
-
|
|
41821
|
-
|
|
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
|
-
|
|
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 (
|
|
41833
|
-
|
|
42104
|
+
if (existsSync13(destination)) {
|
|
42105
|
+
renameSync8(destination, previous);
|
|
41834
42106
|
movedPrevious = true;
|
|
41835
42107
|
}
|
|
41836
|
-
|
|
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 && !
|
|
41841
|
-
|
|
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 =
|
|
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 =
|
|
41862
|
-
if (!
|
|
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,
|
|
42137
|
+
replaceDirectory(source, join16(paths.baseRoot, name));
|
|
41866
42138
|
result.installed += 1;
|
|
41867
42139
|
}
|
|
41868
42140
|
for (const targetRoot of paths.targetRoots) {
|
|
41869
|
-
|
|
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 =
|
|
41873
|
-
const linkPath =
|
|
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 (
|
|
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(
|
|
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((
|
|
42212
|
+
return new Promise((resolve19) => setTimeout(resolve19, milliseconds));
|
|
41941
42213
|
}
|
|
41942
42214
|
async function quarantineStaleLock(lockDirectory, snapshot) {
|
|
41943
|
-
const quarantineRoot =
|
|
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,
|
|
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 =
|
|
41956
|
-
const ownerPath =
|
|
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 =
|
|
41964
|
-
const releasedDirectory =
|
|
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 =
|
|
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 =
|
|
41982
|
-
const ownerId = `${process.pid}.${
|
|
42253
|
+
const lockDirectory = join17(home, ".notis", "skills", ".operation-lock");
|
|
42254
|
+
const ownerId = `${process.pid}.${randomUUID8()}`;
|
|
41983
42255
|
const deadline = now() + timeoutMs;
|
|
41984
|
-
await mkdir(
|
|
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 =
|
|
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,
|
|
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
|
-
{
|
|
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
|
|
42082
|
-
import { homedir as
|
|
42083
|
-
import { dirname as
|
|
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
|
-
|
|
42365
|
+
mkdirSync12(dirname18(target), { recursive: true, mode: 448 });
|
|
42089
42366
|
const temporary = `${target}.${process.pid}.tmp`;
|
|
42090
|
-
|
|
42091
|
-
|
|
42367
|
+
writeFileSync11(temporary, value, { mode });
|
|
42368
|
+
renameSync9(temporary, target);
|
|
42092
42369
|
}
|
|
42093
42370
|
function xml(value) {
|
|
42094
42371
|
return String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
@@ -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 =
|
|
42104
|
-
if (
|
|
42105
|
-
const saved =
|
|
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 =
|
|
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 =
|
|
42138
|
-
const bundle =
|
|
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 =
|
|
42141
|
-
if (!
|
|
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 =
|
|
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 =
|
|
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((
|
|
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
|
|
42177
|
-
import { resolve as
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
42514
|
-
import { join as
|
|
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
|
-
|
|
42824
|
-
|
|
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
|
-
|
|
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
|
-
|
|
42852
|
-
|
|
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
|
|
42893
|
-
import { dirname as
|
|
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
|
|
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(
|
|
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) =>
|
|
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(
|
|
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(
|
|
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(
|
|
42947
|
-
source = (file) => project(file)?.program.getSourceFile(
|
|
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,
|
|
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,
|
|
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 =
|
|
43216
|
-
const manifestPath =
|
|
43217
|
-
|
|
43218
|
-
|
|
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(
|
|
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
|
-
|
|
43511
|
+
writeFileSync13(entryPath, lines.join("\n") + "\n");
|
|
43225
43512
|
}
|
|
43226
|
-
|
|
43513
|
+
writeFileSync13(manifestPath, JSON.stringify(generateSpaceManifest(selection), null, 2) + "\n");
|
|
43227
43514
|
}
|
|
43228
43515
|
function finalizeSelectedArtifact(projectDir) {
|
|
43229
|
-
const manifestPath =
|
|
43230
|
-
const manifest = JSON.parse(
|
|
43231
|
-
if (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
|
-
|
|
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 (
|
|
43246
|
-
symlinkSync2(
|
|
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
|
|
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
|
|
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 =
|
|
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 (!
|
|
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(
|
|
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
|
|
43735
|
-
import { dirname as
|
|
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)
|
|
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) ??
|
|
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 =
|
|
43780
|
-
const file = ["", ".ts", ".tsx", ".js", ".mjs", "/index.ts", "/index.js"].map((suffix) => base + suffix).find(
|
|
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) =>
|
|
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(
|
|
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
|
|
43950
|
-
import { randomUUID as
|
|
43951
|
-
import { dirname as
|
|
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 =
|
|
44006
|
-
if (!
|
|
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(
|
|
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 =
|
|
44028
|
-
const temporary =
|
|
44314
|
+
const root = resolve15(projectDir);
|
|
44315
|
+
const temporary = join25(root, `.${RESOURCES_FILE}-${randomUUID9()}`);
|
|
44029
44316
|
try {
|
|
44030
|
-
|
|
44031
|
-
|
|
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(
|
|
44041
|
-
else if (entry.isFile()) files[path3] =
|
|
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 =
|
|
44332
|
+
const root = join25(resolve15(projectDir), SKILLS_DIR);
|
|
44046
44333
|
const folders = {};
|
|
44047
|
-
if (!
|
|
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(
|
|
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 =
|
|
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 (!
|
|
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(
|
|
44078
|
-
else if (entry.isFile()) current[path3] =
|
|
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 =
|
|
44375
|
+
const staging = join25(resolve15(projectDir), ".notis", `skill-pull-${randomUUID9()}`);
|
|
44089
44376
|
const backup = `${staging}-previous`;
|
|
44090
|
-
|
|
44377
|
+
mkdirSync15(staging, { recursive: true });
|
|
44091
44378
|
let displaced = false;
|
|
44092
44379
|
try {
|
|
44093
44380
|
for (const [path3, bytes] of entries) {
|
|
44094
|
-
const target =
|
|
44095
|
-
|
|
44096
|
-
|
|
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
|
-
|
|
44386
|
+
renameSync10(root, backup);
|
|
44100
44387
|
displaced = true;
|
|
44101
44388
|
try {
|
|
44102
|
-
|
|
44389
|
+
renameSync10(staging, root);
|
|
44103
44390
|
} catch (error) {
|
|
44104
|
-
|
|
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 =
|
|
44118
|
-
|
|
44404
|
+
const target = join25(root, path3);
|
|
44405
|
+
mkdirSync15(dirname23(target), { recursive: true });
|
|
44119
44406
|
try {
|
|
44120
|
-
|
|
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
|
|
44263
|
-
import { resolve as
|
|
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
|
|
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
|
|
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 (
|
|
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 (
|
|
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 =
|
|
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 =
|
|
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
|
|
44341
|
-
import { randomUUID as
|
|
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 =
|
|
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:
|
|
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(
|
|
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 =
|
|
45410
|
-
const version = JSON.parse(
|
|
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
|
}
|