From 9a479b98bf0a64268a3a8906cae64ae3cc6b1aea Mon Sep 17 00:00:00 2001 From: Matthew Goodwin Date: Thu, 24 Sep 2026 15:16:37 -0500 Subject: [PATCH 1/3] rt-client: bump to 0.31.0 (mattstack.mode retired, isRetiredKey) Co-Authored-By: Claude Opus 5.5 --- packages/rt-client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rt-client/package.json b/packages/rt-client/package.json index 21c4cac6a..5181a7324 100644 --- a/packages/rt-client/package.json +++ b/packages/rt-client/package.json @@ -1,6 +1,6 @@ { "name": "@mattstack/rt-client", - "version": "0.30.0", + "version": "0.31.0", "type": "module", "exports": { ".": { From 670bb9c8b0bb8092d6c456345fe371b4672a8b1d Mon Sep 17 00:00:00 2001 From: Matthew Goodwin Date: Thu, 24 Sep 2026 15:17:49 -0500 Subject: [PATCH 2/3] rt-client: settings unset removes a retired key a store still carries Co-Authored-By: Claude Opus 5.5 --- .../rt-client/src/settings/__tests__/write.test.ts | 13 +++++++++++++ packages/rt-client/src/settings/write.ts | 14 ++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/rt-client/src/settings/__tests__/write.test.ts b/packages/rt-client/src/settings/__tests__/write.test.ts index e9cc67091..11f3fe8c7 100644 --- a/packages/rt-client/src/settings/__tests__/write.test.ts +++ b/packages/rt-client/src/settings/__tests__/write.test.ts @@ -521,6 +521,19 @@ describe("settings/unset", () => { expect(() => unsetSetting("rt.doesNotExist", "user")).toThrow(/unknown setting/); }); + test("removes a retired key a store still carries, from any scope", () => { + mkdirSync(dirname(machineSettingsPath()), { recursive: true }); + writeFileSync(machineSettingsPath(), `{\n "mattstack.mode": "dev",\n "mattstack.appPath": "/Applications/mattstack-dev.app"\n}\n`); + expect(unsetSetting("mattstack.mode", "machine")).toBe(true); + const after = readFileSync(machineSettingsPath(), "utf8"); + expect(after).not.toContain("mattstack.mode"); + expect(after).toContain("mattstack.appPath"); + }); + + test("refuses a retired key with a repo identity", () => { + expect(() => unsetSetting("mattstack.mode", "user", { repoIdentity: IDENTITY })).toThrow(/not repo-scoped/); + }); + test("refuses a scope the def does not allow", () => { expect(() => unsetSetting("rt.repoIdentityOverrides", "user")).toThrow(/cannot be unset in the user store/); }); diff --git a/packages/rt-client/src/settings/write.ts b/packages/rt-client/src/settings/write.ts index 48cb5f449..7fe753a51 100644 --- a/packages/rt-client/src/settings/write.ts +++ b/packages/rt-client/src/settings/write.ts @@ -98,7 +98,7 @@ import { applyEdits, modify, parseTree, type JSONPath, type Node, type ParseErro import { randomBytes } from "crypto"; import { dirname } from "path"; import { machineSettingsPath, teamSettingsPath, userSettingsPath } from "./paths.ts"; -import { getDef, isMigrated, validateValue, type SettingDef, type SettingScope } from "./registry-machinery.ts"; +import { getDef, isMigrated, isRetiredKey, validateValue, type SettingDef, type SettingScope } from "./registry-machinery.ts"; import { listTeams } from "./stores.ts"; import { isJoinedTeam } from "./team-local-read.ts"; @@ -171,9 +171,15 @@ export function setSetting(key: string, value: unknown, scope: SettingScope, opt * with no local store included — nothing to remove is success, not an error), * and a key not present in the store is a no-op. Returns whether anything was * actually removed; the local-only reminder prints only on a real removal. + * A retired key is not in the registry but may linger in a store, so it can + * still be removed from any scope. */ export function unsetSetting(key: string, scope: SettingScope, opts: SetSettingOpts = {}): boolean { const def = getDef(key); + if (!def && isRetiredKey(key)) { + if (opts.repoIdentity !== undefined) refuse(`"${key}" is not repo-scoped; omit the repo identity`); + return removeKeyFromScope(key, scope, opts, [key]); + } if (!def) { refuse(`unknown setting "${key}" — not in the settings registry (see \`rt settings list\`)`); } @@ -190,10 +196,14 @@ export function unsetSetting(key: string, scope: SettingScope, opts: SetSettingO refuse(`"${key}" is not repo-scoped — omit the repo identity`); } + const jsonPath: JSONPath = opts.repoIdentity !== undefined ? ["repos", opts.repoIdentity, key] : [key]; + return removeKeyFromScope(key, scope, opts, jsonPath); +} + +function removeKeyFromScope(key: string, scope: SettingScope, opts: SetSettingOpts, jsonPath: JSONPath): boolean { const storePath = resolveStorePathForUnset(scope, opts); if (storePath === null || !existsSync(storePath)) return false; - const jsonPath: JSONPath = opts.repoIdentity !== undefined ? ["repos", opts.repoIdentity, key] : [key]; const removed = removeFromStore(storePath, jsonPath); if (removed) { From 83a0d3d7049405fa3c18f8ce2b2d0af10e440255 Mon Sep 17 00:00:00 2001 From: Matthew Goodwin Date: Thu, 24 Sep 2026 15:21:47 -0500 Subject: [PATCH 3/3] bun.lock: rt-client 0.31.0 Co-Authored-By: Claude Opus 5.5 --- bun.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bun.lock b/bun.lock index b2b0ca63c..697a5f29c 100644 --- a/bun.lock +++ b/bun.lock @@ -38,7 +38,7 @@ }, "packages/rt-client": { "name": "@mattstack/rt-client", - "version": "0.30.0", + "version": "0.31.0", "dependencies": { "jsonc-parser": "^3.3.1", },