@nanopm/cli 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +82 -71
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -606,6 +606,13 @@ function hashDeviceSecret(secret) {
606
606
  return createHash("sha256").update(secret).digest("hex");
607
607
  }
608
608
 
609
+ // ../shared/src/harness.ts
610
+ var CLAUDE_CODE = "claude-code";
611
+ function claudeHarness(harnesses) {
612
+ const entries = Array.isArray(harnesses) ? harnesses : [];
613
+ return entries.find((h) => h.id === CLAUDE_CODE) ?? null;
614
+ }
615
+
609
616
  // ../shared/src/secrets.ts
610
617
  var SECRET_PATTERNS = [
611
618
  "**/.env",
@@ -10829,7 +10836,7 @@ async function runDaemon(options = {}) {
10829
10836
  let daemonId;
10830
10837
  try {
10831
10838
  auth = await authenticate();
10832
- daemonId = await registerDaemon(auth, options.version ?? "dev", options.shared);
10839
+ daemonId = await registerDaemon(auth, options.version ?? "dev", { shared: options.shared });
10833
10840
  log(`daemon ${daemonId} online as ${auth.userId} on ${hostname2()}`);
10834
10841
  for (const reclaimed of await reclaimOwnJobs(auth.client, daemonId)) {
10835
10842
  log(`job ${reclaimed} was running when this daemon last stopped; marked interrupted (resume with \`nanopm resume ${reclaimed}\`)`);
@@ -11137,7 +11144,7 @@ async function killOrphanedHarness(jobId) {
11137
11144
  }
11138
11145
  await rm3(runDir, { recursive: true, force: true });
11139
11146
  }
11140
- async function registerDaemon(auth, version, shared) {
11147
+ async function registerDaemon(auth, version, opts = {}) {
11141
11148
  const path = join10(nanopmHome(), "daemon.json");
11142
11149
  let identity = null;
11143
11150
  try {
@@ -11145,18 +11152,18 @@ async function registerDaemon(auth, version, shared) {
11145
11152
  } catch {
11146
11153
  identity = null;
11147
11154
  }
11148
- const isShared = shared ?? identity?.shared ?? false;
11149
- const detection = await new ClaudeCodeAdapter().detect();
11150
- if (detection.authenticated === null && identity?.id) {
11155
+ const isShared = opts.shared ?? identity?.shared ?? false;
11156
+ const detection = opts.claude ?? await new ClaudeCodeAdapter().detect();
11157
+ if (!opts.claude && detection.authenticated === null && identity?.id) {
11151
11158
  const { data: existing2 } = await auth.client.from("daemons").select("harnesses").eq("id", identity.id).maybeSingle();
11152
- const known = existing2?.harnesses?.find((h) => h.id === "claude-code");
11159
+ const known = claudeHarness(existing2?.harnesses);
11153
11160
  if (typeof known?.authenticated === "boolean") detection.authenticated = known.authenticated;
11154
11161
  }
11155
11162
  const fields = {
11156
11163
  hostname: hostname2(),
11157
11164
  version,
11158
- harnesses: [{ id: "claude-code", ...detection }],
11159
- status: "online",
11165
+ harnesses: [{ id: CLAUDE_CODE, ...detection }],
11166
+ status: opts.claude ? "offline" : "online",
11160
11167
  shared: isShared,
11161
11168
  last_seen_at: (/* @__PURE__ */ new Date()).toISOString()
11162
11169
  };
@@ -13874,6 +13881,59 @@ import { mkdir as mkdir6, readFile as readFile11, rm as rm4, writeFile as writeF
13874
13881
  import { homedir as homedir3 } from "os";
13875
13882
  import { join as join12 } from "path";
13876
13883
  import { promisify as promisify7 } from "util";
13884
+
13885
+ // package.json
13886
+ var package_default = {
13887
+ name: "@nanopm/cli",
13888
+ version: "0.1.1",
13889
+ description: "An autonomous product manager for builders who run several small products. Runs on your machine, drives your own coding harness.",
13890
+ type: "module",
13891
+ license: "MIT",
13892
+ bin: {
13893
+ nanopm: "dist/index.js"
13894
+ },
13895
+ files: [
13896
+ "dist",
13897
+ "skills"
13898
+ ],
13899
+ engines: {
13900
+ node: ">=20"
13901
+ },
13902
+ scripts: {
13903
+ build: "tsup && rm -rf skills && cp -R ../../skills skills"
13904
+ },
13905
+ dependencies: {
13906
+ "@modelcontextprotocol/sdk": "^1.30.0",
13907
+ "@supabase/supabase-js": "^2.116.0",
13908
+ commander: "^15.0.0",
13909
+ postgres: "^3.4.7",
13910
+ zod: "^4.5.4"
13911
+ },
13912
+ repository: {
13913
+ type: "git",
13914
+ url: "git+https://github.com/nmrtn/nanopm2.git"
13915
+ },
13916
+ keywords: [
13917
+ "product-management",
13918
+ "claude-code",
13919
+ "agent",
13920
+ "solopreneur"
13921
+ ],
13922
+ devDependencies: {
13923
+ "@nanopm/connectors": "workspace:*",
13924
+ "@nanopm/daemon": "workspace:*",
13925
+ "@nanopm/memory-mcp": "workspace:*",
13926
+ "@nanopm/shared": "workspace:*"
13927
+ },
13928
+ publishConfig: {
13929
+ access: "public"
13930
+ }
13931
+ };
13932
+
13933
+ // src/version.ts
13934
+ var VERSION = package_default.version;
13935
+
13936
+ // src/commands/daemon-service.ts
13877
13937
  var execFileAsync7 = promisify7(execFile7);
13878
13938
  var LAUNCHD_LABEL = "pm.nano.daemon";
13879
13939
  function plistPath() {
@@ -13919,12 +13979,20 @@ function requireMac() {
13919
13979
  async function installDaemon(out = (l) => console.log(l), opts = {}) {
13920
13980
  requireMac();
13921
13981
  if (!await loadCredentials()) throw new Error("not logged in; run `nanopm login` first");
13982
+ const auth = await authenticate();
13983
+ const found = (claude) => registerDaemon(auth, VERSION, { shared: opts.shared, claude }).catch(() => void 0);
13922
13984
  const adapter = new ClaudeCodeAdapter();
13923
13985
  const detection = await adapter.detect();
13924
- if (!detection.available) throw new Error("Claude Code is not installed on this machine (`claude` not found on PATH)");
13986
+ if (!detection.available) {
13987
+ await found(detection);
13988
+ throw new Error("Claude Code is not installed on this machine (`claude` not found on PATH)");
13989
+ }
13925
13990
  out(`Claude Code ${detection.version} found; checking its login\u2026`);
13926
13991
  const ping = await adapter.ping();
13927
- if (!ping.ok) throw new Error(`Claude Code is installed but not usable headless: ${ping.message}`);
13992
+ if (!ping.ok) {
13993
+ await found({ ...detection, authenticated: false });
13994
+ throw new Error(`Claude Code is installed but not usable headless: ${ping.message}`);
13995
+ }
13928
13996
  out("Claude Code answers.");
13929
13997
  const web = await adapter.probeWebSearch();
13930
13998
  await rememberWebSearch(web.ok);
@@ -13936,6 +14004,7 @@ async function installDaemon(out = (l) => console.log(l), opts = {}) {
13936
14004
  await mkdir6(join12(home, "Library", "LaunchAgents"), { recursive: true });
13937
14005
  await mkdir6(nanopmHome(), { recursive: true, mode: 448 });
13938
14006
  if (opts.shared !== void 0) await rememberShared(opts.shared);
14007
+ await found({ ...detection, authenticated: true });
13939
14008
  await writeFile4(plistPath(), renderPlist({ node: process.execPath, bin, home, path, logPath: daemonLogPath(), nanopmHome: nanopmHome() }), { mode: 420 });
13940
14009
  const target = `gui/${process.getuid?.() ?? 501}`;
13941
14010
  await execFileAsync7("launchctl", ["bootout", target, plistPath()]).catch(() => void 0);
@@ -13944,15 +14013,6 @@ async function installDaemon(out = (l) => console.log(l), opts = {}) {
13944
14013
  const shared = opts.shared ?? await localShared();
13945
14014
  out(shared ? "This machine is shared with your projects: it also runs scheduled reviews and partners' jobs." : "This machine runs your jobs only. `nanopm daemon install --share` to offer it to your projects.");
13946
14015
  if (opts.next !== false) out(`Next, in a repo: nanopm onboard \xB7 or continue at ${webUrl()}/new`);
13947
- const auth = await authenticate();
13948
- for (let i = 0; i < 20; i++) {
13949
- const id = await localDaemonId();
13950
- if (id) {
13951
- await auth.client.from("daemons").update({ harnesses: [{ id: "claude-code", available: true, version: detection.version, authenticated: true }] }).eq("id", id);
13952
- break;
13953
- }
13954
- await new Promise((r) => setTimeout(r, 500));
13955
- }
13956
14016
  }
13957
14017
  async function uninstallDaemon(out = (l) => console.log(l)) {
13958
14018
  requireMac();
@@ -14222,7 +14282,9 @@ async function login(opts = {}) {
14222
14282
  await installDaemon(out, { next: false });
14223
14283
  } catch (err) {
14224
14284
  out(`could not start me in the background: ${err instanceof Error ? err.message : String(err)}`);
14225
- out("run nanopm daemon run in a terminal, or nanopm daemon install once Claude Code is signed in");
14285
+ out("");
14286
+ out("Your account is linked, but I cannot work on this machine yet. Fix the line above, then run: nanopm daemon install. The page in your browser moves on by itself.");
14287
+ return;
14226
14288
  }
14227
14289
  }
14228
14290
  out("");
@@ -15523,57 +15585,6 @@ async function resume(jobId, opts) {
15523
15585
  return streamJob(auth.client, job.id, { pollMs: 1e3, out, renderer, cancelSignal: opts.cancelSignal, answerer, verbose: verboseWanted() });
15524
15586
  }
15525
15587
 
15526
- // package.json
15527
- var package_default = {
15528
- name: "@nanopm/cli",
15529
- version: "0.1.0",
15530
- description: "An autonomous product manager for builders who run several small products. Runs on your machine, drives your own coding harness.",
15531
- type: "module",
15532
- license: "MIT",
15533
- bin: {
15534
- nanopm: "dist/index.js"
15535
- },
15536
- files: [
15537
- "dist",
15538
- "skills"
15539
- ],
15540
- engines: {
15541
- node: ">=20"
15542
- },
15543
- scripts: {
15544
- build: "tsup && rm -rf skills && cp -R ../../skills skills"
15545
- },
15546
- dependencies: {
15547
- "@modelcontextprotocol/sdk": "^1.30.0",
15548
- "@supabase/supabase-js": "^2.116.0",
15549
- commander: "^15.0.0",
15550
- postgres: "^3.4.7",
15551
- zod: "^4.5.4"
15552
- },
15553
- repository: {
15554
- type: "git",
15555
- url: "git+https://github.com/nmrtn/nanopm2.git"
15556
- },
15557
- keywords: [
15558
- "product-management",
15559
- "claude-code",
15560
- "agent",
15561
- "solopreneur"
15562
- ],
15563
- devDependencies: {
15564
- "@nanopm/connectors": "workspace:*",
15565
- "@nanopm/daemon": "workspace:*",
15566
- "@nanopm/memory-mcp": "workspace:*",
15567
- "@nanopm/shared": "workspace:*"
15568
- },
15569
- publishConfig: {
15570
- access: "public"
15571
- }
15572
- };
15573
-
15574
- // src/version.ts
15575
- var VERSION = package_default.version;
15576
-
15577
15588
  // src/commands/connect.ts
15578
15589
  import { createInterface as createInterface4 } from "readline/promises";
15579
15590
  function whereItGoes(color) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanopm/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "An autonomous product manager for builders who run several small products. Runs on your machine, drives your own coding harness.",
5
5
  "type": "module",
6
6
  "license": "MIT",