docks-kit 0.16.15 → 0.16.17
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 +4 -4
- package/cli/docs/install.md +3 -2
- package/cli/docs/sync-layers.md +1 -1
- package/cli/docs/toolchain.md +21 -7
- package/cli/src/commands/sync.ts +1 -1
- package/cli/src/engine-native/claudePlugins.ts +92 -28
- package/cli/src/engine-native/deps.ts +9 -0
- package/cli/src/engine-native/toolchain.ts +13 -1
- package/cli/src/generated/sotPayload.ts +4 -4
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -80,7 +80,7 @@ For per-tool SoT layouts (`SoT/.claude/`, `SoT/.codex/`, `SoT/.omp/`), see the m
|
|
|
80
80
|
- **Idempotent operations.** Every EngineNative sync step must be safe to re-run. Settings merges, plugin installs, and marketplace adds are all idempotent — re-running with no SoT changes is a no-op.
|
|
81
81
|
- **Failed harness-CLI operations fail the sync.** A kit-managed marketplace or plugin command that exits non-zero is recorded through `failures.ts recordFailure` — it still warns in place, and `index.ts engineSync, failure ledger` lists every entry under `--- Failures ---` after the summary, then returns exit 1. A skip is not a failure: a missing harness CLI, missing git, a missing `SoT/toolchain.json` pin, and an unavailable plugin inventory stay warn-only with exit 0, and `ompSync.ts syncMarketplace, probe guard` returns before spawning so a host without omp never records one. Aggregate roll-up warnings (`N plugin operation(s) failed`) stay warns, because each counted site already records itself.
|
|
82
82
|
- **Removed bash engine.** The bash engine was removed after the `bash-engine-final` tag. `DOCKS_KIT_ENGINE=bash` must fail with the removed-engine message; engine bugs are fixed forward in EngineNative.
|
|
83
|
-
- **Effect 4 CLI stack.** The CLI pins `effect@4.0.0-rc.
|
|
83
|
+
- **Effect 4 CLI stack.** The CLI pins `effect@4.0.0-rc.115` (including `effect/unstable/cli`), `@effect/platform-bun@4.0.0-rc.115` (`BunServices.layer`, `BunRuntime.runMain`), `@effect/vitest@4.0.0-rc.115`, and `vitest@5.0.0` (inside the `@effect/vitest` peer range `>=5.0.0 <6.0.0`; 5.0.0 is past the 5.x patch point for GHSA-82fw-gwwq-j7x9, fixed in 5.0.0-rc.2). `@effect/cli` and `@effect/platform` are removed and must not be reintroduced.
|
|
84
84
|
- **Effect skill routing.** Effect work in this checkout must verify migration and API call shapes against the installed declarations under `node_modules/effect/dist/unstable/cli/`, never from memory or a mutable dist-tag. The `effect-ts-setup`, `effect-ts-port`, and `effect-ts-specialist` skills target Effect 3.x and do not apply.
|
|
85
85
|
- **Targeted syncs.** `./docks-kit sync` accepts positional targets: `claude`, `codex`, `agents`, and `omp`. Use the narrowest target that matches the SoT change (for example, `./docks-kit sync omp` for omp-only config edits); targets can be combined with `--dry-run`, `--skip-bubblewrap` (skip optional bubblewrap bootstrap for the Codex Linux sandbox), `--skip-plugin-refresh` (install missing plugins without refreshing existing caches), `--reconcile`, `--prune`, and the deploy-time modifiers `--claude-compact-window=<tokens>` / `--claude-permissive` / `--claude-model=<m>` / `--claude-effort=<level>` / `--claude-advisor=<on|off|default>` / `--codex-model=<m>` / `--codex-effort=<level>` (see `CLAUDE.md` § Deploy-time modifiers).
|
|
86
86
|
- **Per-machine harness selection.** `~/.docks-kit/state.json` drives a flag-less sync. A missing file selects `claude`, `codex`, and `agents`; it never selects `omp` implicitly. `sync` never prompts and never writes the selection file. `docks-kit harnesses` is the only command that writes the selection.
|
package/README.md
CHANGED
|
@@ -59,10 +59,10 @@ docks-kit docs [topic] self-documentation (10 topics)
|
|
|
59
59
|
The CLI is a typed Effect 4 RC front-end on Bun; all mutation runs through
|
|
60
60
|
EngineNative in `cli/src/engine-native/`, with golden-regression coverage for
|
|
61
61
|
dry-run output, mutation snapshots, and argv logs. Its dependency graph is
|
|
62
|
-
`effect@4.0.0-rc.
|
|
63
|
-
`@effect/platform-bun@4.0.0-rc.
|
|
64
|
-
`BunRuntime.runMain`), `@effect/vitest@4.0.0-rc.
|
|
65
|
-
(inside the `@effect/vitest` peer range `>=
|
|
62
|
+
`effect@4.0.0-rc.115` (including `effect/unstable/cli`),
|
|
63
|
+
`@effect/platform-bun@4.0.0-rc.115` (`BunServices.layer` and
|
|
64
|
+
`BunRuntime.runMain`), `@effect/vitest@4.0.0-rc.115`, and `vitest@5.0.0`
|
|
65
|
+
(inside the `@effect/vitest` peer range `>=5.0.0 <6.0.0`). `@effect/cli` and
|
|
66
66
|
`@effect/platform` are removed: neither has a 4.x release, the CLI API moved
|
|
67
67
|
into core, and the standalone platform package was unused here.
|
|
68
68
|
|
package/cli/docs/install.md
CHANGED
|
@@ -40,9 +40,9 @@ one package with an `install` script, `msgpackr-extract` by way of
|
|
|
40
40
|
`effect > msgpackr`, and Bun raises no trust prompt for it.
|
|
41
41
|
|
|
42
42
|
The install prints no peer dependency warning. The root pins
|
|
43
|
-
`@effect/platform-node-shared` at `4.0.0-rc.
|
|
43
|
+
`@effect/platform-node-shared` at `4.0.0-rc.115`, the same release as the
|
|
44
44
|
pinned `effect`, so a fresh registry resolution installs exactly one copy of
|
|
45
|
-
each and the transitive peer range `effect@^4.0.0-rc.
|
|
45
|
+
each and the transitive peer range `effect@^4.0.0-rc.115` is satisfied. Without
|
|
46
46
|
that root pin, `@effect/platform-bun` requests the shared package through a
|
|
47
47
|
caret range over a prerelease and a fresh install can pair a newer shared
|
|
48
48
|
package with the pinned `effect`.
|
|
@@ -153,6 +153,7 @@ sync/config reads.
|
|
|
153
153
|
|
|
154
154
|
- Bun for source/global installs; release binaries embed the runtime
|
|
155
155
|
- Node/npm for npm-global LSP servers
|
|
156
|
+
- rustup is optional and needed only for the Rust language server
|
|
156
157
|
- jq is optional doctor/test tooling; sync has no jq runtime dependency
|
|
157
158
|
- curl is required only when a source launcher must download Bun. The POSIX
|
|
158
159
|
launchers run `install.sh`; Windows runs `install.ps1` through PowerShell.
|
package/cli/docs/sync-layers.md
CHANGED
|
@@ -30,7 +30,7 @@ Order matters — runtime readiness and settings form one transaction:
|
|
|
30
30
|
7. **Plugins** — seven idempotent passes via the `claude plugin` CLI
|
|
31
31
|
(marketplaces → install → update → [--prune: uninstall/remove] → re-assert
|
|
32
32
|
SoT enabled-state). Optional opt-ins via `--claude-plugin=<name>`.
|
|
33
|
-
8. LSP server binaries (npm globals).
|
|
33
|
+
8. LSP server binaries (npm globals plus the rust-analyzer rustup component).
|
|
34
34
|
|
|
35
35
|
The statusline reads Claude's native `rate_limits`. There is no OAuth request,
|
|
36
36
|
usage cache, jq/curl runtime dependency, or Stop fetch hook.
|
package/cli/docs/toolchain.md
CHANGED
|
@@ -34,19 +34,33 @@ an installer. An already-present Bun skips that download on every host.
|
|
|
34
34
|
from `typescript-language-server` 6's `engines` field. The kit installs that
|
|
35
35
|
server as an npm global for the `typescript-lsp` plugin, so an older Node runs
|
|
36
36
|
a server its own manifest rejects. `docks-kit toolchain check` prints
|
|
37
|
-
`below-floor` for a Node older than 22.22.2
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
`below-floor` for a Node older than 22.22.2. The sync pass reads the same
|
|
38
|
+
floor: it skips the `typescript-language-server` install on such a host, warns
|
|
39
|
+
with the host Node version, and installs the other language servers. Nothing
|
|
40
|
+
else consults the floor, so a host below it still runs every kit operation.
|
|
41
|
+
|
|
42
|
+
## rust-analyzer: no floor, no pin
|
|
43
|
+
|
|
44
|
+
`rust-analyzer` is a `check` row with no floor and no `verified` pin. The kit
|
|
45
|
+
installs the component with `rustup component add rust-analyzer` for the
|
|
46
|
+
`rust-analyzer-lsp` plugin, so the version follows the host Rust toolchain. A
|
|
47
|
+
pin would claim control the kit does not have, the stance `bubblewrap` already
|
|
48
|
+
takes for a tool the kit does not publish. `docks-kit toolchain check` reports
|
|
49
|
+
the installed version and judges nothing.
|
|
40
50
|
|
|
41
51
|
## Language-server upgrades
|
|
42
52
|
|
|
43
53
|
`claudeSync syncLspServers` installs `intelephense`, `typescript-language-server`,
|
|
44
|
-
and `
|
|
45
|
-
that is already present. A `verified` bump therefore reaches
|
|
46
|
-
immediately and leaves an existing install alone.
|
|
54
|
+
`typescript`, and `rust-analyzer` only when the binary is missing. It never
|
|
55
|
+
upgrades a server that is already present. A `verified` bump therefore reaches
|
|
56
|
+
a fresh host immediately and leaves an existing install alone.
|
|
57
|
+
|
|
58
|
+
The rustup channel follows the same rule. Sync adds the component only when the
|
|
59
|
+
`rust-analyzer` binary is missing, and `rustup update` is the user's remedy for
|
|
60
|
+
an old component.
|
|
47
61
|
|
|
48
62
|
A lagging server shows as `below-floor` in `docks-kit toolchain check`. To move
|
|
49
|
-
it, install the pinned version by hand:
|
|
63
|
+
it, upgrade Node to 22.22.2 or newer, then install the pinned version by hand:
|
|
50
64
|
|
|
51
65
|
```bash
|
|
52
66
|
npm install -g typescript-language-server@6.0.0
|
package/cli/src/commands/sync.ts
CHANGED
|
@@ -31,7 +31,7 @@ const updateNudge = (logger: Logger): void => {
|
|
|
31
31
|
|
|
32
32
|
const VALID_TARGETS = ["claude", "codex", "agents", "omp"]
|
|
33
33
|
|
|
34
|
-
const targets = Argument.String("target").pipe(
|
|
34
|
+
const targets: Argument.Argument<ReadonlyArray<string>> = Argument.String("target").pipe(
|
|
35
35
|
Argument.withDescription("Sync targets: claude, codex, agents, omp (default: selected harnesses)"),
|
|
36
36
|
Argument.variadic()
|
|
37
37
|
)
|
|
@@ -8,7 +8,7 @@ import { p, spawnProcess } from "./exec"
|
|
|
8
8
|
import { recordFailure } from "./failures"
|
|
9
9
|
import type { Ctx } from "./index"
|
|
10
10
|
import { compareCodepoints, deepMerge, isObject, jqStringify, parseJson, readJsonFile, type Json } from "./jq"
|
|
11
|
-
import { field } from "./toolchain"
|
|
11
|
+
import { belowFloor, field, installedVersion } from "./toolchain"
|
|
12
12
|
import { payloadText } from "../payload"
|
|
13
13
|
|
|
14
14
|
async function cli(args: Array<string>): Promise<{ ok: boolean; out: string; detail: string }> {
|
|
@@ -389,35 +389,23 @@ function lspPkg(ctx: Ctx, tool: string, pkg: string): string | undefined {
|
|
|
389
389
|
return undefined
|
|
390
390
|
}
|
|
391
391
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
const missingToolCount = Number(phpMissing) + Number(tsServerMissing) + Number(tscMissing)
|
|
405
|
-
const missing = [
|
|
406
|
-
phpMissing ? lspPkg(ctx, "intelephense", "intelephense") : undefined,
|
|
407
|
-
tsServerMissing ? lspPkg(ctx, "typescript-language-server", "typescript-language-server") : undefined,
|
|
408
|
-
tscMissing ? lspPkg(ctx, "tsc", "typescript") : undefined
|
|
409
|
-
].filter((spec): spec is string => spec !== undefined)
|
|
392
|
+
/**
|
|
393
|
+
* npm treats a package's `engines` field as advisory unless the host opted
|
|
394
|
+
* into engine-strict, so installing typescript-language-server 6 on an older
|
|
395
|
+
* Node succeeds and then fails at every startup. Report the host Node version
|
|
396
|
+
* when it is too old, and the empty string when the install is safe.
|
|
397
|
+
*/
|
|
398
|
+
async function nodeBelowServerFloor(ctx: Ctx): Promise<string> {
|
|
399
|
+
const floor = field("node", "floor")
|
|
400
|
+
if (floor === "") return ""
|
|
401
|
+
const installed = await installedVersion(ctx, "node")
|
|
402
|
+
return belowFloor(installed, floor) ? installed : ""
|
|
403
|
+
}
|
|
410
404
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
} else {
|
|
415
|
-
verbose("LSP server binaries present")
|
|
416
|
-
}
|
|
417
|
-
return
|
|
418
|
-
}
|
|
405
|
+
/** npm-global channel: intelephense, typescript-language-server, typescript. */
|
|
406
|
+
async function installNpmServers(ctx: Ctx, missing: ReadonlyArray<string>): Promise<void> {
|
|
407
|
+
const { change, clearProgress, echo, progress, verbose, warn } = ctx.services.logger
|
|
419
408
|
if (missing.length === 0) return
|
|
420
|
-
|
|
421
409
|
const specs = missing.join(" ")
|
|
422
410
|
if (ctx.dryRun) {
|
|
423
411
|
echo(`[dry-run] would install: npm install -g ${specs}`)
|
|
@@ -444,3 +432,79 @@ export async function syncLspServers(ctx: Ctx): Promise<void> {
|
|
|
444
432
|
warn(`npm install -g ${specs} failed. Try manually: npm install -g ${specs}`)
|
|
445
433
|
}
|
|
446
434
|
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* rustup channel: rust-analyzer ships no npm package, and upstream's first
|
|
438
|
+
* recommendation is the rustup component, which tracks the toolchain the host
|
|
439
|
+
* already trusts. The component version therefore follows that toolchain, so
|
|
440
|
+
* the manifest row carries no verified pin - the stance bubblewrap already
|
|
441
|
+
* takes for a distro package.
|
|
442
|
+
*/
|
|
443
|
+
async function installRustAnalyzer(ctx: Ctx): Promise<void> {
|
|
444
|
+
const { change, clearProgress, echo, progress, verbose, warn } = ctx.services.logger
|
|
445
|
+
if (ctx.dryRun) {
|
|
446
|
+
echo("[dry-run] would install: rustup component add rust-analyzer")
|
|
447
|
+
return
|
|
448
|
+
}
|
|
449
|
+
verbose("Installing rust-analyzer via rustup...")
|
|
450
|
+
progress("Installing rust-analyzer via rustup...")
|
|
451
|
+
const result = await spawnProcess("rustup", ["component", "add", "rust-analyzer"], { stdio: "ignore" })
|
|
452
|
+
clearProgress()
|
|
453
|
+
if (result.exitCode === 0) {
|
|
454
|
+
change("LSP server installed (rust-analyzer via rustup)")
|
|
455
|
+
ctx.nextStepTriggers.claudeRestart = true
|
|
456
|
+
} else {
|
|
457
|
+
warn("rustup component add rust-analyzer failed. Try manually: rustup component add rust-analyzer")
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
export async function syncLspServers(ctx: Ctx): Promise<void> {
|
|
462
|
+
const { echo, verbose, warn } = ctx.services.logger
|
|
463
|
+
const sot = parseJson(payloadText("SoT/.claude/settings.json"))
|
|
464
|
+
const enabled = sot !== undefined && isObject(sot) && isObject(sot["enabledPlugins"]) ? sot["enabledPlugins"] : undefined
|
|
465
|
+
if (enabled === undefined) return
|
|
466
|
+
const enables = (plugin: string): boolean => Object.prototype.hasOwnProperty.call(enabled, plugin)
|
|
467
|
+
const hasPhp = enables("php-lsp@claude-plugins-official")
|
|
468
|
+
const hasTs = enables("typescript-lsp@claude-plugins-official")
|
|
469
|
+
const hasRust = enables("rust-analyzer-lsp@claude-plugins-official")
|
|
470
|
+
if (!hasPhp && !hasTs && !hasRust) return
|
|
471
|
+
|
|
472
|
+
const phpMissing = hasPhp && ctx.services.deps.probe("intelephense").state === "missing"
|
|
473
|
+
const tsServerMissing = hasTs && ctx.services.deps.probe("typescript-language-server").state === "missing"
|
|
474
|
+
const tscMissing = hasTs && ctx.services.deps.probe("tsc").state === "missing"
|
|
475
|
+
const rustMissing = hasRust && ctx.services.deps.probe("rust-analyzer").state === "missing"
|
|
476
|
+
// A host without rustup does no Rust work, so the plugin has nothing to
|
|
477
|
+
// serve there. Installing is impossible and warning every sync would name no
|
|
478
|
+
// action the user wants, so that host is not counted as missing a tool.
|
|
479
|
+
const rustInstallable = rustMissing && ctx.services.deps.probe("rustup").state === "present"
|
|
480
|
+
if (rustMissing && !rustInstallable) {
|
|
481
|
+
verbose("Skipping rust-analyzer: rustup is not installed, so the rust-analyzer-lsp plugin stays a no-op")
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
const missingToolCount = Number(phpMissing) + Number(tsServerMissing) + Number(tscMissing) + Number(rustInstallable)
|
|
485
|
+
if (missingToolCount === 0) {
|
|
486
|
+
if (ctx.dryRun) {
|
|
487
|
+
echo("[dry-run] LSP server binaries present")
|
|
488
|
+
} else {
|
|
489
|
+
verbose("LSP server binaries present")
|
|
490
|
+
}
|
|
491
|
+
return
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const blockingNode = tsServerMissing ? await nodeBelowServerFloor(ctx) : ""
|
|
495
|
+
if (blockingNode !== "") {
|
|
496
|
+
warn(
|
|
497
|
+
`Skipping typescript-language-server install: Node ${blockingNode} is older than the ${field("node", "floor")} that version requires. Upgrade Node, then re-run sync.`
|
|
498
|
+
)
|
|
499
|
+
}
|
|
500
|
+
const missing = [
|
|
501
|
+
phpMissing ? lspPkg(ctx, "intelephense", "intelephense") : undefined,
|
|
502
|
+
tsServerMissing && blockingNode === ""
|
|
503
|
+
? lspPkg(ctx, "typescript-language-server", "typescript-language-server")
|
|
504
|
+
: undefined,
|
|
505
|
+
tscMissing ? lspPkg(ctx, "tsc", "typescript") : undefined
|
|
506
|
+
].filter((spec): spec is string => spec !== undefined)
|
|
507
|
+
|
|
508
|
+
await installNpmServers(ctx, missing)
|
|
509
|
+
if (rustInstallable) await installRustAnalyzer(ctx)
|
|
510
|
+
}
|
|
@@ -30,6 +30,8 @@ export type ToolId =
|
|
|
30
30
|
| "intelephense"
|
|
31
31
|
| "typescript-language-server"
|
|
32
32
|
| "tsc"
|
|
33
|
+
| "rust-analyzer"
|
|
34
|
+
| "rustup"
|
|
33
35
|
| "apt-get"
|
|
34
36
|
| "dnf"
|
|
35
37
|
| "pacman"
|
|
@@ -224,6 +226,13 @@ export const DEPENDENCIES: Record<ToolId, DependencySpec> = {
|
|
|
224
226
|
resolve: pathProbe("tsc"),
|
|
225
227
|
version: versionProbe("tsc")
|
|
226
228
|
}),
|
|
229
|
+
"rust-analyzer": spec("rust-analyzer", "optional", () => "rustup component add rust-analyzer", {
|
|
230
|
+
resolve: pathProbe("rust-analyzer"),
|
|
231
|
+
version: versionProbe("rust-analyzer")
|
|
232
|
+
}),
|
|
233
|
+
rustup: spec("rustup", "optional", () => "install the Rust toolchain from https://rustup.rs", {
|
|
234
|
+
version: versionProbe("rustup")
|
|
235
|
+
}),
|
|
227
236
|
"apt-get": spec("apt-get", "optional", () => "install apt via your Linux distribution"),
|
|
228
237
|
dnf: spec("dnf", "optional", () => "install dnf via your Linux distribution"),
|
|
229
238
|
pacman: spec("pacman", "optional", () => "install pacman via your Linux distribution"),
|
|
@@ -34,6 +34,15 @@ function isNewer(a: string, b: string): boolean {
|
|
|
34
34
|
return compareCodepoints(a, b) > 0
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
/**
|
|
38
|
+
* A readable installed version strictly older than the manifest floor. The
|
|
39
|
+
* doctor row and the LSP install gate must agree on that judgement, so both
|
|
40
|
+
* ask here rather than re-deriving it.
|
|
41
|
+
*/
|
|
42
|
+
export function belowFloor(installed: string, floor: string): boolean {
|
|
43
|
+
return installed !== "" && floor !== "" && isNewer(floor, installed)
|
|
44
|
+
}
|
|
45
|
+
|
|
37
46
|
export function present(ctx: Ctx, tool: ToolId): boolean {
|
|
38
47
|
return ctx.services.deps.probe(tool).state === "present"
|
|
39
48
|
}
|
|
@@ -58,6 +67,9 @@ export async function installedVersion(ctx: Ctx, tool: ToolId): Promise<string>
|
|
|
58
67
|
return (await version()).replace(/^jq-/, "")
|
|
59
68
|
case "curl":
|
|
60
69
|
case "tsc":
|
|
70
|
+
// `rust-analyzer --version` prints "rust-analyzer <version>", where the
|
|
71
|
+
// version tail also carries a commit and a date in parentheses.
|
|
72
|
+
case "rust-analyzer":
|
|
61
73
|
return firstLineField(await version(), 1)
|
|
62
74
|
case "bun":
|
|
63
75
|
case "omp":
|
|
@@ -103,7 +115,7 @@ export async function report(ctx: Ctx): Promise<void> {
|
|
|
103
115
|
if (present(ctx, toolId)) {
|
|
104
116
|
installed = await installedVersion(ctx, toolId)
|
|
105
117
|
status = installed === "" ? "unknown" : "ok"
|
|
106
|
-
if (
|
|
118
|
+
if (belowFloor(installed, floor)) {
|
|
107
119
|
status = "below-floor"
|
|
108
120
|
} else if (verified !== "" && installed !== "" && isNewer(installed, verified)) {
|
|
109
121
|
status = "above-verified"
|
|
@@ -1,15 +1,15 @@
|
|
|
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.16.
|
|
4
|
+
export const GENERATED_PACKAGE_VERSION = "0.16.17"
|
|
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\": \"Kit-verified model catalog — single source for EngineNative validators, the docks-kit CLI (models/model commands, pickers, and bare-flag help), and docs. Entries are research-proofed: update an entry and its tool-level `verified` date when a model ships or retires. Deploy-time model flags remain permissive.\",\n \"claude\": {\n \"verified\": \"2026-07-27\",\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 — the kit SoT default (Opus 5 on the Anthropic API from Claude Code >=2.1.219; Opus 4.6 on Microsoft Foundry)\" },\n { \"id\": \"fable\", \"kind\": \"alias\", \"note\": \"Fable 5 — advisor opt-in default; 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-5\", \"kind\": \"id\", \"note\": \"Opus 5 — needs Claude Code >=2.1.219\" },\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-16\",\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",
|
|
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.\",\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.219\", \"note\": \"kit floor — lets the `opus` alias select the newest Opus its provider offers (Anthropic API: 5; Foundry: 4.6) and subsumes Fable 5's >=2.1.170 requirement (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.0.8\",\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 \"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.0\",\n \"note\": \"typescript-lsp server binary; `verified` pins claudeSync syncLspServers' npm install. Version 6 requires Node >=22.22.2 (see the `node` floor)\" },\n \"tsc\": { \"kind\": \"check\", \"floor\": \"6.0.3\", \"verified\": \"6.0.3\", \"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 \"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.5.25\",\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.13.0\",\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",
|
|
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.\",\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.219\", \"note\": \"kit floor — lets the `opus` alias select the newest Opus its provider offers (Anthropic API: 5; Foundry: 4.6) and subsumes Fable 5's >=2.1.170 requirement (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.0.8\",\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 \"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.0\",\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\", \"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 \"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.5.25\",\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.13.0\",\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
|
-
"SoT/.claude/settings.json": "{\n \"$schema\": \"https://json.schemastore.org/claude-code-settings.json\",\n \"minimumVersion\": \"2.1.219\",\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 \"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",
|
|
12
|
+
"SoT/.claude/settings.json": "{\n \"$schema\": \"https://json.schemastore.org/claude-code-settings.json\",\n \"minimumVersion\": \"2.1.219\",\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",
|
|
13
13
|
"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",
|
|
14
14
|
"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 const output = {\n hookSpecificOutput: {\n hookEventName: \"SessionStart\",\n additionalContext: sessionStartLines(options).join(\"\\n\")\n }\n }\n writeStdout(`${JSON.stringify(output)}\\n`)\n return 0\n}\n\nif (import.meta.main) process.exit(await main())\n",
|
|
15
15
|
"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 spawnSync(command, { stdin: \"ignore\", stdout: \"ignore\", stderr: \"ignore\" })\n return 0\n}\n\nif (import.meta.main) process.exit(await main())\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 = "1e34340b8f6bc7a0eed95daff076116cd984c808661386c10a3fef914304083b"
|
package/package.json
CHANGED