@noir-ai/cli 1.0.0-beta.1 → 1.2.0-beta.2

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/dist/bin.js CHANGED
@@ -7,15 +7,20 @@ import {
7
7
  handleError,
8
8
  inferExitCode,
9
9
  info,
10
- init,
11
10
  isInteractive,
12
11
  log,
13
12
  serve,
14
- table
15
- } from "./chunk-UXT7YWQY.js";
13
+ table,
14
+ warn
15
+ } from "./chunk-I3L3KNJM.js";
16
+ import {
17
+ init
18
+ } from "./chunk-7WKKZ452.js";
16
19
 
17
20
  // src/bin.ts
21
+ import { realpathSync } from "fs";
18
22
  import { pathToFileURL } from "url";
23
+ import { SUPPORTED_HOSTS } from "@noir-ai/adapters";
19
24
  import { NOIR_VERSION as NOIR_VERSION3 } from "@noir-ai/core";
20
25
  import { Command, Option } from "commander";
21
26
 
@@ -58,7 +63,7 @@ async function probeDaemon(opts = {}) {
58
63
  return { running: false };
59
64
  }
60
65
  const body = await res.json().catch(() => null);
61
- if (!body || body.ok !== true) {
66
+ if (body?.ok !== true) {
62
67
  if (opts.verbose) process.stderr.write("noir: daemon probe: /health body not ok\n");
63
68
  return { running: false };
64
69
  }
@@ -95,7 +100,7 @@ async function connectClient(client, url, opts) {
95
100
  async function callToolParse(client, opts, name, args) {
96
101
  const result = await client.callTool({ name, arguments: args }).catch((err) => failDaemonDown(opts, err));
97
102
  const block = result.content?.[0];
98
- if (!block || block.type !== "text" || typeof block.text !== "string") {
103
+ if (block?.type !== "text" || typeof block.text !== "string") {
99
104
  failDaemonDown(opts, new Error(`tool '${name}' returned no text content`));
100
105
  }
101
106
  const text = block.text;
@@ -183,10 +188,10 @@ function failTool(label, envelope, opts) {
183
188
  function toHit(raw) {
184
189
  const h = raw ?? {};
185
190
  return {
186
- path: typeof h["path"] === "string" ? h["path"] : "<unknown>",
187
- score: typeof h["score"] === "number" ? h["score"] : 0,
188
- snippet: typeof h["snippet"] === "string" ? h["snippet"] : "",
189
- source: typeof h["source"] === "string" ? h["source"] : ""
191
+ path: typeof h.path === "string" ? h.path : "<unknown>",
192
+ score: typeof h.score === "number" ? h.score : 0,
193
+ snippet: typeof h.snippet === "string" ? h.snippet : "",
194
+ source: typeof h.source === "string" ? h.source : ""
190
195
  };
191
196
  }
192
197
  async function contextSearch(opts) {
@@ -422,7 +427,7 @@ async function daemonStatus(opts) {
422
427
  } catch {
423
428
  health = null;
424
429
  }
425
- if (!health || health.ok !== true) {
430
+ if (health?.ok !== true) {
426
431
  clearDaemonRecord();
427
432
  fail(
428
433
  EXIT.DAEMON_DOWN,
@@ -553,15 +558,15 @@ function toHit2(raw) {
553
558
  const h = raw ?? {};
554
559
  const arr = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
555
560
  return {
556
- id: typeof h["id"] === "string" ? h["id"] : "",
557
- type: typeof h["type"] === "string" ? h["type"] : "",
558
- score: typeof h["score"] === "number" ? h["score"] : 0,
559
- content: typeof h["content"] === "string" ? h["content"] : "",
560
- concepts: arr(h["concepts"]),
561
- files: arr(h["files"]),
562
- ts: typeof h["ts"] === "number" ? h["ts"] : 0,
563
- importance: typeof h["importance"] === "number" ? h["importance"] : 0,
564
- source: typeof h["source"] === "string" ? h["source"] : ""
561
+ id: typeof h.id === "string" ? h.id : "",
562
+ type: typeof h.type === "string" ? h.type : "",
563
+ score: typeof h.score === "number" ? h.score : 0,
564
+ content: typeof h.content === "string" ? h.content : "",
565
+ concepts: arr(h.concepts),
566
+ files: arr(h.files),
567
+ ts: typeof h.ts === "number" ? h.ts : 0,
568
+ importance: typeof h.importance === "number" ? h.importance : 0,
569
+ source: typeof h.source === "string" ? h.source : ""
565
570
  };
566
571
  }
567
572
  function failTool2(label, envelope, opts) {
@@ -612,8 +617,8 @@ async function memorySave(opts) {
612
617
  const content = await resolveContent(opts);
613
618
  const files = splitCsv(opts.files);
614
619
  const args = { content };
615
- if (typeof opts.type === "string" && opts.type.length > 0) args["type"] = opts.type;
616
- if (files !== void 0) args["files"] = files;
620
+ if (typeof opts.type === "string" && opts.type.length > 0) args.type = opts.type;
621
+ if (files !== void 0) args.files = files;
617
622
  const res = await callDaemonTool(opts, "memory_save", args);
618
623
  if (res.ok !== true) failTool2("memory save", res, opts);
619
624
  const id = typeof res.id === "string" ? res.id : "";
@@ -654,7 +659,7 @@ function renderObservation(obs, opts) {
654
659
  if (obs[key] !== void 0) rows.push({ Field: key, Value: obs[key] });
655
660
  }
656
661
  if (rows.length > 0) table(rows, ["Field", "Value"], opts);
657
- const content = obs["content"];
662
+ const content = obs.content;
658
663
  if (typeof content === "string") log(`
659
664
  ${content}`, opts);
660
665
  }
@@ -664,9 +669,9 @@ async function memorySessions(opts) {
664
669
  const sessions = Array.isArray(res.sessions) ? res.sessions.map((raw) => {
665
670
  const s = raw ?? {};
666
671
  return {
667
- id: typeof s["id"] === "string" ? s["id"] : "",
668
- count: typeof s["count"] === "number" ? s["count"] : 0,
669
- lastTs: typeof s["lastTs"] === "number" ? s["lastTs"] : 0
672
+ id: typeof s.id === "string" ? s.id : "",
673
+ count: typeof s.count === "number" ? s.count : 0,
674
+ lastTs: typeof s.lastTs === "number" ? s.lastTs : 0
670
675
  };
671
676
  }) : [];
672
677
  const data = { sessions };
@@ -711,8 +716,8 @@ async function memoryConsolidate(opts) {
711
716
  const types = splitCsv(opts.types);
712
717
  const limit = parseLimit2(opts.limit, "memory consolidate", opts);
713
718
  const args = {};
714
- if (types !== void 0) args["types"] = types;
715
- if (limit !== void 0) args["limit"] = limit;
719
+ if (types !== void 0) args.types = types;
720
+ if (limit !== void 0) args.limit = limit;
716
721
  const res = await callDaemonTool(
717
722
  opts,
718
723
  "memory_consolidate",
@@ -735,15 +740,15 @@ async function memoryConsolidate(opts) {
735
740
  const l = lessons[i];
736
741
  if (l === void 0) continue;
737
742
  const obs = l ?? {};
738
- const id = typeof obs["id"] === "string" ? obs["id"] : `<lesson ${i + 1}>`;
739
- const content = typeof obs["content"] === "string" ? obs["content"] : "";
743
+ const id = typeof obs.id === "string" ? obs.id : `<lesson ${i + 1}>`;
744
+ const content = typeof obs.content === "string" ? obs.content : "";
740
745
  log(`- ${id}: ${content}`, opts);
741
746
  }
742
747
  return;
743
748
  }
744
749
  const env = res;
745
- const reason = (typeof env["reason"] === "string" ? env["reason"] : void 0) ?? (typeof env["error"] === "string" ? env["error"] : void 0) ?? "unknown";
746
- const logged = env["logged"] === true || env["degraded"] === true;
750
+ const reason = (typeof env.reason === "string" ? env.reason : void 0) ?? (typeof env.error === "string" ? env.error : void 0) ?? "unknown";
751
+ const logged = env.logged === true || env.degraded === true;
747
752
  const suffix = logged ? " (logged)" : "";
748
753
  fail(EXIT.ERROR, `memory consolidate did not run: ${reason}${suffix}`, opts);
749
754
  }
@@ -751,7 +756,10 @@ async function memoryConsolidate(opts) {
751
756
  // src/commands/skills.ts
752
757
  import { claudeAdapter } from "@noir-ai/adapters";
753
758
  import { loadProjectInfo as loadProjectInfo4 } from "@noir-ai/core";
754
- import { discoverBuiltin, emitSkillsToDir } from "@noir-ai/skills";
759
+ import {
760
+ discoverAll,
761
+ emitSkillsToDir
762
+ } from "@noir-ai/skills";
755
763
  var CATEGORY = {
756
764
  "noir-brainstorm": "discovery",
757
765
  "noir-intake": "discovery",
@@ -790,9 +798,9 @@ function categoryOf(name) {
790
798
  if (mapped !== void 0) return mapped;
791
799
  return name.replace(/^noir-/, "") || "general";
792
800
  }
793
- function toRow(s) {
801
+ function toRow(s, kind = "builtin") {
794
802
  const description = typeof s.frontmatter.description === "string" ? s.frontmatter.description : "";
795
- return { name: s.name, category: categoryOf(s.name), description };
803
+ return { name: s.name, category: categoryOf(s.name), description, kind };
796
804
  }
797
805
  function truncate(text, max) {
798
806
  if (text.length <= max) return text;
@@ -803,30 +811,39 @@ function truncate(text, max) {
803
811
  }
804
812
  async function skillsList(opts) {
805
813
  let builtins;
814
+ let integrations;
806
815
  try {
807
- builtins = discoverBuiltin();
816
+ const all = discoverAll();
817
+ builtins = all.builtins;
818
+ integrations = all.integrations;
808
819
  } catch (err) {
809
820
  fail(
810
821
  EXIT.ERROR,
811
- `skills list: could not discover builtin skills (${err instanceof Error ? err.message : String(err)})`,
822
+ `skills list: could not discover skills (${err instanceof Error ? err.message : String(err)})`,
812
823
  opts
813
824
  );
814
825
  }
815
- const rows = builtins.map(toRow);
826
+ const rows = [
827
+ ...builtins.map((b) => toRow(b, "builtin")),
828
+ ...integrations.map((i) => toRow(i, "integration"))
829
+ ];
816
830
  const data = { count: rows.length, skills: rows };
817
831
  if (opts.json === true) {
818
832
  process.stdout.write(`${JSON.stringify({ ok: true, data })}
819
833
  `);
820
834
  return;
821
835
  }
822
- log(`noir skills \u2014 ${rows.length} builtin skill${rows.length === 1 ? "" : "s"}`, opts);
836
+ const intCount = integrations.length;
837
+ const banner = intCount > 0 ? `noir skills \u2014 ${rows.length} skill${rows.length === 1 ? "" : "s"} (${builtins.length} builtin, ${intCount} integration${intCount === 1 ? "" : "s"})` : `noir skills \u2014 ${rows.length} builtin skill${rows.length === 1 ? "" : "s"}`;
838
+ log(banner, opts);
823
839
  table(
824
840
  rows.map((r) => ({
825
841
  Skill: r.name,
842
+ Kind: r.kind,
826
843
  Category: r.category,
827
844
  Description: truncate(r.description, 80)
828
845
  })),
829
- ["Skill", "Category", "Description"],
846
+ ["Skill", "Kind", "Category", "Description"],
830
847
  opts
831
848
  );
832
849
  }
@@ -850,10 +867,12 @@ async function skillsSync(opts) {
850
867
  }
851
868
  const dir = claudeAdapter.skillsDir({ root });
852
869
  const summary = await emitSkillsToDir(dir);
870
+ const pruned = summary.pruned ?? [];
853
871
  const data = {
854
872
  emitted: summary.emitted,
855
873
  references: summary.references,
856
- dir
874
+ dir,
875
+ pruned
857
876
  };
858
877
  if (opts.json === true) {
859
878
  process.stdout.write(`${JSON.stringify({ ok: true, data })}
@@ -864,6 +883,12 @@ async function skillsSync(opts) {
864
883
  `Synced ${summary.emitted.length} Noir skill${summary.emitted.length === 1 ? "" : "s"} to ${dir}.`,
865
884
  opts
866
885
  );
886
+ if (pruned.length > 0) {
887
+ warn(
888
+ `Pruned ${pruned.length} stale noir-* skill dir${pruned.length === 1 ? "" : "s"}: ${pruned.join(", ")}`,
889
+ opts
890
+ );
891
+ }
867
892
  }
868
893
 
869
894
  // src/commands/status.ts
@@ -876,7 +901,7 @@ async function tryTool(caller, name) {
876
901
  }
877
902
  }
878
903
  function pickStore(s) {
879
- if (!s || s.ok !== true) return null;
904
+ if (s?.ok !== true) return null;
880
905
  return {
881
906
  docCount: s.docCount,
882
907
  vecCount: s.vecCount,
@@ -890,7 +915,7 @@ function describeEmbedder2(e) {
890
915
  return `${e.kind} \xB7 ${model} (${e.dim}-dim)`;
891
916
  }
892
917
  function pickContext(c) {
893
- if (!c || c.ok !== true) return null;
918
+ if (c?.ok !== true) return null;
894
919
  return {
895
920
  docCount: c.docCount,
896
921
  vecCount: c.vecCount,
@@ -900,7 +925,7 @@ function pickContext(c) {
900
925
  };
901
926
  }
902
927
  function pickWorkflow(w) {
903
- if (!w || w.ok !== true) return null;
928
+ if (w?.ok !== true) return null;
904
929
  return {
905
930
  taskId: w.taskId,
906
931
  phase: w.phase,
@@ -911,7 +936,7 @@ function pickWorkflow(w) {
911
936
  };
912
937
  }
913
938
  function pickMemory(m) {
914
- if (!m || m.ok !== true || !Array.isArray(m.sessions)) return null;
939
+ if (m?.ok !== true || !Array.isArray(m.sessions)) return null;
915
940
  let observations = 0;
916
941
  for (const s of m.sessions) observations += s.count;
917
942
  return { sessions: m.sessions.length, observations };
@@ -1186,15 +1211,20 @@ function toStatusOptions(g) {
1186
1211
  input: g.input !== false
1187
1212
  };
1188
1213
  }
1214
+ function parseHost(raw) {
1215
+ if (raw === void 0) return void 0;
1216
+ return raw;
1217
+ }
1189
1218
  function createProgram() {
1190
1219
  const program2 = new Command();
1191
1220
  program2.name("noir").description("Noir \u2014 discipline, context, and memory layer for agentic CLIs.").version(NOIR_VERSION3, "-v, --version").addOption(new Option("--json", "emit machine-readable JSON to stdout")).addOption(new Option("--no-input", "never prompt; error if input is required")).addOption(new Option("--quiet", "suppress non-essential diagnostics")).addOption(new Option("--verbose", "show additional diagnostic detail")).addOption(new Option("--cwd <path>", "run as if started in <path>")).exitOverride((err) => {
1192
1221
  throw err;
1193
1222
  }).configureOutput({
1194
- // S9 stream discipline: data → stdout, diagnostics stderr. Help and
1195
- // errors are diagnostics, so both go to stderr (keeps stdout pristine for
1196
- // --json payloads). commander's default error formatting is preserved.
1197
- writeOut: (str) => process.stderr.write(str),
1223
+ // Stream discipline: --help/--version → stdout (conventional; users pipe
1224
+ // them), errors stderr. --json data is emitted by command actions via
1225
+ // process.stdout directly, NOT by commander's writeOut, so routing help/
1226
+ // version to stdout does not conflict with --json payloads.
1227
+ writeOut: (str) => process.stdout.write(str),
1198
1228
  writeErr: (str) => process.stderr.write(str)
1199
1229
  });
1200
1230
  program2.hook("preAction", (_thisCmd, actionCmd) => {
@@ -1211,13 +1241,66 @@ function createProgram() {
1211
1241
  }
1212
1242
  }
1213
1243
  });
1214
- program2.command("init").description("scaffold Noir in the current project (.noir/, .mcp.json, CLAUDE.md, skills)").option("--transport <transport>", "stdio | streamable-http (default: stdio)", "stdio").option("--url <url>", "streamable-http daemon URL (localhost only)").action(async (opts) => {
1215
- const transport = opts.transport === "streamable-http" ? "streamable-http" : "stdio";
1216
- await init(process.cwd(), { transport, url: opts.url });
1217
- });
1218
- program2.command("sync").description("re-emit the Noir builtin skills into the host skills dir").action(async () => {
1219
- const { sync } = await import("./sync-7YLRJYMR.js");
1220
- await sync(process.cwd());
1244
+ program2.command("init").description("scaffold Noir in the current project (.noir/, .mcp.json, CLAUDE.md, skills)").option("--transport <transport>", "stdio | streamable-http (default: stdio)", "stdio").option("--url <url>", "streamable-http daemon URL (localhost only)").option(
1245
+ "--upgrade",
1246
+ "run scaffold migrations before re-emitting (re-run on an existing project)"
1247
+ ).addOption(
1248
+ // S10: target host. Defaults to `'claude'` (the regression anchor). The
1249
+ // chosen host is forwarded to scaffold() + skills emission via
1250
+ // resolveAdapter. The choice list mirrors `SUPPORTED_HOSTS` so a new host
1251
+ // lands here automatically; commander rejects anything else as usage=2.
1252
+ new Option(
1253
+ "--host <id>",
1254
+ "target agentic CLI (default: claude) \u2014 drives host-side emission"
1255
+ ).choices(SUPPORTED_HOSTS)
1256
+ ).action(
1257
+ async (opts) => {
1258
+ const transport = opts.transport === "streamable-http" ? "streamable-http" : "stdio";
1259
+ const upgrade = opts.upgrade === true;
1260
+ const host = parseHost(opts.host);
1261
+ await init(process.cwd(), {
1262
+ transport,
1263
+ url: opts.url,
1264
+ ...upgrade ? { upgrade } : {},
1265
+ ...host !== void 0 ? { host } : {}
1266
+ });
1267
+ }
1268
+ );
1269
+ program2.command("create [dir]").description("bootstrap the Noir AI layer in a new or empty directory").option("--transport <transport>", "stdio | streamable-http (default: stdio)", "stdio").option("--url <url>", "streamable-http daemon URL (localhost only)").addOption(
1270
+ new Option(
1271
+ "--host <id>",
1272
+ "target agentic CLI (default: claude) \u2014 drives host-side emission"
1273
+ ).choices(SUPPORTED_HOSTS)
1274
+ ).action(
1275
+ async (dir, opts) => {
1276
+ const transport = opts.transport === "streamable-http" ? "streamable-http" : "stdio";
1277
+ const host = parseHost(opts.host);
1278
+ const { create } = await import("./create-ZK2EBXG3.js");
1279
+ await create(dir, {
1280
+ transport,
1281
+ url: opts.url,
1282
+ ...host !== void 0 ? { host } : {}
1283
+ });
1284
+ }
1285
+ );
1286
+ program2.command("sync").description(
1287
+ "re-emit Noir managed files (.mcp.json, CLAUDE.md blocks, NOIR.md brief, ignores) + skills"
1288
+ ).addOption(
1289
+ // S10: optional `--host` override. When omitted, sync reads host from
1290
+ // `.noir/config.yml` (whatever `noir init --host <id>` persisted). The
1291
+ // override is rarely needed — documented as advanced.
1292
+ new Option(
1293
+ "--host <id>",
1294
+ "override the configured host (advanced; default reads .noir/config.yml)"
1295
+ ).choices(SUPPORTED_HOSTS)
1296
+ ).action(async (opts) => {
1297
+ const { sync } = await import("./sync-IEH2BVXU.js");
1298
+ const host = parseHost(opts.host);
1299
+ if (host === void 0) {
1300
+ await sync(process.cwd());
1301
+ } else {
1302
+ await sync(process.cwd(), { host });
1303
+ }
1221
1304
  });
1222
1305
  const mcpCmd = program2.command("mcp").description("MCP server control");
1223
1306
  mcpCmd.command("serve").description("run the Noir MCP server (stdio, or via the shared daemon)").option("--stdio", "force the stdio transport").action(async (opts) => {
@@ -1230,7 +1313,7 @@ function createProgram() {
1230
1313
  daemonGrp.command("start").description("start the Noir daemon (foreground; backgrounding deferred)").option("--detach", "run in the background (not yet implemented; exits 2)").action(async (...args) => {
1231
1314
  const cmd = trailingCmd(args);
1232
1315
  const g = cmd.optsWithGlobals();
1233
- const detach = g["detach"] === true;
1316
+ const detach = g.detach === true;
1234
1317
  await daemonStart({ ...toCliOptions(g), ...detach ? { detach } : {} });
1235
1318
  });
1236
1319
  daemonGrp.command("stop").description("stop the Noir daemon").action(async (...args) => {
@@ -1256,7 +1339,7 @@ function createProgram() {
1256
1339
  const cmd = trailingCmd(args);
1257
1340
  const g = cmd.optsWithGlobals();
1258
1341
  const query = typeof args[0] === "string" ? args[0] : "";
1259
- const limit = typeof g["limit"] === "string" ? g["limit"] : void 0;
1342
+ const limit = typeof g.limit === "string" ? g.limit : void 0;
1260
1343
  await contextSearch({
1261
1344
  ...toCliOptions(g),
1262
1345
  query,
@@ -1271,8 +1354,8 @@ function createProgram() {
1271
1354
  ).option("--force", "ignore content-hash caching (recognized; not yet honored)").action(async (...args) => {
1272
1355
  const cmd = trailingCmd(args);
1273
1356
  const g = cmd.optsWithGlobals();
1274
- const rawPaths = Array.isArray(g["path"]) ? g["path"].filter((p) => typeof p === "string") : [];
1275
- const force = g["force"] === true;
1357
+ const rawPaths = Array.isArray(g.path) ? g.path.filter((p) => typeof p === "string") : [];
1358
+ const force = g.force === true;
1276
1359
  await contextIndex({
1277
1360
  ...toCliOptions(g),
1278
1361
  ...rawPaths.length === 0 ? {} : { paths: rawPaths },
@@ -1290,7 +1373,7 @@ function createProgram() {
1290
1373
  const cmd = trailingCmd(args);
1291
1374
  const g = cmd.optsWithGlobals();
1292
1375
  const query = typeof args[0] === "string" ? args[0] : "";
1293
- const limit = typeof g["limit"] === "string" ? g["limit"] : void 0;
1376
+ const limit = typeof g.limit === "string" ? g.limit : void 0;
1294
1377
  await memoryRecall({
1295
1378
  ...toCliOptions(g),
1296
1379
  query,
@@ -1303,9 +1386,9 @@ function createProgram() {
1303
1386
  ).option("--files <files>", "comma-separated related file paths").action(async (...args) => {
1304
1387
  const cmd = trailingCmd(args);
1305
1388
  const g = cmd.optsWithGlobals();
1306
- const content = typeof g["content"] === "string" ? g["content"] : void 0;
1307
- const type = typeof g["type"] === "string" ? g["type"] : void 0;
1308
- const files = typeof g["files"] === "string" ? g["files"] : void 0;
1389
+ const content = typeof g.content === "string" ? g.content : void 0;
1390
+ const type = typeof g.type === "string" ? g.type : void 0;
1391
+ const files = typeof g.files === "string" ? g.files : void 0;
1309
1392
  await memorySave({
1310
1393
  ...toCliOptions(g),
1311
1394
  ...content === void 0 ? {} : { content },
@@ -1326,8 +1409,8 @@ function createProgram() {
1326
1409
  memoryGrp.command("consolidate").description("consolidate memories into a derived lesson (provider-explicit)").option("--types <types>", "comma-separated observation types to consolidate").option("--limit <n>", "cap on candidate observations").action(async (...args) => {
1327
1410
  const cmd = trailingCmd(args);
1328
1411
  const g = cmd.optsWithGlobals();
1329
- const types = typeof g["types"] === "string" ? g["types"] : void 0;
1330
- const limit = typeof g["limit"] === "string" ? g["limit"] : void 0;
1412
+ const types = typeof g.types === "string" ? g.types : void 0;
1413
+ const limit = typeof g.limit === "string" ? g.limit : void 0;
1331
1414
  await memoryConsolidate({
1332
1415
  ...toCliOptions(g),
1333
1416
  ...types === void 0 ? {} : { types },
@@ -1354,8 +1437,8 @@ function createProgram() {
1354
1437
  taskGrp.command("new").description("start a new workflow task").requiredOption("--slug <slug>", "task slug").option("--mode <mode>", "full | quick").action(async (...args) => {
1355
1438
  const cmd = trailingCmd(args);
1356
1439
  const g = cmd.optsWithGlobals();
1357
- const slug = typeof g["slug"] === "string" ? g["slug"] : "";
1358
- const mode = typeof g["mode"] === "string" ? g["mode"] : void 0;
1440
+ const slug = typeof g.slug === "string" ? g.slug : "";
1441
+ const mode = typeof g.mode === "string" ? g.mode : void 0;
1359
1442
  await taskNew({
1360
1443
  ...toCliOptions(g),
1361
1444
  slug,
@@ -1375,8 +1458,8 @@ function createProgram() {
1375
1458
  taskGrp.command("advance").description("advance the active task to the next phase").option("--to <phase>", "target phase").option("--force <reason>", "force the gate with a reason").action(async (...args) => {
1376
1459
  const cmd = trailingCmd(args);
1377
1460
  const g = cmd.optsWithGlobals();
1378
- const to = typeof g["to"] === "string" ? g["to"] : void 0;
1379
- const force = typeof g["force"] === "string" ? g["force"] : void 0;
1461
+ const to = typeof g.to === "string" ? g.to : void 0;
1462
+ const force = typeof g.force === "string" ? g.force : void 0;
1380
1463
  await taskAdvance({
1381
1464
  ...toCliOptions(g),
1382
1465
  ...to === void 0 ? {} : { to },
@@ -1425,7 +1508,8 @@ async function run(argv = []) {
1425
1508
  var isMainModule = (() => {
1426
1509
  try {
1427
1510
  const entry = process.argv[1];
1428
- return typeof entry === "string" && entry.length > 0 ? pathToFileURL(entry).href === import.meta.url : false;
1511
+ if (typeof entry !== "string" || entry.length === 0) return false;
1512
+ return pathToFileURL(realpathSync(entry)).href === import.meta.url;
1429
1513
  } catch {
1430
1514
  return false;
1431
1515
  }