docks-kit 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +5 -3
- package/README.md +15 -7
- package/cli/docs/install.md +12 -12
- package/cli/docs/overview.md +7 -1
- package/cli/docs/platforms.md +8 -7
- package/cli/docs/sync-layers.md +15 -7
- package/cli/docs/toolchain.md +8 -2
- package/cli/src/engine-native/DESIGN.md +25 -14
- package/cli/src/engine-native/bun.ts +87 -0
- package/cli/src/engine-native/claudeRuntime.ts +132 -0
- package/cli/src/engine-native/claudeSync.ts +179 -115
- package/cli/src/engine-native/codexSync.ts +42 -36
- package/cli/src/engine-native/deps.ts +27 -10
- package/cli/src/engine-native/exec.ts +8 -23
- package/cli/src/engine-native/index.ts +8 -8
- package/cli/src/engine-native/models.ts +14 -16
- package/cli/src/engine-native/modes.ts +18 -9
- package/cli/src/engine-native/parseArgs.ts +1 -17
- package/cli/src/engine-native/powershell.ts +11 -0
- package/cli/src/engine-native/skillsSync.ts +11 -46
- package/cli/src/engine-native/toolchain.ts +6 -6
- package/cli/src/generated/sotPayload.ts +41 -0
- package/cli/src/kitHome.ts +15 -11
- package/cli/src/manifests.ts +17 -15
- package/cli/src/payload.ts +28 -0
- package/docks-kit +6 -6
- package/package.json +2 -3
- package/SoT/.agents/skills.txt +0 -14
- package/SoT/.claude/CLAUDE.md +0 -146
- package/SoT/.claude/fetch-usage.sh +0 -66
- package/SoT/.claude/hooks/notify.sh +0 -14
- package/SoT/.claude/mcp-servers.json +0 -10
- package/SoT/.claude/settings.json +0 -235
- package/SoT/.claude/statusline.sh +0 -175
- package/SoT/.codex/AGENTS.md +0 -75
- package/SoT/.codex/agents/.gitkeep +0 -1
- package/SoT/.codex/config.toml +0 -45
- package/SoT/.codex/plugins/marketplace.json +0 -50
- package/SoT/.codex/rules/docks.rules +0 -116
- package/SoT/models.json +0 -31
- package/SoT/toolchain.json +0 -27
- package/notification.mp3 +0 -0
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { spawnSync } from "node:child_process"
|
|
8
8
|
import { cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readlinkSync, realpathSync, rmdirSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs"
|
|
9
|
-
import { tmpdir } from "node:os"
|
|
10
9
|
import { p, writeFileIfChanged } from "./exec"
|
|
10
|
+
import { bunBootstrap } from "./bun"
|
|
11
11
|
import type { Ctx } from "./index"
|
|
12
12
|
import { compareCodepoints } from "./jq"
|
|
13
13
|
import type { EngineServices, Platform } from "./services"
|
|
14
14
|
import { ensure, field } from "./toolchain"
|
|
15
|
+
import { payloadText } from "../payload"
|
|
15
16
|
|
|
16
17
|
export interface SkillsState {
|
|
17
18
|
present: number
|
|
@@ -20,11 +21,9 @@ export interface SkillsState {
|
|
|
20
21
|
export function skillsSync(ctx: Ctx): SkillsState {
|
|
21
22
|
const state: SkillsState = { present: 0 }
|
|
22
23
|
const skillsDir = p(ctx.agentsDir, "skills")
|
|
23
|
-
const manifest =
|
|
24
|
+
const manifest = payloadText("SoT/.agents/skills.txt")
|
|
24
25
|
const snapshot = p(ctx.agentsDir, ".kit-managed-skills")
|
|
25
26
|
|
|
26
|
-
if (!existsSync(manifest)) return state
|
|
27
|
-
|
|
28
27
|
if (!ctx.dryRun) mkdirSync(skillsDir, { recursive: true })
|
|
29
28
|
|
|
30
29
|
syncUniversal(ctx, state, skillsDir, manifest)
|
|
@@ -69,7 +68,7 @@ function syncUniversal(ctx: Ctx, state: SkillsState, skillsDir: string, manifest
|
|
|
69
68
|
let failed = 0
|
|
70
69
|
let healed = 0
|
|
71
70
|
|
|
72
|
-
for (const slug of
|
|
71
|
+
for (const slug of normalizeManifest(manifest)) {
|
|
73
72
|
const base = slug.slice(slug.lastIndexOf("/") + 1)
|
|
74
73
|
|
|
75
74
|
if (ctx.dryRun) {
|
|
@@ -264,7 +263,7 @@ export function agentBrowserInstall(mode: "install" | "upgrade", version: string
|
|
|
264
263
|
|
|
265
264
|
function syncAgentBrowserCli(ctx: Ctx, manifest: string): void {
|
|
266
265
|
const { warn } = ctx.services.logger
|
|
267
|
-
if (!
|
|
266
|
+
if (!manifest.split("\n").includes("vercel-labs/agent-browser")) return
|
|
268
267
|
|
|
269
268
|
if (ctx.services.deps.probe("npm").state === "missing") {
|
|
270
269
|
if (!ctx.dryRun) {
|
|
@@ -278,39 +277,6 @@ function syncAgentBrowserCli(ctx: Ctx, manifest: string): void {
|
|
|
278
277
|
}
|
|
279
278
|
}
|
|
280
279
|
|
|
281
|
-
/** skills::_find_bun — resolved bun path or "". */
|
|
282
|
-
function findBun(ctx: Ctx): string {
|
|
283
|
-
return ctx.services.deps.path("bun")
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/** skills::_bun_bootstrap — bun path or "" after a failed bootstrap. */
|
|
287
|
-
export function bunBootstrap(ctx: Ctx, services: EngineServices): string {
|
|
288
|
-
const { change, warn } = services.logger
|
|
289
|
-
let bun = findBun(ctx)
|
|
290
|
-
if (bun !== "") return bun
|
|
291
|
-
|
|
292
|
-
if (services.deps.probe("curl").state === "missing") {
|
|
293
|
-
warn("Bun and curl both missing — cannot bootstrap Bun. Install Bun manually, then re-run sync.")
|
|
294
|
-
return ""
|
|
295
|
-
}
|
|
296
|
-
const pin = field(ctx, "bun", "verified")
|
|
297
|
-
warn(`Bun not found — installing Bun${pin !== "" ? ` ${pin} (kit-verified)` : ""}...`)
|
|
298
|
-
const installer = p(tmpdir(), `bun-install-${process.pid}.sh`)
|
|
299
|
-
const dl = spawnSync("curl", ["-fsSL", "https://bun.sh/install", "-o", installer], { stdio: "ignore" })
|
|
300
|
-
if (dl.error === undefined && dl.status === 0) {
|
|
301
|
-
spawnSync("bash", [installer, ...(pin !== "" ? [`bun-v${pin}`] : [])], { stdio: "ignore" })
|
|
302
|
-
}
|
|
303
|
-
rmSync(installer, { force: true })
|
|
304
|
-
bun = findBun(ctx)
|
|
305
|
-
if (bun === "") {
|
|
306
|
-
warn("Bun install failed. Install manually: curl -fsSL https://bun.sh/install -o /tmp/bun.sh && bash /tmp/bun.sh")
|
|
307
|
-
return ""
|
|
308
|
-
}
|
|
309
|
-
const version = services.deps.version("bun")
|
|
310
|
-
change(`Bun installed (${version !== "" ? version : "version unknown"})`)
|
|
311
|
-
return bun
|
|
312
|
-
}
|
|
313
|
-
|
|
314
280
|
/** skills::_effect_solutions_install. */
|
|
315
281
|
export function effectSolutionsInstall(
|
|
316
282
|
ctx: Ctx
|
|
@@ -320,8 +286,9 @@ export function effectSolutionsInstall(
|
|
|
320
286
|
const verb = mode === "upgrade" ? "Upgrading" : "Installing"
|
|
321
287
|
const pkg = `effect-solutions@${version !== "" ? version : "latest"}`
|
|
322
288
|
|
|
323
|
-
const
|
|
324
|
-
if (
|
|
289
|
+
const bunState = bunBootstrap(ctx, services)
|
|
290
|
+
if (bunState.kind === "deferred") return 1
|
|
291
|
+
const bun = bunState.executable
|
|
325
292
|
|
|
326
293
|
verbose(`${verb} effect-solutions CLI via bun${version !== "" ? ` (pinned ${version})` : ""}...`)
|
|
327
294
|
if (spawnSync(bun, ["add", "-g", pkg], { stdio: "ignore" }).status !== 0) {
|
|
@@ -353,9 +320,7 @@ export function effectSolutionsInstall(
|
|
|
353
320
|
|
|
354
321
|
function syncEffectSolutionsCli(ctx: Ctx): void {
|
|
355
322
|
const { warn } = ctx.services.logger
|
|
356
|
-
|
|
357
|
-
if (!existsSync(settings)) return
|
|
358
|
-
if (!/"effect-kit@docks"[ \t]*:[ \t]*true/.test(readFileSync(settings, "utf8"))) return
|
|
323
|
+
if (!/"effect-kit@docks"[ \t]*:[ \t]*true/.test(payloadText("SoT/.claude/settings.json"))) return
|
|
359
324
|
|
|
360
325
|
if (ensure(ctx, "effect-solutions", effectSolutionsInstall(ctx)) !== 0) {
|
|
361
326
|
warn("effect-solutions bootstrap failed — continuing sync")
|
|
@@ -375,7 +340,7 @@ function reconcileRemovals(ctx: Ctx, manifest: string, snapshot: string): void {
|
|
|
375
340
|
return
|
|
376
341
|
}
|
|
377
342
|
|
|
378
|
-
const current =
|
|
343
|
+
const current = normalizeManifest(manifest)
|
|
379
344
|
let removed = 0
|
|
380
345
|
let failed = 0
|
|
381
346
|
for (const slug of readSlugs(snapshot)) {
|
|
@@ -407,7 +372,7 @@ function updateSnapshot(ctx: Ctx, manifest: string, snapshot: string): void {
|
|
|
407
372
|
if (ctx.dryRun) return
|
|
408
373
|
|
|
409
374
|
mkdirSync(ctx.agentsDir, { recursive: true })
|
|
410
|
-
const sorted = [...new Set(
|
|
375
|
+
const sorted = [...new Set(normalizeManifest(manifest))].sort(compareCodepoints)
|
|
411
376
|
writeFileIfChanged(snapshot, sorted.length > 0 ? `${sorted.join("\n")}\n` : "")
|
|
412
377
|
}
|
|
413
378
|
|
|
@@ -2,24 +2,24 @@
|
|
|
2
2
|
* Verified-version-floor layer over SoT/toolchain.json. Probe/install commands
|
|
3
3
|
* spawn deterministic argv arrays and are covered by golden regression cases.
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { readSync } from "node:fs"
|
|
6
6
|
|
|
7
7
|
import type { ToolId } from "./deps"
|
|
8
|
-
import { p } from "./exec"
|
|
9
8
|
import type { Ctx } from "./index"
|
|
10
9
|
import { compareCodepoints, isObject, parseJson, type Json } from "./jq"
|
|
11
10
|
import type { EngineServices } from "./services"
|
|
11
|
+
import { payloadText } from "../payload"
|
|
12
12
|
|
|
13
13
|
type InstallFn = (mode: "install" | "upgrade", version: string, services: EngineServices) => number
|
|
14
14
|
|
|
15
|
-
function manifest(
|
|
16
|
-
const doc = parseJson(
|
|
15
|
+
function manifest(): { [k: string]: Json } {
|
|
16
|
+
const doc = parseJson(payloadText("SoT/toolchain.json"))
|
|
17
17
|
const tools = doc !== undefined && isObject(doc) ? doc["tools"] : undefined
|
|
18
18
|
return tools !== undefined && isObject(tools) ? tools : {}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export function field(ctx: Ctx, tool: string, name: string): string {
|
|
22
|
-
const entry = manifest(
|
|
22
|
+
const entry = manifest()[tool]
|
|
23
23
|
if (entry === undefined || !isObject(entry)) return ""
|
|
24
24
|
const v = entry[name]
|
|
25
25
|
return v === undefined || v === null ? "" : String(v)
|
|
@@ -209,7 +209,7 @@ export function report(ctx: Ctx): void {
|
|
|
209
209
|
echo(row(["TOOL", "KIND", "INSTALLED", "FLOOR", "VERIFIED", "STATUS"]))
|
|
210
210
|
const pn = ctx.services.platform.name()
|
|
211
211
|
const platformOs = pn === "unknown" ? "" : pn
|
|
212
|
-
for (const tool of Object.keys(manifest(
|
|
212
|
+
for (const tool of Object.keys(manifest()).sort(compareCodepoints)) {
|
|
213
213
|
const os = field(ctx, tool, "os")
|
|
214
214
|
if (os !== "" && platformOs !== "" && os !== platformOs) continue
|
|
215
215
|
const kind = field(ctx, tool, "kind")
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Generated by cli/scripts/generate-sot-payload.ts. DO NOT EDIT.
|
|
2
|
+
// Edit SoT/ or notification.mp3, then run: bun cli/scripts/generate-sot-payload.ts
|
|
3
|
+
|
|
4
|
+
export const GENERATED_PAYLOAD_TEXT = {
|
|
5
|
+
"SoT/.agents/skills.txt": "# Universal AI-agent skills (agentskills.io standard).\n# Bootstrapped to ~/.agents/skills/ by cli/src/engine-native/skillsSync.ts during ./docks-kit sync.\n# One slug per line: <owner>/<repo>. Lines starting with # are comments.\n# Each skill's canonical SKILL.md lands in ~/.agents/skills/<name>/ — Codex\n# reads that path natively; Claude Code gets a ~/.claude/skills/<name>\n# symlink to it. The skills sync names both agents the kit supports\n# (-a claude-code codex) so the CLI keeps the shared canonical copy.\n\n# Browser automation CLI — reaches JS-rendered, auth-walled, login-gated pages\n# (x.com, LinkedIn, Confluence) that built-in WebFetch can't. The skills sync\n# auto-installs the `agent-browser` npm package + downloads Chrome for Testing\n# (~175 MB) on first sync; Linux runs `agent-browser install --with-deps` which\n# may prompt for sudo to install system libs (libnss3, libatk, ...).\nvercel-labs/agent-browser\n",
|
|
6
|
+
"SoT/models.json": "{\n \"$comment\": \"Kit-verified model catalog — single source for EngineNative validators, the docks-kit CLI (models/model commands, pickers, bare-flag help), and docs. Entries are research-proofed: update an entry and its tool-level `verified` date when a model ships or retires. The catalog informs, it doesn't imprison: well-formed IDs outside it (claude-* / codex charset) apply with a warning.\",\n \"claude\": {\n \"verified\": \"2026-07-08\",\n \"models\": [\n { \"id\": \"best\", \"kind\": \"alias\", \"note\": \"Fable 5 where the org has access, latest Opus otherwise (Claude Code >=2.1.170)\" },\n { \"id\": \"opus\", \"kind\": \"alias\", \"note\": \"latest Opus (currently Opus 4.8) — the kit SoT default, paired with the fable advisor\" },\n { \"id\": \"fable\", \"kind\": \"alias\", \"note\": \"Fable 5 — needs org access + Claude Code >=2.1.170\" },\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-fable-5\", \"kind\": \"id\", \"note\": \"Fable 5\" },\n { \"id\": \"claude-opus-4-8\", \"kind\": \"id\", \"note\": \"Opus 4.8\" },\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-07-09\",\n \"models\": [\n { \"id\": \"gpt-5.6-sol\", \"kind\": \"id\", \"note\": \"GPT-5.6 Sol — frontier, recommended default; the kit SoT pin\" },\n { \"id\": \"gpt-5.6-terra\", \"kind\": \"id\", \"note\": \"GPT-5.6 Terra — balanced tier\" },\n { \"id\": \"gpt-5.6-luna\", \"kind\": \"id\", \"note\": \"GPT-5.6 Luna — fast/light tier\" },\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",
|
|
7
|
+
"SoT/toolchain.json": "{\n \"$comment\": \"Kit toolchain manifest — DATA only (versions, floors, policy); check/install logic lives in cli/src/engine-native/toolchain.ts with per-surface sync callbacks in cli/src/engine-native/. kind: check (doctor visibility only) | managed (kit installs/upgrades it) | pin (no binary probe — a version pin for a tool the kit invokes via npx). policy (managed only): track (upgrade toward latest, gated by `verified`) | present (install when missing, never upgrade). `verified` = last kit-tested version — anything above it prompts before install (--yes auto-accepts; non-TTY declines and falls back to the pinned `verified` when pinnable). Supply-chain stance: every kit-driven install is pinned to `verified` or gated by it — never floating @latest (npm-worm/Shai-Hulud surface). Update `verified` after testing a new release.\",\n \"tools\": {\n \"jq\": { \"kind\": \"check\", \"note\": \"optional operator CLI; EngineNative JSON and Claude runtime do not invoke it\" },\n \"curl\": { \"kind\": \"check\", \"note\": \"contextual POSIX installer transport for RTK/Bun bootstrap\" },\n \"git\": { \"kind\": \"check\", \"note\": \"plugin marketplaces (claude/codex clone them) + kit checkout updates\" },\n \"node\": { \"kind\": \"check\", \"note\": \"hosts npm globals (agent-browser, LSP servers)\" },\n \"npm\": { \"kind\": \"check\", \"note\": \"npm-global installer\" },\n \"claude\": { \"kind\": \"check\", \"floor\": \"2.1.170\", \"note\": \"kit floor — `best` alias + Fable 5 need >=2.1.170 (mirrors settings minimumVersion)\" },\n \"codex\": { \"kind\": \"check\", \"note\": \"upstream-owned; standalone installer prints when missing\" },\n \"ffplay\": { \"kind\": \"check\", \"note\": \"Notification hook sound (previously unchecked)\" },\n \"bwrap\": { \"kind\": \"check\", \"os\": \"linux\", \"note\": \"Codex Linux sandbox runtime\" },\n \"intelephense\": { \"kind\": \"check\", \"verified\": \"1.18.5\", \"note\": \"php-lsp server binary; `verified` pins claude::sync_lsp_servers' npm install\" },\n \"typescript-language-server\": { \"kind\": \"check\", \"verified\": \"5.3.0\", \"note\": \"typescript-lsp server binary; `verified` pins claude::sync_lsp_servers' npm install\" },\n \"tsc\": { \"kind\": \"check\", \"verified\": \"6.0.3\", \"note\": \"typescript-lsp dependency (npm package `typescript`); `verified` pins claude::sync_lsp_servers' 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 \"rtk\": { \"kind\": \"managed\", \"policy\": \"track\", \"floor\": \"0.43.0\", \"verified\": \"0.43.0\", \"pinnable\": true,\n \"note\": \"PreToolUse hook — supply-chain review before unverified upgrades; installer honors RTK_VERSION=vX.Y.Z pin\" },\n \"bun\": { \"kind\": \"managed\", \"policy\": \"present\", \"verified\": \"1.3.14\", \"pinnable\": true,\n \"note\": \"runtime for effect-solutions + the docks-kit CLI; bootstrap installs the verified release (installer takes bun-vX.Y.Z); self-updates via `bun upgrade` when wanted\" },\n \"effect-solutions\": { \"kind\": \"managed\", \"policy\": \"track\", \"verified\": \"0.5.3\", \"pinnable\": true,\n \"note\": \"Effect docs CLI (bun global) — track keeps it self-upgrading, gated by the verified pin\" },\n \"agent-browser\": { \"kind\": \"managed\", \"policy\": \"track\", \"verified\": \"0.31.1\", \"pinnable\": true,\n \"note\": \"browser-automation CLI (npm global), gated by the verified pin; first install also downloads Chrome for Testing\" },\n \"skills-cli\": { \"kind\": \"pin\", \"verified\": \"1.5.15\",\n \"note\": \"the `skills` npm package the kit runs via `npx skills@<verified>` on every agents sync (universal-skill install/remove) — pinned, never @latest\" }\n }\n}\n",
|
|
8
|
+
"SoT/.claude/CLAUDE.md": "@RTK.md\n\n## 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\n**Research workflow:**\n1. Use `resolve-library-id` → `query-docs` (context7) to fetch up-to-date docs for the specific library/framework\n2. If context7 doesn't cover it, read the official docs with `agent-browser` (it reaches JS-rendered, auth-walled, and login-gated pages); fall back to `WebFetch` for a simple static page\n3. Only then proceed to implementation\n\n**When to research:**\n- Installing or configuring a dependency\n- Using an API, hook, method, or pattern you haven't verified in this session\n- Upgrading or migrating between versions\n- Any task where you'd otherwise rely on training data for syntax/behavior\n\n**Do 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 haven't 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\n## Project Skills\n\nProjects may have a `.claude/skills/` directory with Tool Wrapper skills managed by `/docs`. Claude Code auto-discovers these at session start — only descriptions are loaded, full content loads on demand via the Skill tool.\n\nSkills follow the [agentskills.io](https://agentskills.io) open standard:\n- **SKILL.md**: frontmatter (`name`, `description`, `user-invocable: false`, `metadata`) + body (≤500 lines)\n- **references/**: on-demand detail files (30-150 lines each), loaded when the skill instructs Claude to read them\n- **Discovery**: Claude Code scans `.claude/skills/*/SKILL.md` at session start, loads only `name` + `description` (~100 tokens per skill)\n- **Triggering**: Claude semantically matches descriptions against user tasks, invokes via `Skill` tool — no `@import` or pointer tables needed\n- **CSO (Claude Search Optimization)**: descriptions MUST start with \"Use when...\" and describe trigger conditions, not capabilities\n- **Third-party / vendored skills**: add an `upstream:` frontmatter block (`source`, `license`, `vendored_at: \"YYYY-MM-DD\"`) when vendoring a skill from an external repo. The block marks the skill as vendored so kit-specific checks (CSO start-prefix, `user-invocable`, `metadata.updated`) are relaxed and the skill's body is preserved verbatim from upstream. Universal structural checks (fenced frontmatter, name matches directory, description length, 500-line body cap) still apply.\n\n<constraint>\nAfter any code change affecting documented patterns, update the relevant skill in `.claude/skills/` and its `metadata.updated` frontmatter field. When introducing something new, create a skill or add a `references/` file to an existing skill.\n</constraint>\n\n## Project Agents\n\nProjects and the global kit may have a `.claude/agents/` directory containing subagent definitions. Each agent file declares its `model` (`sonnet`/`opus`/`haiku`/`inherit`/full model ID), `tools`, and system prompt. Claude Code auto-discovers them at session start and delegates when a `subagent_type` matches or when a slash command explicitly invokes them.\n\nAgent files follow this structure:\n- **Frontmatter**: `name` (kebab-case, matches filename), `description` (CSO — starts \"Use when…\" with a \"Not for…\" exclusion clause), `tools`, `model`\n- **Body** (≤500 lines): `<constraint>` blocks for non-negotiable rules, `## Workflow` with context-acknowledgment as step 1, `## Output Format`, `## Anti-Hallucination Checks`, `## Success Criteria`\n- **Model-selection resolution** (per Claude Code docs): `CLAUDE_CODE_SUBAGENT_MODEL` env var → per-invocation `model` param → agent frontmatter `model:` → parent conversation. The env var is NOT set in this kit, so per-agent frontmatter controls selection.\n\n<constraint>\nWhen adding a new agent: use kebab-case name matching filename, CSO-compliant description (starts \"Use when…\", contains a \"Not\" exclusion clause), explicit `model` and `tools`.\n</constraint>\n\n## Picking the right models for workflows and subagents\n\nRankings, higher = better. Intelligence is how hard a problem the model can be handed unsupervised. Taste covers UI/UX, code quality, API design, and copy. Cost is relative spend — a tie-breaker only.\n\n| model | cost | intelligence | taste |\n|----------|------|--------------|-------|\n| gpt-5.5 | 9 | 8 | 5 |\n| opus-4.8 | 4 | 7 | 8 |\n| sonnet-5 | 5 | 5 | 7 |\n\nFable 5 outranks all three on intelligence and taste, but its limits are spent for now — treat opus-4.8 as the ceiling until Fable access returns, then Fable takes the top intelligence+taste slot.\n\nHow to apply:\n- These are defaults, not limits. Standing permission to override: if a cheaper model's output misses the bar, rerun with a smarter one without asking. Judge the output, not the price tag — escalating costs less than shipping mediocre work.\n- Cost is a tie-breaker only; when axes conflict for anything that ships, intelligence > taste > cost.\n- Bulk/mechanical work (clear-spec implementation, data analysis, migrations): gpt-5.5.\n- Anything user-facing (UI, copy, API design) needs taste ≥ 7 → opus-4.8 (sonnet-5 when Opus is saturated).\n- Reviews of plans/implementations: opus-4.8, optionally gpt-5.5 as a second independent perspective.\n- Never use Haiku.\n- gpt-5.5 is reachable only through the Codex CLI (`~/.codex/config.toml` defaults to gpt-5.5): `codex exec` for headless implementation/analysis, `codex review` for diff review, `codex exec -s read-only` with a self-contained prompt for ad-hoc investigation, UI verification, or data analysis. Codex is more efficient than Claude on well-specced execution and stronger at computer-use and UI/UX verification — offload those and report results back.\n- Claude models run via the Agent/Workflow `model` parameter (`opus`, `sonnet`).\n\nUsing gpt-5.5 inside workflows and subagents (the `model` parameter takes only Claude models, so wrap it):\n- Spawn a thin Claude wrapper agent with `model: 'sonnet', effort: 'low'` whose prompt tells it to write a self-contained Codex prompt, run `codex exec` via Bash, and return Codex's output verbatim. The wrapper only shuttles the prompt and result — gpt-5.5 does the work.\n\nReaching gpt-5.5 (or a full-context worker in another project) as a persistent session — the `session-relay` skill (shared bus + `relay` CLI, Claude ⇄ Codex):\n- `codex exec` is one-shot and stateless. When the offload must be resumable, span several turns, or run in another project with that project's own config, spawn a real session instead: `relay spawn <dir> --tool codex --model gpt-5.5 --effort xhigh` (or `--tool claude --model opus` for a Claude worker), then continue it with `send` / `wake`.\n- Two independent perspectives on a plan = the red-team pair spawn: a gpt-5.5 worker and an opus worker debate over the bus, orchestrator writes the verdict — the concrete form of the \"second independent perspective\" review above.\n- Pin `--model`/`--effort` on every spawn/wake; never leave an unattended relay child on a top interactive default (e.g. Fable). Each spawn/wake bills the target's subscription — spawn deliberately, never in loops.\n\n## Agentic Engineering Discipline\n\n1. **State assumptions; push back when warranted.** If a requirement is ambiguous in a way that changes the deliverable, surface the ambiguity and propose 1–2 concrete interpretations in your first message — do not silently pick one and run with it. Surface inconsistencies and confusion instead of guessing past them; present tradeoffs when approaches genuinely differ; push back when the request looks wrong. Agreeable-but-wrong is the failure mode, not disagreement.\n2. **Minimum code that solves the stated problem.** Each named pattern below is a defect — catch it during generation, not after:\n\n **Code slop**\n - **Defensive guards** around internally-trusted calls (`try`, `if x != null`). Validate at system boundaries only.\n - **Speculative abstraction.** No helper for one caller; no interface for one implementer. Three similar lines beats premature DRY.\n - **Backwards-compat shims** without a caller — re-exports, deprecation aliases, untoggled feature flags. Just change the code.\n - **Half-finished stubs.** `TODO handle later`, `throw new Error('not implemented')`. Implement or remove the path.\n - **Underscore-rename of unused vars.** Delete the var.\n - **Dead code left behind.** After a refactor, delete the paths, helpers, and imports the change made unreachable.\n\n **Comment slop**\n - **Restate-the-code.** `// increment i`. The identifier already says it.\n - **Provenance.** `// added for ticket X`, `// used by Y`. Belongs in the PR description; rots in code.\n - **Tombstones.** `// removed Z`, `// previously did W`. Git remembers.\n - **Docstring bloat** on self-evident functions. One line, only when the WHY isn't obvious from the name.\n\n **Output slop**\n - **End-of-turn diff-restatement.** One or two sentences: what changed, what's next. Don't recap what's in the diff.\n - **Narration tics.** \"Now I'll…\", \"Let me check…\", play-by-play between tool calls. Terse working shorthand between tool calls is fine; play-by-play is not — write a sentence when something load-bearing happens (a finding, a direction change, a blocker).\n - **Compressed final summaries.** The final message is for a reader who didn't watch the work: outcome first, complete sentences. Shorten by dropping detail, never by compressing into fragments or arrow chains.\n3. **Surgical changes only.** Do not modify code, comments, or formatting outside the explicit scope of the request. Surface unrelated issues as follow-ups — do not fix inline.\n4. **State how success will be verified before implementing.** Name the test, build, smoke check, or diff inspection that will prove the change works. Prefer executable criteria — a test that fails before and passes after, a command with expected output — over judgment calls, and keep each change small enough that its diff is reviewable in one sitting.\n5. **Review scope follows the pipeline.** In pipeline reviews with a downstream filter (multi-agent scans, verification phases), report every issue found with confidence and severity — filtering happens downstream. In ad-hoc reviews, flag only gaps that affect correctness or the stated requirements; treat the rest as optional.\n6. **Ground every progress claim in evidence.** Before reporting progress or completion, audit each claim against a tool result from this session — show the test output, the command and what it returned. If something is unverified, say so explicitly; if tests fail, say so with the output.\n\n<constraint>\nTreat the six rules above as preventive (during generation), not remedial (after the fact). Self-correct if a turn drifts.\n</constraint>\n",
|
|
9
|
+
"SoT/.claude/mcp-servers.json": "{\n \"mcpServers\": {\n \"chrome-devtools\": {\n \"type\": \"stdio\",\n \"command\": \"npx\",\n \"args\": [\"-y\", \"chrome-devtools-mcp@1.5.0\"],\n \"env\": {}\n }\n }\n}\n",
|
|
10
|
+
"SoT/.claude/settings.json": "{\n \"$schema\": \"https://json.schemastore.org/claude-code-settings.json\",\n \"minimumVersion\": \"2.1.170\",\n \"model\": \"opus\",\n \"advisorModel\": \"fable\",\n \"effortLevel\": \"xhigh\",\n \"autoMemoryEnabled\": true,\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 \"WebFetch\",\n \"WebSearch\",\n \"Edit(./)\",\n \"Write(./)\",\n \"Bash(git *)\",\n \"Bash(git add *)\",\n \"Bash(git commit *)\",\n \"Bash(git status *)\",\n \"Bash(git diff *)\",\n \"Bash(git log *)\",\n \"Bash(git branch *)\",\n \"Bash(git checkout *)\",\n \"Bash(git switch *)\",\n \"Bash(git stash *)\",\n \"Bash(git fetch *)\",\n \"Bash(git pull *)\",\n \"Bash(git tag *)\",\n \"Bash(git show *)\",\n \"Bash(git blame *)\",\n \"Bash(git worktree *)\",\n \"Bash(gh *)\",\n \"Bash(pnpm *)\",\n \"Bash(npm *)\",\n \"Bash(npx *)\",\n \"Bash(node *)\",\n \"Bash(docker *)\",\n \"Bash(docker-compose *)\",\n \"Bash(rtk *)\",\n \"Bash(ls *)\",\n \"Bash(cat *)\",\n \"Bash(find *)\",\n \"Bash(grep *)\",\n \"Bash(head *)\",\n \"Bash(tail *)\",\n \"Bash(wc *)\",\n \"Bash(sort *)\",\n \"Bash(uniq *)\",\n \"Bash(diff *)\",\n \"Bash(which *)\",\n \"Bash(pwd *)\",\n \"Bash(date *)\",\n \"Bash(mkdir *)\",\n \"Bash(basename *)\",\n \"Bash(dirname *)\",\n \"Bash(realpath *)\",\n \"Bash(jq *)\",\n \"Bash(curl *)\",\n \"Bash(tree *)\",\n \"Bash(sed *)\",\n \"Bash(awk *)\",\n \"Bash(cut *)\",\n \"Bash(tr *)\",\n \"Bash(tee *)\",\n \"Bash(echo *)\",\n \"Bash(printf *)\",\n \"Bash(env *)\",\n \"Bash(printenv *)\",\n \"Bash(uname *)\",\n \"Bash(file *)\",\n \"Bash(stat *)\",\n \"Bash(du *)\",\n \"Bash(id *)\",\n \"Bash(whoami *)\",\n \"Bash(php *)\",\n \"Bash(composer *)\",\n \"Bash(python3 *)\",\n \"Bash(python *)\",\n \"Bash(pip *)\",\n \"Bash(pip3 *)\"\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 \"Write(**/.env)\",\n \"Write(**/.env.local)\",\n \"Write(**/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 ],\n \"ask\": [\n \"Bash(git clean *)\",\n \"Bash(docker volume rm *)\",\n \"Bash(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 \"PreToolUse\": [\n {\n \"matcher\": \"Bash\",\n \"hooks\": [\n {\n \"type\": \"command\",\n \"command\": \"rtk hook claude\"\n }\n ]\n }\n ],\n \"PostToolUseFailure\": [\n {\n \"matcher\": \"Bash\",\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 \"context7@claude-plugins-official\": true,\n \"frontend-design@claude-plugins-official\": true,\n \"php-lsp@claude-plugins-official\": true,\n \"typescript-lsp@claude-plugins-official\": true,\n \"docks@docks\": true,\n \"session-relay@docks\": true,\n \"effect-kit@docks\": 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",
|
|
11
|
+
"SoT/.claude/bin/statusline.mjs": "const ESC = \"\\x1b[\"\nconst PIPE = `${ESC}90m | ${ESC}0m`\nconst DOT = `${ESC}90m • ${ESC}0m`\nconst DIM = `${ESC}2m${ESC}38;2;156;162;175m`\n\nfunction isRecord(value) {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nfunction finitePercentage(value) {\n return typeof value === \"number\" && Number.isFinite(value) && value >= 0 && value <= 100\n ? value\n : undefined\n}\n\nfunction roundHalfEven(value) {\n const lower = Math.floor(value)\n const fraction = value - lower\n if (fraction < 0.5) return lower\n if (fraction > 0.5) return lower + 1\n return lower % 2 === 0 ? lower : lower + 1\n}\n\nfunction pathBasename(path) {\n const parts = path.split(/[\\\\/]+/).filter((part) => part !== \"\")\n return parts.at(-1) ?? \"\"\n}\n\nfunction modelName(input) {\n const model = isRecord(input.model) && typeof input.model.display_name === \"string\"\n ? input.model.display_name\n : \"\"\n const suffix = model.indexOf(\" (\")\n return suffix === -1 ? model : model.slice(0, suffix)\n}\n\nfunction workingDirectory(input, cwd) {\n if (isRecord(input.workspace) && typeof input.workspace.current_dir === \"string\" && input.workspace.current_dir !== \"\") {\n return input.workspace.current_dir\n }\n if (typeof input.cwd === \"string\" && input.cwd !== \"\") return input.cwd\n return cwd\n}\n\nfunction compactWindow(env, total) {\n const raw = env.CLAUDE_CODE_AUTO_COMPACT_WINDOW\n if (typeof raw !== \"string\" || !/^[0-9]+$/.test(raw)) return total\n const parsed = Number(raw)\n return Number.isSafeInteger(parsed) && parsed >= 1000 && parsed < total ? parsed : total\n}\n\nfunction formatTokensK(value) {\n if (value < 1000) return `${value}k`\n if (value % 1000 === 0) return `${value / 1000}M`\n return `${(roundHalfEven(value / 100) / 10).toFixed(1)}M`\n}\n\nfunction contextSegment(input, env) {\n if (!isRecord(input.context_window)) return \"\"\n const used = finitePercentage(input.context_window.used_percentage)\n if (used === undefined) return \"\"\n\n const total = input.context_window.context_window_size\n if (typeof total !== \"number\" || !Number.isFinite(total) || total <= 0) {\n return `${ESC}38;2;130;160;230mctx ${roundHalfEven(used)}%${ESC}0m`\n }\n\n const usedK = roundHalfEven((used / 100) * (total / 1000))\n const effectiveK = Math.trunc(compactWindow(env, total) / 1000)\n if (effectiveK <= 0) return `${ESC}38;2;130;160;230mctx ${roundHalfEven(used)}%${ESC}0m`\n const effectivePercentage = roundHalfEven((usedK / effectiveK) * 100)\n return `${ESC}38;2;130;160;230mctx ${effectivePercentage}%${ESC}0m ${DIM}(${formatTokensK(usedK)}/${formatTokensK(effectiveK)})${ESC}0m`\n}\n\nfunction resetDelta(value, nowMs) {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) return \"\"\n const seconds = Math.trunc(value) - Math.floor(nowMs / 1000)\n if (seconds <= 0) return \"now\"\n const days = Math.trunc(seconds / 86_400)\n if (days > 0) return `${days}d`\n const hours = Math.trunc((seconds % 86_400) / 3_600)\n if (hours > 0) return `${hours}h`\n return `${Math.trunc((seconds % 3_600) / 60)}m`\n}\n\nfunction quotaWindow(value, label, color, nowMs) {\n if (!isRecord(value)) return \"\"\n const used = finitePercentage(value.used_percentage)\n if (used === undefined) return \"\"\n const delta = resetDelta(value.resets_at, nowMs)\n const reset = delta === \"\" ? \"\" : ` ${DIM}(${delta})${ESC}0m`\n return `${ESC}38;2;${color}m${label} ${roundHalfEven(used)}%${ESC}0m${reset}`\n}\n\nfunction decodeStdout(result) {\n const stdout = result?.stdout\n if (stdout === undefined || stdout === null) return \"\"\n return typeof stdout === \"string\" ? stdout : stdout.toString()\n}\n\nfunction resolveBranch(directory, which, spawnSync) {\n const git = which(\"git\")\n if (typeof git !== \"string\" || git === \"\") return \"\"\n const commands = [\n [git, \"-C\", directory, \"symbolic-ref\", \"--short\", \"HEAD\"],\n [git, \"-C\", directory, \"rev-parse\", \"--short\", \"HEAD\"]\n ]\n for (const command of commands) {\n try {\n const result = spawnSync(command, { stdin: \"ignore\", stdout: \"pipe\", stderr: \"ignore\" })\n if (result?.success === true) return decodeStdout(result).trim()\n } catch {\n return \"\"\n }\n }\n return \"\"\n}\n\nexport function formatStatusline(input, options = {}) {\n if (!isRecord(input)) return \"\"\n const env = isRecord(options.env) ? options.env : process.env\n const nowMs = typeof options.nowMs === \"number\" ? options.nowMs : Date.now()\n const cwd = typeof options.cwd === \"string\" ? options.cwd : process.cwd()\n const branch = typeof options.branch === \"string\" ? options.branch : \"\"\n const directory = workingDirectory(input, cwd)\n\n const model = `${ESC}38;5;208m${ESC}1m${modelName(input)}${ESC}22m${ESC}0m`\n const folder = `${ESC}1m${ESC}38;2;76;208;222m${pathBasename(directory)}${ESC}22m${ESC}0m`\n const branchSegment = branch === \"\" ? \"\" : `${DOT}${ESC}1m${ESC}38;2;192;103;222m${branch}${ESC}22m${ESC}0m`\n const context = contextSegment(input, env)\n\n const rateLimits = isRecord(input.rate_limits) ? input.rate_limits : {}\n const fiveHour = quotaWindow(rateLimits.five_hour, \"5h\", \"100;200;200\", nowMs)\n const sevenDay = quotaWindow(rateLimits.seven_day, \"7d\", \"230;180;90\", nowMs)\n const quota = fiveHour === \"\" && sevenDay === \"\"\n ? \"\"\n : `${PIPE}${fiveHour}${fiveHour !== \"\" && sevenDay !== \"\" ? DOT : \"\"}${sevenDay}`\n\n return `${model}${PIPE}${folder}${branchSegment}${context === \"\" ? \"\" : `${PIPE}${context}`}${quota}`\n}\n\nexport async function main(options = {}) {\n const readStdin = options.readStdin ?? (() => Bun.stdin.text())\n const writeStdout = options.writeStdout ?? ((value) => process.stdout.write(value))\n let raw\n try {\n raw = await readStdin()\n } catch {\n return 0\n }\n\n let input\n try {\n input = JSON.parse(raw)\n } catch {\n return 0\n }\n if (!isRecord(input)) return 0\n\n const cwd = typeof options.cwd === \"string\" ? options.cwd : process.cwd()\n const directory = workingDirectory(input, cwd)\n const branch = resolveBranch(\n directory,\n options.which ?? ((name) => Bun.which(name)),\n options.spawnSync ?? ((argv, spawnOptions) => Bun.spawnSync(argv, spawnOptions))\n )\n const output = formatStatusline(input, {\n env: options.env ?? process.env,\n nowMs: options.nowMs ?? Date.now(),\n cwd,\n branch\n })\n if (output !== \"\") writeStdout(`${output}\\n`)\n return 0\n}\n\nif (import.meta.main) process.exit(await main())\n",
|
|
12
|
+
"SoT/.claude/bin/session-start.mjs": "import { readFileSync } from \"node:fs\"\nimport { homedir } from \"node:os\"\n\nfunction isRecord(value) {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nfunction nonEmpty(value, fallback) {\n return typeof value === \"string\" && value !== \"\" ? value : fallback\n}\n\nfunction pad(value) {\n return String(value).padStart(2, \"0\")\n}\n\nfunction configuredEffort(home, readText) {\n try {\n const parsed = JSON.parse(readText(`${home}/.claude/settings.json`))\n return isRecord(parsed) ? nonEmpty(parsed.effortLevel, \"default\") : \"default\"\n } catch {\n return \"default\"\n }\n}\n\nfunction localZone(now) {\n const part = new Intl.DateTimeFormat(\"en-US\", { timeZoneName: \"short\" })\n .formatToParts(now)\n .find((value) => value.type === \"timeZoneName\")\n return part?.value ?? \"\"\n}\n\nexport function sessionStartLines(options = {}) {\n const env = isRecord(options.env) ? options.env : process.env\n const now = options.now instanceof Date ? options.now : new Date()\n const home = typeof options.home === \"string\" ? options.home : homedir()\n const readText = options.readText ?? ((path) => readFileSync(path, \"utf8\"))\n const weekday = new Intl.DateTimeFormat(\"en-US\", { weekday: \"long\" }).format(now)\n const date = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`\n const time = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`\n const effort = nonEmpty(env.CLAUDE_CODE_EFFORT_LEVEL, configuredEffort(home, readText))\n const context = env.CLAUDE_CODE_DISABLE_1M_CONTEXT === \"1\" ? \"200K\" : \"1M\"\n const compactWindow = nonEmpty(env.CLAUDE_CODE_AUTO_COMPACT_WINDOW, \"full\")\n const subagent = nonEmpty(env.CLAUDE_CODE_SUBAGENT_MODEL, \"default\")\n return [\n `[CONTEXT] Current date: ${weekday}, ${date} ${time} ${localZone(now)}`,\n `[CONFIG] Context: ${context} | Compact-window: ${compactWindow} | Effort: ${effort} | Thinking: adaptive | Subagent: ${subagent}`\n ]\n}\n\nexport async function main(options = {}) {\n const writeStdout = options.writeStdout ?? ((value) => process.stdout.write(value))\n writeStdout(`${sessionStartLines(options).join(\"\\n\")}\\n`)\n return 0\n}\n\nif (import.meta.main) process.exit(await main())\n",
|
|
13
|
+
"SoT/.claude/bin/notify.mjs": "const DEFAULT_SOUND = `${import.meta.dir}/../notification.mp3`\n\nexport function selectPlayer(options = {}) {\n const platform = options.platform ?? process.platform\n const sound = options.sound ?? DEFAULT_SOUND\n const which = options.which ?? ((name) => Bun.which(name))\n if (platform === \"darwin\") {\n const afplay = which(\"afplay\")\n if (typeof afplay === \"string\" && afplay !== \"\") return [afplay, sound]\n }\n const ffplay = which(\"ffplay\")\n if (typeof ffplay === \"string\" && ffplay !== \"\") {\n return [ffplay, \"-nodisp\", \"-autoexit\", \"-loglevel\", \"quiet\", sound]\n }\n const paplay = which(\"paplay\")\n if (typeof paplay === \"string\" && paplay !== \"\") return [paplay, sound]\n const aplay = which(\"aplay\")\n if (typeof aplay === \"string\" && aplay !== \"\") return [aplay, \"-q\", sound]\n return undefined\n}\n\nexport async function main(options = {}) {\n const sound = options.sound ?? DEFAULT_SOUND\n const fileExists = options.fileExists ?? ((path) => Bun.file(path).exists())\n if (!await fileExists(sound)) return 0\n const command = selectPlayer({ ...options, sound })\n if (command === undefined) return 0\n const spawnSync = options.spawnSync ?? ((argv, spawnOptions) => Bun.spawnSync(argv, spawnOptions))\n const result = spawnSync(command, { stdin: \"ignore\", stdout: \"ignore\", stderr: \"ignore\" })\n return typeof result.exitCode === \"number\" ? result.exitCode : 1\n}\n\nif (import.meta.main) process.exit(await main())\n",
|
|
14
|
+
"SoT/.codex/AGENTS.md": "# AGENTS.md\n\n## 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\nModel-agnostic operating rules for coding-agent work.\n\n1. Persistence. Keep going until the user's request is actually handled. Only yield when the problem is solved or a concrete blocker is identified. Resolve in the fewest useful tool loops — once you can answer the core request with evidence, answer. 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, do that work now.\n2. Default to parallel. When multiple reads, searches, inspections, or independent checks can run without depending on each other, run them together.\n3. Multi-pass search. First-pass search often misses — vary the wording before concluding something does not exist.\n4. Trace symbols. Before modifying a symbol, trace its definition and usages. Do not infer behavior from one call site.\n5. Linter-loop 3-strike rule. Do not loop more than 3 times fixing the same lint/test failure without reassessing the diagnosis.\n6. Read-before-edit TTL. If you have not read a file recently, re-read it before editing. User edits can make cached context stale.\n7. Big-file rule. For files over 1000 lines, prefer targeted search plus scoped reads over whole-file reads.\n8. Task hygiene. Track meaningful deliverables, not operational sub-steps. Mark work complete as soon as it is done.\n9. Literal-instruction rule. Treat explicit user requirements as checklists with success criteria. Do not silently broaden scope.\n10. Context hygiene. Prefer a fresh session at task boundaries over carrying stale context; preserve useful state before quality decays. Never stop, summarize, or suggest a new session on account of context limits.\n11. Autonomy calibration. For minor choices (naming, formatting, defaults, equivalent approaches), pick a reasonable option and note it — do not 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; do not apply fixes until asked.\n12. Capability triggering. Search or fetch current documentation when the answer depends on current or version-specific information. When work fans out across independent items, parallelize or delegate; never delegate work you can complete directly. For verification, prefer a fresh-context check over self-critique. On long tasks, keep running notes and re-read them between phases.\n\n<constraint>\nTreat these heuristics as protocol. If a turn violates an applicable rule, self-correct before continuing.\n</constraint>\n\n## Engineering Discipline\n\n- Prefer the repository's existing patterns and helpers over new abstractions.\n- Keep edits scoped to the user's request and the surrounding ownership boundary.\n- Add abstractions only when they remove real complexity or match an established local pattern.\n- Preserve user changes. Never revert unrelated dirty work unless explicitly asked.\n- Verify with the narrowest useful command first, then broaden if risk warrants it.\n- Surface any test or verification you could not run.\n- Before the first tool call, state in one or two sentences what you are about to do; give a brief progress update every few execution steps.\n- Concise teammate tone: no status tics, no log-style updates; reference file paths instead of dumping contents; lead with what changed and why, not a \"Summary\" heading.\n- The final message is for a reader who did not watch the work: outcome first, complete sentences. Shorten by dropping detail, never by compressing into fragments or arrow chains.\n\n<constraint>\nNo secrets in committed config. Treat plugin marketplaces, installers, and downloaded artifacts as untrusted until verified.\n</constraint>\n\n## Agentic Engineering Discipline\n\n1. **State assumptions; push back when warranted.** If a requirement is ambiguous in a way that changes the deliverable, surface the ambiguity and propose 1–2 concrete interpretations in your first message — do not silently pick one. Surface inconsistencies instead of guessing past them; present tradeoffs when approaches genuinely differ; push back when the request looks wrong.\n2. **Minimum code that solves the stated problem.** No speculative features, no abstractions without a second caller, no broad exception handling around internally-trusted calls, no dead code left behind after a refactor, no comments that restate what the code says.\n3. **Surgical changes only.** Do not modify code, comments, or formatting outside the explicit scope of the request. Surface unrelated issues as follow-ups — do not fix inline.\n4. **State how success will be verified before implementing.** Name the test, build, smoke check, or diff inspection that will prove the change works. Prefer executable criteria — a test that fails before and passes after, a command with expected output — and keep each change small enough that its diff is reviewable in one sitting.\n5. **Review scope follows the pipeline.** In pipeline reviews with a downstream filter, report every issue found with confidence and severity — filtering happens downstream. In ad-hoc reviews, flag only gaps that affect correctness or the stated requirements; treat the rest as optional.\n6. **Ground every progress claim in evidence.** Before reporting progress or completion, audit each claim against a tool result from this session — show the test output, the command and what it returned. If something is unverified, say so explicitly; if tests fail, say so with the output.\n\n<constraint>\nTreat the six rules above as preventive (during generation), not remedial (after the fact). Self-correct if a turn drifts.\n</constraint>\n",
|
|
15
|
+
"SoT/.codex/config.toml": "model = \"gpt-5.6-sol\"\nmodel_reasoning_effort = \"xhigh\"\nplan_mode_reasoning_effort = \"xhigh\"\nmodel_reasoning_summary = \"detailed\"\nmodel_verbosity = \"medium\"\npersonality = \"pragmatic\"\nweb_search = \"live\"\nproject_doc_max_bytes = 131072\napproval_policy = \"on-request\"\nsandbox_mode = \"workspace-write\"\napprovals_reviewer = \"auto_review\"\n\n[sandbox_workspace_write]\nnetwork_access = true\n\n[features]\nmemories = true\n\n[memories]\ndedicated_tools = true\nmax_rollout_age_days = 30\n\n[agents]\nmax_threads = 12\nmax_depth = 2\n\n[tui]\nstatus_line_use_colors = true\nstatus_line = [\n \"model-with-reasoning\",\n \"current-dir\",\n \"git-branch\",\n \"context-used\",\n \"five-hour-limit\",\n \"weekly-limit\",\n]\n\n[plugins.\"docks@docks\"]\nenabled = true\n\n[plugins.\"session-relay@docks\"]\nenabled = true\n\n[plugins.\"effect-kit@docks\"]\nenabled = true\n",
|
|
16
|
+
"SoT/.codex/plugins/marketplace.json": "{\n \"name\": \"docks\",\n \"interface\": {\n \"displayName\": \"DocksDocks\"\n },\n \"plugins\": [\n {\n \"name\": \"docks\",\n \"source\": {\n \"source\": \"git-subdir\",\n \"url\": \"https://github.com/DocksDocks/docks.git\",\n \"path\": \"./plugins/docks\",\n \"ref\": \"main\"\n },\n \"policy\": {\n \"installation\": \"AVAILABLE\",\n \"authentication\": \"ON_INSTALL\"\n },\n \"category\": \"Productivity\"\n },\n {\n \"name\": \"session-relay\",\n \"source\": {\n \"source\": \"git-subdir\",\n \"url\": \"https://github.com/DocksDocks/docks.git\",\n \"path\": \"./plugins/session-relay\",\n \"ref\": \"main\"\n },\n \"policy\": {\n \"installation\": \"AVAILABLE\",\n \"authentication\": \"ON_INSTALL\"\n },\n \"category\": \"Productivity\"\n },\n {\n \"name\": \"effect-kit\",\n \"source\": {\n \"source\": \"git-subdir\",\n \"url\": \"https://github.com/DocksDocks/docks.git\",\n \"path\": \"./plugins/effect-kit\",\n \"ref\": \"main\"\n },\n \"policy\": {\n \"installation\": \"AVAILABLE\",\n \"authentication\": \"ON_INSTALL\"\n },\n \"category\": \"Productivity\"\n }\n ]\n}\n",
|
|
17
|
+
"SoT/.codex/rules/docks.rules": "prefix_rule(pattern=[\"pwd\"], decision=\"allow\")\nprefix_rule(pattern=[\"ls\"], decision=\"allow\")\nprefix_rule(pattern=[\"cat\"], decision=\"allow\")\nprefix_rule(pattern=[\"head\"], decision=\"allow\")\nprefix_rule(pattern=[\"tail\"], decision=\"allow\")\nprefix_rule(pattern=[\"wc\"], decision=\"allow\")\nprefix_rule(pattern=[\"nl\"], decision=\"allow\")\nprefix_rule(pattern=[\"grep\"], decision=\"allow\")\nprefix_rule(pattern=[\"sort\"], decision=\"allow\")\nprefix_rule(pattern=[\"uniq\"], decision=\"allow\")\nprefix_rule(pattern=[\"diff\"], decision=\"allow\")\nprefix_rule(pattern=[\"which\"], decision=\"allow\")\nprefix_rule(pattern=[\"date\"], decision=\"allow\")\nprefix_rule(pattern=[\"basename\"], decision=\"allow\")\nprefix_rule(pattern=[\"dirname\"], decision=\"allow\")\nprefix_rule(pattern=[\"realpath\"], decision=\"allow\")\nprefix_rule(pattern=[\"readlink\"], decision=\"allow\")\nprefix_rule(pattern=[\"jq\"], decision=\"allow\")\nprefix_rule(pattern=[\"tree\"], decision=\"allow\")\nprefix_rule(pattern=[\"cut\"], decision=\"allow\")\nprefix_rule(pattern=[\"tr\"], decision=\"allow\")\nprefix_rule(pattern=[\"echo\"], decision=\"allow\")\nprefix_rule(pattern=[\"printf\"], decision=\"allow\")\nprefix_rule(pattern=[\"printenv\"], decision=\"allow\")\nprefix_rule(pattern=[\"uname\"], decision=\"allow\")\nprefix_rule(pattern=[\"file\"], decision=\"allow\")\nprefix_rule(pattern=[\"stat\"], decision=\"allow\")\nprefix_rule(pattern=[\"du\"], decision=\"allow\")\nprefix_rule(pattern=[\"id\"], decision=\"allow\")\nprefix_rule(pattern=[\"whoami\"], decision=\"allow\")\n\nprefix_rule(pattern=[\"git\", \"status\"], decision=\"allow\")\nprefix_rule(pattern=[\"git\", \"diff\"], decision=\"allow\")\nprefix_rule(pattern=[\"git\", \"log\"], decision=\"allow\")\nprefix_rule(pattern=[\"git\", \"show\"], decision=\"allow\")\nprefix_rule(pattern=[\"git\", \"blame\"], decision=\"allow\")\nprefix_rule(pattern=[\"git\", \"rev-parse\"], decision=\"allow\")\nprefix_rule(pattern=[\"git\", \"ls-files\"], decision=\"allow\")\nprefix_rule(pattern=[\"git\", \"grep\"], decision=\"allow\")\nprefix_rule(pattern=[\"git\", \"ls-tree\"], decision=\"allow\")\nprefix_rule(pattern=[\"git\", \"branch\", \"--show-current\"], decision=\"allow\")\nprefix_rule(pattern=[\"git\", \"branch\", \"-vv\"], decision=\"allow\")\nprefix_rule(pattern=[\"git\", \"mv\"], decision=\"allow\")\n\nprefix_rule(pattern=[\"gh\", \"pr\", \"view\"], decision=\"allow\")\nprefix_rule(pattern=[\"gh\", \"pr\", \"list\"], decision=\"allow\")\nprefix_rule(pattern=[\"gh\", \"pr\", \"diff\"], decision=\"allow\")\nprefix_rule(pattern=[\"gh\", \"pr\", \"status\"], decision=\"allow\")\nprefix_rule(pattern=[\"gh\", \"pr\", \"checks\"], decision=\"allow\")\n\nprefix_rule(pattern=[\"docker\", \"ps\"], decision=\"allow\")\n\nprefix_rule(pattern=[\"git\", \"push\"], decision=\"prompt\")\nprefix_rule(pattern=[\"git\", \"reset\"], decision=\"prompt\")\nprefix_rule(pattern=[\"git\", \"clean\"], decision=\"prompt\")\nprefix_rule(pattern=[\"git\", \"merge\"], decision=\"prompt\")\nprefix_rule(pattern=[\"git\", \"rebase\"], decision=\"prompt\")\nprefix_rule(pattern=[\"git\", \"checkout\"], decision=\"prompt\")\n\nprefix_rule(pattern=[\"rm\"], decision=\"prompt\")\nprefix_rule(pattern=[\"mv\"], decision=\"prompt\")\nprefix_rule(pattern=[\"chmod\"], decision=\"prompt\")\nprefix_rule(pattern=[\"chown\"], decision=\"prompt\")\nprefix_rule(pattern=[\"kill\"], decision=\"prompt\")\nprefix_rule(pattern=[\"pkill\"], decision=\"prompt\")\n\nprefix_rule(pattern=[\"npm\", \"install\"], decision=\"prompt\")\nprefix_rule(pattern=[\"npm\", \"uninstall\"], decision=\"prompt\")\nprefix_rule(pattern=[\"pnpm\", \"add\"], decision=\"prompt\")\nprefix_rule(pattern=[\"pnpm\", \"remove\"], decision=\"prompt\")\nprefix_rule(pattern=[\"yarn\", \"add\"], decision=\"prompt\")\nprefix_rule(pattern=[\"yarn\", \"remove\"], decision=\"prompt\")\nprefix_rule(pattern=[\"pip\", \"install\"], decision=\"prompt\")\nprefix_rule(pattern=[\"pip\", \"uninstall\"], decision=\"prompt\")\nprefix_rule(pattern=[\"pip3\", \"install\"], decision=\"prompt\")\nprefix_rule(pattern=[\"pip3\", \"uninstall\"], decision=\"prompt\")\n\nprefix_rule(pattern=[\"docker\", \"run\"], decision=\"prompt\")\nprefix_rule(pattern=[\"docker\", \"rm\"], decision=\"prompt\")\nprefix_rule(pattern=[\"docker\", \"stop\"], decision=\"prompt\")\nprefix_rule(pattern=[\"docker\", \"volume\"], decision=\"prompt\")\nprefix_rule(pattern=[\"docker\", \"system\"], decision=\"prompt\")\nprefix_rule(pattern=[\"docker\", \"compose\", \"up\"], decision=\"prompt\")\nprefix_rule(pattern=[\"docker\", \"compose\", \"down\"], decision=\"prompt\")\nprefix_rule(pattern=[\"docker\", \"compose\", \"rm\"], decision=\"prompt\")\nprefix_rule(pattern=[\"docker\", \"compose\", \"stop\"], decision=\"prompt\")\nprefix_rule(pattern=[\"docker-compose\", \"up\"], decision=\"prompt\")\nprefix_rule(pattern=[\"docker-compose\", \"down\"], decision=\"prompt\")\nprefix_rule(pattern=[\"docker-compose\", \"rm\"], decision=\"prompt\")\nprefix_rule(pattern=[\"docker-compose\", \"stop\"], decision=\"prompt\")\n\n# `tail -f`/`--follow` never returns and hangs the agent (bare `tail` stays allowed above).\nprefix_rule(pattern=[\"tail\", \"-f\"], decision=\"prompt\")\nprefix_rule(pattern=[\"tail\", \"--follow\"], decision=\"prompt\")\n# rg and `sed -n` are prompt, NOT allow: argv-prefix matching cannot gate their\n# code-exec forms (rg --pre=CMD or a reordered --pre; sed -n 'e CMD' / -ni) while a\n# shorter allow prefix would auto-approve the whole command.\nprefix_rule(pattern=[\"rg\"], decision=\"prompt\")\nprefix_rule(pattern=[\"sed\", \"-n\"], decision=\"prompt\")\nprefix_rule(pattern=[\"find\"], decision=\"prompt\")\nprefix_rule(pattern=[\"sed\", \"-i\"], decision=\"prompt\")\nprefix_rule(pattern=[\"sed\", \"--in-place\"], decision=\"prompt\")\nprefix_rule(pattern=[\"awk\"], decision=\"prompt\")\nprefix_rule(pattern=[\"xargs\"], decision=\"prompt\")\nprefix_rule(pattern=[\"tee\"], decision=\"prompt\")\nprefix_rule(pattern=[\"curl\"], decision=\"prompt\")\nprefix_rule(pattern=[\"env\"], decision=\"prompt\")\n\nprefix_rule(pattern=[\"sudo\"], decision=\"forbidden\")\nprefix_rule(pattern=[\"eval\"], decision=\"forbidden\")\nprefix_rule(pattern=[\"mkfs\"], decision=\"forbidden\")\nprefix_rule(pattern=[\"dd\"], decision=\"forbidden\")\nprefix_rule(pattern=[\"git\", \"push\", \"--force\", \"origin\", \"main\"], decision=\"forbidden\")\nprefix_rule(pattern=[\"git\", \"push\", \"--force\", \"origin\", \"master\"], decision=\"forbidden\")\nprefix_rule(pattern=[\"git\", \"push\", \"-f\", \"origin\", \"main\"], decision=\"forbidden\")\nprefix_rule(pattern=[\"git\", \"push\", \"-f\", \"origin\", \"master\"], decision=\"forbidden\")\n"
|
|
18
|
+
} as const
|
|
19
|
+
|
|
20
|
+
export const GENERATED_PAYLOAD_BASE64 = {
|
|
21
|
+
"notification.mp3": "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"
|
|
22
|
+
} as const
|
|
23
|
+
|
|
24
|
+
export const GENERATED_PAYLOAD_PATHS = [
|
|
25
|
+
"SoT/.agents/skills.txt",
|
|
26
|
+
"SoT/models.json",
|
|
27
|
+
"SoT/toolchain.json",
|
|
28
|
+
"SoT/.claude/CLAUDE.md",
|
|
29
|
+
"SoT/.claude/mcp-servers.json",
|
|
30
|
+
"SoT/.claude/settings.json",
|
|
31
|
+
"SoT/.claude/bin/statusline.mjs",
|
|
32
|
+
"SoT/.claude/bin/session-start.mjs",
|
|
33
|
+
"SoT/.claude/bin/notify.mjs",
|
|
34
|
+
"SoT/.codex/AGENTS.md",
|
|
35
|
+
"SoT/.codex/config.toml",
|
|
36
|
+
"SoT/.codex/plugins/marketplace.json",
|
|
37
|
+
"SoT/.codex/rules/docks.rules",
|
|
38
|
+
"notification.mp3"
|
|
39
|
+
] as const
|
|
40
|
+
|
|
41
|
+
export const GENERATED_PAYLOAD_HASH = "4b7580dd66aeaabf4a11c62a01290837398c9ced7790d2dcb2ef056c9f2151e7"
|
package/cli/src/kitHome.ts
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readFileSync } from "node:fs"
|
|
2
2
|
import { dirname, join, resolve } from "node:path"
|
|
3
3
|
|
|
4
|
-
const isKitHome = (dir: string): boolean =>
|
|
5
|
-
|
|
4
|
+
const isKitHome = (dir: string): boolean => {
|
|
5
|
+
try {
|
|
6
|
+
const manifest = JSON.parse(readFileSync(join(dir, "package.json"), "utf8")) as { name?: unknown }
|
|
7
|
+
return manifest.name === "docks-kit"
|
|
8
|
+
} catch {
|
|
9
|
+
return false
|
|
10
|
+
}
|
|
11
|
+
}
|
|
6
12
|
|
|
7
13
|
/**
|
|
8
|
-
* Resolve the
|
|
14
|
+
* Resolve the optional checkout/package home used for display and updates:
|
|
9
15
|
* DOCKS_KIT_HOME env → nearest ancestor of cwd (repo-checkout usage) →
|
|
10
|
-
* the package's own root (bunx / bun add -g usage
|
|
11
|
-
*
|
|
16
|
+
* the package's own root (bunx / bun add -g usage) → standalone executable
|
|
17
|
+
* directory. Payload availability is independent of this location.
|
|
12
18
|
*/
|
|
13
19
|
export const kitHome = (): string => {
|
|
14
20
|
const env = process.env["DOCKS_KIT_HOME"]
|
|
15
21
|
if (env !== undefined && env !== "") {
|
|
16
|
-
if (isKitHome(env)) return env
|
|
17
|
-
throw new Error(`DOCKS_KIT_HOME=${env}
|
|
22
|
+
if (isKitHome(env)) return resolve(env)
|
|
23
|
+
throw new Error(`DOCKS_KIT_HOME=${env} is not a docks-kit package root (package.json name must be "docks-kit")`)
|
|
18
24
|
}
|
|
19
25
|
let dir = process.cwd()
|
|
20
26
|
for (;;) {
|
|
@@ -25,7 +31,5 @@ export const kitHome = (): string => {
|
|
|
25
31
|
}
|
|
26
32
|
const packageRoot = resolve(import.meta.dir, "..", "..")
|
|
27
33
|
if (isKitHome(packageRoot)) return packageRoot
|
|
28
|
-
|
|
29
|
-
"docks-kit home not found — run inside the kit repo or set DOCKS_KIT_HOME"
|
|
30
|
-
)
|
|
34
|
+
return dirname(process.execPath)
|
|
31
35
|
}
|
package/cli/src/manifests.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFileSync, readdirSync, readlinkSync, existsSync } from "node:fs"
|
|
2
2
|
import { homedir } from "node:os"
|
|
3
3
|
import { join } from "node:path"
|
|
4
|
-
import {
|
|
4
|
+
import { payloadText } from "./payload"
|
|
5
5
|
|
|
6
6
|
export { homedir }
|
|
7
7
|
|
|
@@ -19,30 +19,35 @@ export interface ModelCatalog {
|
|
|
19
19
|
export type Tool = "claude" | "codex"
|
|
20
20
|
|
|
21
21
|
const readJson = (path: string): any => JSON.parse(readFileSync(path, "utf8"))
|
|
22
|
+
const readJsonText = (text: string): any => JSON.parse(text)
|
|
22
23
|
|
|
23
24
|
export const modelCatalog = (tool: Tool): ModelCatalog =>
|
|
24
|
-
|
|
25
|
+
readJsonText(payloadText("SoT/models.json"))[tool]
|
|
25
26
|
|
|
26
27
|
export const toolchainManifest = (): Record<string, any> =>
|
|
27
|
-
|
|
28
|
+
readJsonText(payloadText("SoT/toolchain.json")).tools
|
|
28
29
|
|
|
29
30
|
/** SoT settings (claude) — model/effort/env for drift display. */
|
|
30
31
|
export const sotClaudeSettings = (): any =>
|
|
31
|
-
|
|
32
|
+
readJsonText(payloadText("SoT/.claude/settings.json"))
|
|
32
33
|
|
|
33
34
|
export const deployedClaudeSettings = (): any | undefined => {
|
|
34
35
|
const p = join(homedir(), ".claude", "settings.json")
|
|
35
36
|
return existsSync(p) ? readJson(p) : undefined
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
const tomlModelText = (text: string): string | undefined => {
|
|
40
|
+
const m = text.match(/^model\s*=\s*"([^"]+)"/m)
|
|
41
|
+
return m?.[1]
|
|
42
|
+
}
|
|
43
|
+
|
|
38
44
|
const tomlModel = (path: string): string | undefined => {
|
|
39
45
|
if (!existsSync(path)) return undefined
|
|
40
|
-
|
|
41
|
-
return m?.[1]
|
|
46
|
+
return tomlModelText(readFileSync(path, "utf8"))
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
export const sotCodexModel = (): string | undefined =>
|
|
45
|
-
|
|
50
|
+
tomlModelText(payloadText("SoT/.codex/config.toml"))
|
|
46
51
|
|
|
47
52
|
export const deployedCodexModel = (): string | undefined =>
|
|
48
53
|
tomlModel(join(homedir(), ".codex", "config.toml"))
|
|
@@ -73,14 +78,11 @@ export const skillsView = (): Array<{
|
|
|
73
78
|
installed: boolean
|
|
74
79
|
claudeSymlink: boolean
|
|
75
80
|
}> => {
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
.filter((l) => l.length > 0)
|
|
82
|
-
.map((slug) => slug.split("/").pop() as string)
|
|
83
|
-
: []
|
|
81
|
+
const declared = payloadText("SoT/.agents/skills.txt")
|
|
82
|
+
.split("\n")
|
|
83
|
+
.map((l) => l.replace(/#.*$/, "").trim())
|
|
84
|
+
.filter((l) => l.length > 0)
|
|
85
|
+
.map((slug) => slug.split("/").pop() as string)
|
|
84
86
|
const skillsDir = join(homedir(), ".agents", "skills")
|
|
85
87
|
const installed = existsSync(skillsDir)
|
|
86
88
|
? readdirSync(skillsDir, { withFileTypes: true })
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { existsSync } from "node:fs"
|
|
2
|
+
import { join } from "node:path"
|
|
3
|
+
import {
|
|
4
|
+
GENERATED_PAYLOAD_BASE64,
|
|
5
|
+
GENERATED_PAYLOAD_PATHS,
|
|
6
|
+
GENERATED_PAYLOAD_TEXT
|
|
7
|
+
} from "./generated/sotPayload"
|
|
8
|
+
|
|
9
|
+
export type PayloadPath = typeof GENERATED_PAYLOAD_PATHS[number]
|
|
10
|
+
type TextPayloadPath = Exclude<PayloadPath, "notification.mp3">
|
|
11
|
+
|
|
12
|
+
export function payloadText(path: TextPayloadPath): string {
|
|
13
|
+
return GENERATED_PAYLOAD_TEXT[path]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function payloadBytes(path: PayloadPath): Buffer {
|
|
17
|
+
if (path === "notification.mp3") return Buffer.from(GENERATED_PAYLOAD_BASE64[path], "base64")
|
|
18
|
+
return Buffer.from(payloadText(path))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function payloadPaths(prefix: string): ReadonlyArray<PayloadPath> {
|
|
22
|
+
return GENERATED_PAYLOAD_PATHS.filter((path) => path.startsWith(prefix))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function payloadDisplayPath(path: PayloadPath, kitHome?: string): string {
|
|
26
|
+
if (kitHome === undefined || !existsSync(join(kitHome, "package.json"))) return `embedded:${path}`
|
|
27
|
+
return `${kitHome.replace(/[\\/]+$/, "")}/${path}`
|
|
28
|
+
}
|
package/docks-kit
CHANGED
|
@@ -7,6 +7,10 @@ set -euo pipefail
|
|
|
7
7
|
|
|
8
8
|
REPO_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
9
9
|
|
|
10
|
+
# BEGIN GENERATED BUN PIN
|
|
11
|
+
BUN_PIN="1.3.14"
|
|
12
|
+
# END GENERATED BUN PIN
|
|
13
|
+
|
|
10
14
|
case "$(uname -s)-$(uname -m)" in
|
|
11
15
|
Linux-x86_64) KIT_BIN="docks-kit-linux-x64" ;;
|
|
12
16
|
Linux-aarch64) KIT_BIN="docks-kit-linux-arm64" ;;
|
|
@@ -39,12 +43,8 @@ if ! BUN="$(find_bun)"; then
|
|
|
39
43
|
echo "[docks-kit] curl missing too. Install Bun manually (https://bun.sh) or download a docks-kit release binary." >&2
|
|
40
44
|
exit 1
|
|
41
45
|
fi
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
BUN_PIN=""
|
|
45
|
-
if command -v jq >/dev/null 2>&1; then
|
|
46
|
-
BUN_PIN="$(jq -r '.tools.bun.verified // empty' "$REPO_DIR/SoT/toolchain.json" 2>/dev/null || true)"
|
|
47
|
-
fi
|
|
46
|
+
# The installer takes a bun-vX.Y.Z release tag as $1. BUN_PIN is generated
|
|
47
|
+
# from the authoring toolchain manifest alongside the embedded payload.
|
|
48
48
|
tmp_installer=$(mktemp 2>/dev/null || echo "/tmp/bun-install-$$.sh")
|
|
49
49
|
curl -fsSL https://bun.sh/install -o "$tmp_installer" && bash "$tmp_installer" ${BUN_PIN:+"bun-v$BUN_PIN"} >/dev/null 2>&1 || true
|
|
50
50
|
rm -f "$tmp_installer"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docks-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Portable AI coding agent config kit — SoT sync engine + typed CLI for Claude Code, Codex, and universal agent skills",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -15,8 +15,6 @@
|
|
|
15
15
|
"cli/src",
|
|
16
16
|
"cli/docs",
|
|
17
17
|
"cli/tsconfig.json",
|
|
18
|
-
"SoT",
|
|
19
|
-
"notification.mp3",
|
|
20
18
|
"docks-kit",
|
|
21
19
|
"AGENTS.md",
|
|
22
20
|
"README.md"
|
|
@@ -24,6 +22,7 @@
|
|
|
24
22
|
"scripts": {
|
|
25
23
|
"typecheck": "tsc --noEmit -p cli",
|
|
26
24
|
"build:binaries": "bash cli/build-binaries.sh",
|
|
25
|
+
"prepack": "bun cli/scripts/generate-sot-payload.ts --check",
|
|
27
26
|
"golden:dryrun": "bun cli/test/golden-dryrun.ts",
|
|
28
27
|
"golden:mutation": "bun cli/test/golden-mutation.ts",
|
|
29
28
|
"test:unit": "vitest run"
|
package/SoT/.agents/skills.txt
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Universal AI-agent skills (agentskills.io standard).
|
|
2
|
-
# Bootstrapped to ~/.agents/skills/ by cli/src/engine-native/skillsSync.ts during ./docks-kit sync.
|
|
3
|
-
# One slug per line: <owner>/<repo>. Lines starting with # are comments.
|
|
4
|
-
# Each skill's canonical SKILL.md lands in ~/.agents/skills/<name>/ — Codex
|
|
5
|
-
# reads that path natively; Claude Code gets a ~/.claude/skills/<name>
|
|
6
|
-
# symlink to it. The skills sync names both agents the kit supports
|
|
7
|
-
# (-a claude-code codex) so the CLI keeps the shared canonical copy.
|
|
8
|
-
|
|
9
|
-
# Browser automation CLI — reaches JS-rendered, auth-walled, login-gated pages
|
|
10
|
-
# (x.com, LinkedIn, Confluence) that built-in WebFetch can't. The skills sync
|
|
11
|
-
# auto-installs the `agent-browser` npm package + downloads Chrome for Testing
|
|
12
|
-
# (~175 MB) on first sync; Linux runs `agent-browser install --with-deps` which
|
|
13
|
-
# may prompt for sudo to install system libs (libnss3, libatk, ...).
|
|
14
|
-
vercel-labs/agent-browser
|