docks-kit 0.19.0 → 0.19.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.
- package/AGENTS.md +1 -1
- package/README.md +3 -2
- package/cli/docs/omp-models.md +5 -2
- package/cli/docs/overview.md +1 -1
- package/cli/src/commands/docs.ts +8 -2
- package/cli/src/commands/toolchain.ts +9 -2
- package/cli/src/commands/update.ts +6 -6
- package/cli/src/engine-native/claudePluginPasses.ts +33 -11
- package/cli/src/engine-native/codexConfig.ts +6 -6
- package/cli/src/engine-native/codexPlugins.ts +6 -5
- package/cli/src/engine-native/codexToml.ts +10 -6
- package/cli/src/engine-native/modes.ts +7 -11
- package/cli/src/generated/sotPayload.ts +3 -3
- package/cli/src/main.ts +2 -2
- package/cli/src/manifests.ts +2 -2
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -75,7 +75,7 @@ omp SoT notes:
|
|
|
75
75
|
- `ompSync.ts syncMergedYaml` deep-merges `config.yml` through `ompYaml.ts mergeOmpConfig` and `models.yml` through `mergeOmpModels`. Both wrap one generic mapping merge; only the config wrapper prunes stale `retry.fallbackChains` wildcards.
|
|
76
76
|
- `ompSync.ts` runs `ompRemovals.ts syncOmpRemovals, retired-key inventory` right after the config merge, and that pass force-prunes retired kit-owned keys from `~/.omp/agent/config.yml` on every sync, without `--reconcile`. The pass is required because `mergeOmpConfig` is additive, so removing a key from the SoT alone never removes it from a deployed file. A key retired with a recorded value is pruned only while the deployed value still matches that value, so a user edit survives; a key retired outright, such as `providers.webSearchOrder`, is pruned at any value.
|
|
77
77
|
- `cycleOrder` ends with `astra` as its fifth stop. `modelRoles.astra` is `openai-codex/gpt-6-astra:xhigh`, and `modelTags.astra` is visible. Astra and Fable fall back to each other through concrete selectors. `modelRoles.fable` remains `anthropic/claude-fable-5-1:medium`, with visible `modelTags.fable`. The hidden `switch_fable` role uses the same Fable selector and keeps an empty fallback chain.
|
|
78
|
-
- `modelRoles.task` is `openai-codex/gpt-6-sol:high`. `advisor` is `anthropic/claude-opus-5-5:medium` with an empty fallback chain, because a GPT-6 Sol advisor looped on repeated reads under an Opus 5.5 session; never put GPT-6 Sol in the advisor role or chain. `smol`, `commit`, and `tiny` use `openai-codex/gpt-6-luna`. The four reviewer entries in `task.agentModelOverrides` inherit `task` through `@task`. Only bundled `reviewer` and `security-reviewer` are discoverable OMP agents; `code-reviewer` and `plan-reviewer` stay dormant. omp 18.2.9
|
|
78
|
+
- `modelRoles.task` is `openai-codex/gpt-6-sol:high`. `advisor` is `anthropic/claude-opus-5-5:medium` with an empty fallback chain, because a GPT-6 Sol advisor looped on repeated reads under an Opus 5.5 session; never put GPT-6 Sol in the advisor role or chain. `smol`, `commit`, and `tiny` use `openai-codex/gpt-6-luna`. The four reviewer entries in `task.agentModelOverrides` inherit `task` through `@task`. Only bundled `reviewer` and `security-reviewer` are discoverable OMP agents; `code-reviewer` and `plan-reviewer` stay dormant. omp 18.2.9 did not list `gpt-6-sol` or `gpt-6-luna` in its `openai-codex` catalog and fuzzy-matched both selectors to the GPT-5.6 models. omp 18.3.1 lists both ids and serves them as named. `cli/docs/omp-models.md` records the checks.
|
|
79
79
|
- The five Anthropic roles (`default`, `slow`, `plan`, `designer`, `vision`) and the five Anthropic retry chains use `anthropic/claude-opus-5-5` at the levels the role map records. `cli/docs/omp-models.md` carries the Artificial Analysis capture behind the role map, read 2026-09-22 at Intelligence Index v4.3.2 and Coding Agent Index v1.5 from the AA comparison-page metric tables. Opus 5.5 max has the highest index in that topic. AA has not measured speed or latency for Opus 5.5 max, GPT-6 Sol, or GPT-6 Luna.
|
|
80
80
|
- `modelRoles.web` is `web/firecrawl` and `retry.fallbackChains.web` carries the explicit 20-entry provider order. The kit declares both keys because the legacy `providers.webSearchOrder` key is retired: omp expands it in memory into these two keys and then drops it, and never writes that expansion back to disk. An explicit chain replaces omp's built-in web order wholesale, so every entry left out is a provider omp never tries. The owner removed the seven entries that named older models (Gemini 2.5 Flash, Claude Haiku 4.5, GPT-5.6, GPT-5.5, and Grok 4.5); keep every other provider.
|
|
81
81
|
- `SoT/.omp/models.yml` declares Astra's full `low, medium, high, xhigh, max` ladder with `defaultLevel: xhigh` as the worked provider ladder-override example. It also carries a temporary `anthropic.modelOverrides.claude-opus-5-5` block with that model's limits, ladder, and prices, because the shared catalog still serves the id as a stub with null limits and zero cost; remove the block once the catalog publishes the row. `ompYaml.ts mergeOmpModels` preserves deployed-only keys in `~/.omp/agent/models.yml`, because a user file may carry provider credentials. Whole-file replacement is wrong.
|
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ docks-kit toolchain [check|ensure <tool>|outdated] verified-version floors for
|
|
|
53
53
|
docks-kit status [--json] deployed-vs-SoT drift + toolchain + counts
|
|
54
54
|
docks-kit plugins list [--json] enabledPlugins tri-state vs installed
|
|
55
55
|
docks-kit skills list [--json] universal skills vs manifest
|
|
56
|
-
docks-kit docs [topic] self-documentation (
|
|
56
|
+
docks-kit docs [topic] self-documentation (11 topics)
|
|
57
57
|
--help --version --wizard --completions built-in
|
|
58
58
|
```
|
|
59
59
|
|
|
@@ -100,7 +100,8 @@ and a later flag-less sync reverts them. Full reference: `docks-kit docs flags`
|
|
|
100
100
|
the full doctor table. Bun is the one managed install and is pinned to its
|
|
101
101
|
verified version.
|
|
102
102
|
- **Model catalog** — enabled harnesses provide live Claude, Codex, or omp
|
|
103
|
-
model IDs; `SoT/models.json` supplies aliases, notes, and the
|
|
103
|
+
model IDs; `SoT/models.json` supplies Claude and Codex aliases, notes, and the
|
|
104
|
+
offline fallback. omp has no curated fallback list.
|
|
104
105
|
- **Claude runtime** — sync materializes three dependency-free Bun `.mjs`
|
|
105
106
|
programs for statusline, SessionStart, and Notification. Quota display uses
|
|
106
107
|
Claude's native `rate_limits`; there is no OAuth fetch, shared usage cache,
|
package/cli/docs/omp-models.md
CHANGED
|
@@ -54,8 +54,11 @@ omp 18.2.9 and codex-cli 0.153.3:
|
|
|
54
54
|
`openai-codex/gpt-6-sol:low` recorded `gpt-5.6-sol` as the serving model,
|
|
55
55
|
and the Luna selector recorded `gpt-5.6-luna`. omp printed no warning.
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
`omp models openai-codex
|
|
57
|
+
On 2026-09-25, omp 18.3.1 listed `gpt-6-sol` and `gpt-6-luna` in
|
|
58
|
+
`omp models openai-codex`. An `omp -p --mode json` run on each selector
|
|
59
|
+
recorded `gpt-6-sol` and `gpt-6-luna` as the serving model, so the omp roles
|
|
60
|
+
now run GPT-6. To check again, run `omp models openai-codex`: the `gpt-6-sol`
|
|
61
|
+
and `gpt-6-luna` rows must appear.
|
|
59
62
|
|
|
60
63
|
What omp's settings catalog establishes about these roles:
|
|
61
64
|
|
package/cli/docs/overview.md
CHANGED
|
@@ -13,7 +13,7 @@ AI-assisted dev environment on every machine.
|
|
|
13
13
|
| `SoT/.codex/` | Codex config (config.toml, rules, AGENTS.md, marketplace) |
|
|
14
14
|
| `SoT/.agents/` | Universal agent skills manifest (agentskills.io standard) |
|
|
15
15
|
| `SoT/.omp/` | omp config deployed to `~/.omp/agent/` (AGENTS.md, config.yml, models.yml, mcp.json) plus `intercom.json` for pi intercom |
|
|
16
|
-
| `SoT/models.json` |
|
|
16
|
+
| `SoT/models.json` | Curated Claude and Codex aliases, notes, and offline fallback for the live model lists (see `docks-kit docs models`) |
|
|
17
17
|
| `SoT/toolchain.json` | Verified-version floors for external tools (see `docks-kit docs toolchain`) |
|
|
18
18
|
| `cli/src/generated/sotPayload.ts` | Deterministic generated payload embedded in standalone/npm execution |
|
|
19
19
|
| `cli/src/engine-native/` | EngineNative mutation logic for sync/model/toolchain and the `docks-kit omp` session overlay |
|
package/cli/src/commands/docs.ts
CHANGED
|
@@ -24,8 +24,14 @@ const TOPICS: Record<string, { summary: string; body: string }> = {
|
|
|
24
24
|
summary: "Deploy-time modifiers and the flag-less-sync-reverts contract",
|
|
25
25
|
body: modifiers,
|
|
26
26
|
},
|
|
27
|
-
models: {
|
|
28
|
-
|
|
27
|
+
models: {
|
|
28
|
+
summary: "Live model lists, the curated overlay, validation, model get/set",
|
|
29
|
+
body: models,
|
|
30
|
+
},
|
|
31
|
+
toolchain: {
|
|
32
|
+
summary: "Verified-version floors, the doctor table, and the upstream outdated report",
|
|
33
|
+
body: toolchain,
|
|
34
|
+
},
|
|
29
35
|
plugins: { summary: "enabledPlugins tri-state + optional plugin opt-ins", body: plugins },
|
|
30
36
|
install: {
|
|
31
37
|
summary: "Install paths: repo checkout, bun add -g, POSIX/Windows installers",
|
|
@@ -29,10 +29,12 @@ export const toolchainCommand = Command.make(
|
|
|
29
29
|
Effect.gen(function* () {
|
|
30
30
|
const operation = Option.getOrElse(config.op, () => "check");
|
|
31
31
|
const flags = config.verbose ? ["--verbose"] : [];
|
|
32
|
+
const operand = Option.getOrUndefined(config.tool);
|
|
33
|
+
const words = operand === undefined ? [] : [operand];
|
|
32
34
|
|
|
33
35
|
switch (operation) {
|
|
34
36
|
case "check":
|
|
35
|
-
return yield* engine(["toolchain", "check", ...
|
|
37
|
+
return yield* engine(["toolchain", "check", ...words, ...flags]);
|
|
36
38
|
case "ensure": {
|
|
37
39
|
const t = Option.getOrUndefined(config.tool);
|
|
38
40
|
if (t === undefined || !MANAGED.includes(t)) {
|
|
@@ -41,7 +43,12 @@ export const toolchainCommand = Command.make(
|
|
|
41
43
|
return yield* engine(["toolchain", "ensure", t, ...flags]);
|
|
42
44
|
}
|
|
43
45
|
case "outdated":
|
|
44
|
-
return yield* engine([
|
|
46
|
+
return yield* engine([
|
|
47
|
+
"toolchain",
|
|
48
|
+
"outdated",
|
|
49
|
+
...words,
|
|
50
|
+
...(config.refresh ? ["--refresh"] : []),
|
|
51
|
+
]);
|
|
45
52
|
default:
|
|
46
53
|
return yield* bail(
|
|
47
54
|
`Unknown toolchain op '${operation}' (valid: check, ensure, outdated)`,
|
|
@@ -60,9 +60,8 @@ const capturePackageRoot: CapturePackageRoot = (command, args) => {
|
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* A Bun global home is `<root>/.bun/install/global/node_modules/<pkg>`. Windows
|
|
63
|
-
* reports that path with backslashes
|
|
64
|
-
*
|
|
65
|
-
* character and must never be read as a separator there.
|
|
63
|
+
* reports that path with backslashes and compares it without case sensitivity.
|
|
64
|
+
* On POSIX, a backslash remains a legal filename character, not a separator.
|
|
66
65
|
*/
|
|
67
66
|
export const packageManagerForHome = (
|
|
68
67
|
home: string,
|
|
@@ -70,13 +69,14 @@ export const packageManagerForHome = (
|
|
|
70
69
|
host: HostOs = hostOs(),
|
|
71
70
|
): PackageManager => {
|
|
72
71
|
const normalize = (value: string): string =>
|
|
73
|
-
host.id === "windows" ? value.replaceAll("\\", "/") : value;
|
|
72
|
+
host.id === "windows" ? value.replaceAll("\\", "/").toLowerCase() : value;
|
|
74
73
|
const normalizedHome = normalize(home);
|
|
75
74
|
const underEnvironmentRoot = (name: "BUN_INSTALL_GLOBAL_DIR" | "BUN_INSTALL"): boolean => {
|
|
76
75
|
const root = environment[name]?.trim();
|
|
77
76
|
if (root === undefined || root === "") return false;
|
|
78
|
-
const normalizedRoot = normalize(root);
|
|
79
|
-
|
|
77
|
+
const normalizedRoot = normalize(root).replace(/\/+$/, "") || "/";
|
|
78
|
+
const prefix = normalizedRoot.endsWith("/") ? normalizedRoot : `${normalizedRoot}/`;
|
|
79
|
+
return normalizedHome === normalizedRoot || normalizedHome.startsWith(prefix);
|
|
80
80
|
};
|
|
81
81
|
return normalizedHome.includes("/.bun/") ||
|
|
82
82
|
underEnvironmentRoot("BUN_INSTALL_GLOBAL_DIR") ||
|
|
@@ -19,6 +19,9 @@ import {
|
|
|
19
19
|
import { payloadText } from "../payload";
|
|
20
20
|
import type { JsonObject } from "./sharedTypes";
|
|
21
21
|
|
|
22
|
+
/** Claude Code's built-in marketplace: always present, never added or pruned by the kit. */
|
|
23
|
+
const OFFICIAL_MARKETPLACE = "claude-plugins-official";
|
|
24
|
+
|
|
22
25
|
export async function cli(
|
|
23
26
|
args: Array<string>,
|
|
24
27
|
): Promise<{ ok: boolean; out: string; detail: string }> {
|
|
@@ -113,20 +116,38 @@ export async function syncPlugins(ctx: Ctx, claudeDir: string): Promise<void> {
|
|
|
113
116
|
? repoObj["extraKnownMarketplaces"]
|
|
114
117
|
: {};
|
|
115
118
|
const sotPlugins = isObject(repoObj["enabledPlugins"]) ? repoObj["enabledPlugins"] : {};
|
|
116
|
-
|
|
117
|
-
// Pass 1 — add missing marketplaces (SoT insertion order, like to_entries).
|
|
118
|
-
let addedMp = 0;
|
|
119
|
-
let f1 = 0;
|
|
120
|
-
for (const [mpName, mpValue] of Object.entries(sotMarketplaces)) {
|
|
119
|
+
const knownMarketplace = (mpName: string): boolean => {
|
|
121
120
|
const known = readJsonFile(knownMarketplaces);
|
|
122
|
-
|
|
121
|
+
return (
|
|
123
122
|
known !== undefined &&
|
|
124
123
|
isObject(known) &&
|
|
125
124
|
known[mpName] !== undefined &&
|
|
126
125
|
known[mpName] !== null &&
|
|
127
126
|
known[mpName] !== false
|
|
128
|
-
)
|
|
129
|
-
|
|
127
|
+
);
|
|
128
|
+
};
|
|
129
|
+
const addedMarketplaces = new Set<string>();
|
|
130
|
+
// The official marketplace is built in; a successful add is usable before its inventory is written.
|
|
131
|
+
// A missing inventory proves absence (fresh home); an unreadable one does not, so refresh as before.
|
|
132
|
+
const skippedRefresh = new Set<string>();
|
|
133
|
+
const marketplaceReady = (mpName: string): boolean => {
|
|
134
|
+
if (mpName === OFFICIAL_MARKETPLACE || addedMarketplaces.has(mpName)) return true;
|
|
135
|
+
const known = existsSync(knownMarketplaces) ? readJsonFile(knownMarketplaces) : {};
|
|
136
|
+
if (known === undefined || !isObject(known) || knownMarketplace(mpName)) return true;
|
|
137
|
+
if (!skippedRefresh.has(mpName)) {
|
|
138
|
+
skippedRefresh.add(mpName);
|
|
139
|
+
verbose(
|
|
140
|
+
`Skipping refresh of marketplace ${mpName}: not added yet; the next sync refreshes it`,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Pass 1 — add missing marketplaces (SoT insertion order, like to_entries).
|
|
147
|
+
let addedMp = 0;
|
|
148
|
+
let f1 = 0;
|
|
149
|
+
for (const [mpName, mpValue] of Object.entries(sotMarketplaces)) {
|
|
150
|
+
if (knownMarketplace(mpName)) continue;
|
|
130
151
|
const repo =
|
|
131
152
|
isObject(mpValue) && isObject(mpValue["source"])
|
|
132
153
|
? String((mpValue["source"] as JsonObject)["repo"] ?? "")
|
|
@@ -136,6 +157,7 @@ export async function syncPlugins(ctx: Ctx, claudeDir: string): Promise<void> {
|
|
|
136
157
|
clearProgress();
|
|
137
158
|
if (marketplaceResult.ok) {
|
|
138
159
|
addedMp++;
|
|
160
|
+
addedMarketplaces.add(mpName);
|
|
139
161
|
} else {
|
|
140
162
|
recordFailure(
|
|
141
163
|
ctx,
|
|
@@ -156,7 +178,7 @@ export async function syncPlugins(ctx: Ctx, claudeDir: string): Promise<void> {
|
|
|
156
178
|
if (pluginUserScopeInstalled(installedPlugins, pluginId)) continue;
|
|
157
179
|
const separator = pluginId.lastIndexOf("@");
|
|
158
180
|
const mpName = separator > 0 ? pluginId.slice(separator + 1) : "";
|
|
159
|
-
if (mpName !== "" && !refreshedMarketplaces.has(mpName)) {
|
|
181
|
+
if (mpName !== "" && marketplaceReady(mpName) && !refreshedMarketplaces.has(mpName)) {
|
|
160
182
|
progress(`Refreshing marketplace ${mpName}...`);
|
|
161
183
|
const refreshResult = await cli(["plugin", "marketplace", "update", mpName]);
|
|
162
184
|
clearProgress();
|
|
@@ -207,7 +229,7 @@ export async function syncPlugins(ctx: Ctx, claudeDir: string): Promise<void> {
|
|
|
207
229
|
// would duplicate one failure in the ledger and in the failed-operation count.
|
|
208
230
|
if (!ctx.skipPluginRefresh) {
|
|
209
231
|
for (const mpName of [...kitMarketplaces].sort(compareCodepoints)) {
|
|
210
|
-
if (refreshedMarketplaces.has(mpName)) continue;
|
|
232
|
+
if (refreshedMarketplaces.has(mpName) || !marketplaceReady(mpName)) continue;
|
|
211
233
|
progress(`Refreshing marketplace ${mpName}...`);
|
|
212
234
|
const refreshResult = await cli(["plugin", "marketplace", "update", mpName]);
|
|
213
235
|
clearProgress();
|
|
@@ -263,7 +285,7 @@ export async function syncPlugins(ctx: Ctx, claudeDir: string): Promise<void> {
|
|
|
263
285
|
// Pass 6 — prune-gated marketplace removal.
|
|
264
286
|
const known = readJsonFile(knownMarketplaces);
|
|
265
287
|
for (const mpName of sortedKeys(known)) {
|
|
266
|
-
if (mpName ===
|
|
288
|
+
if (mpName === OFFICIAL_MARKETPLACE) continue;
|
|
267
289
|
if (nonUserMarketplaces.has(mpName)) continue;
|
|
268
290
|
if (kitMarketplaces.has(mpName)) continue;
|
|
269
291
|
progress(`Removing marketplace ${mpName}...`);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { copyFileSync, existsSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
8
8
|
|
|
9
9
|
import { payloadDisplayPath } from "../payload";
|
|
10
|
-
import { mergeTableSettings, mergeTopLevelSettings } from "./codexToml";
|
|
10
|
+
import { isTomlHeaderLine, mergeTableSettings, mergeTopLevelSettings } from "./codexToml";
|
|
11
11
|
import type { Ctx } from "./index";
|
|
12
12
|
|
|
13
13
|
// --------------------------------------------------------------- config ----
|
|
@@ -68,14 +68,14 @@ function scrubDeprecatedFeaturesText(content: string): string {
|
|
|
68
68
|
let changed = false;
|
|
69
69
|
for (const line of lines) {
|
|
70
70
|
if (inFeatures) {
|
|
71
|
-
if (line
|
|
71
|
+
if (isTomlHeaderLine(line)) {
|
|
72
72
|
inFeatures = false;
|
|
73
73
|
if (keep) out += `${header}\n${body}`;
|
|
74
74
|
else changed = true;
|
|
75
75
|
out += `${line}\n`;
|
|
76
76
|
continue;
|
|
77
77
|
}
|
|
78
|
-
if (/^use_legacy_landlock[ \t]*=/.test(line)) {
|
|
78
|
+
if (/^[ \t]*use_legacy_landlock[ \t]*=/.test(line)) {
|
|
79
79
|
changed = true;
|
|
80
80
|
continue;
|
|
81
81
|
}
|
|
@@ -83,7 +83,7 @@ function scrubDeprecatedFeaturesText(content: string): string {
|
|
|
83
83
|
if (/[^ \t\f\v\r]/.test(line)) keep = true;
|
|
84
84
|
continue;
|
|
85
85
|
}
|
|
86
|
-
if (
|
|
86
|
+
if (/^[ \t]*\[features\][ \t]*$/.test(line)) {
|
|
87
87
|
inFeatures = true;
|
|
88
88
|
header = line;
|
|
89
89
|
body = "";
|
|
@@ -111,7 +111,7 @@ function scrubDeprecatedFeatures(ctx: Ctx, userConfig: string): void {
|
|
|
111
111
|
change("Codex: scrubbed deprecated [features].use_legacy_landlock");
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
export const PLUGIN_TABLE_HEADER =
|
|
114
|
+
export const PLUGIN_TABLE_HEADER = /^[ \t]*\[plugins\."([^"]+)"\][ \t]*$/;
|
|
115
115
|
/** Plugin ids the kit retired; their deployed tables are stripped on every sync. */
|
|
116
116
|
const RETIRED_PLUGIN_IDS: Readonly<Record<string, true>> = {
|
|
117
117
|
"effect-kit@docks": true,
|
|
@@ -130,7 +130,7 @@ export function removeRetiredPluginTablesText(content: string): string {
|
|
|
130
130
|
skipping = RETIRED_PLUGIN_IDS[header[1]!] === true;
|
|
131
131
|
if (skipping) continue;
|
|
132
132
|
} else if (skipping) {
|
|
133
|
-
if (!line
|
|
133
|
+
if (!isTomlHeaderLine(line)) continue;
|
|
134
134
|
skipping = false;
|
|
135
135
|
}
|
|
136
136
|
out += `${line}\n`;
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
|
|
15
15
|
import { payloadDisplayPath } from "../payload";
|
|
16
16
|
import { PLUGIN_TABLE_HEADER } from "./codexConfig";
|
|
17
|
+
import { isTomlHeaderLine } from "./codexToml";
|
|
17
18
|
import { p, spawnProcess } from "./exec";
|
|
18
19
|
import { recordFailure } from "./failures";
|
|
19
20
|
import type { Ctx } from "./index";
|
|
@@ -107,20 +108,20 @@ function mergeMarketplace(repo: Json, user: Json): Json {
|
|
|
107
108
|
// -------------------------------------------------------------- plugins ----
|
|
108
109
|
|
|
109
110
|
/** codex::_marketplace_source — first `source =` inside [marketplaces.<name>]. */
|
|
110
|
-
function marketplaceSource(marketplace: string, configFile: string): string {
|
|
111
|
+
export function marketplaceSource(marketplace: string, configFile: string): string {
|
|
111
112
|
if (!existsSync(configFile)) return "";
|
|
112
113
|
let inMarketplace = false;
|
|
113
114
|
for (const line of readFileSync(configFile, "utf8").split("\n")) {
|
|
114
|
-
if (line === `[marketplaces.${marketplace}]`) {
|
|
115
|
+
if (line.trim() === `[marketplaces.${marketplace}]`) {
|
|
115
116
|
inMarketplace = true;
|
|
116
117
|
continue;
|
|
117
118
|
}
|
|
118
|
-
if (line
|
|
119
|
+
if (isTomlHeaderLine(line)) inMarketplace = false;
|
|
119
120
|
if (inMarketplace && /^[ \t]*source[ \t]*=/.test(line)) {
|
|
120
121
|
return line
|
|
121
122
|
.replace(/^[^=]+=[ \t]*/, "")
|
|
122
123
|
.replace(/[ \t]*#.*/, "")
|
|
123
|
-
.replace(/^"
|
|
124
|
+
.replace(/^(["'])(.*)\1$/, "$2");
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
127
|
return "";
|
|
@@ -175,7 +176,7 @@ function enabledPluginIdsFromText(configText: string): Array<string> {
|
|
|
175
176
|
enabled = false;
|
|
176
177
|
continue;
|
|
177
178
|
}
|
|
178
|
-
if (line
|
|
179
|
+
if (isTomlHeaderLine(line)) {
|
|
179
180
|
flush();
|
|
180
181
|
plugin = "";
|
|
181
182
|
enabled = false;
|
|
@@ -12,15 +12,19 @@ import { resolveEffort } from "../efforts";
|
|
|
12
12
|
import type { Ctx } from "./index";
|
|
13
13
|
import type { SettingEdit } from "./sharedTypes";
|
|
14
14
|
|
|
15
|
+
export function isTomlHeaderLine(line: string): boolean {
|
|
16
|
+
return /^[ \t]*\[/.test(line);
|
|
17
|
+
}
|
|
18
|
+
|
|
15
19
|
export function replaceTopLevelSetting(content: string, key: string, replacement: string): string {
|
|
16
20
|
const lines = content.split("\n");
|
|
17
21
|
if (lines[lines.length - 1] === "") lines.pop(); // awk records exclude a trailing empty split artifact
|
|
18
|
-
const keyRe = new RegExp(
|
|
22
|
+
const keyRe = new RegExp(`^[ \\t]*${key}[ \\t]*=`);
|
|
19
23
|
const out: Array<string> = [];
|
|
20
24
|
let inTable = false;
|
|
21
25
|
let replaced = false;
|
|
22
26
|
for (const line of lines) {
|
|
23
|
-
if (line
|
|
27
|
+
if (isTomlHeaderLine(line)) {
|
|
24
28
|
if (!replaced) {
|
|
25
29
|
out.push(replacement);
|
|
26
30
|
replaced = true;
|
|
@@ -113,11 +117,11 @@ export function syncCodexEffort(ctx: Ctx, effort: string): void {
|
|
|
113
117
|
|
|
114
118
|
export function mergeTopLevelSettings(sotConfigText: string, userConfig: string): void {
|
|
115
119
|
for (const line of sotConfigText.split("\n")) {
|
|
116
|
-
if (line
|
|
120
|
+
if (isTomlHeaderLine(line)) break;
|
|
117
121
|
if (/^[ \t]*($|#)/.test(line)) continue;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
replaceTopLevelSettingInFile(userConfig,
|
|
122
|
+
const setting = /^[ \t]*([A-Za-z0-9_.-]+)[ \t]*=/.exec(line);
|
|
123
|
+
if (setting === null) continue;
|
|
124
|
+
replaceTopLevelSettingInFile(userConfig, setting[1]!, line);
|
|
121
125
|
}
|
|
122
126
|
}
|
|
123
127
|
|
|
@@ -14,6 +14,7 @@ import { printModels, validateClaudeModel, validateCodexModel } from "./models";
|
|
|
14
14
|
import { defaultLiveInputs, resolveCatalog } from "./liveModels";
|
|
15
15
|
import { bunBootstrap } from "./bun";
|
|
16
16
|
import { installedVersion, outdatedReport, present, report } from "./toolchain";
|
|
17
|
+
import { topLevelTomlString } from "../manifests";
|
|
17
18
|
|
|
18
19
|
export async function modeModel(ctx: Ctx, args: ReadonlyArray<string>): Promise<number> {
|
|
19
20
|
const { echo, err, warn } = ctx.services.logger;
|
|
@@ -59,8 +60,8 @@ export async function modeModel(ctx: Ctx, args: ReadonlyArray<string>): Promise<
|
|
|
59
60
|
err(`Failed to read ~/.codex/config.toml: ${String(result.error)}`);
|
|
60
61
|
return 1;
|
|
61
62
|
}
|
|
62
|
-
echo(`deployed: ${
|
|
63
|
-
echo(`SoT: ${
|
|
63
|
+
echo(`deployed: ${topLevelTomlString(result.data, "model") ?? ""}`);
|
|
64
|
+
echo(`SoT: ${topLevelTomlString(payloadText("SoT/.codex/config.toml"), "model") ?? ""}`);
|
|
64
65
|
}
|
|
65
66
|
printModels(ctx, catalog);
|
|
66
67
|
return 0;
|
|
@@ -112,15 +113,6 @@ function jsonModelText(text: string): string {
|
|
|
112
113
|
return typeof v === "string" ? v : JSON.stringify(v);
|
|
113
114
|
}
|
|
114
115
|
|
|
115
|
-
/** `awk -F'"' '/^model[[:space:]]*=/{print $2; exit}'`. */
|
|
116
|
-
|
|
117
|
-
function tomlModelText(text: string): string {
|
|
118
|
-
for (const line of text.split("\n")) {
|
|
119
|
-
if (/^model[ \t]*=/.test(line)) return line.split('"')[1] ?? "";
|
|
120
|
-
}
|
|
121
|
-
return "";
|
|
122
|
-
}
|
|
123
|
-
|
|
124
116
|
export async function modeToolchain(ctx: Ctx, args: ReadonlyArray<string>): Promise<number> {
|
|
125
117
|
const { echo, err, verbose } = ctx.services.logger;
|
|
126
118
|
const words = args.filter((arg) => !arg.startsWith("--"));
|
|
@@ -129,6 +121,10 @@ export async function modeToolchain(ctx: Ctx, args: ReadonlyArray<string>): Prom
|
|
|
129
121
|
for (const arg of args) {
|
|
130
122
|
if (arg === "--verbose") ctx.verbose = true;
|
|
131
123
|
}
|
|
124
|
+
if (words.length > (op === "ensure" ? 2 : 1)) {
|
|
125
|
+
err("Usage: toolchain [check|ensure <tool>|outdated [--refresh]]");
|
|
126
|
+
return 2;
|
|
127
|
+
}
|
|
132
128
|
|
|
133
129
|
if (op === "check") {
|
|
134
130
|
await report(ctx);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// Generated by cli/scripts/generate-sot-payload.ts. DO NOT EDIT.
|
|
2
2
|
// Edit SoT/, notification.mp3, or package.json, then run: bun cli/scripts/generate-sot-payload.ts
|
|
3
3
|
|
|
4
|
-
export const GENERATED_PACKAGE_VERSION = "0.19.
|
|
4
|
+
export const GENERATED_PACKAGE_VERSION = "0.19.2"
|
|
5
5
|
|
|
6
6
|
export const GENERATED_PAYLOAD_TEXT = {
|
|
7
7
|
"SoT/.agents/skills.txt": "# Universal AI-agent skill manifest intentionally empty.\n# Global skill discovery is opt-in: add one <owner>/<repo> slug per line.\n# EngineNative ignores comments and blank lines.\n",
|
|
8
8
|
"SoT/models.json": "{\n \"$comment\": \"Curated overlay for docks-kit model listings: aliases (kind alias) and notes always apply; the id rows are the fallback when the harness's live list is unavailable (harness not enabled, no login or cache, offline). Live sources: Claude via the Claude Code login against the Anthropic models API (cached 6 h in ~/.docks-kit/kit.db), Codex via ~/.codex/models_cache.json, omp via omp models --json.\",\n \"claude\": {\n \"verified\": \"2026-09-22\",\n \"models\": [\n { \"id\": \"best\", \"kind\": \"alias\", \"note\": \"Fable 5.1 where the org has access, latest Opus otherwise (Claude Code >=2.1.257; Claude apps gateway sessions still resolve Fable 5)\" },\n { \"id\": \"opus\", \"kind\": \"alias\", \"note\": \"latest Opus — the kit SoT default (Opus 5.5 from Claude Code >=2.1.280)\" },\n { \"id\": \"fable\", \"kind\": \"alias\", \"note\": \"Fable 5.1 — needs org access + Claude Code >=2.1.257 (Claude apps gateway sessions still resolve Fable 5)\" },\n { \"id\": \"sonnet\", \"kind\": \"alias\", \"note\": \"latest Sonnet (currently Sonnet 5)\" },\n { \"id\": \"haiku\", \"kind\": \"alias\", \"note\": \"latest Haiku (currently Haiku 4.5)\" },\n { \"id\": \"default\", \"kind\": \"alias\", \"note\": \"engine pseudo-value: deletes the deployed model key so the account default applies\" },\n { \"id\": \"claude-opus-5-5\", \"kind\": \"id\", \"note\": \"Opus 5.5 — needs Claude Code >=2.1.280\" },\n { \"id\": \"claude-fable-5-1\", \"kind\": \"id\", \"note\": \"Fable 5.1 — needs Claude Code >=2.1.257\" },\n { \"id\": \"claude-fable-5\", \"kind\": \"id\", \"note\": \"Fable 5 (legacy)\" },\n { \"id\": \"claude-opus-5\", \"kind\": \"id\", \"note\": \"Opus 5 (legacy)\" },\n { \"id\": \"claude-opus-4-8\", \"kind\": \"id\", \"note\": \"Opus 4.8 (legacy)\" },\n { \"id\": \"claude-sonnet-5\", \"kind\": \"id\", \"note\": \"Sonnet 5\" },\n { \"id\": \"claude-haiku-4-5-20251001\", \"kind\": \"id\", \"note\": \"Haiku 4.5\" }\n ]\n },\n \"codex\": {\n \"verified\": \"2026-09-22\",\n \"models\": [\n { \"id\": \"gpt-6-sol\", \"kind\": \"id\", \"note\": \"GPT-6 Sol — complex coding and agentic work, recommended default; the kit SoT pin\" },\n { \"id\": \"gpt-6-luna\", \"kind\": \"id\", \"note\": \"GPT-6 Luna — fast/light tier\" },\n { \"id\": \"gpt-6-astra\", \"kind\": \"id\", \"note\": \"GPT-6 Astra — most capable, highest cost\" },\n { \"id\": \"gpt-5.6-sol\", \"kind\": \"id\", \"note\": \"previous generation\" },\n { \"id\": \"gpt-5.6-terra\", \"kind\": \"id\", \"note\": \"previous generation, balanced tier\" },\n { \"id\": \"gpt-5.6-luna\", \"kind\": \"id\", \"note\": \"previous generation\" },\n { \"id\": \"gpt-5.5\", \"kind\": \"id\", \"note\": \"previous generation\" },\n { \"id\": \"gpt-5.5-codex\", \"kind\": \"id\", \"note\": \"codex-tuned gpt-5.5\" },\n { \"id\": \"gpt-5.1\", \"kind\": \"id\", \"note\": \"previous generation\" },\n { \"id\": \"gpt-5\", \"kind\": \"id\", \"note\": \"previous generation\" },\n { \"id\": \"gpt-5-codex\", \"kind\": \"id\", \"note\": \"codex-tuned gpt-5\" }\n ]\n }\n}\n",
|
|
9
|
-
"SoT/toolchain.json": "{\n \"$comment\": \"Kit toolchain manifest - DATA only (versions, floors, policy); version probing and the doctor report live in cli/src/engine-native/toolchain.ts, and the one managed install lives in cli/src/engine-native/bun.ts bunBootstrap. kind: check (doctor visibility only) | managed (kit installs it when missing) | pin (no binary probe - a version pin for a package the kit installs through another tool, such as npx or `omp install`). policy (managed only): present (install when missing, never upgrade). `verified` = last kit-tested version; `pinnable` marks a tool whose `verified` release the bootstrap can install by exact tag. Supply-chain stance: every kit-driven install is pinned to `verified` - never floating @latest (npm-worm/Shai-Hulud surface). Update `verified` after testing a new release. upstream (optional) names where `docks-kit toolchain outdated` reads the newest release: npm package (optional major line) or GitHub repo releases with a tag prefix; results cache 24 h in ~/.docks-kit/kit.db; the report never installs or edits pins.\",\n \"tools\": {\n \"jq\": { \"kind\": \"check\", \"note\": \"optional operator CLI; EngineNative JSON and Claude runtime do not invoke it\" },\n \"curl\": { \"kind\": \"check\", \"note\": \"POSIX installer transport for the Bun bootstrap\" },\n \"git\": { \"kind\": \"check\", \"note\": \"plugin marketplaces (claude/codex clone them) + kit checkout updates\" },\n \"node\": { \"kind\": \"check\", \"floor\": \"22.22.2\",\n \"note\": \"hosts the npm globals installed for the Claude LSP plugins; the floor is typescript-language-server 6's engines requirement, so an older Node reports `below-floor` in `docks-kit toolchain` instead of silently installing an LSP server that cannot start\" },\n \"npm\": { \"kind\": \"check\", \"note\": \"npm-global installer; also backs the intelephense version probe (`npm ls -g`)\" },\n \"claude\": { \"kind\": \"check\", \"floor\": \"2.1.280\", \"note\": \"kit floor — lets the `opus` alias resolve to Opus 5.5, the default Opus from Claude Code 2.1.280, and subsumes the older Fable 5.1 (>=2.1.257) and Opus 5 (>=2.1.219) requirements (mirrors settings minimumVersion)\" },\n \"codex\": { \"kind\": \"check\", \"note\": \"upstream-owned; standalone installer prints when missing\" },\n \"omp\": { \"kind\": \"check\", \"floor\": \"18.0.8\", \"verified\": \"18.
|
|
9
|
+
"SoT/toolchain.json": "{\n \"$comment\": \"Kit toolchain manifest - DATA only (versions, floors, policy); version probing and the doctor report live in cli/src/engine-native/toolchain.ts, and the one managed install lives in cli/src/engine-native/bun.ts bunBootstrap. kind: check (doctor visibility only) | managed (kit installs it when missing) | pin (no binary probe - a version pin for a package the kit installs through another tool, such as npx or `omp install`). policy (managed only): present (install when missing, never upgrade). `verified` = last kit-tested version; `pinnable` marks a tool whose `verified` release the bootstrap can install by exact tag. Supply-chain stance: every kit-driven install is pinned to `verified` - never floating @latest (npm-worm/Shai-Hulud surface). Update `verified` after testing a new release. upstream (optional) names where `docks-kit toolchain outdated` reads the newest release: npm package (optional major line) or GitHub repo releases with a tag prefix; results cache 24 h in ~/.docks-kit/kit.db; the report never installs or edits pins.\",\n \"tools\": {\n \"jq\": { \"kind\": \"check\", \"note\": \"optional operator CLI; EngineNative JSON and Claude runtime do not invoke it\" },\n \"curl\": { \"kind\": \"check\", \"note\": \"POSIX installer transport for the Bun bootstrap\" },\n \"git\": { \"kind\": \"check\", \"note\": \"plugin marketplaces (claude/codex clone them) + kit checkout updates\" },\n \"node\": { \"kind\": \"check\", \"floor\": \"22.22.2\",\n \"note\": \"hosts the npm globals installed for the Claude LSP plugins; the floor is typescript-language-server 6's engines requirement, so an older Node reports `below-floor` in `docks-kit toolchain` instead of silently installing an LSP server that cannot start\" },\n \"npm\": { \"kind\": \"check\", \"note\": \"npm-global installer; also backs the intelephense version probe (`npm ls -g`)\" },\n \"claude\": { \"kind\": \"check\", \"floor\": \"2.1.280\", \"note\": \"kit floor — lets the `opus` alias resolve to Opus 5.5, the default Opus from Claude Code 2.1.280, and subsumes the older Fable 5.1 (>=2.1.257) and Opus 5 (>=2.1.219) requirements (mirrors settings minimumVersion)\" },\n \"codex\": { \"kind\": \"check\", \"note\": \"upstream-owned; standalone installer prints when missing\" },\n \"omp\": { \"kind\": \"check\", \"floor\": \"18.0.8\", \"verified\": \"18.3.1\",\n \"upstream\": { \"github\": \"can1357/oh-my-pi\", \"tagPrefix\": \"v\" },\n \"note\": \"Oh My Pi harness (https://github.com/can1357/oh-my-pi); upstream-owned and self-updating through `omp update`, so sync never installs or upgrades it. `sync omp` needs the CLI only for the marketplace and plugin passes; the file deploys proceed without it\" },\n \"ffplay\": { \"kind\": \"check\", \"note\": \"Notification hook sound; distro-installed, so no kit floor applies\" },\n \"bwrap\": { \"kind\": \"check\", \"os\": \"linux\", \"floor\": \"0.9.0\",\n \"note\": \"Codex Linux sandbox runtime; sync installs it via the distro package manager, so the floor is the kit-tested baseline (Ubuntu 24.04 LTS) and no verified pin applies\" },\n \"intelephense\": { \"kind\": \"check\", \"floor\": \"1.18.5\", \"verified\": \"1.18.5\",\n \"upstream\": { \"npm\": \"intelephense\" },\n \"note\": \"php-lsp server; `verified` pins claudeSync syncLspServers' npm install. Version comes from `npm ls -g` — its own --version prints minified source\" },\n \"typescript-language-server\": { \"kind\": \"check\", \"floor\": \"6.0.0\", \"verified\": \"6.0.1\",\n \"upstream\": { \"npm\": \"typescript-language-server\" },\n \"note\": \"typescript-lsp server binary; `verified` pins claudeSync syncLspServers' npm install. Version 6 requires Node >=22.22.2 (see the `node` floor)\" },\n \"rust-analyzer\": { \"kind\": \"check\",\n \"note\": \"rust-analyzer-lsp server binary; claudeSync syncLspServers installs it with `rustup component add rust-analyzer` when rustup is present, so the version follows the host Rust toolchain and no verified pin applies (the bubblewrap stance for a tool the kit does not publish). A host without rustup is skipped in silence\" },\n \"tsc\": { \"kind\": \"check\", \"floor\": \"6.0.3\", \"verified\": \"6.0.3\",\n \"upstream\": { \"npm\": \"typescript\", \"line\": \"6\" }, \"note\": \"typescript-lsp dependency (npm package `typescript`); `verified` pins claudeSync syncLspServers' npm install. Deliberately on the 6.x line: typescript-language-server embeds TypeScript's programmatic API, which TS7 (native) doesn't yet expose — the repo's own devDependency runs TS7 for tsc --noEmit\" },\n \"bun\": { \"kind\": \"managed\", \"policy\": \"present\", \"floor\": \"1.4.0\", \"verified\": \"1.4.2\", \"pinnable\": true,\n \"upstream\": { \"github\": \"oven-sh/bun\", \"tagPrefix\": \"bun-v\" },\n \"note\": \"runtime for the docks-kit CLI and the Claude statusline/hook programs; bootstrap installs the verified release (installer takes bun-vX.Y.Z); self-updates via `bun upgrade` when wanted\" },\n \"skills-cli\": { \"kind\": \"pin\", \"verified\": \"1.7.0\",\n \"upstream\": { \"npm\": \"skills\" },\n \"note\": \"the `skills` npm package the kit runs via `npx skills@<verified>` when SoT/.agents/skills.txt names a slug (it is empty by default) — pinned, never @latest\" },\n \"pi-intercom\": { \"kind\": \"pin\", \"verified\": \"0.14.0\",\n \"upstream\": { \"npm\": \"pi-intercom\" },\n \"note\": \"the cross-session messaging plugin ompSync installs with `omp install pi-intercom@<verified>` - pinned, never floating. Its broker runs under Bun because omp's flat plugin store cannot resolve the default `npx --no-install tsx` launcher\" }\n }\n}\n",
|
|
10
10
|
"SoT/.claude/CLAUDE.md": "## Research Before Implementation\n\nBefore writing or modifying code that uses an API, hook, method, or config surface you have not verified in this session, research current documentation first.\n\nResearch workflow:\n1. Prefer official documentation and primary sources for the specific library, framework, or API.\n2. If a local docs or MCP tool is available, use it before broad web search.\n3. Only then proceed to implementation.\n\nResearch when:\n- Installing or configuring a dependency.\n- Using an API, hook, method, or pattern not verified in this session.\n- Upgrading or migrating between versions.\n- Any task where relying on memory could cause stale syntax or behavior.\n\nDo not:\n- Assume API signatures, method names, or config options from memory.\n- Generate framework code without checking current docs first.\n- Skip research because the library seems familiar.\n\n<constraint>\nResearch the codebase before editing. Never change code you have not read.\n</constraint>\n\n## Agentic Harness Heuristics\n\n**1. Persistence.** Keep going until the user's query is completely resolved. Only yield when sure the problem is solved. Before ending a turn, check the last paragraph: if it is a plan, a question you can answer yourself, or a promise of work not done (\"I'll…\"), do that work now.\n\n**2. Default to parallel.** Whenever you have multiple independent operations (reads, greps, web fetches, independent edits), invoke them in a single response with multiple tool-use blocks. Sequential calls only when output of one operation is required as input to the next.\n\n**3. Multi-pass search.** First-pass search often misses — vary the wording (colleague-questions over keywords) before concluding something doesn't exist.\n\n**4. Trace symbols.** Before modifying a symbol, trace it to its definitions and all usages. Don't assume a function's behavior or a type's shape from the call site alone.\n\n**5. Linter-loop 3-strike rule.** Don't loop more than 3 times fixing linter errors on the same file. On the third attempt, stop and ask the user — repeated failure usually means the diagnosis is wrong, not the code.\n\n**6. Read-before-Edit TTL.** If you haven't read a file with the Read tool in the last ~5 messages, re-read it before editing. Cached file content goes stale silently when the user edits between turns.\n\n**7. Big-file rule.** For files >1000 lines, prefer Grep + scoped Read (`offset` + `limit`) over reading the entire file. Whole-file reads bloat context; targeted reads keep the working set small.\n\n**8. Todo hygiene.** Use TaskCreate for items with meaningful outcome (≥5 min, distinct deliverable). Never include operational sub-actions (linting, testing, searching, examining the codebase) as their own todos — those are sub-steps in service of higher-level tasks. Mark complete immediately when done, never in batches.\n\n**9. Literal-instruction rule.** Current frontier models follow instructions literally — they do not silently generalize from intent. Phrase requirements as explicit checklists with success criteria, not narrative.\n\n**10. Context hygiene.** Prefer `/clear` at task boundaries and `/rewind` for wrong-path detours over carrying rot forward (corrections accumulate noise; rewinds preserve the prefix and discard the bad branch). On a continuing task, run `/compact` with steering before context quality degrades. Never stop, summarize, or suggest a new session on account of context limits.\n\n**11. Autonomy calibration.** For minor choices (naming, formatting, default values, which of two equivalent approaches), pick a reasonable option and note it — don't ask. Ask first only for scope changes, destructive actions, or decisions that change the deliverable. When the user is describing a problem or asking a question rather than requesting a change, the deliverable is your assessment — report findings and stop; don't apply fixes until asked. Don't close a finished task with \"Want me to also…?\" — run the obvious verification, then stop cleanly.\n\n**12. Capability triggering.** When the answer depends on current or version-specific information, search or fetch before answering — never answer from memory. When work fans out across independent items (many files to read, many tests to run, many candidates to check), delegate to parallel subagents; never spawn one for work you can complete directly. For verification, prefer a fresh-context subagent over self-critique. On tasks longer than a few turns, keep a running notes file and re-read it before each phase.\n\n<constraint>\nTreat the 12 heuristics above as protocol, not preference. If a turn ends without honoring an applicable one (e.g., lint-loop guard not respected, edit without re-read), self-correct in the next turn before continuing.\n</constraint>\n\nReuse before invention: inventory existing code, components, conventions, and dependencies; extend them instead of creating a parallel pattern. Load only the narrow skills supported by the task and repository evidence. If a request establishes a new React/Tailwind system and no convention exists, prefer current shadcn/ui `base-*` components backed by Base UI; otherwise preserve the existing stack. Treat probe, production access, publish, push, release, and deploy as literal current-request effects—never infer external authority from a plan, schedule, review, or old receipt.\n\nFor Docks plan reviews, cross-company review is standing-authorized; do not ask for export consent. This never overrides a host or platform security denial.\n\nUse a narrow-to-broad verification ladder: direct acceptance while iterating, focused regressions next, and one full CI at the pre-commit or release boundary. Reuse still-matching evidence; rerun full CI only after a relevant edit invalidates it.\n\n<constraint>\nNo secrets in committed config. Treat plugin marketplaces, installers, and downloaded artifacts as untrusted until verified.\n</constraint>\n",
|
|
11
11
|
"SoT/.claude/mcp-servers.json": "{\n \"mcpServers\": {}\n}\n",
|
|
12
12
|
"SoT/.claude/settings.json": "{\n \"$schema\": \"https://json.schemastore.org/claude-code-settings.json\",\n \"minimumVersion\": \"2.1.280\",\n \"model\": \"opus\",\n \"effortLevel\": \"high\",\n \"autoMemoryEnabled\": false,\n \"autoDreamEnabled\": false,\n \"skillListingMaxDescChars\": 2048,\n \"respectGitignore\": true,\n \"cleanupPeriodDays\": 14,\n \"skillListingBudgetFraction\": 0.05,\n \"env\": {\n \"CLAUDE_CODE_MAX_OUTPUT_TOKENS\": \"64000\",\n \"CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR\": \"1\",\n \"CLAUDE_CODE_AUTO_COMPACT_WINDOW\": \"468000\",\n \"CLAUDE_CODE_NO_FLICKER\": \"1\"\n },\n \"permissions\": {\n \"defaultMode\": \"auto\",\n \"allow\": [\n \"Read\",\n \"Glob\",\n \"Grep\",\n \"WebSearch\",\n \"Edit(./)\"\n ],\n \"deny\": [\n \"Read(**/.env)\",\n \"Read(**/.env.local)\",\n \"Read(**/secrets/**)\",\n \"Read(**/*.key)\",\n \"Read(**/*.pem)\",\n \"Read(**/*.p12)\",\n \"Read(**/.credentials*)\",\n \"Edit(**/.env)\",\n \"Edit(**/.env.local)\",\n \"Edit(**/secrets/**)\",\n \"Bash(sudo *)\",\n \"Bash(rm -rf /)\",\n \"Bash(rm -rf / *)\",\n \"Bash(rm -rf ~)\",\n \"Bash(rm -rf ~ *)\",\n \"Bash(rm -rf $HOME)\",\n \"Bash(rm -rf $HOME *)\",\n \"Bash(> /dev *)\",\n \"Bash(dd if= *)\",\n \"Bash(mkfs *)\",\n \"Bash(eval *)\",\n \"Bash(chmod 777 *)\",\n \"Bash(chmod -R 777 *)\",\n \"Bash(git push --force origin main *)\",\n \"Bash(git push --force origin master *)\",\n \"Bash(git push -f origin main *)\",\n \"Bash(git push -f origin master *)\",\n \"PowerShell(sudo *)\",\n \"PowerShell(rm -rf /)\",\n \"PowerShell(rm -rf / *)\",\n \"PowerShell(rm -rf ~)\",\n \"PowerShell(rm -rf ~ *)\",\n \"PowerShell(rm -rf $HOME)\",\n \"PowerShell(rm -rf $HOME *)\",\n \"PowerShell(> /dev *)\",\n \"PowerShell(dd if= *)\",\n \"PowerShell(mkfs *)\",\n \"PowerShell(eval *)\",\n \"PowerShell(chmod 777 *)\",\n \"PowerShell(chmod -R 777 *)\",\n \"PowerShell(git push --force origin main *)\",\n \"PowerShell(git push --force origin master *)\",\n \"PowerShell(git push -f origin main *)\",\n \"PowerShell(git push -f origin master *)\",\n \"PowerShell(Remove-Item *-Recurse* /)\",\n \"PowerShell(Remove-Item *-Recurse* / *)\",\n \"PowerShell(Remove-Item / *-Recurse*)\",\n \"PowerShell(Remove-Item -Path / *-Recurse*)\",\n \"PowerShell(Remove-Item -LiteralPath / *-Recurse*)\",\n \"PowerShell(Remove-Item *-Recurse* ~)\",\n \"PowerShell(Remove-Item *-Recurse* ~ *)\",\n \"PowerShell(Remove-Item ~ *-Recurse*)\",\n \"PowerShell(Remove-Item -Path ~ *-Recurse*)\",\n \"PowerShell(Remove-Item -LiteralPath ~ *-Recurse*)\",\n \"PowerShell(Remove-Item *-Recurse* $HOME)\",\n \"PowerShell(Remove-Item *-Recurse* $HOME *)\",\n \"PowerShell(Remove-Item $HOME *-Recurse*)\",\n \"PowerShell(Remove-Item -Path $HOME *-Recurse*)\",\n \"PowerShell(Remove-Item -LiteralPath $HOME *-Recurse*)\",\n \"PowerShell(Remove-Item *-Recurse* $env:USERPROFILE)\",\n \"PowerShell(Remove-Item *-Recurse* $env:USERPROFILE *)\",\n \"PowerShell(Remove-Item $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(Remove-Item -Path $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(Remove-Item -LiteralPath $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(Remove-Item *-Recurse* \\\\\\\\)\",\n \"PowerShell(Remove-Item *-Recurse* \\\\ *)\",\n \"PowerShell(Remove-Item \\\\ *-Recurse*)\",\n \"PowerShell(Remove-Item -Path \\\\ *-Recurse*)\",\n \"PowerShell(Remove-Item -LiteralPath \\\\ *-Recurse*)\",\n \"PowerShell(Remove-Item *-Recurse* *:\\\\\\\\)\",\n \"PowerShell(Remove-Item *-Recurse* *:\\\\ *)\",\n \"PowerShell(Remove-Item *:\\\\ *-Recurse*)\",\n \"PowerShell(Remove-Item -Path *:\\\\ *-Recurse*)\",\n \"PowerShell(Remove-Item -LiteralPath *:\\\\ *-Recurse*)\",\n \"PowerShell(del *-Recurse* /)\",\n \"PowerShell(del *-Recurse* / *)\",\n \"PowerShell(del / *-Recurse*)\",\n \"PowerShell(del -Path / *-Recurse*)\",\n \"PowerShell(del -LiteralPath / *-Recurse*)\",\n \"PowerShell(del *-Recurse* ~)\",\n \"PowerShell(del *-Recurse* ~ *)\",\n \"PowerShell(del ~ *-Recurse*)\",\n \"PowerShell(del -Path ~ *-Recurse*)\",\n \"PowerShell(del -LiteralPath ~ *-Recurse*)\",\n \"PowerShell(del *-Recurse* $HOME)\",\n \"PowerShell(del *-Recurse* $HOME *)\",\n \"PowerShell(del $HOME *-Recurse*)\",\n \"PowerShell(del -Path $HOME *-Recurse*)\",\n \"PowerShell(del -LiteralPath $HOME *-Recurse*)\",\n \"PowerShell(del *-Recurse* $env:USERPROFILE)\",\n \"PowerShell(del *-Recurse* $env:USERPROFILE *)\",\n \"PowerShell(del $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(del -Path $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(del -LiteralPath $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(del *-Recurse* \\\\\\\\)\",\n \"PowerShell(del *-Recurse* \\\\ *)\",\n \"PowerShell(del \\\\ *-Recurse*)\",\n \"PowerShell(del -Path \\\\ *-Recurse*)\",\n \"PowerShell(del -LiteralPath \\\\ *-Recurse*)\",\n \"PowerShell(del *-Recurse* *:\\\\\\\\)\",\n \"PowerShell(del *-Recurse* *:\\\\ *)\",\n \"PowerShell(del *:\\\\ *-Recurse*)\",\n \"PowerShell(del -Path *:\\\\ *-Recurse*)\",\n \"PowerShell(del -LiteralPath *:\\\\ *-Recurse*)\",\n \"PowerShell(erase *-Recurse* /)\",\n \"PowerShell(erase *-Recurse* / *)\",\n \"PowerShell(erase / *-Recurse*)\",\n \"PowerShell(erase -Path / *-Recurse*)\",\n \"PowerShell(erase -LiteralPath / *-Recurse*)\",\n \"PowerShell(erase *-Recurse* ~)\",\n \"PowerShell(erase *-Recurse* ~ *)\",\n \"PowerShell(erase ~ *-Recurse*)\",\n \"PowerShell(erase -Path ~ *-Recurse*)\",\n \"PowerShell(erase -LiteralPath ~ *-Recurse*)\",\n \"PowerShell(erase *-Recurse* $HOME)\",\n \"PowerShell(erase *-Recurse* $HOME *)\",\n \"PowerShell(erase $HOME *-Recurse*)\",\n \"PowerShell(erase -Path $HOME *-Recurse*)\",\n \"PowerShell(erase -LiteralPath $HOME *-Recurse*)\",\n \"PowerShell(erase *-Recurse* $env:USERPROFILE)\",\n \"PowerShell(erase *-Recurse* $env:USERPROFILE *)\",\n \"PowerShell(erase $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(erase -Path $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(erase -LiteralPath $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(erase *-Recurse* \\\\\\\\)\",\n \"PowerShell(erase *-Recurse* \\\\ *)\",\n \"PowerShell(erase \\\\ *-Recurse*)\",\n \"PowerShell(erase -Path \\\\ *-Recurse*)\",\n \"PowerShell(erase -LiteralPath \\\\ *-Recurse*)\",\n \"PowerShell(erase *-Recurse* *:\\\\\\\\)\",\n \"PowerShell(erase *-Recurse* *:\\\\ *)\",\n \"PowerShell(erase *:\\\\ *-Recurse*)\",\n \"PowerShell(erase -Path *:\\\\ *-Recurse*)\",\n \"PowerShell(erase -LiteralPath *:\\\\ *-Recurse*)\",\n \"PowerShell(rd *-Recurse* /)\",\n \"PowerShell(rd *-Recurse* / *)\",\n \"PowerShell(rd / *-Recurse*)\",\n \"PowerShell(rd -Path / *-Recurse*)\",\n \"PowerShell(rd -LiteralPath / *-Recurse*)\",\n \"PowerShell(rd *-Recurse* ~)\",\n \"PowerShell(rd *-Recurse* ~ *)\",\n \"PowerShell(rd ~ *-Recurse*)\",\n \"PowerShell(rd -Path ~ *-Recurse*)\",\n \"PowerShell(rd -LiteralPath ~ *-Recurse*)\",\n \"PowerShell(rd *-Recurse* $HOME)\",\n \"PowerShell(rd *-Recurse* $HOME *)\",\n \"PowerShell(rd $HOME *-Recurse*)\",\n \"PowerShell(rd -Path $HOME *-Recurse*)\",\n \"PowerShell(rd -LiteralPath $HOME *-Recurse*)\",\n \"PowerShell(rd *-Recurse* $env:USERPROFILE)\",\n \"PowerShell(rd *-Recurse* $env:USERPROFILE *)\",\n \"PowerShell(rd $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(rd -Path $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(rd -LiteralPath $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(rd *-Recurse* \\\\\\\\)\",\n \"PowerShell(rd *-Recurse* \\\\ *)\",\n \"PowerShell(rd \\\\ *-Recurse*)\",\n \"PowerShell(rd -Path \\\\ *-Recurse*)\",\n \"PowerShell(rd -LiteralPath \\\\ *-Recurse*)\",\n \"PowerShell(rd *-Recurse* *:\\\\\\\\)\",\n \"PowerShell(rd *-Recurse* *:\\\\ *)\",\n \"PowerShell(rd *:\\\\ *-Recurse*)\",\n \"PowerShell(rd -Path *:\\\\ *-Recurse*)\",\n \"PowerShell(rd -LiteralPath *:\\\\ *-Recurse*)\",\n \"PowerShell(ri *-Recurse* /)\",\n \"PowerShell(ri *-Recurse* / *)\",\n \"PowerShell(ri / *-Recurse*)\",\n \"PowerShell(ri -Path / *-Recurse*)\",\n \"PowerShell(ri -LiteralPath / *-Recurse*)\",\n \"PowerShell(ri *-Recurse* ~)\",\n \"PowerShell(ri *-Recurse* ~ *)\",\n \"PowerShell(ri ~ *-Recurse*)\",\n \"PowerShell(ri -Path ~ *-Recurse*)\",\n \"PowerShell(ri -LiteralPath ~ *-Recurse*)\",\n \"PowerShell(ri *-Recurse* $HOME)\",\n \"PowerShell(ri *-Recurse* $HOME *)\",\n \"PowerShell(ri $HOME *-Recurse*)\",\n \"PowerShell(ri -Path $HOME *-Recurse*)\",\n \"PowerShell(ri -LiteralPath $HOME *-Recurse*)\",\n \"PowerShell(ri *-Recurse* $env:USERPROFILE)\",\n \"PowerShell(ri *-Recurse* $env:USERPROFILE *)\",\n \"PowerShell(ri $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(ri -Path $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(ri -LiteralPath $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(ri *-Recurse* \\\\\\\\)\",\n \"PowerShell(ri *-Recurse* \\\\ *)\",\n \"PowerShell(ri \\\\ *-Recurse*)\",\n \"PowerShell(ri -Path \\\\ *-Recurse*)\",\n \"PowerShell(ri -LiteralPath \\\\ *-Recurse*)\",\n \"PowerShell(ri *-Recurse* *:\\\\\\\\)\",\n \"PowerShell(ri *-Recurse* *:\\\\ *)\",\n \"PowerShell(ri *:\\\\ *-Recurse*)\",\n \"PowerShell(ri -Path *:\\\\ *-Recurse*)\",\n \"PowerShell(ri -LiteralPath *:\\\\ *-Recurse*)\",\n \"PowerShell(rm *-Recurse* /)\",\n \"PowerShell(rm *-Recurse* / *)\",\n \"PowerShell(rm / *-Recurse*)\",\n \"PowerShell(rm -Path / *-Recurse*)\",\n \"PowerShell(rm -LiteralPath / *-Recurse*)\",\n \"PowerShell(rm *-Recurse* ~)\",\n \"PowerShell(rm *-Recurse* ~ *)\",\n \"PowerShell(rm ~ *-Recurse*)\",\n \"PowerShell(rm -Path ~ *-Recurse*)\",\n \"PowerShell(rm -LiteralPath ~ *-Recurse*)\",\n \"PowerShell(rm *-Recurse* $HOME)\",\n \"PowerShell(rm *-Recurse* $HOME *)\",\n \"PowerShell(rm $HOME *-Recurse*)\",\n \"PowerShell(rm -Path $HOME *-Recurse*)\",\n \"PowerShell(rm -LiteralPath $HOME *-Recurse*)\",\n \"PowerShell(rm *-Recurse* $env:USERPROFILE)\",\n \"PowerShell(rm *-Recurse* $env:USERPROFILE *)\",\n \"PowerShell(rm $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(rm -Path $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(rm -LiteralPath $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(rm *-Recurse* \\\\\\\\)\",\n \"PowerShell(rm *-Recurse* \\\\ *)\",\n \"PowerShell(rm \\\\ *-Recurse*)\",\n \"PowerShell(rm -Path \\\\ *-Recurse*)\",\n \"PowerShell(rm -LiteralPath \\\\ *-Recurse*)\",\n \"PowerShell(rm *-Recurse* *:\\\\\\\\)\",\n \"PowerShell(rm *-Recurse* *:\\\\ *)\",\n \"PowerShell(rm *:\\\\ *-Recurse*)\",\n \"PowerShell(rm -Path *:\\\\ *-Recurse*)\",\n \"PowerShell(rm -LiteralPath *:\\\\ *-Recurse*)\",\n \"PowerShell(rmdir *-Recurse* /)\",\n \"PowerShell(rmdir *-Recurse* / *)\",\n \"PowerShell(rmdir / *-Recurse*)\",\n \"PowerShell(rmdir -Path / *-Recurse*)\",\n \"PowerShell(rmdir -LiteralPath / *-Recurse*)\",\n \"PowerShell(rmdir *-Recurse* ~)\",\n \"PowerShell(rmdir *-Recurse* ~ *)\",\n \"PowerShell(rmdir ~ *-Recurse*)\",\n \"PowerShell(rmdir -Path ~ *-Recurse*)\",\n \"PowerShell(rmdir -LiteralPath ~ *-Recurse*)\",\n \"PowerShell(rmdir *-Recurse* $HOME)\",\n \"PowerShell(rmdir *-Recurse* $HOME *)\",\n \"PowerShell(rmdir $HOME *-Recurse*)\",\n \"PowerShell(rmdir -Path $HOME *-Recurse*)\",\n \"PowerShell(rmdir -LiteralPath $HOME *-Recurse*)\",\n \"PowerShell(rmdir *-Recurse* $env:USERPROFILE)\",\n \"PowerShell(rmdir *-Recurse* $env:USERPROFILE *)\",\n \"PowerShell(rmdir $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(rmdir -Path $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(rmdir -LiteralPath $env:USERPROFILE *-Recurse*)\",\n \"PowerShell(rmdir *-Recurse* \\\\\\\\)\",\n \"PowerShell(rmdir *-Recurse* \\\\ *)\",\n \"PowerShell(rmdir \\\\ *-Recurse*)\",\n \"PowerShell(rmdir -Path \\\\ *-Recurse*)\",\n \"PowerShell(rmdir -LiteralPath \\\\ *-Recurse*)\",\n \"PowerShell(rmdir *-Recurse* *:\\\\\\\\)\",\n \"PowerShell(rmdir *-Recurse* *:\\\\ *)\",\n \"PowerShell(rmdir *:\\\\ *-Recurse*)\",\n \"PowerShell(rmdir -Path *:\\\\ *-Recurse*)\",\n \"PowerShell(rmdir -LiteralPath *:\\\\ *-Recurse*)\",\n \"PowerShell(Start-Process *-Verb RunAs*)\",\n \"PowerShell(Invoke-Expression *)\",\n \"PowerShell(iex *)\",\n \"PowerShell(Format-Volume *)\",\n \"PowerShell(icacls */grant*Everyone:F*)\",\n \"PowerShell(icacls */grant*Everyone:(F)*)\"\n ],\n \"ask\": [\n \"Bash(git clean *)\",\n \"Bash(docker volume rm *)\",\n \"Bash(docker system prune *)\",\n \"PowerShell(git clean *)\",\n \"PowerShell(docker volume rm *)\",\n \"PowerShell(docker system prune *)\"\n ]\n },\n \"hooks\": {\n \"SessionStart\": [\n {\n \"hooks\": [\n {\n \"type\": \"command\",\n \"command\": \"__DOCKS_KIT_BUN__\",\n \"args\": [\"__DOCKS_KIT_SESSION_START__\"],\n \"timeout\": 5\n }\n ]\n }\n ],\n \"Notification\": [\n {\n \"hooks\": [\n {\n \"type\": \"command\",\n \"command\": \"__DOCKS_KIT_BUN__\",\n \"args\": [\"__DOCKS_KIT_NOTIFY__\"],\n \"timeout\": 10,\n \"async\": true\n }\n ]\n }\n ],\n \"PostToolUseFailure\": [\n {\n \"matcher\": \"Bash|PowerShell\",\n \"hooks\": [\n {\n \"type\": \"command\",\n \"command\": \"echo '{\\\"hookSpecificOutput\\\":{\\\"hookEventName\\\":\\\"PostToolUseFailure\\\",\\\"additionalContext\\\":\\\"Last bash command failed. Repository / file state may have shifted \\u2014 re-read affected files before retrying. If the failure is a missing dependency or env mismatch, surface it to the user rather than retrying blindly.\\\"}}'\",\n \"timeout\": 5\n }\n ]\n }\n ],\n \"SubagentStop\": [\n {\n \"hooks\": [\n {\n \"type\": \"prompt\",\n \"prompt\": \"You are a quality gate for subagent outputs in a multi-agent code-analysis pipeline.\\n\\nEvaluate the subagent's `last_assistant_message` field (in the JSON below) against these requirements:\\n\\n1. ALLOW (return `{}`): Mode-selection or no-issues responses. Examples: \\\"Which mode do you prefer\\\", \\\"select an option\\\", \\\"no issues / problems / violations / blockers found\\\".\\n\\n2. ALLOW (return `{}`): Output contains at least one concrete file:line citation \\u2014 e.g. `src/auth.ts:42`, `lib/db.ts:100-115`, or path references that include line numbers.\\n\\n3. BLOCK (return `{\\\"decision\\\":\\\"block\\\",\\\"reason\\\":\\\"<one-line explanation>\\\"}`): Output claims about code or findings WITHOUT concrete file:line citations. Vague references like \\\"the auth handler\\\" or \\\"near the database code\\\" are not acceptable as the only evidence.\\n\\nSubagent invocation JSON:\\n$ARGUMENTS\\n\\nReturn ONLY the JSON decision (no commentary, no markdown fences).\",\n \"timeout\": 30\n }\n ]\n }\n ]\n },\n \"statusLine\": {\n \"type\": \"command\",\n \"command\": \"__DOCKS_KIT_STATUSLINE__\",\n \"refreshInterval\": 5\n },\n \"enabledPlugins\": {\n \"docks@docks\": true,\n \"plan-lifecycle@docks\": true,\n \"php-lsp@claude-plugins-official\": true,\n \"rust-analyzer-lsp@claude-plugins-official\": true,\n \"typescript-lsp@claude-plugins-official\": true\n },\n \"extraKnownMarketplaces\": {\n \"docks\": {\n \"source\": {\n \"source\": \"github\",\n \"repo\": \"DocksDocks/docks\"\n }\n }\n },\n \"alwaysThinkingEnabled\": true,\n \"showThinkingSummaries\": true,\n \"viewMode\": \"default\",\n \"theme\": \"dark-daltonized\",\n \"skipDangerousModePermissionPrompt\": true\n}\n",
|
|
@@ -50,4 +50,4 @@ export const GENERATED_PAYLOAD_PATHS = [
|
|
|
50
50
|
"notification.mp3"
|
|
51
51
|
] as const
|
|
52
52
|
|
|
53
|
-
export const GENERATED_PAYLOAD_HASH = "
|
|
53
|
+
export const GENERATED_PAYLOAD_HASH = "a835a0ab987f426d0ac3250116a047504e45e775ec3771cecc499fbcaec2f060"
|
package/cli/src/main.ts
CHANGED
|
@@ -32,8 +32,8 @@ const root = Command.make("docks-kit", {}, () =>
|
|
|
32
32
|
" docks-kit update [--no-sync] self-update the kit, then sync",
|
|
33
33
|
);
|
|
34
34
|
yield* Console.log(" docks-kit model <claude|codex> [value] get/set the deployed model");
|
|
35
|
-
yield* Console.log(" docks-kit models [tool]
|
|
36
|
-
yield* Console.log(" docks-kit toolchain [check|ensure
|
|
35
|
+
yield* Console.log(" docks-kit models [tool] [--refresh] live model lists per harness");
|
|
36
|
+
yield* Console.log(" docks-kit toolchain [check|ensure|outdated] verified-version floors");
|
|
37
37
|
yield* Console.log(" docks-kit status deployed-vs-SoT doctor view");
|
|
38
38
|
yield* Console.log(" docks-kit plugins list plugin tri-state");
|
|
39
39
|
yield* Console.log(" docks-kit skills list universal skills");
|
package/cli/src/manifests.ts
CHANGED
|
@@ -23,8 +23,8 @@ export const deployedClaudeSettings = (): any | undefined => {
|
|
|
23
23
|
export function topLevelTomlString(text: string, setting: string): string | undefined {
|
|
24
24
|
for (const line of text.split(/\r?\n/)) {
|
|
25
25
|
if (/^\s*\[/.test(line)) return undefined;
|
|
26
|
-
const assignment = line.match(/^\s*([A-Za-z0-9_-]+)\s*=\s*"([^"]+)"/);
|
|
27
|
-
if (assignment?.[1] === setting) return assignment[2];
|
|
26
|
+
const assignment = line.match(/^\s*([A-Za-z0-9_-]+)\s*=\s*(?:"([^"]+)"|'([^']*)')/);
|
|
27
|
+
if (assignment?.[1] === setting) return assignment[2] ?? assignment[3];
|
|
28
28
|
}
|
|
29
29
|
return undefined;
|
|
30
30
|
}
|
package/package.json
CHANGED