@notis_ai/cli 0.2.0-beta.177.1 → 0.2.0-beta.178.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.
@@ -4797,7 +4797,7 @@ var init_skill_sync = __esm({
4797
4797
 
4798
4798
  // src/cli.js
4799
4799
  import { readFileSync as readFileSync18 } from "node:fs";
4800
- import { dirname as dirname16, join as join16 } from "node:path";
4800
+ import { dirname as dirname16, join as join17 } from "node:path";
4801
4801
  import { fileURLToPath as fileURLToPath11 } from "node:url";
4802
4802
 
4803
4803
  // node_modules/commander/lib/error.js
@@ -8169,8 +8169,8 @@ function useColor() {
8169
8169
  var program = new Command();
8170
8170
 
8171
8171
  // src/command-specs/reports.js
8172
- import { readFileSync as readFileSync9 } from "node:fs";
8173
- import { resolve as resolve6 } from "node:path";
8172
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, rmSync as rmSync6 } from "node:fs";
8173
+ import { resolve as resolve6, join as join9 } from "node:path";
8174
8174
 
8175
8175
  // src/command-specs/apps.js
8176
8176
  init_errors();
@@ -9223,10 +9223,10 @@ function detectProjectWarnings(projectDir, appConfig = null) {
9223
9223
  warnings.push("Missing Tailwind config.");
9224
9224
  }
9225
9225
  const readsWorkspaceDatabases = appConfig?.capabilities?.workspaceDatabases === "read";
9226
- if (appConfig && !readsWorkspaceDatabases && (!Array.isArray(appConfig.databases) || appConfig.databases.length === 0)) {
9226
+ if (appConfig && appConfig.kind !== "report" && !readsWorkspaceDatabases && (!Array.isArray(appConfig.databases) || appConfig.databases.length === 0)) {
9227
9227
  warnings.push("No database references declared in notis.config.ts.");
9228
9228
  }
9229
- if (appConfig) {
9229
+ if (appConfig && appConfig.kind !== "report") {
9230
9230
  try {
9231
9231
  const listing = inspectListingReadiness(projectDir, appConfig);
9232
9232
  warnings.push(...listing.errors, ...listing.warnings);
@@ -9657,6 +9657,33 @@ function generateManifest(appConfig, projectDir) {
9657
9657
  }
9658
9658
  return entry;
9659
9659
  });
9660
+ if (appConfig.kind === "report") {
9661
+ if (routes.length !== 1 || routes[0].collection || routes[0].resourceDeepLinks) {
9662
+ throw usageError("Reports require one standalone route, without app collections or resource deep links.");
9663
+ }
9664
+ if (["databases", "skills", "automations", "onboarding", "tagline", "categories", "author", "screenshots"].some((key) => {
9665
+ const value = appConfig[key];
9666
+ return Array.isArray(value) ? value.length > 0 : Boolean(value);
9667
+ })) throw usageError("Reports cannot own databases, skills, automations or Store metadata.");
9668
+ if (Object.values(appConfig.capabilities || {}).some((value) => value !== "read")) {
9669
+ throw usageError("Reports support read capabilities only; shell grants require an installed app.");
9670
+ }
9671
+ const databaseAccess = appConfig.databaseAccess || [];
9672
+ if (!Array.isArray(databaseAccess) || databaseAccess.some(
9673
+ (entry) => !entry || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(entry.id || "") || !["read", "write"].includes(entry.access)
9674
+ )) throw usageError("databaseAccess entries require an existing database UUID and read/write access.");
9675
+ return {
9676
+ kind: "report",
9677
+ version: 1,
9678
+ spec_version: 4,
9679
+ routes: routes.map((route) => ({ ...route, default: true, tool_access: { base: { tools: appConfig.tools || [] } } })),
9680
+ bundle: { js: "bundle/app.js", css: "bundle/app.css" },
9681
+ tools: appConfig.tools || [],
9682
+ tool_bindings: normalizeAppToolBindings(appConfig.toolBindings),
9683
+ capabilities: normalizeAppCapabilities(appConfig.capabilities),
9684
+ database_access: databaseAccess
9685
+ };
9686
+ }
9660
9687
  const databases = (appConfig.databases || []).map((entry) => {
9661
9688
  if (typeof entry === "string") return entry;
9662
9689
  if (!entry || typeof entry !== "object" || !entry.slug) return entry;
@@ -11600,6 +11627,7 @@ function buildHarnessDescriptor({ state, manifest, appConfig, route, scenario =
11600
11627
  Array.isArray(appConfig?.tools) && appConfig.tools.length ? appConfig.tools : manifest.tools
11601
11628
  );
11602
11629
  return {
11630
+ ...state.resource ? { resource: state.resource } : {},
11603
11631
  app: {
11604
11632
  id: state.appId || "harness-app",
11605
11633
  slug: state.slug,
@@ -11902,7 +11930,8 @@ async function runHarnessRoute({
11902
11930
  sessionName,
11903
11931
  timeoutMs = 1e4,
11904
11932
  snapshotPath = null,
11905
- designViewports = DEFAULT_DESIGN_VIEWPORTS
11933
+ designViewports = DEFAULT_DESIGN_VIEWPORTS,
11934
+ waitForRuntime = false
11906
11935
  }) {
11907
11936
  const opened = await runAgentBrowser(["--session", sessionName, "open", url], {
11908
11937
  timeoutMs: Math.min(Math.max(timeoutMs, 5e3), 3e4)
@@ -11918,17 +11947,21 @@ async function runHarnessRoute({
11918
11947
  };
11919
11948
  }
11920
11949
  const deadline = Date.now() + timeoutMs;
11950
+ let readySince = null;
11921
11951
  while (Date.now() < deadline) {
11922
11952
  const lastRead = await readHarness(sessionName, 5e3);
11923
11953
  if (!lastRead.ok) {
11954
+ readySince = null;
11924
11955
  await delay(250);
11925
11956
  continue;
11926
11957
  }
11927
11958
  const harness2 = lastRead.harness;
11928
- if (harness2?.mounted || Array.isArray(harness2?.errors) && harness2.errors.length > 0) {
11929
- await delay(250);
11930
- break;
11931
- }
11959
+ if (Array.isArray(harness2?.errors) && harness2.errors.length > 0) break;
11960
+ const pending = (harness2?.runtimeCalls || []).some((call) => call?.ok == null);
11961
+ if (harness2?.mounted && (!waitForRuntime || !pending)) {
11962
+ readySince ??= Date.now();
11963
+ if (Date.now() - readySince >= 250) break;
11964
+ } else readySince = null;
11932
11965
  await delay(250);
11933
11966
  }
11934
11967
  const finalRead = await readHarness(sessionName, 5e3);
@@ -11954,8 +11987,8 @@ async function runHarnessRoute({
11954
11987
  savedSnapshotPath = snapshotPath;
11955
11988
  }
11956
11989
  }
11957
- const timedOut = !harness.mounted && Date.now() >= deadline;
11958
11990
  const runtimeCalls = Array.isArray(harness.runtimeCalls) ? harness.runtimeCalls : [];
11991
+ const timedOut = (!harness.mounted || waitForRuntime && runtimeCalls.some((call) => call?.ok == null)) && Date.now() >= deadline;
11959
11992
  let design = [];
11960
11993
  let designToolError = null;
11961
11994
  if (harness.mounted && Array.isArray(designViewports) && designViewports.length > 0) {
@@ -13176,6 +13209,9 @@ function assertHarnessResult(result, route, databaseSlugs, mode = "stub", capabi
13176
13209
  });
13177
13210
  }
13178
13211
  if (mode === "live") {
13212
+ if (runtimeCalls.some((call) => call?.ok == null)) {
13213
+ assertions.push({ ok: false, code: "runtime_calls_pending", message: "Live verification ended before every started runtime call settled." });
13214
+ }
13179
13215
  if (runtimeCalls.length > 0 && runtimeCalls.every((call) => call?.ok === false)) {
13180
13216
  assertions.push({
13181
13217
  ok: false,
@@ -13414,6 +13450,8 @@ async function appsVerifyHandler(ctx) {
13414
13450
  throw usageError(`Project has problems:
13415
13451
  ${problems.map((p) => ` - ${p}`).join("\n")}`);
13416
13452
  }
13453
+ const appConfig = await loadAppConfig(projectDir);
13454
+ const isReport = appConfig.kind === "report";
13417
13455
  const mode = ctx.options.mode || "stub";
13418
13456
  if (!["stub", "live"].includes(mode)) {
13419
13457
  throw usageError('--mode must be either "stub" or "live".');
@@ -13426,8 +13464,10 @@ ${problems.map((p) => ` - ${p}`).join("\n")}`);
13426
13464
  if (!ctx.runtime.jwt) {
13427
13465
  throw usageError("Live verify mode requires CLI auth. Run notis login and retry.");
13428
13466
  }
13429
- linkedState = readLinkedState(projectDir, linkedStateProfileKey(ctx.runtime));
13430
- if (!linkedState?.app_id) {
13467
+ if (isReport) {
13468
+ if (!ctx.options.documentId || !/^\d+$/.test(String(ctx.options.expectedRevision ?? ""))) throw usageError("Live report verification requires --document-id and --expected-revision of the saved report.");
13469
+ } else linkedState = readLinkedState(projectDir, linkedStateProfileKey(ctx.runtime));
13470
+ if (!isReport && !linkedState?.app_id) {
13431
13471
  throw usageError("Live verify mode requires a linked app. Run `notis apps link <app-id> .` first.");
13432
13472
  }
13433
13473
  }
@@ -13437,15 +13477,14 @@ ${problems.map((p) => ` - ${p}`).join("\n")}`);
13437
13477
  });
13438
13478
  }
13439
13479
  const manifest = readManifest(projectDir);
13440
- const appConfig = await loadAppConfig(projectDir);
13441
- const listing = inspectListingReadiness(projectDir, appConfig);
13480
+ const listing = isReport ? { ready: true, errors: [], warnings: [] } : inspectListingReadiness(projectDir, appConfig);
13442
13481
  if (listing.errors.length && ctx.options.listing === true) {
13443
13482
  throw usageError(`Listing metadata has problems:
13444
13483
  ${listing.errors.map((error) => ` - ${error}`).join("\n")}`);
13445
13484
  }
13446
13485
  const listingWarnings = [
13447
13486
  ...[...listing.errors, ...listing.warnings].map((message) => `Store readiness: ${message}`),
13448
- ...findUnknownScreenshotScenarios(projectDir, resolveListingScreenshots(projectDir, appConfig))
13487
+ ...isReport ? [] : findUnknownScreenshotScenarios(projectDir, resolveListingScreenshots(projectDir, appConfig))
13449
13488
  ];
13450
13489
  const routes = routeSelection(manifest, parseRouteSlugs(ctx.options.routes));
13451
13490
  const port = parsePort(ctx.options.port) || await getAvailablePort();
@@ -13467,7 +13506,8 @@ ${listing.errors.map((error) => ` - ${error}`).join("\n")}`);
13467
13506
  apps: [{
13468
13507
  slug: appSlug,
13469
13508
  projectDir,
13470
- appId: linkedState?.app_id || "harness-app"
13509
+ appId: linkedState?.app_id || "harness-app",
13510
+ resource: isReport ? { kind: "report", id: ctx.options.documentId || "preview", revision: Number(ctx.options.expectedRevision || 0) } : void 0
13471
13511
  }],
13472
13512
  port,
13473
13513
  harness: {
@@ -13541,7 +13581,8 @@ ${listing.errors.map((error) => ` - ${error}`).join("\n")}`);
13541
13581
  const result = await runHarnessRoute({
13542
13582
  url,
13543
13583
  sessionName: browserSessionName,
13544
- timeoutMs: Number.parseInt(ctx.globalOptions.timeoutMs || "", 10) || 1e4,
13584
+ timeoutMs: Number.parseInt(ctx.globalOptions.timeoutMs || "", 10) || (mode === "live" ? 9e4 : 1e4),
13585
+ waitForRuntime: mode === "live",
13545
13586
  snapshotPath
13546
13587
  });
13547
13588
  const assertions = assertHarnessResult(
@@ -13596,11 +13637,7 @@ ${listing.errors.map((error) => ` - ${error}`).join("\n")}`);
13596
13637
  },
13597
13638
  summary,
13598
13639
  results,
13599
- listing: {
13600
- ready: listing.ready,
13601
- gated: ctx.options.listing === true,
13602
- problems: listing.errors
13603
- }
13640
+ ...!isReport ? { listing: { ready: listing.ready, gated: ctx.options.listing === true, problems: listing.errors } } : {}
13604
13641
  };
13605
13642
  if (!keepOpen) await cleanup();
13606
13643
  ctx.output.emitSuccess({
@@ -14513,76 +14550,86 @@ var appsCommandSpecs = [
14513
14550
 
14514
14551
  // src/command-specs/reports.js
14515
14552
  init_errors();
14516
- var reuse = (command, name = command) => {
14517
- const spec = appsCommandSpecs.find((item) => item.command_path.join(" ") === `apps ${command}`);
14553
+ async function assertReportProject(ctx) {
14554
+ const dir = resolveProjectDir(ctx.args.dir || ".");
14555
+ if ((await loadAppConfig(dir)).kind !== "report") throw usageError('Set kind: "report" in notis.config.ts. Reports have no app installation or owned resources.');
14556
+ return dir;
14557
+ }
14558
+ async function initReport(ctx) {
14559
+ const dir = resolveProjectDir(ctx.args.dir || `./${ctx.args.name.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`);
14560
+ const result = await appsInitHandler({ ...ctx, args: { ...ctx.args, dir }, options: {}, output: { emitSuccess: (value) => value } });
14561
+ writeFileSync6(join9(dir, "notis.config.ts"), `import { defineNotisApp } from '@notis/sdk/config';
14562
+ export default defineNotisApp({
14563
+ kind: 'report', name: ${JSON.stringify(ctx.args.name)},
14564
+ routes: [{ path: '/', slug: 'home', name: 'Report', default: true }],
14565
+ tools: [],
14566
+ });
14567
+ `);
14568
+ writeFileSync6(join9(dir, "app/page.tsx"), `'use client';
14569
+ import { useNotis, NotisCommentBoundary } from '@notis/sdk';
14570
+ export default function Report() {
14571
+ const { app } = useNotis();
14572
+ return <NotisCommentBoundary><main className="notis-app-shell space-y-6">
14573
+ <h1 className="text-2xl font-semibold">{app?.name || 'Report'}</h1>
14574
+ <p className="text-muted-foreground">Your report is ready to build.</p>
14575
+ </main></NotisCommentBoundary>;
14576
+ }
14577
+ `);
14578
+ rmSync6(join9(dir, "CHANGELOG.md"), { force: true });
14579
+ return ctx.output.emitSuccess({ ...result, command: "reports init", hints: [
14580
+ { command: `cd ${dir} && npm install`, reason: "Install dependencies" },
14581
+ { command: `notis reports build ${dir}`, reason: "Build the standalone report" }
14582
+ ] });
14583
+ }
14584
+ var localReportCommand = (command, name = command) => {
14585
+ const app = appsCommandSpecs.find((item) => item.command_path.join(" ") === `apps ${command}`);
14518
14586
  return {
14519
- ...spec,
14520
- handler: async (ctx) => {
14521
- const output = new Proxy(ctx.output, {
14522
- get(target, key) {
14523
- if (key === "emitSuccess") return (result) => {
14524
- const value2 = { ...result, warnings: (result.warnings || []).filter((warning) => !warning.startsWith("Store readiness:")) };
14525
- if (value2.data?.listing) {
14526
- value2.data = { ...value2.data };
14527
- delete value2.data.listing;
14528
- }
14529
- return target.emitSuccess(value2);
14530
- };
14531
- const value = Reflect.get(target, key);
14532
- return typeof value === "function" ? value.bind(target) : value;
14533
- }
14534
- });
14535
- return spec.handler({ ...ctx, options: { ...ctx.options, listing: false, ...name === "preview" ? { keepOpen: true } : {} }, output });
14536
- },
14587
+ ...app,
14537
14588
  command_path: ["reports", name],
14538
- summary: `${name[0].toUpperCase() + name.slice(1)} a record-owned SDK report locally.${name === "preview" ? " Keeps the preview server and browser session open." : ""}`,
14539
- args_schema: {
14540
- ...spec.args_schema,
14541
- options: (spec.args_schema?.options || []).map((option) => option.flags === "--listing" ? { ...option, description: "Ignored for reports; saving a report does not publish a Store listing." } : option)
14542
- },
14543
- examples: (spec.examples || []).filter((example) => !example.includes("--listing")).map((example) => example.replace(`apps ${command}`, `reports ${name}`)),
14544
- when_to_use: "Author an independent report without deploying its owning app."
14589
+ summary: `${name[0].toUpperCase() + name.slice(1)} a standalone live SDK report.`,
14590
+ when_to_use: "Author a private standalone document using the shared view runtime; no app or database is required.",
14591
+ args_schema: { ...app.args_schema, options: [...(app.args_schema.options || []).filter((option) => !["--listing", "--from <slug>"].includes(option.flags)), ...command === "verify" ? [{ flags: "--document-id <id>", description: "Saved report for live verification." }, { flags: "--expected-revision <revision>", description: "Saved report revision for live verification." }] : []] },
14592
+ examples: [`notis reports ${name} ${command === "init" ? '"Weekly report" ./weekly-report' : "./weekly-report"}`],
14593
+ handler: async (ctx) => {
14594
+ if (command === "init") return initReport(ctx);
14595
+ await assertReportProject(ctx);
14596
+ return (command === "build" ? appsBuildHandler : appsVerifyHandler)({ ...ctx, options: { ...ctx.options, ...name === "preview" ? { keepOpen: true } : {} } });
14597
+ }
14545
14598
  };
14546
14599
  };
14547
14600
  var reportsCommandSpecs = [
14548
- reuse("init"),
14549
- reuse("build"),
14550
- reuse("verify"),
14551
- reuse("verify", "preview"),
14601
+ localReportCommand("init"),
14602
+ localReportCommand("build"),
14603
+ localReportCommand("verify"),
14604
+ localReportCommand("verify", "preview"),
14552
14605
  {
14553
14606
  command_path: ["reports", "save"],
14554
- summary: "Build, verify and save a report into an app-owned database record.",
14555
- when_to_use: "Persist an independently authored report, not an app release.",
14607
+ summary: "Build, verify and save a standalone live report document.",
14608
+ when_to_use: "Persist an independently owned report, not an app release.",
14556
14609
  args_schema: {
14557
14610
  arguments: [{ token: "[dir]", key: "dir", description: "Report source directory." }],
14558
14611
  options: [
14559
- { flags: "--database-id <id>", description: "Required. Owning app database." },
14560
- { flags: "--document-id <id>", description: "Existing record to update or attach to." },
14561
- { flags: "--attach", description: "Attach to an existing non-view record." },
14562
- { flags: "--expected-revision <revision>", description: "Fresh view revision (0 for a record without a view)." },
14563
- { flags: "--title <title>", description: "Required, including updates. Record title." },
14564
- { flags: "--context-file <file>", description: "Required. UTF-8 readable report content and structure." },
14565
- { flags: "--properties-file <file>", description: "JSON database property values keyed by name." }
14612
+ { flags: "--document-id <id>", description: "Existing report document to update." },
14613
+ { flags: "--expected-revision <revision>", description: "Current saved report revision; required for updates." },
14614
+ { flags: "--title <title>", description: "Required, including updates. Document title." },
14615
+ { flags: "--context-file <file>", description: "Required. UTF-8 readable report content and structure." }
14566
14616
  ]
14567
14617
  },
14568
- examples: ['notis reports save ./weekly-report --database-id <id> --title "Weekly review" --context-file ./context.md'],
14618
+ examples: ['notis reports save ./weekly-report --title "Weekly review" --context-file ./context.md'],
14569
14619
  mutates: true,
14570
14620
  idempotent: true,
14571
14621
  backend_call: { type: "tool", name: "LOCAL_NOTIS_SAVE_REPORT" },
14572
14622
  async handler(ctx) {
14573
- const dir = resolveProjectDir(ctx.args.dir || ".");
14574
- if (!ctx.options.databaseId || !ctx.options.title || !ctx.options.contextFile) throw usageError("--database-id, --title and --context-file are required.");
14575
- if (ctx.options.documentId && (!/^\d+$/.test(String(ctx.options.expectedRevision ?? "")) || !Number.isSafeInteger(Number(ctx.options.expectedRevision)))) throw usageError("--expected-revision is required for update/attach.");
14576
- if (ctx.options.attach && !ctx.options.documentId) throw usageError("--attach requires --document-id.");
14623
+ const dir = await assertReportProject(ctx);
14624
+ if (!ctx.options.title || !ctx.options.contextFile) throw usageError("--title and --context-file are required.");
14625
+ if (ctx.options.documentId && (!/^\d+$/.test(String(ctx.options.expectedRevision ?? "")) || !Number.isSafeInteger(Number(ctx.options.expectedRevision)))) throw usageError("--expected-revision is required for update.");
14577
14626
  const context = readFileSync9(resolve6(ctx.options.contextFile), "utf8");
14578
- const properties = ctx.options.propertiesFile ? JSON.parse(readFileSync9(resolve6(ctx.options.propertiesFile), "utf8")) : {};
14579
14627
  await buildArtifact(dir, { stdio: ctx.output.isMachineMode() ? "pipe" : "inherit" });
14580
14628
  const release = prepareAppRelease(dir);
14581
14629
  try {
14582
14630
  if (release.manifest.routes?.length !== 1) throw usageError("Reports require exactly one SDK route.");
14583
14631
  let verification;
14584
- const verify = appsCommandSpecs.find((item) => item.command_path.join(" ") === "apps verify");
14585
- const exit = await verify.handler({ ...ctx, args: { dir: release.projectDir }, options: { skipBuild: true, mode: "stub" }, output: { ...ctx.output, isMachineMode: () => true, emitSuccess: (value) => {
14632
+ const exit = await appsVerifyHandler({ ...ctx, args: { dir: release.projectDir }, options: { skipBuild: true, mode: "stub" }, output: { ...ctx.output, isMachineMode: () => true, emitSuccess: (value) => {
14586
14633
  verification = value;
14587
14634
  } } });
14588
14635
  if (exit !== EXIT_CODES.ok || verification?.data?.status !== "passed") throw usageError("Report verification failed; nothing saved.");
@@ -14593,12 +14640,10 @@ var reportsCommandSpecs = [
14593
14640
  mutating: true,
14594
14641
  idempotencyKey: nextIdempotencyKey(ctx.globalOptions),
14595
14642
  arguments_: {
14596
- operation: ctx.options.attach ? "attach" : ctx.options.documentId ? "update" : "create",
14597
- database_id: ctx.options.databaseId,
14643
+ operation: ctx.options.documentId ? "update" : "create",
14598
14644
  title: ctx.options.title,
14599
- properties,
14600
14645
  ...ctx.options.documentId ? { document_id: ctx.options.documentId, expected_revision: Number(ctx.options.expectedRevision) } : {},
14601
- report: { schema: "notis-report/v2", context, artifact: { manifest: release.manifest, files, encoding: "base64" } }
14646
+ report: { schema: "notis-report/v3", context, artifact: { manifest: release.manifest, files, encoding: "base64" } }
14602
14647
  }
14603
14648
  });
14604
14649
  if (!result?.payload?.document?.id || !result.payload.document.view_revision) throw usageError("Save returned no record identity. Read back before retrying; the outcome may be unknown.");
@@ -15518,7 +15563,7 @@ init_auth_recovery();
15518
15563
  init_profiles();
15519
15564
  init_oauth();
15520
15565
  import { readFileSync as readFileSync13 } from "node:fs";
15521
- import { dirname as dirname12, join as join11 } from "node:path";
15566
+ import { dirname as dirname12, join as join12 } from "node:path";
15522
15567
  import { fileURLToPath as fileURLToPath8 } from "node:url";
15523
15568
 
15524
15569
  // src/command-specs/auth.js
@@ -15536,15 +15581,15 @@ import {
15536
15581
  readFileSync as readFileSync11,
15537
15582
  readdirSync as readdirSync6,
15538
15583
  renameSync as renameSync4,
15539
- writeFileSync as writeFileSync6
15584
+ writeFileSync as writeFileSync7
15540
15585
  } from "node:fs";
15541
15586
  import { createHash as createHash4 } from "node:crypto";
15542
15587
  import { homedir as homedir4 } from "node:os";
15543
- import { dirname as dirname10, join as join9 } from "node:path";
15588
+ import { dirname as dirname10, join as join10 } from "node:path";
15544
15589
  import { fileURLToPath as fileURLToPath7 } from "node:url";
15545
15590
  var HERE = dirname10(fileURLToPath7(import.meta.url));
15546
- var INSTRUCTIONS_PATH = join9(HERE, "..", "..", "skills", "notis-cli", "AGENT_INSTRUCTIONS.md");
15547
- var HOOK_BUNDLE_PATH = join9(HERE, "..", "..", "dist", "agent-hooks", "notis-agent-hook.mjs");
15591
+ var INSTRUCTIONS_PATH = join10(HERE, "..", "..", "skills", "notis-cli", "AGENT_INSTRUCTIONS.md");
15592
+ var HOOK_BUNDLE_PATH = join10(HERE, "..", "..", "dist", "agent-hooks", "notis-agent-hook.mjs");
15548
15593
  var START_MARKER = "<!-- notis-cli:instructions:start -->";
15549
15594
  var END_MARKER = "<!-- notis-cli:instructions:end -->";
15550
15595
  var LEGACY_SENTINEL = "Use the Notis CLI (`npx --package @notis_ai/cli@latest -- notis ...`)";
@@ -15554,18 +15599,18 @@ var AGENT_IDS = Object.freeze(["codex", "claude-code"]);
15554
15599
  function atomicWrite(filePath, contents, mode = 384) {
15555
15600
  mkdirSync7(dirname10(filePath), { recursive: true, mode: 448 });
15556
15601
  const temporaryPath = `${filePath}.notis-${process.pid}-${Date.now()}.tmp`;
15557
- writeFileSync6(temporaryPath, contents, { mode });
15602
+ writeFileSync7(temporaryPath, contents, { mode });
15558
15603
  renameSync4(temporaryPath, filePath);
15559
15604
  }
15560
15605
  function readText(filePath) {
15561
15606
  return existsSync9(filePath) ? readFileSync11(filePath, "utf-8") : "";
15562
15607
  }
15563
15608
  function activeCodexInstructionsPath(home) {
15564
- const overridePath = join9(home, ".codex", "AGENTS.override.md");
15609
+ const overridePath = join10(home, ".codex", "AGENTS.override.md");
15565
15610
  if (existsSync9(overridePath) && readText(overridePath).trim()) {
15566
15611
  return overridePath;
15567
15612
  }
15568
- return join9(home, ".codex", "AGENTS.md");
15613
+ return join10(home, ".codex", "AGENTS.md");
15569
15614
  }
15570
15615
  function upsertInstructionBlock(filePath, block) {
15571
15616
  const existing = readText(filePath);
@@ -15655,7 +15700,7 @@ function installManagedHookRuntime({
15655
15700
  } = {}) {
15656
15701
  const bundle = readFileSync11(bundlePath2);
15657
15702
  const digest = createHash4("sha256").update(bundle).digest("hex");
15658
- const runtimePath = join9(
15703
+ const runtimePath = join10(
15659
15704
  home,
15660
15705
  ".notis",
15661
15706
  "agent-hooks",
@@ -15666,7 +15711,7 @@ function installManagedHookRuntime({
15666
15711
  const existingDigest = existsSync9(runtimePath) ? createHash4("sha256").update(readFileSync11(runtimePath)).digest("hex") : null;
15667
15712
  if (existingDigest !== digest) atomicWrite(runtimePath, bundle, 320);
15668
15713
  chmodSync(runtimePath, 320);
15669
- const launcherPath = join9(
15714
+ const launcherPath = join10(
15670
15715
  home,
15671
15716
  ".notis",
15672
15717
  "agent-hooks",
@@ -15750,16 +15795,16 @@ function upsertPromptHooks(filePath, agentId, profileName, enabled, launcherPath
15750
15795
  function agentPaths(agentId, home) {
15751
15796
  if (agentId === "codex") {
15752
15797
  return {
15753
- root: join9(home, ".codex"),
15798
+ root: join10(home, ".codex"),
15754
15799
  instructions: activeCodexInstructionsPath(home),
15755
- hooks: join9(home, ".codex", "hooks.json")
15800
+ hooks: join10(home, ".codex", "hooks.json")
15756
15801
  };
15757
15802
  }
15758
15803
  if (agentId === "claude-code") {
15759
15804
  return {
15760
- root: join9(home, ".claude"),
15761
- instructions: join9(home, ".claude", "CLAUDE.md"),
15762
- hooks: join9(home, ".claude", "settings.json")
15805
+ root: join10(home, ".claude"),
15806
+ instructions: join10(home, ".claude", "CLAUDE.md"),
15807
+ hooks: join10(home, ".claude", "settings.json")
15763
15808
  };
15764
15809
  }
15765
15810
  throw new Error(`Unsupported agent: ${agentId}`);
@@ -15830,10 +15875,10 @@ import {
15830
15875
  mkdirSync as mkdirSync8,
15831
15876
  readFileSync as readFileSync12,
15832
15877
  renameSync as renameSync5,
15833
- writeFileSync as writeFileSync7
15878
+ writeFileSync as writeFileSync8
15834
15879
  } from "node:fs";
15835
15880
  import { homedir as homedir5 } from "node:os";
15836
- import { dirname as dirname11, join as join10 } from "node:path";
15881
+ import { dirname as dirname11, join as join11 } from "node:path";
15837
15882
  var MAX_SEEN_HASHES = 500;
15838
15883
  var MAX_PROMPT_CHARS = 12e3;
15839
15884
  function hash(value) {
@@ -15841,7 +15886,7 @@ function hash(value) {
15841
15886
  }
15842
15887
  function statePath(sessionId, home = homedir5()) {
15843
15888
  if (!sessionId) return null;
15844
- return join10(home, ".notis", "agent-memory-hooks", `${hash(sessionId)}.json`);
15889
+ return join11(home, ".notis", "agent-memory-hooks", `${hash(sessionId)}.json`);
15845
15890
  }
15846
15891
  function readState(sessionId, home) {
15847
15892
  const filePath = statePath(sessionId, home);
@@ -15879,7 +15924,7 @@ function writeState(sessionId, state, home) {
15879
15924
  if (!filePath) return;
15880
15925
  mkdirSync8(dirname11(filePath), { recursive: true, mode: 448 });
15881
15926
  const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
15882
- writeFileSync7(temporaryPath, `${JSON.stringify(state)}
15927
+ writeFileSync8(temporaryPath, `${JSON.stringify(state)}
15883
15928
  `, { mode: 384 });
15884
15929
  renameSync5(temporaryPath, filePath);
15885
15930
  }
@@ -16383,7 +16428,7 @@ var authCommandSpecs = [
16383
16428
 
16384
16429
  // src/command-specs/onboarding.js
16385
16430
  var HERE2 = dirname12(fileURLToPath8(import.meta.url));
16386
- var BUNDLED_BRIEF_PATH = join11(HERE2, "..", "..", "skills", "notis-onboarding", "BRIEF.md");
16431
+ var BUNDLED_BRIEF_PATH = join12(HERE2, "..", "..", "skills", "notis-onboarding", "BRIEF.md");
16387
16432
  async function fetchOnboardingState(runtime) {
16388
16433
  try {
16389
16434
  const { payload } = await runToolCommand({
@@ -17239,11 +17284,11 @@ import { createHash as createHash8, randomUUID as randomUUID6 } from "node:crypt
17239
17284
  import {
17240
17285
  mkdtempSync as mkdtempSync4,
17241
17286
  readFileSync as readFileSync15,
17242
- rmSync as rmSync6,
17243
- writeFileSync as writeFileSync8
17287
+ rmSync as rmSync7,
17288
+ writeFileSync as writeFileSync9
17244
17289
  } from "node:fs";
17245
17290
  import { tmpdir as tmpdir3 } from "node:os";
17246
- import { basename as basename6, join as join12 } from "node:path";
17291
+ import { basename as basename6, join as join13 } from "node:path";
17247
17292
  import { setTimeout as delay2 } from "node:timers/promises";
17248
17293
  function discoveryNames(payload) {
17249
17294
  return [...new Set(
@@ -17324,12 +17369,12 @@ function remotePath(folder, name) {
17324
17369
  return `${normalizedFolder}/${name}`;
17325
17370
  }
17326
17371
  async function smokeFileUploadHandler(ctx) {
17327
- const tempDir = mkdtempSync4(join12(tmpdir3(), "notis-smoke-file-upload-"));
17372
+ const tempDir = mkdtempSync4(join13(tmpdir3(), "notis-smoke-file-upload-"));
17328
17373
  const marker = `${(/* @__PURE__ */ new Date()).toISOString().replaceAll(/[-:.]/g, "")}-${randomUUID6().slice(0, 8)}`;
17329
17374
  const generatedFixture = !ctx.options.sourceFile;
17330
- const fixturePath = ctx.options.sourceFile || join12(tempDir, `notis-file-upload-${marker}.txt`);
17375
+ const fixturePath = ctx.options.sourceFile || join13(tempDir, `notis-file-upload-${marker}.txt`);
17331
17376
  if (generatedFixture) {
17332
- writeFileSync8(
17377
+ writeFileSync9(
17333
17378
  fixturePath,
17334
17379
  `Notis Dropbox file-upload smoke
17335
17380
  marker=${marker}
@@ -17552,7 +17597,7 @@ unicode=\xE9t\xE9 Z\xFCrich \u6771\u4EAC
17552
17597
  result.cleanup.deleted = false;
17553
17598
  }
17554
17599
  }
17555
- rmSync6(tempDir, { recursive: true, force: true });
17600
+ rmSync7(tempDir, { recursive: true, force: true });
17556
17601
  }
17557
17602
  }
17558
17603
  var smokeCommandSpecs = [
@@ -18318,7 +18363,7 @@ init_profiles();
18318
18363
  import { createHash as createHash9, randomUUID as randomUUID7 } from "node:crypto";
18319
18364
  import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
18320
18365
  import { homedir as homedir7 } from "node:os";
18321
- import { dirname as dirname14, join as join14 } from "node:path";
18366
+ import { dirname as dirname14, join as join15 } from "node:path";
18322
18367
 
18323
18368
  // src/runtime/base-skills.js
18324
18369
  import {
@@ -18328,11 +18373,11 @@ import {
18328
18373
  mkdirSync as mkdirSync9,
18329
18374
  readlinkSync,
18330
18375
  renameSync as renameSync6,
18331
- rmSync as rmSync7,
18376
+ rmSync as rmSync8,
18332
18377
  symlinkSync
18333
18378
  } from "node:fs";
18334
18379
  import { homedir as homedir6 } from "node:os";
18335
- import { dirname as dirname13, join as join13, relative as relative5, resolve as resolve8 } from "node:path";
18380
+ import { dirname as dirname13, join as join14, relative as relative5, resolve as resolve8 } from "node:path";
18336
18381
  import { fileURLToPath as fileURLToPath9 } from "node:url";
18337
18382
  var BASE_SKILL_NAMES = Object.freeze([
18338
18383
  "notis-apps",
@@ -18343,29 +18388,29 @@ var HERE3 = dirname13(fileURLToPath9(import.meta.url));
18343
18388
  function resolveBundledBaseSkillsRoot({ resourcesPath = process.resourcesPath } = {}) {
18344
18389
  const sourceCheckout = resolve8(HERE3, "../../../../server/skills");
18345
18390
  const packaged = resolve8(HERE3, "../../dist/base-skills");
18346
- const desktopResource = resourcesPath ? join13(resourcesPath, "base-skills") : null;
18391
+ const desktopResource = resourcesPath ? join14(resourcesPath, "base-skills") : null;
18347
18392
  const desktopPackagerRoot = resourcesPath || null;
18348
18393
  for (const candidate of [sourceCheckout, packaged, desktopResource, desktopPackagerRoot]) {
18349
- if (candidate && BASE_SKILL_NAMES.every((name) => existsSync12(join13(candidate, name, "SKILL.md")))) {
18394
+ if (candidate && BASE_SKILL_NAMES.every((name) => existsSync12(join14(candidate, name, "SKILL.md")))) {
18350
18395
  return candidate;
18351
18396
  }
18352
18397
  }
18353
18398
  return packaged;
18354
18399
  }
18355
18400
  function getBaseSkillPaths({ home = homedir6(), userId = null } = {}) {
18356
- const notisRoot = join13(home, ".notis", "skills");
18401
+ const notisRoot = join14(home, ".notis", "skills");
18357
18402
  const targetRoots = [
18358
- join13(home, ".agents", "skills"),
18359
- join13(home, ".codex", "skills"),
18360
- join13(home, ".cursor", "skills"),
18361
- join13(home, ".claude", "skills")
18403
+ join14(home, ".agents", "skills"),
18404
+ join14(home, ".codex", "skills"),
18405
+ join14(home, ".cursor", "skills"),
18406
+ join14(home, ".claude", "skills")
18362
18407
  ];
18363
18408
  if (userId) {
18364
- targetRoots.push(join13(notisRoot, "users", userId, "skills"));
18409
+ targetRoots.push(join14(notisRoot, "users", userId, "skills"));
18365
18410
  }
18366
18411
  return {
18367
- baseRoot: join13(notisRoot, "base"),
18368
- backupRoot: join13(notisRoot, "backups"),
18412
+ baseRoot: join14(notisRoot, "base"),
18413
+ backupRoot: join14(notisRoot, "backups"),
18369
18414
  targetRoots
18370
18415
  };
18371
18416
  }
@@ -18378,7 +18423,7 @@ function sameLinkTarget(linkPath, expectedTarget) {
18378
18423
  }
18379
18424
  }
18380
18425
  function backupConflict(linkPath, backupRoot, targetLabel, skillName, now) {
18381
- const backupPath = join13(backupRoot, String(now), targetLabel, skillName);
18426
+ const backupPath = join14(backupRoot, String(now), targetLabel, skillName);
18382
18427
  mkdirSync9(dirname13(backupPath), { recursive: true, mode: 448 });
18383
18428
  renameSync6(linkPath, backupPath);
18384
18429
  return backupPath;
@@ -18387,7 +18432,7 @@ function replaceDirectory(source, destination) {
18387
18432
  mkdirSync9(dirname13(destination), { recursive: true, mode: 448 });
18388
18433
  const temporary = `${destination}.tmp-${process.pid}-${Date.now()}`;
18389
18434
  const previous = `${destination}.previous-${process.pid}-${Date.now()}`;
18390
- rmSync7(temporary, { recursive: true, force: true });
18435
+ rmSync8(temporary, { recursive: true, force: true });
18391
18436
  cpSync2(source, temporary, { recursive: true });
18392
18437
  let movedPrevious = false;
18393
18438
  try {
@@ -18396,9 +18441,9 @@ function replaceDirectory(source, destination) {
18396
18441
  movedPrevious = true;
18397
18442
  }
18398
18443
  renameSync6(temporary, destination);
18399
- if (movedPrevious) rmSync7(previous, { recursive: true, force: true });
18444
+ if (movedPrevious) rmSync8(previous, { recursive: true, force: true });
18400
18445
  } catch (error) {
18401
- rmSync7(temporary, { recursive: true, force: true });
18446
+ rmSync8(temporary, { recursive: true, force: true });
18402
18447
  if (movedPrevious && !existsSync12(destination) && existsSync12(previous)) {
18403
18448
  renameSync6(previous, destination);
18404
18449
  }
@@ -18420,19 +18465,19 @@ function reconcileBaseSkills({
18420
18465
  skills: [...BASE_SKILL_NAMES]
18421
18466
  };
18422
18467
  for (const name of BASE_SKILL_NAMES) {
18423
- const source = join13(sourceRoot, name);
18424
- if (!existsSync12(join13(source, "SKILL.md"))) {
18468
+ const source = join14(sourceRoot, name);
18469
+ if (!existsSync12(join14(source, "SKILL.md"))) {
18425
18470
  throw new Error(`Bundled base skill is missing: ${name}`);
18426
18471
  }
18427
- replaceDirectory(source, join13(paths.baseRoot, name));
18472
+ replaceDirectory(source, join14(paths.baseRoot, name));
18428
18473
  result.installed += 1;
18429
18474
  }
18430
18475
  for (const targetRoot of paths.targetRoots) {
18431
18476
  mkdirSync9(targetRoot, { recursive: true, mode: 448 });
18432
18477
  const targetLabel = relative5(home, targetRoot).replaceAll("/", "_") || "home";
18433
18478
  for (const name of BASE_SKILL_NAMES) {
18434
- const skillTarget = join13(paths.baseRoot, name);
18435
- const linkPath = join13(targetRoot, name);
18479
+ const skillTarget = join14(paths.baseRoot, name);
18480
+ const linkPath = join14(targetRoot, name);
18436
18481
  if (sameLinkTarget(linkPath, skillTarget)) {
18437
18482
  result.unchanged += 1;
18438
18483
  continue;
@@ -18466,7 +18511,7 @@ var DEFAULT_LOCK_POLL_MS = 50;
18466
18511
  async function lockSnapshot(lockDirectory) {
18467
18512
  try {
18468
18513
  const [raw, metadata] = await Promise.all([
18469
- readFile(join14(lockDirectory, "owner"), "utf8").catch(() => ""),
18514
+ readFile(join15(lockDirectory, "owner"), "utf8").catch(() => ""),
18470
18515
  stat(lockDirectory)
18471
18516
  ]);
18472
18517
  let owner = {};
@@ -18502,11 +18547,11 @@ function delay3(milliseconds) {
18502
18547
  return new Promise((resolve9) => setTimeout(resolve9, milliseconds));
18503
18548
  }
18504
18549
  async function quarantineStaleLock(lockDirectory, snapshot) {
18505
- const quarantineRoot = join14(dirname14(lockDirectory), ".stale-operation-locks");
18550
+ const quarantineRoot = join15(dirname14(lockDirectory), ".stale-operation-locks");
18506
18551
  const snapshotToken = createHash9("sha256").update(JSON.stringify(snapshot)).digest("hex");
18507
18552
  await mkdir(quarantineRoot, { recursive: true, mode: 448 });
18508
18553
  try {
18509
- await rename(lockDirectory, join14(quarantineRoot, snapshotToken));
18554
+ await rename(lockDirectory, join15(quarantineRoot, snapshotToken));
18510
18555
  return true;
18511
18556
  } catch (error) {
18512
18557
  if (["EEXIST", "ENOTEMPTY", "ENOENT"].includes(error?.code)) return false;
@@ -18514,16 +18559,16 @@ async function quarantineStaleLock(lockDirectory, snapshot) {
18514
18559
  }
18515
18560
  }
18516
18561
  async function writeLockOwnerAtomically(lockDirectory, owner) {
18517
- const temporaryOwnerPath = join14(lockDirectory, `.owner.${owner.id}.tmp`);
18518
- const ownerPath = join14(lockDirectory, "owner");
18562
+ const temporaryOwnerPath = join15(lockDirectory, `.owner.${owner.id}.tmp`);
18563
+ const ownerPath = join15(lockDirectory, "owner");
18519
18564
  await writeFile(temporaryOwnerPath, JSON.stringify(owner), { mode: 384 });
18520
18565
  await rename(temporaryOwnerPath, ownerPath);
18521
18566
  }
18522
18567
  async function releaseOwnedLock(lockDirectory, ownerId) {
18523
18568
  const owner = await lockSnapshot(lockDirectory);
18524
18569
  if (owner?.id !== ownerId) return;
18525
- const quarantineRoot = join14(dirname14(lockDirectory), ".stale-operation-locks");
18526
- const releasedDirectory = join14(quarantineRoot, `released.${ownerId}`);
18570
+ const quarantineRoot = join15(dirname14(lockDirectory), ".stale-operation-locks");
18571
+ const releasedDirectory = join15(quarantineRoot, `released.${ownerId}`);
18527
18572
  await mkdir(quarantineRoot, { recursive: true, mode: 448 });
18528
18573
  try {
18529
18574
  await rename(lockDirectory, releasedDirectory);
@@ -18540,7 +18585,7 @@ async function withSkillSyncLock(callback, {
18540
18585
  pollMs = DEFAULT_LOCK_POLL_MS,
18541
18586
  now = () => Date.now()
18542
18587
  } = {}) {
18543
- const lockDirectory = join14(home, ".notis", "skills", ".operation-lock");
18588
+ const lockDirectory = join15(home, ".notis", "skills", ".operation-lock");
18544
18589
  const ownerId = `${process.pid}.${randomUUID7()}`;
18545
18590
  const deadline = now() + timeoutMs;
18546
18591
  await mkdir(dirname14(lockDirectory), { recursive: true, mode: 448 });
@@ -18579,7 +18624,7 @@ async function withSkillSyncLock(callback, {
18579
18624
  let heartbeatInFlight = Promise.resolve();
18580
18625
  const refreshHeartbeat = async () => {
18581
18626
  if (heartbeatStopped) return;
18582
- const temporaryOwnerPath = join14(lockDirectory, `.owner.${ownerId}.tmp`);
18627
+ const temporaryOwnerPath = join15(lockDirectory, `.owner.${ownerId}.tmp`);
18583
18628
  await writeFile(
18584
18629
  temporaryOwnerPath,
18585
18630
  JSON.stringify({ id: ownerId, pid: process.pid, at: now() }),
@@ -18590,7 +18635,7 @@ async function withSkillSyncLock(callback, {
18590
18635
  await rm(temporaryOwnerPath, { force: true });
18591
18636
  return;
18592
18637
  }
18593
- await rename(temporaryOwnerPath, join14(lockDirectory, "owner"));
18638
+ await rename(temporaryOwnerPath, join15(lockDirectory, "owner"));
18594
18639
  };
18595
18640
  const heartbeat = setInterval(() => {
18596
18641
  heartbeatInFlight = heartbeatInFlight.then(refreshHeartbeat).catch(() => void 0);
@@ -18640,16 +18685,16 @@ init_oauth();
18640
18685
  init_profiles();
18641
18686
  import { spawnSync as spawnSync3 } from "node:child_process";
18642
18687
  import { createHash as createHash11 } from "node:crypto";
18643
- import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync17, renameSync as renameSync7, writeFileSync as writeFileSync9 } from "node:fs";
18688
+ import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync17, renameSync as renameSync7, writeFileSync as writeFileSync10 } from "node:fs";
18644
18689
  import { homedir as homedir8 } from "node:os";
18645
- import { dirname as dirname15, join as join15 } from "node:path";
18690
+ import { dirname as dirname15, join as join16 } from "node:path";
18646
18691
  import { fileURLToPath as fileURLToPath10 } from "node:url";
18647
18692
  var SKILL_SYNC_SERVICE_LABEL = "ai.notis.skills-sync";
18648
18693
  var bundlePath = fileURLToPath10(new URL("../../dist/skill-sync-worker.mjs", import.meta.url));
18649
18694
  function atomicWrite2(target, value, mode = 384) {
18650
18695
  mkdirSync10(dirname15(target), { recursive: true, mode: 448 });
18651
18696
  const temporary = `${target}.${process.pid}.tmp`;
18652
- writeFileSync9(temporary, value, { mode });
18697
+ writeFileSync10(temporary, value, { mode });
18653
18698
  renameSync7(temporary, target);
18654
18699
  }
18655
18700
  function xml(value) {
@@ -18662,7 +18707,7 @@ async function maybeInstallSkillSyncService(runtime, {
18662
18707
  refresh
18663
18708
  } = {}) {
18664
18709
  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;
18665
- const plist = join15(homedir8(), "Library", "LaunchAgents", `${SKILL_SYNC_SERVICE_LABEL}.plist`);
18710
+ const plist = join16(homedir8(), "Library", "LaunchAgents", `${SKILL_SYNC_SERVICE_LABEL}.plist`);
18666
18711
  if (existsSync13(plist)) {
18667
18712
  const saved = readFileSync17(plist, "utf8");
18668
18713
  if (runtime.oauthUserId && [runtime.profileName, runtime.apiBase, runtime.oauthUserId].every((value) => saved.includes(`<string>${xml(value)}</string>`))) return install(runtime);
@@ -18696,10 +18741,10 @@ async function installSkillSyncServiceLocked(runtime, {
18696
18741
  if (runtime.credentialKind !== "oauth" || runtime.envCredentialOverride || !isValidProfileName(runtime.profileName) || !["https://api.notis.ai", "https://api-beta.notis.ai"].includes(runtime.apiBase)) {
18697
18742
  return { status: "skipped_non_personal_profile" };
18698
18743
  }
18699
- const root = join15(home, ".notis", "skills", "service");
18744
+ const root = join16(home, ".notis", "skills", "service");
18700
18745
  const bundle = readFileSync17(source);
18701
18746
  const digest = createHash11("sha256").update(bundle).digest("hex");
18702
- const installedBundle = join15(root, "runtime", digest, "worker.mjs");
18747
+ const installedBundle = join16(root, "runtime", digest, "worker.mjs");
18703
18748
  if (!existsSync13(installedBundle) || !readFileSync17(installedBundle).equals(bundle)) atomicWrite2(installedBundle, bundle, 320);
18704
18749
  const args = [nodePath, installedBundle, runtime.profileName, runtime.apiBase, runtime.oauthUserId];
18705
18750
  if (!runtime.oauthUserId) return { status: "skipped_missing_account" };
@@ -18713,7 +18758,7 @@ async function installSkillSyncServiceLocked(runtime, {
18713
18758
  <key>ProcessType</key><string>Background</string>
18714
18759
  </dict></plist>
18715
18760
  `;
18716
- const plistPath = join15(home, "Library", "LaunchAgents", `${SKILL_SYNC_SERVICE_LABEL}.plist`);
18761
+ const plistPath = join16(home, "Library", "LaunchAgents", `${SKILL_SYNC_SERVICE_LABEL}.plist`);
18717
18762
  const domain = `gui/${uid}`;
18718
18763
  const target = `${domain}/${SKILL_SYNC_SERVICE_LABEL}`;
18719
18764
  const unchanged = existsSync13(plistPath) && readFileSync17(plistPath, "utf8") === plist;
@@ -18916,7 +18961,7 @@ init_channel();
18916
18961
  init_profiles();
18917
18962
  function readCliVersion() {
18918
18963
  try {
18919
- const manifestPath = join16(dirname16(fileURLToPath11(import.meta.url)), "..", "package.json");
18964
+ const manifestPath = join17(dirname16(fileURLToPath11(import.meta.url)), "..", "package.json");
18920
18965
  const version = JSON.parse(readFileSync18(manifestPath, "utf-8")).version;
18921
18966
  if (typeof version === "string" && version.trim()) {
18922
18967
  return version.trim();