@nanopm/cli 0.1.0 → 0.1.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.
Files changed (2) hide show
  1. package/dist/index.js +130 -95
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import { Command } from "commander";
5
5
 
6
6
  // ../daemon/src/adapters/claude-code/index.ts
7
7
  import { execFile, spawn } from "child_process";
8
+ import { randomUUID } from "crypto";
8
9
  import { createInterface } from "readline";
9
10
  import { writeFile as writeFile2 } from "fs/promises";
10
11
  import { join as join3 } from "path";
@@ -606,6 +607,13 @@ function hashDeviceSecret(secret) {
606
607
  return createHash("sha256").update(secret).digest("hex");
607
608
  }
608
609
 
610
+ // ../shared/src/harness.ts
611
+ var CLAUDE_CODE = "claude-code";
612
+ function claudeHarness(harnesses) {
613
+ const entries = Array.isArray(harnesses) ? harnesses : [];
614
+ return entries.find((h) => h.id === CLAUDE_CODE) ?? null;
615
+ }
616
+
609
617
  // ../shared/src/secrets.ts
610
618
  var SECRET_PATTERNS = [
611
619
  "**/.env",
@@ -3785,7 +3793,26 @@ var ClaudeCodeAdapter = class {
3785
3793
  else args.push("--session-id", spec.sessionId);
3786
3794
  return args;
3787
3795
  }
3796
+ /**
3797
+ * One session, and one more when the model asked for is newer than this Claude Code: a
3798
+ * skill names `claude-opus-5-5`, a Claude Code older than 2.1.280 refuses it, and the run
3799
+ * used to end there with no roadmap (activation row 36). The second session asks for the
3800
+ * family alias under a fresh id and says so, so the run works on the Opus the machine has.
3801
+ * Any other failure stays a failure.
3802
+ */
3788
3803
  async *run(spec) {
3804
+ for await (const event of this.runOnce(spec)) {
3805
+ const alias = event.type === "failed" ? olderAlias(spec.model, event.message) : null;
3806
+ if (!alias) {
3807
+ yield event;
3808
+ continue;
3809
+ }
3810
+ yield { type: "text", text: `This Claude Code does not know ${spec.model} yet; using ${alias}. \`claude update\` brings the newer model.` };
3811
+ yield* this.runOnce({ ...spec, model: alias, sessionId: randomUUID(), resumeSessionId: void 0 });
3812
+ return;
3813
+ }
3814
+ }
3815
+ async *runOnce(spec) {
3789
3816
  const mcpConfigPath = join3(spec.runDir, "mcp.json");
3790
3817
  const mcpServers = Object.fromEntries(
3791
3818
  spec.mcp.map((s) => [s.name, { command: s.command, args: s.args, env: s.env }])
@@ -3832,6 +3859,10 @@ var ClaudeCodeAdapter = class {
3832
3859
  }
3833
3860
  }
3834
3861
  };
3862
+ function olderAlias(model, message) {
3863
+ if (!model || !/does not support this model/i.test(message)) return null;
3864
+ return ["opus", "sonnet", "haiku"].find((family) => model.includes(family) && model !== family) ?? null;
3865
+ }
3835
3866
  function appendExit(message, code) {
3836
3867
  return code === null || code === 0 ? message : `${message} (exit ${code})`;
3837
3868
  }
@@ -5193,7 +5224,7 @@ async function clonelessSkills(skillsDir = findSkillsDir()) {
5193
5224
  }
5194
5225
 
5195
5226
  // ../daemon/src/problem-mapping-harness.ts
5196
- import { randomUUID } from "crypto";
5227
+ import { randomUUID as randomUUID2 } from "crypto";
5197
5228
  function mappingHarnessRunner(options) {
5198
5229
  return async (input) => {
5199
5230
  const skill = await loadSkill(`problem-${input.role}`);
@@ -5202,7 +5233,7 @@ function mappingHarnessRunner(options) {
5202
5233
  for await (const event of options.adapter.run({
5203
5234
  cwd: options.runDir,
5204
5235
  runDir: options.runDir,
5205
- sessionId: randomUUID(),
5236
+ sessionId: randomUUID2(),
5206
5237
  systemPrompt: `${skill.body}
5207
5238
 
5208
5239
  Output schema:
@@ -5493,7 +5524,7 @@ function mappingUsage(checkpoints) {
5493
5524
  }
5494
5525
 
5495
5526
  // ../daemon/src/persona-job.ts
5496
- import { randomUUID as randomUUID2 } from "crypto";
5527
+ import { randomUUID as randomUUID3 } from "crypto";
5497
5528
 
5498
5529
  // ../daemon/src/crew-retry.ts
5499
5530
  async function askAgainIfUnanswered(attempt7, say, role7) {
@@ -5806,7 +5837,7 @@ async function attempt({
5806
5837
  await onEvent({ type: "text", text: say });
5807
5838
  for await (const event of adapter.run({
5808
5839
  ...spec,
5809
- sessionId: randomUUID2(),
5840
+ sessionId: randomUUID3(),
5810
5841
  resumeSessionId: void 0,
5811
5842
  capabilities: [],
5812
5843
  mcp: [],
@@ -6027,7 +6058,7 @@ async function collect2(client, projectId, cwd, replace) {
6027
6058
  }
6028
6059
 
6029
6060
  // ../daemon/src/direction-job.ts
6030
- import { randomUUID as randomUUID3 } from "crypto";
6061
+ import { randomUUID as randomUUID4 } from "crypto";
6031
6062
 
6032
6063
  // ../daemon/src/crew-no-downgrade.ts
6033
6064
  function keepsTheLine(job, live, confidence) {
@@ -6222,7 +6253,7 @@ ${renderTests()}` : skill.body;
6222
6253
  await onEvent({ type: "text", text: say });
6223
6254
  for await (const event of adapter.run({
6224
6255
  ...spec,
6225
- sessionId: randomUUID3(),
6256
+ sessionId: randomUUID4(),
6226
6257
  resumeSessionId: void 0,
6227
6258
  capabilities: [],
6228
6259
  mcp: [],
@@ -6351,7 +6382,7 @@ async function collect3(client, projectId) {
6351
6382
  }
6352
6383
 
6353
6384
  // ../daemon/src/pitch-job.ts
6354
- import { randomUUID as randomUUID4 } from "crypto";
6385
+ import { randomUUID as randomUUID5 } from "crypto";
6355
6386
  async function runPitchJob({ client, job, adapter, spec, onEvent }) {
6356
6387
  if (!job.project_id) throw new Error("A pitch needs a project.");
6357
6388
  const projectId = job.project_id;
@@ -6456,7 +6487,7 @@ async function attempt3({
6456
6487
  await onEvent({ type: "text", text: say });
6457
6488
  for await (const event of adapter.run({
6458
6489
  ...spec,
6459
- sessionId: randomUUID4(),
6490
+ sessionId: randomUUID5(),
6460
6491
  resumeSessionId: void 0,
6461
6492
  capabilities: [],
6462
6493
  mcp: [],
@@ -6568,7 +6599,7 @@ async function collect4(client, projectId) {
6568
6599
  }
6569
6600
 
6570
6601
  // ../daemon/src/market-job.ts
6571
- import { randomUUID as randomUUID5 } from "crypto";
6602
+ import { randomUUID as randomUUID6 } from "crypto";
6572
6603
 
6573
6604
  // ../daemon/src/web-journal.ts
6574
6605
  var HARNESS_WEB_TOOLS = ["WebSearch", "WebFetch"];
@@ -6809,7 +6840,7 @@ async function attempt4({ adapter, spec, onEvent, role: which, prompt, say }) {
6809
6840
  await onEvent({ type: "text", text: say });
6810
6841
  for await (const event of adapter.run({
6811
6842
  ...spec,
6812
- sessionId: randomUUID5(),
6843
+ sessionId: randomUUID6(),
6813
6844
  resumeSessionId: void 0,
6814
6845
  capabilities,
6815
6846
  mcp: which === "scout" ? spec.mcp : [],
@@ -6892,7 +6923,7 @@ async function collect5(client, projectId, ask6) {
6892
6923
  }
6893
6924
 
6894
6925
  // ../daemon/src/needs-job.ts
6895
- import { randomUUID as randomUUID6 } from "crypto";
6926
+ import { randomUUID as randomUUID7 } from "crypto";
6896
6927
  var SIGNALS_MAX = 40;
6897
6928
  var SIGNAL_CHARS = 3e3;
6898
6929
  async function runNeedsJob({ client, job, adapter, spec, onEvent }) {
@@ -7471,7 +7502,7 @@ async function attempt5({ adapter, spec, onEvent, role: which, schema: shape2, t
7471
7502
  await onEvent({ type: "text", text: say });
7472
7503
  for await (const event of adapter.run({
7473
7504
  ...spec,
7474
- sessionId: randomUUID6(),
7505
+ sessionId: randomUUID7(),
7475
7506
  resumeSessionId: void 0,
7476
7507
  capabilities: granted,
7477
7508
  mcp: granted.length ? spec.mcp : [],
@@ -7693,7 +7724,7 @@ function opportunitiesOutputSchema(which) {
7693
7724
  }
7694
7725
 
7695
7726
  // ../daemon/src/crew.ts
7696
- import { randomUUID as randomUUID7 } from "crypto";
7727
+ import { randomUUID as randomUUID8 } from "crypto";
7697
7728
  import { mkdir as mkdir2 } from "fs/promises";
7698
7729
  import { join as join7 } from "path";
7699
7730
  var READ_ONLY = {
@@ -7720,7 +7751,7 @@ async function attempt6({ adapter, spec, onEvent, skill: skillName, name, schema
7720
7751
  // A role that may not read the code does not stand in it (docs/nanopm-71-deep-dive-lenses.md).
7721
7752
  cwd: grant.includes("read_repo") ? spec.cwd : runDir,
7722
7753
  runDir,
7723
- sessionId: randomUUID7(),
7754
+ sessionId: randomUUID8(),
7724
7755
  resumeSessionId: void 0,
7725
7756
  capabilities: [...grant],
7726
7757
  mcp: grant.includes("read_data") ? spec.mcp : [],
@@ -9222,7 +9253,7 @@ async function readRoadmap(client, projectId) {
9222
9253
  }
9223
9254
 
9224
9255
  // ../daemon/src/reword-job.ts
9225
- import { randomUUID as randomUUID8 } from "crypto";
9256
+ import { randomUUID as randomUUID9 } from "crypto";
9226
9257
  async function runRewordJob({ client, job, adapter, spec, onEvent }) {
9227
9258
  if (!job.project_id) throw new Error("A rewrite needs a project.");
9228
9259
  const asked = RewordParams.safeParse(job.params);
@@ -9284,7 +9315,7 @@ async function session({ adapter, spec, onEvent, prompt }) {
9284
9315
  let usage;
9285
9316
  for await (const event of adapter.run({
9286
9317
  ...spec,
9287
- sessionId: randomUUID8(),
9318
+ sessionId: randomUUID9(),
9288
9319
  resumeSessionId: void 0,
9289
9320
  capabilities: [],
9290
9321
  mcp: [],
@@ -9319,7 +9350,7 @@ ${body}
9319
9350
  }
9320
9351
 
9321
9352
  // ../daemon/src/talk-job.ts
9322
- import { randomUUID as randomUUID9 } from "crypto";
9353
+ import { randomUUID as randomUUID10 } from "crypto";
9323
9354
  var ALLOWED = /* @__PURE__ */ new Set([...TALK_TOOLS.map((t) => `mcp__nanopm__${t}`), "StructuredOutput"]);
9324
9355
  async function runTalkJob({ client, job, adapter, spec, onEvent }) {
9325
9356
  if (!job.project_id) throw new Error("A conversation needs a project.");
@@ -9351,7 +9382,7 @@ async function runTalkJob({ client, job, adapter, spec, onEvent }) {
9351
9382
  let usage;
9352
9383
  for await (const event of adapter.run({
9353
9384
  ...spec,
9354
- sessionId: randomUUID9(),
9385
+ sessionId: randomUUID10(),
9355
9386
  resumeSessionId: void 0,
9356
9387
  capabilities: skill.manifest.capabilities,
9357
9388
  harnessWeb: false,
@@ -9388,7 +9419,7 @@ var told = (r) => ({
9388
9419
 
9389
9420
  // ../daemon/src/objective-definitions.ts
9390
9421
  import { execFile as execFile4 } from "child_process";
9391
- import { randomUUID as randomUUID10 } from "crypto";
9422
+ import { randomUUID as randomUUID11 } from "crypto";
9392
9423
  import { existsSync as existsSync2 } from "fs";
9393
9424
  import { mkdir as mkdir3, readFile as readFile5 } from "fs/promises";
9394
9425
  import { join as join8 } from "path";
@@ -9564,7 +9595,7 @@ async function readDefinitions({ adapter, spec, publish: publish5, journal, hasR
9564
9595
  for await (const event of adapter.run({
9565
9596
  ...spec,
9566
9597
  runDir,
9567
- sessionId: randomUUID10(),
9598
+ sessionId: randomUUID11(),
9568
9599
  resumeSessionId: void 0,
9569
9600
  capabilities: ["read_repo"],
9570
9601
  // No Glob: it read the folder at 15 s a search (Guillaume's suggestions took 75 s,
@@ -9888,7 +9919,7 @@ function localDate(timezone, at) {
9888
9919
  }
9889
9920
 
9890
9921
  // ../daemon/src/run-job.ts
9891
- import { randomUUID as randomUUID11 } from "crypto";
9922
+ import { randomUUID as randomUUID12 } from "crypto";
9892
9923
  import { existsSync as existsSync3 } from "fs";
9893
9924
  import { mkdir as mkdir4, readFile as readFile6, rm as rm2 } from "fs/promises";
9894
9925
  import { homedir as homedir2, tmpdir } from "os";
@@ -10333,7 +10364,7 @@ async function execute(job, skill, ctx, events) {
10333
10364
  const runDir = join9(nanopmHome(), "run", job.id);
10334
10365
  await mkdir4(runDir, { recursive: true, mode: 448 });
10335
10366
  const resumeSessionId = job.resume_of ? await sessionOf(ctx.client, job.resume_of) : void 0;
10336
- const sessionId = resumeSessionId ?? randomUUID11();
10367
+ const sessionId = resumeSessionId ?? randomUUID12();
10337
10368
  await ctx.client.from("jobs").update({ harness_session_id: sessionId }).eq("id", job.id);
10338
10369
  const adapter = ctx.adapter ?? new ClaudeCodeAdapter();
10339
10370
  const [project, searchProvider] = job.project_id ? await Promise.all([loadProject(ctx.client, job.project_id), loadSearchProvider(ctx.client, job.project_id)]) : [null, null];
@@ -10829,7 +10860,7 @@ async function runDaemon(options = {}) {
10829
10860
  let daemonId;
10830
10861
  try {
10831
10862
  auth = await authenticate();
10832
- daemonId = await registerDaemon(auth, options.version ?? "dev", options.shared);
10863
+ daemonId = await registerDaemon(auth, options.version ?? "dev", { shared: options.shared });
10833
10864
  log(`daemon ${daemonId} online as ${auth.userId} on ${hostname2()}`);
10834
10865
  for (const reclaimed of await reclaimOwnJobs(auth.client, daemonId)) {
10835
10866
  log(`job ${reclaimed} was running when this daemon last stopped; marked interrupted (resume with \`nanopm resume ${reclaimed}\`)`);
@@ -11137,7 +11168,7 @@ async function killOrphanedHarness(jobId) {
11137
11168
  }
11138
11169
  await rm3(runDir, { recursive: true, force: true });
11139
11170
  }
11140
- async function registerDaemon(auth, version, shared) {
11171
+ async function registerDaemon(auth, version, opts = {}) {
11141
11172
  const path = join10(nanopmHome(), "daemon.json");
11142
11173
  let identity = null;
11143
11174
  try {
@@ -11145,18 +11176,18 @@ async function registerDaemon(auth, version, shared) {
11145
11176
  } catch {
11146
11177
  identity = null;
11147
11178
  }
11148
- const isShared = shared ?? identity?.shared ?? false;
11149
- const detection = await new ClaudeCodeAdapter().detect();
11150
- if (detection.authenticated === null && identity?.id) {
11179
+ const isShared = opts.shared ?? identity?.shared ?? false;
11180
+ const detection = opts.claude ?? await new ClaudeCodeAdapter().detect();
11181
+ if (!opts.claude && detection.authenticated === null && identity?.id) {
11151
11182
  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");
11183
+ const known = claudeHarness(existing2?.harnesses);
11153
11184
  if (typeof known?.authenticated === "boolean") detection.authenticated = known.authenticated;
11154
11185
  }
11155
11186
  const fields = {
11156
11187
  hostname: hostname2(),
11157
11188
  version,
11158
- harnesses: [{ id: "claude-code", ...detection }],
11159
- status: "online",
11189
+ harnesses: [{ id: CLAUDE_CODE, ...detection }],
11190
+ status: opts.claude ? "offline" : "online",
11160
11191
  shared: isShared,
11161
11192
  last_seen_at: (/* @__PURE__ */ new Date()).toISOString()
11162
11193
  };
@@ -11240,7 +11271,7 @@ function contextFromEnv(env = process.env) {
11240
11271
 
11241
11272
  // ../memory-mcp/src/server.ts
11242
11273
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
11243
- import { randomUUID as randomUUID12 } from "crypto";
11274
+ import { randomUUID as randomUUID13 } from "crypto";
11244
11275
  import { setTimeout as sleep2 } from "timers/promises";
11245
11276
  import { z as z20 } from "zod";
11246
11277
 
@@ -13083,7 +13114,7 @@ async function talkAct(ctx, roundOf, proposed, asked, why) {
13083
13114
  const [round2, world] = await Promise.all([roundOf, talkWorld(ctx.client, ctx.projectId)]);
13084
13115
  const ref = change.kind === "add" ? change.parent : change.kind === "add_solution" ? change.leaf : change.ref;
13085
13116
  const target = ref ? currentRow(world, ref)?.ref ?? currentSolution(world, ref)?.ref ?? ref : void 0;
13086
- const base = { id: randomUUID12(), change, ...movesDown(change, world) ? { down: true } : {}, ...change.kind === "brainstorm" ? { cost: runCost(change.depth) } : {} };
13117
+ const base = { id: randomUUID13(), change, ...movesDown(change, world) ? { down: true } : {}, ...change.kind === "brainstorm" ? { cost: runCost(change.depth) } : {} };
13087
13118
  let action;
13088
13119
  if (!askedIn(asked, round2.words)) {
13089
13120
  action = { ...base, state: "suggested", line: talkLine(change, world, false), ...target ? { target } : {} };
@@ -13874,6 +13905,59 @@ import { mkdir as mkdir6, readFile as readFile11, rm as rm4, writeFile as writeF
13874
13905
  import { homedir as homedir3 } from "os";
13875
13906
  import { join as join12 } from "path";
13876
13907
  import { promisify as promisify7 } from "util";
13908
+
13909
+ // package.json
13910
+ var package_default = {
13911
+ name: "@nanopm/cli",
13912
+ version: "0.1.2",
13913
+ description: "An autonomous product manager for builders who run several small products. Runs on your machine, drives your own coding harness.",
13914
+ type: "module",
13915
+ license: "MIT",
13916
+ bin: {
13917
+ nanopm: "dist/index.js"
13918
+ },
13919
+ files: [
13920
+ "dist",
13921
+ "skills"
13922
+ ],
13923
+ engines: {
13924
+ node: ">=20"
13925
+ },
13926
+ scripts: {
13927
+ build: "tsup && rm -rf skills && cp -R ../../skills skills"
13928
+ },
13929
+ dependencies: {
13930
+ "@modelcontextprotocol/sdk": "^1.30.0",
13931
+ "@supabase/supabase-js": "^2.116.0",
13932
+ commander: "^15.0.0",
13933
+ postgres: "^3.4.7",
13934
+ zod: "^4.5.4"
13935
+ },
13936
+ repository: {
13937
+ type: "git",
13938
+ url: "git+https://github.com/nmrtn/nanopm2.git"
13939
+ },
13940
+ keywords: [
13941
+ "product-management",
13942
+ "claude-code",
13943
+ "agent",
13944
+ "solopreneur"
13945
+ ],
13946
+ devDependencies: {
13947
+ "@nanopm/connectors": "workspace:*",
13948
+ "@nanopm/daemon": "workspace:*",
13949
+ "@nanopm/memory-mcp": "workspace:*",
13950
+ "@nanopm/shared": "workspace:*"
13951
+ },
13952
+ publishConfig: {
13953
+ access: "public"
13954
+ }
13955
+ };
13956
+
13957
+ // src/version.ts
13958
+ var VERSION = package_default.version;
13959
+
13960
+ // src/commands/daemon-service.ts
13877
13961
  var execFileAsync7 = promisify7(execFile7);
13878
13962
  var LAUNCHD_LABEL = "pm.nano.daemon";
13879
13963
  function plistPath() {
@@ -13919,12 +14003,20 @@ function requireMac() {
13919
14003
  async function installDaemon(out = (l) => console.log(l), opts = {}) {
13920
14004
  requireMac();
13921
14005
  if (!await loadCredentials()) throw new Error("not logged in; run `nanopm login` first");
14006
+ const auth = await authenticate();
14007
+ const found = (claude) => registerDaemon(auth, VERSION, { shared: opts.shared, claude }).catch(() => void 0);
13922
14008
  const adapter = new ClaudeCodeAdapter();
13923
14009
  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)");
14010
+ if (!detection.available) {
14011
+ await found(detection);
14012
+ throw new Error("Claude Code is not installed on this machine (`claude` not found on PATH)");
14013
+ }
13925
14014
  out(`Claude Code ${detection.version} found; checking its login\u2026`);
13926
14015
  const ping = await adapter.ping();
13927
- if (!ping.ok) throw new Error(`Claude Code is installed but not usable headless: ${ping.message}`);
14016
+ if (!ping.ok) {
14017
+ await found({ ...detection, authenticated: false });
14018
+ throw new Error(`Claude Code is installed but not usable headless: ${ping.message}`);
14019
+ }
13928
14020
  out("Claude Code answers.");
13929
14021
  const web = await adapter.probeWebSearch();
13930
14022
  await rememberWebSearch(web.ok);
@@ -13936,6 +14028,7 @@ async function installDaemon(out = (l) => console.log(l), opts = {}) {
13936
14028
  await mkdir6(join12(home, "Library", "LaunchAgents"), { recursive: true });
13937
14029
  await mkdir6(nanopmHome(), { recursive: true, mode: 448 });
13938
14030
  if (opts.shared !== void 0) await rememberShared(opts.shared);
14031
+ await found({ ...detection, authenticated: true });
13939
14032
  await writeFile4(plistPath(), renderPlist({ node: process.execPath, bin, home, path, logPath: daemonLogPath(), nanopmHome: nanopmHome() }), { mode: 420 });
13940
14033
  const target = `gui/${process.getuid?.() ?? 501}`;
13941
14034
  await execFileAsync7("launchctl", ["bootout", target, plistPath()]).catch(() => void 0);
@@ -13944,15 +14037,6 @@ async function installDaemon(out = (l) => console.log(l), opts = {}) {
13944
14037
  const shared = opts.shared ?? await localShared();
13945
14038
  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
14039
  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
14040
  }
13957
14041
  async function uninstallDaemon(out = (l) => console.log(l)) {
13958
14042
  requireMac();
@@ -14222,7 +14306,9 @@ async function login(opts = {}) {
14222
14306
  await installDaemon(out, { next: false });
14223
14307
  } catch (err) {
14224
14308
  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");
14309
+ out("");
14310
+ 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.");
14311
+ return;
14226
14312
  }
14227
14313
  }
14228
14314
  out("");
@@ -15523,57 +15609,6 @@ async function resume(jobId, opts) {
15523
15609
  return streamJob(auth.client, job.id, { pollMs: 1e3, out, renderer, cancelSignal: opts.cancelSignal, answerer, verbose: verboseWanted() });
15524
15610
  }
15525
15611
 
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
15612
  // src/commands/connect.ts
15578
15613
  import { createInterface as createInterface4 } from "readline/promises";
15579
15614
  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.2",
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",