From 99caa3bb39cf1bf3cb54b603872e4b41349a3ddd Mon Sep 17 00:00:00 2001 From: colosair Date: Tue, 8 Sep 2026 12:53:39 +0900 Subject: [PATCH] =?UTF-8?q?chore(release):=201.7.0=20=E2=80=94=20a=20write?= =?UTF-8?q?=20path=20that=20survives=20its=20transport?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The three packages move to 1.7.0 together, and the release note records what shipped, what was verified, and what was not. Contents: `jam jira write-plan` / `jam jira write-apply`, plans persisted to ~/.jam/write-plans/ so both transports read one store, and integrity by re-derivation rather than a signature (JAM_WRITE_PLAN_TAMPERED). No new behaviour is added here - this commit is version, lockfile and note. Gate: npm run release:verify - build, test, release:check, smoke, all green. Not exercised, and said so in the note: JAM_WRITE_UNCERTAIN, whose trigger is an ambiguous transport failure that cannot be produced against real Jira on demand. Also recorded there: `--input` JSON does not survive PowerShell quoting, which matters because the sessions that lose their MCP tools are often on Windows. Co-Authored-By: Claude Opus 5 --- AGENTS.md | 16 +- CLAUDE.md | 16 +- README.md | 26 +-- .../distribution-and-bootstrap.md | 12 +- docs/architecture/jira-agent-mcp-design.md | 6 +- docs/operations/setup-ux.md | 20 +-- docs/releases/v1.7.0.md | 151 ++++++++++++++++++ package-lock.json | 14 +- packages/bootstrap/README.md | 6 +- packages/bootstrap/package.json | 6 +- packages/launcher/README.md | 4 +- packages/launcher/package.json | 4 +- packages/launcher/src/release.ts | 2 +- packages/server/README.md | 4 +- packages/server/package.json | 4 +- packages/server/tests/unit/lifecycle.test.ts | 10 +- scripts/dev-setup.ps1 | 2 +- 17 files changed, 227 insertions(+), 76 deletions(-) create mode 100644 docs/releases/v1.7.0.md diff --git a/AGENTS.md b/AGENTS.md index e831d8b..30f2c2f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -131,7 +131,7 @@ If asked to set JAM up somewhere, use the official setup path — do not work ou an installation procedure from the README. One command does the whole thing: ```bash -npx --yes @jam-mcp/bootstrap@1.6.0 setup --agent +npx --yes @jam-mcp/bootstrap@1.7.0 setup --agent ``` **If you are reading this inside a clone of the JAM repository** — because @@ -160,7 +160,7 @@ before re-registering, reads the registration back, and finishes with `doctor` so a registration that lands but is not healthy is rolled back. ```bash -jam update # or: npx --yes @jam-mcp/bootstrap@1.6.0 update +jam update # or: npx --yes @jam-mcp/bootstrap@1.7.0 update jam update check --json # what is registered, what is published; changes nothing ``` @@ -173,9 +173,9 @@ then `asc update`, and report both. To inspect before acting, the same three steps separately: ```bash -npx --yes @jam-mcp/bootstrap@1.6.0 setup plan --json # what would change; changes nothing -npx --yes @jam-mcp/bootstrap@1.6.0 setup apply --non-interactive --json # execute it -npx --yes @jam-mcp/bootstrap@1.6.0 doctor --json # verify +npx --yes @jam-mcp/bootstrap@1.7.0 setup plan --json # what would change; changes nothing +npx --yes @jam-mcp/bootstrap@1.7.0 setup apply --non-interactive --json # execute it +npx --yes @jam-mcp/bootstrap@1.7.0 doctor --json # verify ``` Run them through `npx` exactly as written. A bare `jam` is a convenience some @@ -236,8 +236,8 @@ Code that is `~/.claude/settings.json`: { "permissions": { "allow": [ - "Bash(npx --yes @jam-mcp/bootstrap@1.6.0 setup --agent)", - "Bash(npx --yes @jam-mcp/bootstrap@1.6.0 runtime use package)" + "Bash(npx --yes @jam-mcp/bootstrap@1.7.0 setup --agent)", + "Bash(npx --yes @jam-mcp/bootstrap@1.7.0 runtime use package)" ] } } @@ -254,7 +254,7 @@ tooling, and never reach for a shell variant, a wrapper script, or a different runner to get past a refusal. If the user declines, that is an answer: say what cannot be done without it. -Finish with `npx --yes @jam-mcp/bootstrap@1.6.0 doctor --json`. +Finish with `npx --yes @jam-mcp/bootstrap@1.7.0 doctor --json`. Authentication is the one step that is not yours to do. `JAM_AUTH_REQUIRED` carries no `command` for exactly that reason — what it carries is a diff --git a/CLAUDE.md b/CLAUDE.md index 9de0191..317aa15 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -162,7 +162,7 @@ If asked to set JAM up somewhere, use the official setup path — do not work ou an installation procedure from the README. One command does the whole thing: ```bash -npx --yes @jam-mcp/bootstrap@1.6.0 setup --agent +npx --yes @jam-mcp/bootstrap@1.7.0 setup --agent ``` **If you are reading this inside a clone of the JAM repository** — because @@ -191,7 +191,7 @@ before re-registering, reads the registration back, and finishes with `doctor` so a registration that lands but is not healthy is rolled back. ```bash -jam update # or: npx --yes @jam-mcp/bootstrap@1.6.0 update +jam update # or: npx --yes @jam-mcp/bootstrap@1.7.0 update jam update check --json # what is registered, what is published; changes nothing ``` @@ -204,9 +204,9 @@ then `asc update`, and report both. To inspect before acting, the same three steps separately: ```bash -npx --yes @jam-mcp/bootstrap@1.6.0 setup plan --json # what would change; changes nothing -npx --yes @jam-mcp/bootstrap@1.6.0 setup apply --non-interactive --json # execute it -npx --yes @jam-mcp/bootstrap@1.6.0 doctor --json # verify +npx --yes @jam-mcp/bootstrap@1.7.0 setup plan --json # what would change; changes nothing +npx --yes @jam-mcp/bootstrap@1.7.0 setup apply --non-interactive --json # execute it +npx --yes @jam-mcp/bootstrap@1.7.0 doctor --json # verify ``` Run them through `npx` exactly as written. A bare `jam` is a convenience some @@ -267,8 +267,8 @@ Code that is `~/.claude/settings.json`: { "permissions": { "allow": [ - "Bash(npx --yes @jam-mcp/bootstrap@1.6.0 setup --agent)", - "Bash(npx --yes @jam-mcp/bootstrap@1.6.0 runtime use package)" + "Bash(npx --yes @jam-mcp/bootstrap@1.7.0 setup --agent)", + "Bash(npx --yes @jam-mcp/bootstrap@1.7.0 runtime use package)" ] } } @@ -285,7 +285,7 @@ tooling, and never reach for a shell variant, a wrapper script, or a different runner to get past a refusal. If the user declines, that is an answer: say what cannot be done without it. -Finish with `npx --yes @jam-mcp/bootstrap@1.6.0 doctor --json`. +Finish with `npx --yes @jam-mcp/bootstrap@1.7.0 doctor --json`. Authentication is the one step that is not yours to do. `JAM_AUTH_REQUIRED` carries no `command` for exactly that reason — what it carries is a diff --git a/README.md b/README.md index dd3d84d..9bbf942 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ itself — the MCP server, the setup core and the CLI they all reach. **For a person**, once per machine: ```bash -npx --yes @jam-mcp/bootstrap@1.6.0 init +npx --yes @jam-mcp/bootstrap@1.7.0 init ``` Choose whether you're *using* JAM (runs the published package) or *developing* @@ -179,10 +179,10 @@ installing the launcher globally, and everything it runs still goes through the runtime you chose above: ```bash -npm install -g @jam-mcp/launcher@1.6.0 +npm install -g @jam-mcp/launcher@1.7.0 ``` -Without it, the same commands are `npx --yes @jam-mcp/launcher@1.6.0 `. +Without it, the same commands are `npx --yes @jam-mcp/launcher@1.7.0 `. Nothing else changes — not your editor's wiring, not a shared `.mcp.json`, not a teammate who never installed it. @@ -223,7 +223,7 @@ to set JAM up in a project, **use the official path** rather than working out an installation from this README: ```bash -npx --yes @jam-mcp/bootstrap@1.6.0 setup --agent +npx --yes @jam-mcp/bootstrap@1.7.0 setup --agent ``` **If you are reading this inside a clone of this repository** — because someone @@ -240,9 +240,9 @@ asking is done. Install, register, and verify without further confirmation. or, to inspect before acting: ```bash -npx --yes @jam-mcp/bootstrap@1.6.0 setup plan --json # what would change; changes nothing -npx --yes @jam-mcp/bootstrap@1.6.0 setup apply --non-interactive --json # execute it -npx --yes @jam-mcp/bootstrap@1.6.0 doctor --json # verify +npx --yes @jam-mcp/bootstrap@1.7.0 setup plan --json # what would change; changes nothing +npx --yes @jam-mcp/bootstrap@1.7.0 setup apply --non-interactive --json # execute it +npx --yes @jam-mcp/bootstrap@1.7.0 doctor --json # verify ``` Each returns a single JSON document on stdout with a stable status code. Branch @@ -270,7 +270,7 @@ or a legacy preset entry needs no hand-editing first — the stale binding is replaced as part of the plan: ```bash -npx --yes @jam-mcp/bootstrap@1.6.0 setup --agent --project PROJECT +npx --yes @jam-mcp/bootstrap@1.7.0 setup --agent --project PROJECT ``` The one source it does not override is the repository's own committed @@ -342,8 +342,8 @@ settings rather than the repository's. For Claude Code that is { "permissions": { "allow": [ - "Bash(npx --yes @jam-mcp/bootstrap@1.6.0 setup --agent)", - "Bash(npx --yes @jam-mcp/bootstrap@1.6.0 runtime use package)" + "Bash(npx --yes @jam-mcp/bootstrap@1.7.0 setup --agent)", + "Bash(npx --yes @jam-mcp/bootstrap@1.7.0 runtime use package)" ] } } @@ -359,12 +359,12 @@ yourself, never put it in the repository so the project approves its own tooling, and never reach for a shell variant, a wrapper script, or a different runner to get past a refusal. If the user declines, that is an answer. -Finish with `npx --yes @jam-mcp/bootstrap@1.6.0 status --json`. +Finish with `npx --yes @jam-mcp/bootstrap@1.7.0 status --json`. ## Commands These read as `jam …` throughout — the short form from the optional global -install above. Everything works the same as `npx --yes @jam-mcp/launcher@1.6.0 +install above. Everything works the same as `npx --yes @jam-mcp/launcher@1.7.0 …` if you skipped it. ```text @@ -454,7 +454,7 @@ and is safe to commit: ```json { "mcpServers": { - "jam": { "command": "npx", "args": ["--yes", "@jam-mcp/launcher@1.6.0", "serve"] } + "jam": { "command": "npx", "args": ["--yes", "@jam-mcp/launcher@1.7.0", "serve"] } } } ``` diff --git a/docs/architecture/distribution-and-bootstrap.md b/docs/architecture/distribution-and-bootstrap.md index ca74b57..78f0514 100644 --- a/docs/architecture/distribution-and-bootstrap.md +++ b/docs/architecture/distribution-and-bootstrap.md @@ -103,7 +103,7 @@ Neither touches a project. ```json { "mcpServers": { - "jam": { "command": "npx", "args": ["--yes", "@jam-mcp/launcher@1.6.0", "serve"] } + "jam": { "command": "npx", "args": ["--yes", "@jam-mcp/launcher@1.7.0", "serve"] } } } ``` @@ -316,14 +316,14 @@ would silently change what a teammate's editor launches. ```bash # one shot: detect, plan, apply safe, verify -npx --yes @jam-mcp/bootstrap@1.6.0 setup --agent +npx --yes @jam-mcp/bootstrap@1.7.0 setup --agent # what would change, changing nothing -npx --yes @jam-mcp/bootstrap@1.6.0 setup plan --json +npx --yes @jam-mcp/bootstrap@1.7.0 setup plan --json # execute -npx --yes @jam-mcp/bootstrap@1.6.0 setup apply --non-interactive --json -npx --yes @jam-mcp/bootstrap@1.6.0 doctor --json +npx --yes @jam-mcp/bootstrap@1.7.0 setup apply --non-interactive --json +npx --yes @jam-mcp/bootstrap@1.7.0 doctor --json # presence and origin, never the value -npx --yes @jam-mcp/bootstrap@1.6.0 auth status --json +npx --yes @jam-mcp/bootstrap@1.7.0 auth status --json ``` Bootstrap, not `jam` — an agent's first command runs on a machine with no diff --git a/docs/architecture/jira-agent-mcp-design.md b/docs/architecture/jira-agent-mcp-design.md index 93cd08a..fd6e273 100644 --- a/docs/architecture/jira-agent-mcp-design.md +++ b/docs/architecture/jira-agent-mcp-design.md @@ -1089,8 +1089,8 @@ Claude Code zero-install 경로로 대체됐다. ```bash -npx --yes @jam-mcp/bootstrap@1.6.0 init # 사람 -npx --yes @jam-mcp/bootstrap@1.6.0 setup --agent # 코딩 에이전트 +npx --yes @jam-mcp/bootstrap@1.7.0 init # 사람 +npx --yes @jam-mcp/bootstrap@1.7.0 setup --agent # 코딩 에이전트 ``` 배포·부트스트랩의 설계 정본은 `docs/architecture/distribution-and-bootstrap.md`, @@ -1106,7 +1106,7 @@ README에서 설치 절차를 지어내던 문제가 이 절에서 시작됐다. zero-install 형태는 다음이다. ```bash -npx --yes @jam-mcp/bootstrap@1.6.0 doctor --json +npx --yes @jam-mcp/bootstrap@1.7.0 doctor --json ``` 검사 항목의 정본은 코드다: `packages/server/src/bootstrap/boot-health-gate.ts`. diff --git a/docs/operations/setup-ux.md b/docs/operations/setup-ux.md index 544bc5f..754c38d 100644 --- a/docs/operations/setup-ux.md +++ b/docs/operations/setup-ux.md @@ -194,7 +194,7 @@ probe blocks the process, so a spinner would print one frame and then freeze — it gets a pending line instead, and only when a probe actually happens: ```text -○ Checking @jam-mcp/launcher@1.6.0 on npm... +○ Checking @jam-mcp/launcher@1.7.0 on npm... ``` Disabled entirely when not interactive, where it degrades to a single pending @@ -235,7 +235,7 @@ shell history: ```text × Migration target is not available from the configured npm registry - npm could not find @jam-mcp/launcher@1.6.0 in the configured registry. + npm could not find @jam-mcp/launcher@1.7.0 in the configured registry. Existing .mcp.json was left unchanged. ``` @@ -283,7 +283,7 @@ adoption is asked for. Recorded for you only - the repository was not touched. ✓ Registered with claude-code ! codex was not reachable, so JAM was not registered with it. -› If you use it, run: codex mcp add jam -- npx --yes @jam-mcp/launcher@1.6.0 serve +› If you use it, run: codex mcp add jam -- npx --yes @jam-mcp/launcher@1.7.0 serve ``` **A rebind names what it replaces.** `jam setup --project OTHER` on a workspace @@ -347,12 +347,12 @@ method creates, so that one row stays a human check. For agents and scripts: ```bash -npx --yes @jam-mcp/bootstrap@1.6.0 setup plan --json -npx --yes @jam-mcp/bootstrap@1.6.0 setup apply --non-interactive --json -npx --yes @jam-mcp/bootstrap@1.6.0 setup --agent -npx --yes @jam-mcp/bootstrap@1.6.0 doctor --json -npx --yes @jam-mcp/bootstrap@1.6.0 runtime --json -npx --yes @jam-mcp/bootstrap@1.6.0 auth status --json +npx --yes @jam-mcp/bootstrap@1.7.0 setup plan --json +npx --yes @jam-mcp/bootstrap@1.7.0 setup apply --non-interactive --json +npx --yes @jam-mcp/bootstrap@1.7.0 setup --agent +npx --yes @jam-mcp/bootstrap@1.7.0 doctor --json +npx --yes @jam-mcp/bootstrap@1.7.0 runtime --json +npx --yes @jam-mcp/bootstrap@1.7.0 auth status --json ``` A locally installed `jam` runs each of these identically, and this document @@ -360,7 +360,7 @@ writes the short form elsewhere for readability. Bootstrap stays the zero-state default — the machine an agent lands on usually has no global install. But the launcher is no longer ruled out on a fresh machine: it answers `jam runtime use package` itself, so `npm install -g -@jam-mcp/launcher@1.6.0` followed by that one command reaches the same place. +@jam-mcp/launcher@1.7.0` followed by that one command reaches the same place. That persistent path is also the fallback when `npx` itself cannot start a process (a package-runner failure, which is not a JAM failure). diff --git a/docs/releases/v1.7.0.md b/docs/releases/v1.7.0.md new file mode 100644 index 0000000..d26390f --- /dev/null +++ b/docs/releases/v1.7.0.md @@ -0,0 +1,151 @@ +# JAM v1.7.0 — writing Jira when the tools are unreachable + +## What changed + +**`jam jira write-plan` and `jam jira write-apply`.** Reads got a shell address +in 1.4.6 and writes did not. The gap shows up in exactly the situation the reads +were opened for: a session whose MCP registry came up in a failed state cannot be +shown the tools — Claude Code has no reload surface for a running session — while +JAM, its credentials and its Jira access are all fine. That session could read +Jira and could not change it. + +```bash +jam jira write-plan --operation [--key KEY] --input '' +jam jira write-apply +``` + +Nothing here implements a second write path. Both call the same `planWrite` / +`applyWritePlan` the MCP tools call, with the same deps, project binding, +whitelist and normalized error codes. The two-call contract is not relaxed for +the shell: planning changes nothing, and apply takes a `planId` and has no flag +through which a payload could arrive. There is deliberately no `jam jira comment` +or `jam jira close` — a shortcut past planning is what the write plane exists to +prevent, and a terminal does not change that. `issue.create` goes through the +same `write-plan` rather than getting a command of its own. + +**Plans now live in a file, shared by both transports.** They lived in the server +process, and the ADR said why. The same section named the condition for +revisiting — "if plans ever need to outlive a process" — and `write-plan` and +`write-apply` are two processes. + +```text +before in the server process, in memory +after ~/.jam/write-plans/.json, read by MCP and the CLI alike +``` + +Sharing the store is the point rather than a side effect: **a plan made through +the tools can be applied from the shell after the tools stop answering**, which +is the case this release exists for. Single use moved to the filesystem — `take` +claims a plan by renaming it, so two concurrent applies cannot both hold one. +For `comment.add` the alternative is two comments. + +**Integrity is re-derivation, not a signature.** Apply reads the plan's own +recorded input, derives the mutation from it again, and refuses with the new +`JAM_WRITE_PLAN_TAMPERED` when the stored mutation is not what that input +produces. Editing the file to smuggle a different write means editing the input +to match — which is asking JAM to plan that write. The whitelist runs again too, +so an edited input cannot reach a field planning refuses. The check runs after +the revision check: a moved issue is a conflict, not tampering. + +`docs/decisions/adr-jira-write-plane.md` §"Where plans live" is rewritten rather +than quietly contradicted, and it records what was lost as well as what was +gained. + +## What did not change + +The MCP surface. Five tools, the same names, the same inputs, the same `meta` +semantics: `jira_search`, `jira_context`, `jira_full`, `jira_write_plan`, +`jira_write_apply`. The operation set and both whitelists are untouched, and so +is every existing error code. + +JAM still has no Execution Mode. That axis belongs to ASC, and a Jira write still +travels ASC's decision path. + +## Install / Upgrade + +```bash +jam update +``` + +Moves this machine's registration to the published release. It does not re-plan +the project binding — that is `jam setup`'s job. + +First run on a machine with no JAM: + +```bash +npx --yes @jam-mcp/bootstrap@1.7.0 setup --agent +``` + +## Agent setup + +Unchanged from 1.6.0. The agent entry points are the same: + +```bash +npx --yes @jam-mcp/bootstrap@1.7.0 setup --agent +jam status --json +``` + +An agent that has just registered JAM and cannot yet see the tools now has a +complete shell path — reads since 1.4.6, and writes as of this release. + +## Compatibility + +Node >= 20. The three packages ship in lockstep at 1.7.0 and depend on each +other at that exact version. + +**One state change on disk.** Plans are now files under `~/.jam/write-plans/`, +created 0600 in a 0700 directory. Nothing else in `~/.jam` is touched, and +plans still expire in ten minutes and are still single-use. A plan made by 1.6.0 +cannot exist across an upgrade — it was in a process that has since exited — so +there is nothing to migrate. + +## Verified + +```text +npx tsc --noEmit green +npm test 538 pass / 0 fail / 4 skipped (542) +npm run build green +npm run release:check consistent across manifests, code and docs +CI pr-title + ubuntu/windows × node 20/22, all green +``` + +Against real Jira, on a dedicated health-check issue in the bound project — no +team ticket was touched: + +```text +write-plan planned, no mutation +write-apply from a second process applied · verified: true +same planId again JAM_WRITE_PLAN_NOT_FOUND, directory empty +plan, move the issue, then apply JAM_WRITE_CONFLICT +edit the stored mutation, leave input JAM_WRITE_PLAN_TAMPERED, nothing reached Jira +read → plan → apply, no MCP at all applied · verified: true +``` + +The last line is what this release exists for. + +## Known limitations + +**`JAM_WRITE_UNCERTAIN` was not exercised.** Its trigger is an ambiguous +transport failure — a request that may or may not have landed — and that cannot +be produced against real Jira on demand. Only its code path was read. This is +recorded rather than implied because it is the failure whose handling matters +most: retrying it is what turns one comment into two. + +**`--input` JSON does not survive PowerShell quoting.** + +```text +PowerShell --input '{\"text\":\"...\"}' → "--input must be a JSON object." +Git Bash --input '{"text":"..."}' → fine +``` + +Not specific to JAM — the same happens to any CLI taking a JSON argument — but +it is a real obstacle in the environment this feature is most needed in, since +the sessions that lose their MCP tools are often on Windows. Use Git Bash, or +match PowerShell's quoting. A `--input-file` or reading the object from stdin +would remove the problem and is a candidate for a follow-up; neither was added +here to keep this release to the change it describes. + +**A mutation is now serialized where the machine's user can read and edit it.** +That is a real reduction from "forgery is impossible" to "forgery gains +nothing", and it is the price of a write path that survives its transport. See +the ADR for why a signed token was still not the shape. diff --git a/package-lock.json b/package-lock.json index 3779691..90d02b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2438,11 +2438,11 @@ }, "packages/bootstrap": { "name": "@jam-mcp/bootstrap", - "version": "1.6.0", + "version": "1.7.0", "license": "MIT", "dependencies": { - "@jam-mcp/launcher": "1.6.0", - "@jam-mcp/server": "1.6.0" + "@jam-mcp/launcher": "1.7.0", + "@jam-mcp/server": "1.7.0" }, "bin": { "jam-bootstrap": "dist/cli.js" @@ -2457,10 +2457,10 @@ }, "packages/launcher": { "name": "@jam-mcp/launcher", - "version": "1.6.0", + "version": "1.7.0", "license": "MIT", "dependencies": { - "@jam-mcp/server": "1.6.0", + "@jam-mcp/server": "1.7.0", "yaml": "^2.9.0" }, "bin": { @@ -2478,10 +2478,10 @@ }, "packages/server": { "name": "@jam-mcp/server", - "version": "1.6.0", + "version": "1.7.0", "license": "MIT", "dependencies": { - "@jam-mcp/launcher": "1.6.0", + "@jam-mcp/launcher": "1.7.0", "@modelcontextprotocol/sdk": "^1.30.0", "yaml": "^2.9.0", "zod": "^4.4.3" diff --git a/packages/bootstrap/README.md b/packages/bootstrap/README.md index e26b103..855186c 100644 --- a/packages/bootstrap/README.md +++ b/packages/bootstrap/README.md @@ -6,8 +6,8 @@ This package exists so the *first* command a person or a coding agent runs needs nothing installed beforehand: ```bash -npx --yes @jam-mcp/bootstrap@1.6.0 init # for a person -npx --yes @jam-mcp/bootstrap@1.6.0 setup --agent # for a coding agent, JSON only +npx --yes @jam-mcp/bootstrap@1.7.0 init # for a person +npx --yes @jam-mcp/bootstrap@1.7.0 setup --agent # for a coding agent, JSON only ``` `init` chooses how JAM runs on this machine and wires up the current project. @@ -26,7 +26,7 @@ sync with the setup core. That pass-through is also why bootstrap is what JAM names in machine-readable instructions. On a machine that has just met JAM there is no global command to call and no configured runtime for the launcher to dispatch to — bootstrap -needs neither, so `npx --yes @jam-mcp/bootstrap@1.6.0 ` works when +needs neither, so `npx --yes @jam-mcp/bootstrap@1.7.0 ` works when nothing else does. The three packages divide up like this: diff --git a/packages/bootstrap/package.json b/packages/bootstrap/package.json index 4b85571..90b99ed 100644 --- a/packages/bootstrap/package.json +++ b/packages/bootstrap/package.json @@ -1,6 +1,6 @@ { "name": "@jam-mcp/bootstrap", - "version": "1.6.0", + "version": "1.7.0", "description": "Zero-install entry point for JAM (Jira Agent MCP) - first-run setup for humans and coding agents", "keywords": [ "jira", @@ -37,8 +37,8 @@ "build": "tsc" }, "dependencies": { - "@jam-mcp/launcher": "1.6.0", - "@jam-mcp/server": "1.6.0" + "@jam-mcp/launcher": "1.7.0", + "@jam-mcp/server": "1.7.0" }, "devDependencies": { "@types/node": "^24.0.0", diff --git a/packages/launcher/README.md b/packages/launcher/README.md index f5e8b26..88a3eff 100644 --- a/packages/launcher/README.md +++ b/packages/launcher/README.md @@ -9,7 +9,7 @@ indirection is what lets a committed `.mcp.json` name no machine-specific path: ```json { "mcpServers": { - "jam": { "command": "npx", "args": ["--yes", "@jam-mcp/launcher@1.6.0", "serve"] } + "jam": { "command": "npx", "args": ["--yes", "@jam-mcp/launcher@1.7.0", "serve"] } } } ``` @@ -40,7 +40,7 @@ This package installs under two names from one entry point: `jam-launcher`, and `jam` for people who want the short form. ```bash -npm install -g @jam-mcp/launcher@1.6.0 +npm install -g @jam-mcp/launcher@1.7.0 ``` That is the **persistent** way to run JAM, and it is self-sufficient: the diff --git a/packages/launcher/package.json b/packages/launcher/package.json index 5ab1f5a..8ed771d 100644 --- a/packages/launcher/package.json +++ b/packages/launcher/package.json @@ -1,6 +1,6 @@ { "name": "@jam-mcp/launcher", - "version": "1.6.0", + "version": "1.7.0", "description": "JAM launcher - resolves which JAM runtime to run and dispatches to it", "keywords": [ "jira", @@ -55,7 +55,7 @@ }, "dependencies": { "yaml": "^2.9.0", - "@jam-mcp/server": "1.6.0" + "@jam-mcp/server": "1.7.0" }, "devDependencies": { "@types/node": "^24.0.0", diff --git a/packages/launcher/src/release.ts b/packages/launcher/src/release.ts index 63811ae..5585795 100644 --- a/packages/launcher/src/release.ts +++ b/packages/launcher/src/release.ts @@ -10,7 +10,7 @@ * default that the project's own pin overrides, not a value that disappears. */ export const SERVER_PACKAGE = "@jam-mcp/server"; -export const SERVER_VERSION = "1.6.0"; +export const SERVER_VERSION = "1.7.0"; export const SERVER_PACKAGE_SPEC = `${SERVER_PACKAGE}@${SERVER_VERSION}`; export const LAUNCHER_PACKAGE = "@jam-mcp/launcher"; diff --git a/packages/server/README.md b/packages/server/README.md index c6e5c64..9e153df 100644 --- a/packages/server/README.md +++ b/packages/server/README.md @@ -74,10 +74,10 @@ auth login Store Jira credentials in this user's OS secret store runtime Show or change which JAM build this machine runs ``` -Written out, that is `npx --yes @jam-mcp/launcher@1.6.0 doctor`, or just `jam +Written out, that is `npx --yes @jam-mcp/launcher@1.7.0 doctor`, or just `jam doctor` if you took the launcher's optional global install. Starting from nothing — no install, no runtime chosen yet — use -`npx --yes @jam-mcp/bootstrap@1.6.0 init` instead. +`npx --yes @jam-mcp/bootstrap@1.7.0 init` instead. Credentials come from the process environment or this user's OS secret store — never from a repository file — and never appear in logs, telemetry, or tool diff --git a/packages/server/package.json b/packages/server/package.json index 9174614..1662ff8 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@jam-mcp/server", - "version": "1.6.0", + "version": "1.7.0", "description": "JAM (Jira Agent MCP) - agent-facing Jira access layer: MCP server, setup core, and CLI", "keywords": [ "jira", @@ -41,7 +41,7 @@ "test:watch": "vitest" }, "dependencies": { - "@jam-mcp/launcher": "1.6.0", + "@jam-mcp/launcher": "1.7.0", "@modelcontextprotocol/sdk": "^1.30.0", "yaml": "^2.9.0", "zod": "^4.4.3" diff --git a/packages/server/tests/unit/lifecycle.test.ts b/packages/server/tests/unit/lifecycle.test.ts index 6288000..488c2f9 100644 --- a/packages/server/tests/unit/lifecycle.test.ts +++ b/packages/server/tests/unit/lifecycle.test.ts @@ -39,25 +39,25 @@ function recorder(answers: (cmd: HostCommand) => HostRunResult) { describe("planRefresh", () => { it("a line pinned to another version is what refresh converges", () => { - const plan = planRefresh([claude({ entryVersion: "1.4.6" })], "1.6.0"); - expect(plan.version).toBe("1.6.0"); + const plan = planRefresh([claude({ entryVersion: "1.4.6" })], "1.7.0"); + expect(plan.version).toBe("1.7.0"); expect(plan.hosts[0]).toMatchObject({ id: "claude-code", from: "1.4.6", action: "repin" }); expect(plan.steps).toEqual(["switch-registration", "verify"]); }); it("a line already on this version is left alone", () => { - const plan = planRefresh([claude({ entryVersion: "1.6.0" })], "1.6.0"); + const plan = planRefresh([claude({ entryVersion: "1.7.0" })], "1.7.0"); expect(plan.hosts[0]?.action).toBe("none"); expect(plan.steps).toEqual([]); }); it("a bare entry runs the executable, so the line has nothing to move", () => { - const plan = planRefresh([claude({ entryBare: true, entryVersion: "1.4.6" })], "1.6.0"); + const plan = planRefresh([claude({ entryBare: true, entryVersion: "1.4.6" })], "1.7.0"); expect(plan.hosts[0]?.action).toBe("none"); }); it("a host with no jam entry is not adopted here — that is setup", () => { - expect(planRefresh([claude({ hasJamEntry: false })], "1.6.0").hosts).toEqual([]); + expect(planRefresh([claude({ hasJamEntry: false })], "1.7.0").hosts).toEqual([]); }); it("refresh never claims a version this build is not", () => { diff --git a/scripts/dev-setup.ps1 b/scripts/dev-setup.ps1 index 8c6ea51..94ea446 100644 --- a/scripts/dev-setup.ps1 +++ b/scripts/dev-setup.ps1 @@ -5,7 +5,7 @@ .DESCRIPTION Not the installation path. Someone who wants to use JAM runs - `npx --yes @jam-mcp/bootstrap@1.6.0 init` and never clones this repository. + `npx --yes @jam-mcp/bootstrap@1.7.0 init` and never clones this repository. This is for working on JAM itself: it checks the Node version, installs dependencies, builds, then runs doctor so the result is a verdict rather than