@passioncode-ai/passioncode 0.2.52 → 0.2.53

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.53 - 2026-11-02
4
+
5
+ ### Fixed
6
+
7
+ - What the launcher prints for a person carries no em dash (PC-95): the `setup` install question, its
8
+ app verification lines and its "Your steps" header, the `doctor` details and fixes for Node, a stopped
9
+ app, Docker, the Supabase CLI, MCP registrations and proving calls, and services, the `help` title,
10
+ the `update` closing line, and the session-start update notices. A
11
+ colon, comma, semicolon or parentheses take its place. Each line keeps its meaning, except that the
12
+ "Your steps" header no longer says an agent cannot do any of them (some are commands an agent runs):
13
+ it now reads "sign-ins, consents and secrets in hidden prompts need you in person". A test now
14
+ fails on an em dash, or its escape, in any string under `bin/`, `lib/` or the plugin's hooks. The npm
15
+ description and the GitHub release title (now "PassionCode.ai <tag>") carry none either.
16
+
3
17
  ## 0.2.52 - 2026-11-02
4
18
 
5
19
  ### Fixed
package/SECURITY.md CHANGED
@@ -72,7 +72,7 @@ The hook installs a newer version on its own only when all of these hold:
72
72
  It then runs `npx --yes @passioncode-ai/passioncode@<that exact version> update --quiet`, detached, so
73
73
  the version that was checked is the version that runs. In every other case it spawns
74
74
  nothing: a version from an account outside the list is reported in one line naming the
75
- account ("… not a trusted PassionCode publisher — not installing"); a name nobody has
75
+ account ("… not a trusted PassionCode publisher, so it is not installed"); a name nobody has
76
76
  published (npm E404) is silent; a failed check is shown once.
77
77
 
78
78
  The current allowlist lives in [`plugin/passioncode/trust.json`](plugin/passioncode/trust.json).
@@ -17,7 +17,7 @@ function cachedNpmStatus({ latest, checkedAt, installed }) {
17
17
  return `npm latest (cached) ${latest} (${checked}${stale ? '; stale: older than installed' : ''})`;
18
18
  }
19
19
 
20
- const HELP = `passioncode — set up and check PassionCode.ai on this machine: the apps, their MCP servers, the skills
20
+ const HELP = `passioncode sets up and checks PassionCode.ai on this machine: the apps, their MCP servers, the skills
21
21
 
22
22
  npx @passioncode-ai/passioncode@latest setup [--yes] [--with ids] [--without ids] [--train name|none] [--no-apps] [--no-open] [--dry-run] [--json]
23
23
  a new machine: install and configure everything; an existing one: check, repair, check again
@@ -126,7 +126,7 @@ async function main(argv) {
126
126
  out(r, [
127
127
  ...r.steps.map((s) => `${s.outcome.padEnd(8)} ${s.kind.padEnd(11)} ${s.detail}${s.error ? `\n ${s.error}` : ''}`),
128
128
  '',
129
- failed.length ? `${failed.length} step(s) failed. Completed steps remain applied. Fix the cause and retry; use passioncode restore for displaced files.` : rest.includes('--dry-run') ? `Plan for PassionCode.ai ${r.version}: nothing was changed.` : `PassionCode.ai ${r.version}: done. Restart your agent — skills load at session start.`,
129
+ failed.length ? `${failed.length} step(s) failed. Completed steps remain applied. Fix the cause and retry; use passioncode restore for displaced files.` : rest.includes('--dry-run') ? `Plan for PassionCode.ai ${r.version}: nothing was changed.` : `PassionCode.ai ${r.version}: done. Restart your agent: skills load at session start.`,
130
130
  r.moved.length ? `${r.moved.length} recovery entry(s) saved; use \`passioncode restore\`.` : '',
131
131
  ].filter(Boolean).join('\n'));
132
132
  }
package/lib/doctor.js CHANGED
@@ -151,7 +151,7 @@ async function collect({ home, platform, claude, online, train: trainName }) {
151
151
 
152
152
  // Prerequisites and agents.
153
153
  const major = Number(process.versions.node.split('.')[0]);
154
- add({ id: 'prereq.node', area: 'prerequisites', state: major >= 18 ? 'ok' : 'fail', detail: `Node ${process.versions.node}${major >= 18 ? '' : ' — 18 or newer is needed'}`, fix: major >= 18 ? null : 'install Node 18+ from https://nodejs.org' });
154
+ add({ id: 'prereq.node', area: 'prerequisites', state: major >= 18 ? 'ok' : 'fail', detail: `Node ${process.versions.node}${major >= 18 ? '' : ' (18 or newer is needed)'}`, fix: major >= 18 ? null : 'install Node 18+ from https://nodejs.org' });
155
155
  const agents = presentAgents(home, claude);
156
156
  add({ id: 'prereq.agents', area: 'prerequisites', state: agents.length ? 'ok' : 'warn', detail: agents.length ? `coding agents: ${agents.map((a) => a.name).join(', ')}` : 'no coding agent found (Claude Code, Codex CLI, Gemini CLI or Kimi Code)', fix: agents.length ? null : 'install Claude Code: npm install -g @anthropic-ai/claude-code' });
157
157
 
@@ -243,15 +243,15 @@ async function collect({ home, platform, claude, online, train: trainName }) {
243
243
  }
244
244
  const v = releases.verifyApp(at, { gatekeeper: false });
245
245
  add({ id: `app.${pr.id}.signature`, area: 'apps', product: pr.id, state: v.ok ? 'ok' : 'fail', detail: `${pr.name}: ${v.checks.map((c) => `${c.check} ${c.ok ? 'ok' : `FAILED (${c.detail})`}`).join(', ')}`, fix: v.ok ? null : (running ? `quit ${pr.name}, then run \`${NPX} setup\`` : `${NPX} setup`), repair: !v.ok && !running ? { kind: 'replace', product: pr.id } : null });
246
- add({ id: `app.${pr.id}.running`, area: 'apps', product: pr.id, state: 'info', detail: `${pr.name}: ${running ? 'in use (the app, or an agent\'s MCP server from its bundle)' : 'not running (it starts when opened)'}`, fix: running ? null : `open "${at}" — or ask this machine's app supervisor to start it` });
246
+ add({ id: `app.${pr.id}.running`, area: 'apps', product: pr.id, state: 'info', detail: `${pr.name}: ${running ? 'in use (the app, or an agent\'s MCP server from its bundle)' : 'not running (it starts when opened)'}`, fix: running ? null : `open "${at}", or ask this machine's app supervisor to start it` });
247
247
  if (pr.needs && pr.needs.includes('docker')) {
248
248
  docker = docker || releases.run('docker', ['info', '--format', '{{.ServerVersion}}'], { timeout: 15000 });
249
249
  const missing = docker.code === 127;
250
- add({ id: 'prereq.docker', area: 'prerequisites', product: pr.id, state: docker.code === 0 ? 'ok' : missing ? 'fail' : 'warn', detail: docker.code === 0 ? `Docker answers (server ${docker.out.trim()})` : missing ? 'Docker is not installed — Fabric needs it' : 'Docker is installed but not running — Fabric needs it running', fix: docker.code === 0 ? null : missing ? 'install OrbStack (https://orbstack.dev) or Docker Desktop, then start it' : 'start OrbStack or Docker Desktop before you open Fabric' });
250
+ add({ id: 'prereq.docker', area: 'prerequisites', product: pr.id, state: docker.code === 0 ? 'ok' : missing ? 'fail' : 'warn', detail: docker.code === 0 ? `Docker answers (server ${docker.out.trim()})` : missing ? 'Docker is not installed; Fabric needs it' : 'Docker is installed but not running; Fabric needs it running', fix: docker.code === 0 ? null : missing ? 'install OrbStack (https://orbstack.dev) or Docker Desktop, then start it' : 'start OrbStack or Docker Desktop before you open Fabric' });
251
251
  }
252
252
  if (pr.needs && pr.needs.includes('supabase')) {
253
253
  const sb = releases.run('supabase', ['--version'], { timeout: 15000 });
254
- add({ id: 'prereq.supabase', area: 'prerequisites', product: pr.id, state: sb.code === 0 ? 'ok' : 'fail', detail: sb.code === 0 ? `Supabase CLI ${sb.out.trim()}` : 'Supabase CLI not found — Fabric needs it', fix: sb.code === 0 ? null : 'brew install supabase/tap/supabase' });
254
+ add({ id: 'prereq.supabase', area: 'prerequisites', product: pr.id, state: sb.code === 0 ? 'ok' : 'fail', detail: sb.code === 0 ? `Supabase CLI ${sb.out.trim()}` : 'Supabase CLI not found; Fabric needs it', fix: sb.code === 0 ? null : 'brew install supabase/tap/supabase' });
255
255
  }
256
256
  }
257
257
 
@@ -285,7 +285,7 @@ async function collect({ home, platform, claude, online, train: trainName }) {
285
285
  const runner = entry.args.includes('--runner');
286
286
  add({
287
287
  id, area: 'mcp', product: pr.id, state: exec && runner ? 'ok' : 'fail',
288
- detail: `${agent.name}: ${m.name} ${exec && runner ? 'registered; doctor does not start it (it enrols a session) — your agent\'s first fabric_whoami proves it' : !exec ? `points at ${entry.command}, which cannot run` : 'is registered without --runner, so it exits at start'}`,
288
+ detail: `${agent.name}: ${m.name} ${exec && runner ? 'registered; doctor does not start it (it enrols a session), and your agent\'s first fabric_whoami proves it' : !exec ? `points at ${entry.command}, which cannot run` : 'is registered without --runner, so it exits at start'}`,
289
289
  fix: exec && runner ? null : `remove that entry from ${agent.name}, then ${NPX} setup`,
290
290
  });
291
291
  continue;
@@ -333,7 +333,7 @@ async function collect({ home, platform, claude, online, train: trainName }) {
333
333
  const what = tool ? `${tool} answered` : 'initialize answered (its first real call is the agent\'s)';
334
334
  add({
335
335
  id, area: 'mcp', product: t.product.id, state: r.ok ? 'ok' : 'fail',
336
- detail: `${agent.name}: ${t.product.mcp.name} — ${r.ok ? `${what}${r.server ? ` (${r.server.name} ${r.server.version || ''})`.replace(' )', ')') : ''}${r.tools !== null && r.tools !== undefined ? `, ${r.tools} tools` : ''}` : `proving call failed: ${r.reason}`}`,
336
+ detail: `${agent.name}: ${t.product.mcp.name}, ${r.ok ? `${what}${r.server ? ` (${r.server.name} ${r.server.version || ''})`.replace(' )', ')') : ''}${r.tools !== null && r.tools !== undefined ? `, ${r.tools} tools` : ''}` : `proving call failed: ${r.reason}`}`,
337
337
  fix: r.ok ? null : `open ${t.product.name}, then run doctor again; if it still fails, reinstall it from ${t.product.page}`,
338
338
  });
339
339
  }
@@ -358,8 +358,8 @@ async function collect({ home, platform, claude, online, train: trainName }) {
358
358
  add({
359
359
  id: `service.${d.id}.${d.instance || 'default'}`, area: 'services', product: pr.id,
360
360
  state: w.ok === true ? (w.status === 'ok' ? 'ok' : 'warn') : w.ok === null ? 'info' : 'fail',
361
- detail: `${d.name || d.id}: ${w.ok ? `answers at ${d.origin}${w.version ? ` (${w.version})` : ''}, status ${w.status}${w.degraded.length ? ` — degraded: ${w.degraded.join(', ')}` : ''}` : w.reason}`,
362
- fix: w.ok === false ? `${supervisor} restarts it — never kill it by hand${doctorCmd ? `; diagnose with ${doctorCmd}` : ''}` : (w.ok && w.status !== 'ok' && doctorCmd ? doctorCmd : null),
361
+ detail: `${d.name || d.id}: ${w.ok ? `answers at ${d.origin}${w.version ? ` (${w.version})` : ''}, status ${w.status}${w.degraded.length ? `; degraded: ${w.degraded.join(', ')}` : ''}` : w.reason}`,
362
+ fix: w.ok === false ? `${supervisor} restarts it, so never kill it by hand${doctorCmd ? `; diagnose with ${doctorCmd}` : ''}` : (w.ok && w.status !== 'ok' && doctorCmd ? doctorCmd : null),
363
363
  repair: w.ok === false && platform === 'darwin' && d.lifecycle && d.lifecycle.manager === 'launchd' && d.lifecycle.label ? { kind: 'kickstart', label: d.lifecycle.label } : null,
364
364
  });
365
365
  }
package/lib/releases.js CHANGED
@@ -217,7 +217,7 @@ async function installApp(product, release, { work, report = () => {}, replace =
217
217
  }
218
218
  if (!source) throw new Error(`${assetName} holds no ${product.app}`);
219
219
  const app = verifyApp(source);
220
- for (const c of app.checks) report({ kind: 'verify', detail: `${product.app}: ${c.check} — ${c.detail}`, ok: c.ok });
220
+ for (const c of app.checks) report({ kind: 'verify', detail: `${product.app}, ${c.check}: ${c.detail}`, ok: c.ok });
221
221
  if (!app.ok) throw new Error(`${product.app} failed ${app.checks.filter((c) => !c.ok).map((c) => c.check).join(', ')}; nothing was installed`);
222
222
  // Copy beside the target first, so /Applications never holds a half-written bundle; then two
223
223
  // same-volume renames: the old bundle to the person's Trash (never deleted), the new one into place.
package/lib/setup.js CHANGED
@@ -137,7 +137,7 @@ async function setup({
137
137
  asked = true;
138
138
  for (const i of items.filter((x) => x.kind === 'install')) {
139
139
  const pr = catalog.byId(i.product);
140
- i.selected = await yesNo(ask, `Install ${pr.name}${pr.preview ? ' (early preview)' : ''}${i.note ? ` — ${i.note}` : ''}?`, i.selected);
140
+ i.selected = await yesNo(ask, `Install ${pr.name}${pr.preview ? ' (early preview)' : ''}${i.note ? `: ${i.note}` : ''}?`, i.selected);
141
141
  }
142
142
  const repairs = items.filter((x) => x.kind !== 'install');
143
143
  if (repairs.length) {
@@ -313,7 +313,7 @@ function render(result, { repairOnly = false } = {}) {
313
313
  for (const c of left) lines.push(` ${c.state === 'fail' ? 'FAIL' : 'warn'} ${c.detail}`);
314
314
  }
315
315
  if (result.humanSteps.length) {
316
- lines.push('', 'Your steps (an agent cannot do these for you — sign-ins, consents, secrets in hidden prompts):');
316
+ lines.push('', 'Your steps (sign-ins, consents and secrets in hidden prompts need you in person):');
317
317
  result.humanSteps.forEach((t, n) => lines.push(` ${n + 1}. ${t}`));
318
318
  }
319
319
  lines.push('', single ? `${a.fail ? `${a.fail} problem(s)` : 'No problems'}. Check again any time: npx @passioncode-ai/passioncode@latest doctor`
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@passioncode-ai/passioncode",
3
- "version": "0.2.52",
4
- "description": "Set up PassionCode.ai on a computer with one command — the apps from their verified releases, their MCP servers for every coding agent and the PassionCode.ai skills — and check and repair it with the same command or `doctor`.",
3
+ "version": "0.2.53",
4
+ "description": "Set up PassionCode.ai on a computer with one command: the apps from their verified releases, their MCP servers for every coding agent and the PassionCode.ai skills. Check and repair it with the same command or `doctor`.",
5
5
  "bin": {
6
6
  "passioncode": "bin/passioncode.js"
7
7
  },
@@ -35,7 +35,7 @@
35
35
  "name": "passioncode",
36
36
  "displayName": "PassionCode.ai",
37
37
  "source": "./plugins/passioncode",
38
- "version": "0.2.52",
38
+ "version": "0.2.53",
39
39
  "description": "Set up and check PassionCode.ai on a computer with one command (setting-up-passioncode), the organisation's working rules for every contributor's agent (working-in-passioncode), and a once-a-day check that keeps the PassionCode.ai set current.",
40
40
  "author": {
41
41
  "name": "PassionCode.ai",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "family": "passioncode",
3
- "version": "0.2.52",
3
+ "version": "0.2.53",
4
4
  "release": true,
5
5
  "members": [
6
6
  {
@@ -62,9 +62,9 @@
62
62
  "name": "passioncode",
63
63
  "displayName": "PassionCode.ai",
64
64
  "repo": "passioncode-ai/passioncode",
65
- "ref": "v0.2.52",
65
+ "ref": "v0.2.53",
66
66
  "commit": null,
67
- "version": "0.2.52",
67
+ "version": "0.2.53",
68
68
  "via": "this repository",
69
69
  "skills": [
70
70
  "setting-up-passioncode",
@@ -72,7 +72,7 @@
72
72
  ],
73
73
  "legacyPluginIds": [],
74
74
  "legacyMarketplaces": [],
75
- "contentHash": "sha256:8b9f7952e681760859099cf84a4f29a0cd264dde45b7287765aac937218b068e",
75
+ "contentHash": "sha256:cc227b983b8e104b34579a4a12749e15bbd5f35ea30fe75b86475afde618492f",
76
76
  "description": "Set up and check PassionCode.ai on a computer with one command (setting-up-passioncode), the organisation's working rules for every contributor's agent (working-in-passioncode), and a once-a-day check that keeps the PassionCode.ai set current.",
77
77
  "author": {
78
78
  "name": "PassionCode.ai",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "passioncode",
4
4
  "displayName": "PassionCode.ai",
5
- "version": "0.2.52",
5
+ "version": "0.2.53",
6
6
  "description": "Set up and check PassionCode.ai on a computer with one command (setting-up-passioncode), the organisation's working rules for every contributor's agent (working-in-passioncode), and a once-a-day check at session start that keeps the PassionCode.ai skill set current.",
7
7
  "author": {
8
8
  "name": "PassionCode.ai",
@@ -157,9 +157,9 @@ function decide(state, trust, now = Date.now()) {
157
157
  const untrusted = [...maintainers, ...(state.publisher ? [state.publisher] : [])].filter((m) => !trusted.has(m));
158
158
  if (!maintainers.length || !maintainers.every((m) => typeof m === 'string' && accountName(m) === m)
159
159
  || typeof state.publisher !== 'string' || !state.publisher || accountName(state.publisher) !== state.publisher) {
160
- lines.push(`[passioncode] ${PACKAGE}@${latest} is on npm but who published it could not be read — not installing; see SECURITY.md.`);
160
+ lines.push(`[passioncode] ${PACKAGE}@${latest} is on npm but who published it could not be read, so it is not installed; see SECURITY.md.`);
161
161
  } else if (untrusted.length) {
162
- lines.push(`[passioncode] ${PACKAGE}@${latest} is on npm but published by ${[...new Set(untrusted)].join(', ')}, not a trusted PassionCode publisher — not installing; see SECURITY.md.`);
162
+ lines.push(`[passioncode] ${PACKAGE}@${latest} is on npm but published by ${[...new Set(untrusted)].join(', ')}, not a trusted PassionCode publisher, so it is not installed; see SECURITY.md.`);
163
163
  } else {
164
164
  const auto = (state.config && state.config.auto) !== false;
165
165
  const runningAge = now - Date.parse(state.updatingSince);
@@ -167,7 +167,7 @@ function decide(state, trust, now = Date.now()) {
167
167
  if (auto && !running) {
168
168
  spawn = ['--yes', `${PACKAGE}@${latest}`, 'update', '--quiet'];
169
169
  stateChanges.updatingSince = new Date(now).toISOString();
170
- lines.push(`[passioncode] ${latest} is out (you have ${state.installed}); updating in the background — it takes effect next session.`);
170
+ lines.push(`[passioncode] ${latest} is out (you have ${state.installed}); updating in the background; it takes effect next session.`);
171
171
  } else if (!auto) {
172
172
  lines.push(`[passioncode] ${latest} is out (you have ${state.installed}): npx ${PACKAGE}@${latest} update`);
173
173
  }