@passioncode-ai/passioncode 0.1.53 → 0.2.0
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 +35 -0
- package/README.md +72 -23
- package/SECURITY.md +23 -3
- package/bin/passioncode.js +71 -6
- package/family.json +1 -1
- package/lib/catalog.js +91 -0
- package/lib/doctor.js +288 -0
- package/lib/launcher.js +123 -58
- package/lib/mcp-probe.js +91 -0
- package/lib/openpgp.js +209 -0
- package/lib/release-key.asc +10 -0
- package/lib/releases.js +211 -0
- package/lib/setup.js +238 -0
- package/package.json +6 -3
- package/payload/.claude-plugin/marketplace.json +2 -2
- package/payload/manifest.json +6 -5
- package/payload/plugins/passioncode/.claude-plugin/plugin.json +2 -2
- package/payload/plugins/passioncode/hooks/session-start.js +13 -1
- package/payload/plugins/passioncode/skills/setting-up-passioncode/SKILL.md +109 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.0 - 2026-10-13
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`setup` (alias `onboard`): one command for a new computer and for one that is already set up.**
|
|
8
|
+
It checks everything first, then installs the PassionCode.ai apps that are missing (Fabric
|
|
9
|
+
Switchboard, Fabric Dashboards, Project Observatory, Fabric Inbox, and Fabric as an early
|
|
10
|
+
preview when Docker and the Supabase CLI are present), installs the skills, registers every
|
|
11
|
+
app's MCP server for every coding agent present, repairs what is wrong, checks again and prints
|
|
12
|
+
a before → after table with one list of the steps that stay yours. On a healthy computer it
|
|
13
|
+
changes nothing and exits 0. In a terminal it asks one question per app; `--yes`, `--with`,
|
|
14
|
+
`--without`, `--no-apps`, `--no-open`, `--dry-run` and `--json` serve agents and scripts.
|
|
15
|
+
- **No unverified byte is installed.** Each release's `SHA256SUMS.asc` is verified against the
|
|
16
|
+
PassionCode.ai release key bundled in the package (pinned by fingerprint, no gpg needed); the
|
|
17
|
+
download must match the signed checksum and GitHub's digest; the app must pass `codesign`,
|
|
18
|
+
carry team `KJ35UYYL22`, have its notarization ticket stapled and pass Gatekeeper. An outdated
|
|
19
|
+
or damaged app is reinstalled only when it is not running, and the old one goes to the Trash.
|
|
20
|
+
- **`doctor`: a read-only check of the whole setup** — prerequisites, the skill set, each app's
|
|
21
|
+
version, signature and team, each agent's MCP entries with one real proving call per server,
|
|
22
|
+
and the family's Fabric services. Every line names its state and its fix; exit 0 means no check
|
|
23
|
+
failed. `doctor --fix` runs setup's repairs without installing new apps.
|
|
24
|
+
- **`update` registers Fabric Switchboard's MCP server (`switchboard mcp`)** next to Fabric
|
|
25
|
+
Dashboards', under the same never-clobber, reversible rules; an entry counts as the same only
|
|
26
|
+
with the same command and arguments. **`setup` also registers Fabric's (`fabric-mcp --runner
|
|
27
|
+
<agent>`)**: an early preview, it is never added by a background update (ADR-0004).
|
|
28
|
+
- **Safer installs and removals**: an app is copied beside its target and swapped in with two
|
|
29
|
+
renames, after a second check that nothing runs from it; uninstall keeps a Codex entry that
|
|
30
|
+
gained settings since it was written; a dry run copies no config file.
|
|
31
|
+
- **The `setting-up-passioncode` skill**: "set me up" or "check my setup" makes any coding agent
|
|
32
|
+
run setup or doctor, finish the steps an agent may take and hand you only sign-ins, consents
|
|
33
|
+
and secrets typed into a product's own hidden prompt. The README and passioncode.ai/start/
|
|
34
|
+
carry a one-paragraph prompt to paste into Claude Code or Codex.
|
|
35
|
+
- **Session start names the problems of the last setup check** while it has any; it never runs
|
|
36
|
+
the check itself.
|
|
37
|
+
|
|
3
38
|
## 0.1.53 - 2026-10-13
|
|
4
39
|
|
|
5
40
|
### Changed
|
package/README.md
CHANGED
|
@@ -1,38 +1,65 @@
|
|
|
1
1
|
# PassionCode.ai launcher
|
|
2
2
|
|
|
3
|
-
The **PassionCode.ai launcher** (`@passioncode-ai/passioncode` on npm)
|
|
4
|
-
|
|
5
|
-
Observatory
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
The **PassionCode.ai launcher** (`@passioncode-ai/passioncode` on npm) sets up PassionCode.ai on a
|
|
4
|
+
computer with one command: the apps (Fabric, Fabric Switchboard, Fabric Dashboards, Fabric Inbox,
|
|
5
|
+
Project Observatory) from their signed releases, their MCP servers for every coding agent on it,
|
|
6
|
+
and the PassionCode.ai skills listed in [`family.json`](family.json). Run the same command on a
|
|
7
|
+
computer that is already set up, and it checks everything, repairs what is wrong and tells you
|
|
8
|
+
what changed.
|
|
8
9
|
|
|
9
10
|
```bash
|
|
10
|
-
npx @passioncode-ai/passioncode@latest
|
|
11
|
+
npx @passioncode-ai/passioncode@latest setup # a new computer: set up · an existing one: check and repair
|
|
12
|
+
npx @passioncode-ai/passioncode@latest doctor # check only; changes nothing
|
|
11
13
|
```
|
|
12
14
|
|
|
13
15
|
| Member | Skills |
|
|
14
16
|
|---|---|
|
|
15
17
|
| Fabric Agent Adapter | `creating-fabric-agents`, `adapting-projects-to-fabric`, `building-fabric-services` |
|
|
16
18
|
| Observatory Log | `explaining-changes`, `handling-secrets`, `tracking-resources` (+ its session hooks) |
|
|
17
|
-
| passioncode | `working-in-passioncode` (the organisation's working rules, for every contributor's agent) and the once-a-day update check |
|
|
19
|
+
| passioncode | `setting-up-passioncode` (set up and check a computer), `working-in-passioncode` (the organisation's working rules, for every contributor's agent) and the once-a-day update check |
|
|
18
20
|
|
|
19
21
|
Only PassionCode.ai products are members. Agents that people build for themselves stay
|
|
20
22
|
out of it, even when they implement Fabric protocols.
|
|
21
23
|
|
|
24
|
+
## Set it up with your coding agent
|
|
25
|
+
|
|
26
|
+
Paste this into Claude Code, Codex or another coding agent:
|
|
27
|
+
|
|
28
|
+
> Set up PassionCode.ai on this computer, or check and repair it if it is already set up. Run
|
|
29
|
+
> `npx --yes @passioncode-ai/passioncode@latest setup --yes --json` (it needs Node 18 or newer)
|
|
30
|
+
> and read its JSON: it installs the missing apps from their signed releases, the skills and
|
|
31
|
+
> every MCP server, repairs whatever is wrong, and checks everything again. Do not download or
|
|
32
|
+
> install anything by hand, and never stop or kill a running app. Then run each product
|
|
33
|
+
> onboarding step it lists that an agent may run, never ask me for a key or password in the
|
|
34
|
+
> chat (the tools open their own hidden prompts), and finish with
|
|
35
|
+
> `npx --yes @passioncode-ai/passioncode@latest doctor`. Tell me briefly what you set up or
|
|
36
|
+
> fixed, what still fails, and the numbered steps only I can do, such as signing in, and
|
|
37
|
+
> remind me to restart you so the new skills and MCP servers load.
|
|
38
|
+
|
|
39
|
+
Once the skills are installed, "set me up" or "check my setup" is enough: the
|
|
40
|
+
`setting-up-passioncode` skill knows the rest. What stays yours: signing in, consenting, typing a
|
|
41
|
+
secret into a product's own hidden prompt, starting Docker for Fabric, and restarting your agent.
|
|
42
|
+
|
|
22
43
|
## Quick start for a new teammate
|
|
23
44
|
|
|
24
45
|
1. **Install** (Node 18 or newer; the Claude Code CLI on `PATH` for the plugins):
|
|
25
|
-
`npx @passioncode-ai/passioncode@latest
|
|
26
|
-
|
|
27
|
-
`
|
|
28
|
-
|
|
46
|
+
`npx @passioncode-ai/passioncode@latest setup`, then restart your agents. In a terminal it asks
|
|
47
|
+
one question per app; `--yes` accepts the plan, `--with`/`--without <ids>` choose apps
|
|
48
|
+
(`switchboard`, `dashboards`, `observatory`, `inbox`, `fabric`), `--no-apps` sets up the skills
|
|
49
|
+
and MCP only, `--dry-run` shows the plan. Apps are installed on macOS; on other systems setup
|
|
50
|
+
names each download page. Skills only: `npx @passioncode-ai/passioncode@latest update`.
|
|
29
51
|
2. **Configure:** nothing to set, no account and no key. Background updates are on by default;
|
|
30
|
-
`npx @passioncode-ai/passioncode@latest config set update.auto off` turns them off.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
52
|
+
`npx @passioncode-ai/passioncode@latest config set update.auto off` turns them off. Each app's
|
|
53
|
+
own onboarding (sign-ins, Fabric Inbox's server, Observatory's projects) is listed by `setup`.
|
|
54
|
+
3. **MCP:** the launcher serves no MCP server of its own. It registers the apps' servers —
|
|
55
|
+
`fabric-dashboards`, `fabric` (`fabric-mcp --runner <agent>`) and `switchboard`
|
|
56
|
+
(`switchboard mcp`) — for Claude Code, Codex CLI, Gemini CLI and Kimi Code, and `doctor` proves
|
|
57
|
+
each one with a real call: `initialize`, `tools/list`, then `list_services`,
|
|
58
|
+
`switchboard_accounts` or `observatory_status`. Fabric's server is never started by doctor,
|
|
59
|
+
because it enrols a session as it starts: doctor checks its entry, and your agent's first
|
|
60
|
+
`fabric_whoami` is the proving call. Fabric is an early preview, so only `setup` registers it,
|
|
61
|
+
never a background update. Project Observatory and Fabric Inbox register their
|
|
62
|
+
own servers through their onboarding; `doctor` checks those too.
|
|
36
63
|
4. **Develop:** clone, then `npm test` — there are no dependencies and no lockfile, so there is
|
|
37
64
|
nothing to install (`npm ci` refuses to run here). `npm run vendor` builds `payload/` from the
|
|
38
65
|
members pinned in `family.json`; `claude plugin validate ./payload --strict` checks it. Start
|
|
@@ -55,12 +82,34 @@ out of it, even when they implement Fabric protocols.
|
|
|
55
82
|
`~/.passioncode/quarantine/` — `npx @passioncode-ai/passioncode@latest restore` puts them back.
|
|
56
83
|
- Each version is an immutable release under `~/.passioncode/releases/<version>`; an update
|
|
57
84
|
keeps the release it replaced for rollback and removes older ones.
|
|
58
|
-
-
|
|
59
|
-
(`fabric-dashboards`)
|
|
60
|
-
|
|
61
|
-
(
|
|
62
|
-
|
|
63
|
-
|
|
85
|
+
- `update` (and therefore `setup`) registers the MCP server inside each installed app — Fabric
|
|
86
|
+
Dashboards (`fabric-dashboards`), Fabric Switchboard (`switchboard`, unless Claude Code already
|
|
87
|
+
gets it from the `switchboard` plugin) and, from `setup` only because it is an early preview,
|
|
88
|
+
Fabric (`fabric`, with each agent's own `--runner`) —
|
|
89
|
+
for every agent that is present: Claude Code (through `claude mcp add --scope user`), Codex CLI
|
|
90
|
+
(`~/.codex/config.toml`), Gemini CLI (`~/.gemini/settings.json`) and Kimi Code
|
|
91
|
+
(`~/.kimi-code/mcp.json`). An entry that already exists is left alone; one that points elsewhere
|
|
92
|
+
is reported and kept. `restore` and `uninstall` remove what the launcher added
|
|
93
|
+
([ADR-0003](docs/adr/0003-fabric-dashboards-mcp-registration.md),
|
|
94
|
+
[ADR-0004](docs/adr/0004-setup-installs-verified-apps-and-registers-their-mcp.md)).
|
|
95
|
+
|
|
96
|
+
## Setup and doctor
|
|
97
|
+
|
|
98
|
+
`setup` checks first, then installs the absent apps you chose, repairs what the checks found,
|
|
99
|
+
checks again and prints a before → after table and the steps that stay yours. On a healthy
|
|
100
|
+
computer it changes nothing and exits 0. An app is installed only after its release's
|
|
101
|
+
`SHA256SUMS.asc` verifies against the PassionCode.ai release key bundled in this package
|
|
102
|
+
(fingerprint `63B3 0DC3 24BD 6974 87AA 3194 4FAF B8AE C803 B6A7`), the file matches the signed
|
|
103
|
+
checksum and GitHub's digest, and the app passes `codesign`, carries team `KJ35UYYL22`, has its
|
|
104
|
+
notarization ticket stapled and is accepted by Gatekeeper. An outdated or damaged app is
|
|
105
|
+
reinstalled only when it is not running; the old one goes to the Trash. A family service that
|
|
106
|
+
does not answer is started through launchd (`launchctl kickstart`, never a kill).
|
|
107
|
+
|
|
108
|
+
`doctor` changes nothing. It reads prerequisites, the skill set, each app's version, signature
|
|
109
|
+
and team, each agent's MCP entries with one proving call per server, and the Fabric services of
|
|
110
|
+
the family; each line names its state and its fix. Exit codes: **0** no check failed, **1** a
|
|
111
|
+
check (or a setup step) failed, **2** bad arguments. `doctor --fix` runs setup's repairs without
|
|
112
|
+
installing new apps. Details: the [CLI contract](docs/reference/cli.md#setup-and-doctor).
|
|
64
113
|
|
|
65
114
|
## Staying current
|
|
66
115
|
|
package/SECURITY.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Report vulnerabilities privately to contact@passioncode.ai. Do not open an issue that
|
|
4
4
|
carries credentials or a working exploit.
|
|
5
5
|
|
|
6
|
-
What `passioncode update` touches: `~/.passioncode/` (releases, state, quarantine,
|
|
6
|
+
What `passioncode update` touches (setup and doctor: [below](#what-setup-and-doctor-touch)): `~/.passioncode/` (releases, state, quarantine,
|
|
7
7
|
logs); Claude Code's plugin registry through the `claude plugin` CLI only;
|
|
8
8
|
`~/.agents/skills/<member skill>` and `<agent channel>/<member skill>` links; and
|
|
9
9
|
`~/.claude/skills/<member skill>`, which it moves into the quarantine once the plugin
|
|
@@ -11,8 +11,9 @@ that replaces it is verified. For a member's old single-member marketplace
|
|
|
11
11
|
(`legacyMarketplaces` in `family.json`), once that plugin is verified and nothing else
|
|
12
12
|
installed comes from it, it also moves the `extraKnownMarketplaces` entry out of
|
|
13
13
|
`~/.claude/settings.json` (a copy of the file is kept in the quarantine) and runs
|
|
14
|
-
`claude plugin marketplace remove <name>`.
|
|
15
|
-
|
|
14
|
+
`claude plugin marketplace remove <name>`. For each installed app with an MCP server in its
|
|
15
|
+
bundle (Fabric Dashboards, Fabric, Fabric Switchboard) it also registers that entry for every
|
|
16
|
+
agent that is present: through
|
|
16
17
|
`claude mcp add --scope user` for Claude Code (it never writes `~/.claude.json` itself),
|
|
17
18
|
and in `~/.codex/config.toml`, `~/.gemini/settings.json` and `~/.kimi-code/mcp.json`,
|
|
18
19
|
copying each existing file into the quarantine first; an entry that already exists is
|
|
@@ -26,6 +27,25 @@ records. Each update removes the launcher's own older releases (its output, rein
|
|
|
26
27
|
from npm) and keeps the one it replaced for rollback. A failed removal
|
|
27
28
|
returns a nonzero exit code. See the [CLI recovery contract](docs/reference/cli.md).
|
|
28
29
|
|
|
30
|
+
## What `setup` and `doctor` touch
|
|
31
|
+
|
|
32
|
+
`doctor` reads: `~/.claude.json`, `~/.codex/config.toml`, `~/.gemini/settings.json`,
|
|
33
|
+
`~/.kimi-code/mcp.json` (entry names, commands and arguments; environment values are passed to
|
|
34
|
+
the server it starts and never printed), the Fabric service descriptors (never their token
|
|
35
|
+
files), the apps' `Info.plist`, and the GitHub releases API. It starts each registered stdio MCP
|
|
36
|
+
server for one proving call and stops it (never Fabric's, which enrols a session as it starts), and writes only `~/.passioncode/doctor.json` and a
|
|
37
|
+
release cache.
|
|
38
|
+
|
|
39
|
+
`setup` also downloads releases from GitHub into `~/.passioncode/downloads/` (removed after
|
|
40
|
+
each app), copies a verified app into `/Applications`, moves an app it replaces into `~/.Trash/`,
|
|
41
|
+
runs `update` (above), runs `launchctl kickstart gui/<uid>/<label>` for a family service whose
|
|
42
|
+
descriptor names launchd and that does not answer, and opens the apps it installed. It never
|
|
43
|
+
stops or kills a process, never replaces a running app, never asks for or stores a secret, and
|
|
44
|
+
never installs a byte whose signature, checksum, team or notarization does not verify. The trust
|
|
45
|
+
root is the release key bundled at `lib/release-key.asc`, pinned by fingerprint in
|
|
46
|
+
`lib/openpgp.js`; a new key needs a launcher release. `PASSIONCODE_RELEASE_KEY` replaces it for
|
|
47
|
+
tests and is named in setup's output whenever it is set.
|
|
48
|
+
|
|
29
49
|
## The self-update and who it trusts
|
|
30
50
|
|
|
31
51
|
The SessionStart hook reads `~/.passioncode/state.json` and reuses a check for up to
|
package/bin/passioncode.js
CHANGED
|
@@ -17,19 +17,84 @@ 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 —
|
|
20
|
+
const HELP = `passioncode — set up and check PassionCode.ai on this machine: the apps, their MCP servers, the skills
|
|
21
21
|
|
|
22
|
-
npx @passioncode-ai/passioncode@latest
|
|
22
|
+
npx @passioncode-ai/passioncode@latest setup [--yes] [--with ids] [--without ids] [--no-apps] [--no-open] [--dry-run] [--json]
|
|
23
|
+
a new machine: install and configure everything; an existing one: check, repair, check again
|
|
24
|
+
npx @passioncode-ai/passioncode@latest doctor [--fix] [--json] check everything (read-only); --fix repairs as setup does
|
|
25
|
+
npx @passioncode-ai/passioncode@latest update [--dry-run] [--json] install or update the skill set and the apps' MCP registrations
|
|
23
26
|
npx @passioncode-ai/passioncode@latest status [--json] what is installed where
|
|
24
27
|
npx @passioncode-ai/passioncode@latest restore put back what the last update moved aside
|
|
25
28
|
npx @passioncode-ai/passioncode@latest config set update.auto on|off background updates at session start
|
|
26
29
|
npx @passioncode-ai/passioncode@latest uninstall remove the set (quarantined items stay restorable)
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
App ids: switchboard, dashboards, observatory, inbox, fabric. Exit codes: 0 nothing failed,
|
|
32
|
+
1 a check or a step failed, 2 bad arguments. Claude Code gets plugins from the local
|
|
33
|
+
"passioncode" marketplace; other agents get the same skills through ~/.agents/skills.
|
|
34
|
+
Restart your agent after a change.`;
|
|
30
35
|
|
|
31
|
-
|
|
36
|
+
const IDS = ['switchboard', 'dashboards', 'observatory', 'inbox', 'fabric'];
|
|
37
|
+
|
|
38
|
+
/** Flags of setup and doctor: booleans, plus --with/--without taking a comma list. Null when invalid. */
|
|
39
|
+
function parseSetupArgs(cmd, rest) {
|
|
40
|
+
const allowed = cmd === 'doctor' ? ['--fix', '--json', '--offline'] : ['--yes', '-y', '--json', '--offline', '--no-apps', '--no-open', '--dry-run'];
|
|
41
|
+
const o = { flags: new Set(), withIds: null, withoutIds: [] };
|
|
42
|
+
for (let i = 0; i < rest.length; i++) {
|
|
43
|
+
const arg = rest[i];
|
|
44
|
+
const m = /^--(with|without)(?:=(.*))?$/.exec(arg);
|
|
45
|
+
if (m && cmd !== 'doctor') {
|
|
46
|
+
const value = m[2] !== undefined ? m[2] : rest[++i];
|
|
47
|
+
const ids = String(value || '').split(',').map((x) => x.trim()).filter(Boolean);
|
|
48
|
+
if (!ids.length || ids.some((x) => !IDS.includes(x))) return null;
|
|
49
|
+
if (m[1] === 'with') o.withIds = [...(o.withIds || []), ...ids]; else o.withoutIds.push(...ids);
|
|
50
|
+
} else if (allowed.includes(arg)) o.flags.add(arg === '-y' ? '--yes' : arg);
|
|
51
|
+
else return null;
|
|
52
|
+
}
|
|
53
|
+
return o;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function asker() {
|
|
57
|
+
if (!process.stdin.isTTY || !process.stderr.isTTY) return null;
|
|
58
|
+
const readline = require('readline');
|
|
59
|
+
return (question) => new Promise((resolve) => {
|
|
60
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
61
|
+
rl.question(question, (answer) => { rl.close(); resolve(answer); });
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function setupOrDoctor(cmd, rest) {
|
|
66
|
+
const o = parseSetupArgs(cmd, rest);
|
|
67
|
+
if (!o) {
|
|
68
|
+
process.stderr.write(`passioncode: unsupported arguments for ${cmd}; run passioncode help. App ids: ${IDS.join(', ')}.\n`);
|
|
69
|
+
return 2;
|
|
70
|
+
}
|
|
71
|
+
const json = o.flags.has('--json');
|
|
72
|
+
const online = !o.flags.has('--offline');
|
|
73
|
+
if (cmd === 'doctor' && !o.flags.has('--fix')) {
|
|
74
|
+
const D = require('../lib/doctor');
|
|
75
|
+
const r = await D.doctor({ online });
|
|
76
|
+
process.stdout.write(json ? JSON.stringify(r, null, 2) + '\n' : D.render(r) + '\n');
|
|
77
|
+
return r.ok ? 0 : 1;
|
|
78
|
+
}
|
|
79
|
+
const S = require('../lib/setup');
|
|
80
|
+
const repairOnly = cmd === 'doctor';
|
|
81
|
+
const log = json ? () => {} : (line) => process.stderr.write(`${line}\n`);
|
|
82
|
+
const r = await S.setup({
|
|
83
|
+
yes: repairOnly || o.flags.has('--yes'), withIds: o.withIds, withoutIds: o.withoutIds, noApps: o.flags.has('--no-apps'),
|
|
84
|
+
noOpen: o.flags.has('--no-open'), dryRun: o.flags.has('--dry-run'), repairOnly, online, ask: json ? null : asker(), log,
|
|
85
|
+
});
|
|
86
|
+
process.stdout.write(json ? JSON.stringify(r, null, 2) + '\n' : S.render(r, { repairOnly }) + '\n');
|
|
87
|
+
return r.planOnly ? 0 : r.ok ? 0 : 1;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function main(argv) {
|
|
32
91
|
const [cmd = 'help', ...rest] = argv;
|
|
92
|
+
if (cmd === 'setup' || cmd === 'onboard' || cmd === 'doctor') {
|
|
93
|
+
try { return await setupOrDoctor(cmd === 'onboard' ? 'setup' : cmd, rest); } catch (error) {
|
|
94
|
+
process.stderr.write(`passioncode: ${error.message}\n`);
|
|
95
|
+
return 1;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
33
98
|
const json = rest.includes('--json');
|
|
34
99
|
const quiet = rest.includes('--quiet');
|
|
35
100
|
const out = (value, text) => process.stdout.write(json ? JSON.stringify(value, null, 2) + '\n' : text + '\n');
|
|
@@ -89,4 +154,4 @@ function main(argv) {
|
|
|
89
154
|
}
|
|
90
155
|
}
|
|
91
156
|
|
|
92
|
-
|
|
157
|
+
main(process.argv.slice(2)).then((code) => { process.exitCode = code; });
|
package/family.json
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"displayName": "PassionCode.ai",
|
|
38
38
|
"kind": "self",
|
|
39
39
|
"path": "plugin/passioncode",
|
|
40
|
-
"description": "
|
|
40
|
+
"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."
|
|
41
41
|
}
|
|
42
42
|
]
|
|
43
43
|
}
|
package/lib/catalog.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* The PassionCode.ai apps `setup` installs and `doctor` checks: where each is released, which
|
|
4
|
+
* asset is its macOS build, where it lives once installed, its MCP server and the one read-only
|
|
5
|
+
* call that proves the server answers, and the product's own onboarding step. Public facts only;
|
|
6
|
+
* each is the product's own documentation (named per entry).
|
|
7
|
+
*/
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
const TEAM_ID = 'KJ35UYYL22'; // Developer ID Application team of every PassionCode.ai macOS build
|
|
11
|
+
const SITE = 'https://passioncode.ai';
|
|
12
|
+
|
|
13
|
+
/** Agents the launcher registers MCP servers for: `cli` is detected by its command, the rest by a directory. */
|
|
14
|
+
const AGENTS = [
|
|
15
|
+
{ id: 'claude', name: 'Claude Code', fabricRunner: 'claude-code' },
|
|
16
|
+
{ id: 'codex', name: 'Codex CLI', fabricRunner: 'codex' },
|
|
17
|
+
{ id: 'gemini', name: 'Gemini CLI', fabricRunner: null }, // fabric-mcp has no Gemini runner
|
|
18
|
+
{ id: 'kimi', name: 'Kimi Code', fabricRunner: 'kimi-code' },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const PRODUCTS = [
|
|
22
|
+
{
|
|
23
|
+
// fabric-switchboard docs/INSTALL.md, docs/AGENT-ONBOARDING.md
|
|
24
|
+
id: 'switchboard', name: 'Fabric Switchboard', repo: 'passioncode-ai/fabric-switchboard',
|
|
25
|
+
app: 'Fabric Switchboard.app', page: `${SITE}/switchboard/`,
|
|
26
|
+
asset: (v) => `Fabric-Switchboard-${v}-macos-universal.zip`,
|
|
27
|
+
mcp: {
|
|
28
|
+
name: 'switchboard', bin: 'Contents/MacOS/switchboard', args: () => ['mcp'],
|
|
29
|
+
claudePlugin: 'switchboard@', prove: { tool: 'switchboard_accounts', args: {} },
|
|
30
|
+
},
|
|
31
|
+
guide: 'Fabric Switchboard: your agent runs `switchboard onboard --status --json` and follows it; you sign in to each coding-agent account in the app.',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
// fabric-dashboards README "Install", src/core/setup.ts
|
|
35
|
+
id: 'dashboards', name: 'Fabric Dashboards', repo: 'passioncode-ai/fabric-dashboards',
|
|
36
|
+
app: 'Fabric Dashboards.app', page: `${SITE}/dashboards/`,
|
|
37
|
+
asset: (v) => `Fabric-Dashboards-${v}-mac.zip`,
|
|
38
|
+
mcp: { name: 'fabric-dashboards', bin: 'Contents/Resources/bin/fabric-dashboards-mcp', args: () => [], prove: { tool: 'list_services', args: {} } },
|
|
39
|
+
guide: 'Fabric Dashboards: open it once; its first session is a Setup console your coding agent runs.',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
// project-observatory-dashboard docs/AGENT-ONBOARDING.md (`full onboard`)
|
|
43
|
+
id: 'observatory', name: 'Project Observatory', repo: 'passioncode-ai/project-observatory-dashboard',
|
|
44
|
+
app: 'Project Observatory.app', page: `${SITE}/observatory/`,
|
|
45
|
+
asset: (v) => `ProjectObservatory-${v}-macos.zip`,
|
|
46
|
+
serviceIds: ['project-observatory'],
|
|
47
|
+
mcp: { name: 'observatory', external: true, prove: { tool: 'observatory_status', args: {} } },
|
|
48
|
+
guide: 'Project Observatory: your agent runs `project-observatory full onboard` and follows it (it registers the `observatory` MCP server); secrets go in through its hidden prompt, never the chat.',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
// fabric-inbox docs/agents/onboard.md (B-79)
|
|
52
|
+
id: 'inbox', name: 'Fabric Inbox', repo: 'passioncode-ai/fabric-inbox',
|
|
53
|
+
app: 'Fabric Inbox.app', page: `${SITE}/inbox/`,
|
|
54
|
+
asset: (v) => `Fabric-Inbox-${v}-mac.zip`,
|
|
55
|
+
mcp: { name: 'fabric-inbox', external: true, remote: true },
|
|
56
|
+
guide: 'Fabric Inbox: your agent follows its onboard guide (github.com/passioncode-ai/fabric-inbox, docs/agents/onboard.md) to create your mail server; you enter the Cloudflare token in its hidden prompt, sign in with the emailed code and press Allow.',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
// fabric apps/desktop/resources/bin/fabric-mcp, src/main/fabricMcpMain.ts
|
|
60
|
+
id: 'fabric', name: 'Fabric', repo: 'passioncode-ai/fabric', preview: true, prerelease: true,
|
|
61
|
+
app: 'Fabric.app', page: `${SITE}/fabric/`,
|
|
62
|
+
asset: (v) => `Fabric-${v}-universal.dmg`,
|
|
63
|
+
needs: ['docker', 'supabase'],
|
|
64
|
+
mcp: {
|
|
65
|
+
name: 'fabric', bin: 'Contents/Resources/bin/fabric-mcp',
|
|
66
|
+
args: (agent) => (agent.fabricRunner ? ['--runner', agent.fabricRunner] : null),
|
|
67
|
+
// fabric-mcp enrols a session with Fabric's hub as soon as it starts (fabricMcpMain.ts runs
|
|
68
|
+
// proxy.run at start), so doctor never starts it: it checks the entry and the binary, and the
|
|
69
|
+
// agent's own `fabric_whoami` is the proving call.
|
|
70
|
+
prove: null, spawn: false,
|
|
71
|
+
},
|
|
72
|
+
guide: 'Fabric (early preview): open it and finish its first run; Docker or OrbStack must be running. Then your agent calls `fabric_whoami` once to prove its MCP server.',
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
function appsDir() { return process.env.PASSIONCODE_APPLICATIONS || '/Applications'; }
|
|
77
|
+
function appPath(product) { return path.join(appsDir(), product.app); }
|
|
78
|
+
|
|
79
|
+
/** The stdio command of a product's MCP server for one agent, or null (not bundled / no runner). */
|
|
80
|
+
function mcpCommand(product, agent) {
|
|
81
|
+
const m = product.mcp;
|
|
82
|
+
if (!m || m.external || !m.bin) return null;
|
|
83
|
+
const override = product.id === 'dashboards' ? process.env.PASSIONCODE_FABRIC_DASHBOARDS_MCP : null;
|
|
84
|
+
const command = override || path.join(appPath(product), m.bin);
|
|
85
|
+
const args = m.args(agent);
|
|
86
|
+
return args ? { command, args } : null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function byId(id) { return PRODUCTS.find((p) => p.id === id) || null; }
|
|
90
|
+
|
|
91
|
+
module.exports = { PRODUCTS, AGENTS, TEAM_ID, SITE, appsDir, appPath, mcpCommand, byId };
|