docks-kit 0.1.4 → 0.2.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/README.md +1 -1
- package/SoT/.codex/config.toml +1 -1
- package/SoT/models.json +5 -2
- package/SoT/toolchain.json +1 -0
- package/cli/docs/flags.md +1 -0
- package/cli/docs/overview.md +3 -0
- package/cli/docs/platforms.md +6 -5
- package/cli/src/commands/model.ts +7 -3
- package/cli/src/commands/sync.ts +14 -3
- package/cli/src/commands/toolchain.ts +7 -3
- package/cli/src/engine-native/DESIGN.md +75 -2
- package/cli/src/engine-native/claudeModel.ts +9 -3
- package/cli/src/engine-native/claudeSync.ts +205 -94
- package/cli/src/engine-native/codexSync.ts +97 -44
- package/cli/src/engine-native/codexToml.ts +12 -5
- package/cli/src/engine-native/deps.ts +325 -0
- package/cli/src/engine-native/exec.ts +50 -2
- package/cli/src/engine-native/index.ts +45 -9
- package/cli/src/engine-native/logger.ts +35 -0
- package/cli/src/engine-native/models.ts +13 -12
- package/cli/src/engine-native/modes.ts +17 -10
- package/cli/src/engine-native/os.ts +29 -0
- package/cli/src/engine-native/parseArgs.ts +19 -17
- package/cli/src/engine-native/services.ts +96 -0
- package/cli/src/engine-native/skillsSync.ts +70 -51
- package/cli/src/engine-native/toolchain.ts +46 -62
- package/cli/src/engine.ts +11 -2
- package/cli/src/main.ts +3 -2
- package/cli/src/services.ts +34 -0
- package/package.json +1 -1
- package/cli/src/engine-native/output.ts +0 -20
package/README.md
CHANGED
|
@@ -105,7 +105,7 @@ and a later flag-less sync reverts them. Full reference: `docks-kit docs flags`
|
|
|
105
105
|
|----------|-----|-------------|
|
|
106
106
|
| Linux | ✅ native | ✅ native |
|
|
107
107
|
| macOS (x64/arm64) | ✅ native | ✅ native |
|
|
108
|
-
| Windows | ✅ native binary (`.exe` and `bun add -g` CI-verified) | ✅ EngineNative (TS, default engine — no Git Bash); real-machine
|
|
108
|
+
| Windows | ✅ native binary (`.exe` and `bun add -g` CI-verified) | ✅ EngineNative (TS, default engine — no Git Bash); real-machine verified 2026-07-09 — RTK hooks are native too (rtk ≥0.37.2) |
|
|
109
109
|
|
|
110
110
|
Details: `docks-kit docs platforms`.
|
|
111
111
|
|
package/SoT/.codex/config.toml
CHANGED
package/SoT/models.json
CHANGED
|
@@ -16,9 +16,12 @@
|
|
|
16
16
|
]
|
|
17
17
|
},
|
|
18
18
|
"codex": {
|
|
19
|
-
"verified": "2026-07-
|
|
19
|
+
"verified": "2026-07-09",
|
|
20
20
|
"models": [
|
|
21
|
-
{ "id": "gpt-5.
|
|
21
|
+
{ "id": "gpt-5.6-sol", "kind": "id", "note": "GPT-5.6 Sol — frontier, recommended default; the kit SoT pin" },
|
|
22
|
+
{ "id": "gpt-5.6-terra", "kind": "id", "note": "GPT-5.6 Terra — balanced tier" },
|
|
23
|
+
{ "id": "gpt-5.6-luna", "kind": "id", "note": "GPT-5.6 Luna — fast/light tier" },
|
|
24
|
+
{ "id": "gpt-5.5", "kind": "id", "note": "previous generation" },
|
|
22
25
|
{ "id": "gpt-5.5-codex", "kind": "id", "note": "codex-tuned gpt-5.5" },
|
|
23
26
|
{ "id": "gpt-5.1", "kind": "id", "note": "previous generation" },
|
|
24
27
|
{ "id": "gpt-5", "kind": "id", "note": "previous generation" },
|
package/SoT/toolchain.json
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"tools": {
|
|
4
4
|
"jq": { "kind": "required", "note": "deployed Claude hooks/statusline assets" },
|
|
5
5
|
"curl": { "kind": "required", "note": "installers + usage fetch" },
|
|
6
|
+
"git": { "kind": "check", "note": "plugin marketplaces (claude/codex clone them) + kit checkout updates" },
|
|
6
7
|
"node": { "kind": "check", "note": "hosts npm globals (agent-browser, LSP servers)" },
|
|
7
8
|
"npm": { "kind": "check", "note": "npm-global installer" },
|
|
8
9
|
"claude": { "kind": "check", "floor": "2.1.170", "note": "kit floor — `best` alias + Fable 5 need >=2.1.170 (mirrors settings minimumVersion)" },
|
package/cli/docs/flags.md
CHANGED
|
@@ -20,6 +20,7 @@ docks-kit sync claude agents # two
|
|
|
20
20
|
| `--prune` | Uninstall kit-managed installs not in SoT: plugins, marketplaces, universal skills |
|
|
21
21
|
| `--skip-rtk` | Skip optional tool bootstrap (RTK, bubblewrap) |
|
|
22
22
|
| `--yes` | Auto-accept toolchain above-verified prompts (containers/CI) |
|
|
23
|
+
| `--verbose` / `-v` | Also print no-op confirmations (already in sync, up to date, left as-is); accepted on `sync`, `model`, and `toolchain` |
|
|
23
24
|
|
|
24
25
|
## Per-tool flags
|
|
25
26
|
|
package/cli/docs/overview.md
CHANGED
|
@@ -21,6 +21,9 @@ AI-assisted dev environment on every machine.
|
|
|
21
21
|
## Design rules
|
|
22
22
|
|
|
23
23
|
- **Idempotent**: every sync step is safe to re-run; no-change syncs are no-ops.
|
|
24
|
+
- **Quiet on no-ops**: by default a re-run prints only real changes, warnings
|
|
25
|
+
(with a platform-correct install command when a tool is missing), and the
|
|
26
|
+
summary; `--verbose` / `-v` also prints the no-op confirmations.
|
|
24
27
|
- **Additive by default**: user-only keys/plugins/skills survive a plain sync.
|
|
25
28
|
Reconciliation toward the SoT is explicit: `--reconcile` (settings) and
|
|
26
29
|
`--prune` (plugins/marketplaces/skills).
|
package/cli/docs/platforms.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|----------|-----------------|-------------|-------|
|
|
5
5
|
| Linux | native | EngineNative (TS) | Primary target |
|
|
6
6
|
| macOS | native (x64 + arm64) | EngineNative (TS) | Release binary or Bun source path |
|
|
7
|
-
| Windows | native (`.exe` / `bun add -g`, CI-verified) | EngineNative (TS) — no Git Bash | Real-machine
|
|
7
|
+
| Windows | native (`.exe` / `bun add -g`, CI-verified) | EngineNative (TS) — no Git Bash | Real-machine verified 2026-07-09 |
|
|
8
8
|
|
|
9
9
|
EngineNative is the only supported engine on all platforms. `DOCKS_KIT_ENGINE=bash`
|
|
10
10
|
now exits with the removed-engine message and points at the `bash-engine-final`
|
|
@@ -38,7 +38,8 @@ spawning (npm), toolchain gate branches (`.github/workflows/parity.yml`,
|
|
|
38
38
|
Deployed hook/statusline assets stay shell scripts by design — Claude Code on
|
|
39
39
|
Windows executes them through its own Git Bash.
|
|
40
40
|
|
|
41
|
-
**Status: supported
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
**Status: supported** — real-machine verified 2026-07-09 (Claude Code loads
|
|
42
|
+
the synced `%USERPROFILE%\.claude`; full sync, self-update, plugin passes,
|
|
43
|
+
universal skills, and agent-browser all green on native PowerShell). Needs
|
|
44
|
+
git on PATH for plugin marketplaces; rtk installs natively via its Windows
|
|
45
|
+
release (the kit's auto-install is Unix-only).
|
|
@@ -13,26 +13,30 @@ const value = Args.text({ name: "value" }).pipe(
|
|
|
13
13
|
const dryRun = Options.boolean("dry-run").pipe(
|
|
14
14
|
Options.withDescription("Preview without applying")
|
|
15
15
|
)
|
|
16
|
+
const verbose = Options.boolean("verbose").pipe(
|
|
17
|
+
Options.withAlias("v"),
|
|
18
|
+
Options.withDescription("Also print no-op confirmations (already in sync, up to date)")
|
|
19
|
+
)
|
|
16
20
|
|
|
17
21
|
const KEEP = "__keep__"
|
|
18
22
|
|
|
19
23
|
export const modelCommand = Command.make(
|
|
20
24
|
"model",
|
|
21
|
-
{ tool, value, dryRun },
|
|
25
|
+
{ tool, value, dryRun, verbose },
|
|
22
26
|
(config) =>
|
|
23
27
|
Effect.gen(function* () {
|
|
24
28
|
if (config.tool !== "claude" && config.tool !== "codex") {
|
|
25
29
|
return yield* bail(`Unknown tool '${config.tool}' (valid: claude, codex)`)
|
|
26
30
|
}
|
|
27
31
|
const t = config.tool as Tool
|
|
28
|
-
const dry = config.dryRun ? ["--dry-run"] : []
|
|
32
|
+
const dry = [...(config.dryRun ? ["--dry-run"] : []), ...(config.verbose ? ["--verbose"] : [])]
|
|
29
33
|
|
|
30
34
|
if (Option.isSome(config.value)) {
|
|
31
35
|
return yield* engine(["model", t, config.value.value, ...dry])
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
// No value: show current (engine prints deployed + SoT + catalog) …
|
|
35
|
-
yield* engine(["model", t])
|
|
39
|
+
yield* engine(["model", t, ...(config.verbose ? ["--verbose"] : [])])
|
|
36
40
|
|
|
37
41
|
// … and offer an interactive picker when attached to a terminal.
|
|
38
42
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return
|
package/cli/src/commands/sync.ts
CHANGED
|
@@ -4,13 +4,15 @@ import { spawnSync } from "node:child_process"
|
|
|
4
4
|
import { existsSync } from "node:fs"
|
|
5
5
|
import { join } from "node:path"
|
|
6
6
|
import { bail, engine } from "../engine"
|
|
7
|
+
import type { Logger } from "../engine-native/logger"
|
|
7
8
|
import { kitHome } from "../kitHome"
|
|
8
9
|
import { modelCatalog, type Tool } from "../manifests"
|
|
10
|
+
import { LoggerService } from "../services"
|
|
9
11
|
|
|
10
12
|
/** Best-effort update autodetection: nudge (never block, never fail) when
|
|
11
13
|
* the kit checkout is behind its upstream. Silent on detached HEADs, no
|
|
12
14
|
* upstream, no network, no git. */
|
|
13
|
-
const updateNudge = (): void => {
|
|
15
|
+
const updateNudge = (logger: Logger): void => {
|
|
14
16
|
try {
|
|
15
17
|
const home = kitHome()
|
|
16
18
|
if (!existsSync(join(home, ".git"))) return
|
|
@@ -21,7 +23,7 @@ const updateNudge = (): void => {
|
|
|
21
23
|
})
|
|
22
24
|
const behind = (res.stdout ?? "").trim()
|
|
23
25
|
if (res.status === 0 && behind !== "" && behind !== "0") {
|
|
24
|
-
|
|
26
|
+
logger.warn(`kit checkout is ${behind} commit(s) behind its upstream — run: docks-kit update`)
|
|
25
27
|
}
|
|
26
28
|
} catch {
|
|
27
29
|
// nudge only — a sync must never fail because the update check did
|
|
@@ -75,6 +77,10 @@ const skipRtk = Options.boolean("skip-rtk").pipe(
|
|
|
75
77
|
const yes = Options.boolean("yes").pipe(
|
|
76
78
|
Options.withDescription("Auto-accept toolchain prompts (containers/CI)")
|
|
77
79
|
)
|
|
80
|
+
const verbose = Options.boolean("verbose").pipe(
|
|
81
|
+
Options.withAlias("v"),
|
|
82
|
+
Options.withDescription("Also print no-op confirmations (already in sync, up to date, left as-is)")
|
|
83
|
+
)
|
|
78
84
|
const claudeModel = Options.text("claude-model").pipe(
|
|
79
85
|
Options.withDescription("Deploy-time modifier: set deployed Claude model (see `docks-kit models claude`)"),
|
|
80
86
|
Options.optional
|
|
@@ -106,6 +112,7 @@ export const syncCommand = Command.make(
|
|
|
106
112
|
prune,
|
|
107
113
|
skipRtk,
|
|
108
114
|
yes,
|
|
115
|
+
verbose,
|
|
109
116
|
claudeModel,
|
|
110
117
|
claudeCompactWindow,
|
|
111
118
|
claudePermissive,
|
|
@@ -138,6 +145,7 @@ export const syncCommand = Command.make(
|
|
|
138
145
|
if (config.prune) args.push("--prune")
|
|
139
146
|
if (config.skipRtk) args.push("--skip-rtk")
|
|
140
147
|
if (config.yes) args.push("--yes")
|
|
148
|
+
if (config.verbose) args.push("--verbose")
|
|
141
149
|
if (config.claudePermissive) args.push("--claude-permissive")
|
|
142
150
|
Option.map(config.claudeModel, (m) => args.push(`--claude-model=${m}`))
|
|
143
151
|
Option.map(config.claudeCompactWindow, (w) => args.push(`--claude-compact-window=${w}`))
|
|
@@ -152,7 +160,10 @@ export const syncCommand = Command.make(
|
|
|
152
160
|
|
|
153
161
|
// Not on --dry-run: the nudge's git fetch writes FETCH_HEAD/remote
|
|
154
162
|
// refs, and a preview command must not mutate the checkout.
|
|
155
|
-
if (!config.dryRun)
|
|
163
|
+
if (!config.dryRun) {
|
|
164
|
+
const logger = yield* LoggerService
|
|
165
|
+
yield* Effect.sync(() => updateNudge(logger))
|
|
166
|
+
}
|
|
156
167
|
yield* engine(args)
|
|
157
168
|
})
|
|
158
169
|
).pipe(
|
|
@@ -15,15 +15,19 @@ const tool = Args.text({ name: "tool" }).pipe(
|
|
|
15
15
|
const yes = Options.boolean("yes").pipe(
|
|
16
16
|
Options.withDescription("Auto-accept above-verified installs")
|
|
17
17
|
)
|
|
18
|
+
const verbose = Options.boolean("verbose").pipe(
|
|
19
|
+
Options.withAlias("v"),
|
|
20
|
+
Options.withDescription("Also print no-op confirmations (present, up to date)")
|
|
21
|
+
)
|
|
18
22
|
|
|
19
|
-
export const toolchainCommand = Command.make("toolchain", { op, tool, yes }, (config) =>
|
|
23
|
+
export const toolchainCommand = Command.make("toolchain", { op, tool, yes, verbose }, (config) =>
|
|
20
24
|
Effect.gen(function* () {
|
|
21
25
|
const operation = Option.getOrElse(config.op, () => "check")
|
|
22
|
-
const flags = config.yes ? ["--yes"] : []
|
|
26
|
+
const flags = [...(config.yes ? ["--yes"] : []), ...(config.verbose ? ["--verbose"] : [])]
|
|
23
27
|
|
|
24
28
|
switch (operation) {
|
|
25
29
|
case "check":
|
|
26
|
-
return yield* engine(["toolchain", "check"])
|
|
30
|
+
return yield* engine(["toolchain", "check", ...(config.verbose ? ["--verbose"] : [])])
|
|
27
31
|
case "ensure": {
|
|
28
32
|
const t = Option.getOrUndefined(config.tool)
|
|
29
33
|
if (t === undefined || !MANAGED.includes(t)) {
|
|
@@ -37,6 +37,76 @@ explicit removed-engine diagnostic and exits 2 with the recovery tag message.
|
|
|
37
37
|
- **Backups precede mutation.** Deployed settings/config files write `.bak`
|
|
38
38
|
backups before replacement.
|
|
39
39
|
|
|
40
|
+
## Output Policy (log UX contract)
|
|
41
|
+
|
|
42
|
+
The default run reads like a change report: only actual changes, actionable
|
|
43
|
+
warnings, and the summary. Status-quo confirmations exist but are opt-in.
|
|
44
|
+
(Rationale + full call-site audit: `docs/plans/active/cli-log-ux-overhaul.md`.)
|
|
45
|
+
|
|
46
|
+
### Channels and levels
|
|
47
|
+
|
|
48
|
+
| Emitter | Channel | Default | `--verbose` | Prefix / form |
|
|
49
|
+
|---|---|---|---|---|
|
|
50
|
+
| `error(msg)` | stderr | shown | shown | `[err]` red (`\x1b[1;31m`) |
|
|
51
|
+
| `warn(msg)` | stderr | shown | shown | `[warn]` yellow (`\x1b[1;33m`) |
|
|
52
|
+
| `change(msg)` | stderr | shown | shown | `[ok]` green (`\x1b[1;32m`) — ONLY after an operation actually mutated |
|
|
53
|
+
| `verbose(msg)` | stderr | hidden | shown | `[ok]` green — no-op confirmations ("already …", "present", "up to date", "left as-is"), skips |
|
|
54
|
+
| `data(line)` | stdout | shown | shown | bare — dry-run report lines, `status --json`, summary block, usage text |
|
|
55
|
+
|
|
56
|
+
- stdout is data, stderr is logs — the logger NEVER writes to stdout
|
|
57
|
+
(`engineCapture` depends on it).
|
|
58
|
+
- **Dry-run is a complete inspection report**: `[dry-run]` lines are `data`,
|
|
59
|
+
printed unfiltered at every verbosity.
|
|
60
|
+
- Prefixes and ANSI codes are stable golden surface; the level controls
|
|
61
|
+
visibility, not the prefix.
|
|
62
|
+
|
|
63
|
+
### Change detection
|
|
64
|
+
|
|
65
|
+
Every mutating operation reports `changed: boolean`. A changed outcome logs
|
|
66
|
+
via `change`; an unchanged outcome logs via `verbose`. Operations that today
|
|
67
|
+
rewrite deployed files unconditionally may skip a provably-identical rewrite —
|
|
68
|
+
each such skip is an intentional behavior change named in its golden diff.
|
|
69
|
+
|
|
70
|
+
### Missing dependencies
|
|
71
|
+
|
|
72
|
+
Exactly one deduplicated warn per missing tool per run, uniform shape:
|
|
73
|
+
`[warn] <tool> not installed — <platform-correct install command>`, sourced
|
|
74
|
+
from the dependency registry (`deps.ts`). Required tools keep their current
|
|
75
|
+
exit behavior — the error carries the same install hint.
|
|
76
|
+
|
|
77
|
+
### Summary and next steps
|
|
78
|
+
|
|
79
|
+
`model` and `toolchain` modes have no separate summary block by design —
|
|
80
|
+
their stdout IS the deliverable (`deployed:`/`SoT:` + catalog lines for
|
|
81
|
+
`model`; the report table for `toolchain check`), so nothing prints after
|
|
82
|
+
it. The schema below applies to `sync` only.
|
|
83
|
+
|
|
84
|
+
The `--- Sync complete ---` block (stdout, `data`) prints on every run,
|
|
85
|
+
including dry-run, with the per-target inventory lines (`Claude:`/`Hooks:`/
|
|
86
|
+
`RTK:`/`Plugins:`/`Codex:`/`Skills:`). Next-step advice lines print only when
|
|
87
|
+
their trigger changed this run (plugins changed → `/reload-plugins` line;
|
|
88
|
+
hooks/env changed → restart line; skills changed → discovery line) or under
|
|
89
|
+
`--verbose`.
|
|
90
|
+
|
|
91
|
+
### Platform seam
|
|
92
|
+
|
|
93
|
+
All platform branching routes through `os.ts` — the only engine module that
|
|
94
|
+
reads `process.platform`, with one named exemption: `exec.ts`'s path/exec
|
|
95
|
+
primitives (`commandExists` PATHEXT resolution and `X_OK` probing) stay
|
|
96
|
+
self-contained because they sit below the seam. `deps.ts` install hints
|
|
97
|
+
default their platform from `os.ts` and keep the parameter injectable for
|
|
98
|
+
tests.
|
|
99
|
+
|
|
100
|
+
### Verbosity plumbing
|
|
101
|
+
|
|
102
|
+
`--verbose` / `-v` on the public `sync`, `model`, and `toolchain` commands;
|
|
103
|
+
`DOCKS_KIT_VERBOSE=1` selects it on the harness-private raw channel (same
|
|
104
|
+
`${VAR:-default}` contract as the other `Ctx` env globals). The default
|
|
105
|
+
service factory returns a raw Logger. `runEngineNative` wraps the default or
|
|
106
|
+
injected Logger with explicit delegates and owns the sole `ctx.verbose` gate.
|
|
107
|
+
There is no factory-level verbosity callback, module-global verbosity flag, or
|
|
108
|
+
active logger binding.
|
|
109
|
+
|
|
40
110
|
## Module Map
|
|
41
111
|
|
|
42
112
|
| Module | Owns |
|
|
@@ -53,8 +123,11 @@ explicit removed-engine diagnostic and exits 2 with the recovery tag message.
|
|
|
53
123
|
| `modes.ts` | direct `model` and `toolchain` modes |
|
|
54
124
|
| `models.ts` | model catalog listing and validation |
|
|
55
125
|
| `jq.ts` | JSON helpers that preserve jq-style merge/order/stringify behavior where the deployed file contract needs it |
|
|
56
|
-
| `exec.ts` | path helpers, command probes, capture/spawn wrappers, Windows command resolution |
|
|
57
|
-
| `
|
|
126
|
+
| `exec.ts` | path helpers, command probes, capture/spawn wrappers, Windows command resolution, change-detecting write/copy helpers |
|
|
127
|
+
| `logger.ts` | Logger shape + stable raw stdout/stderr sink factory; the run-scoped verbosity gate lives in `index.ts` |
|
|
128
|
+
| `deps.ts` | external-tool registry: identity, requirement class, presence probe, platform-correct install hints, per-manager missing-tool dedup; callers supply the current run Logger to `warnMissing` |
|
|
129
|
+
| `os.ts` | platform capability seam — the single `process.platform` reader (`platformName`, `isWindows`, `isLinux`, shell-rc applicability) |
|
|
130
|
+
| `services.ts` | shared raw-Logger + DependencyManager + Platform factory; wrapped in Effect Layers at `cli/src/services.ts`, with the run-scoped Logger gate applied only by `runEngineNative` |
|
|
58
131
|
|
|
59
132
|
## Windows Specifics
|
|
60
133
|
|
|
@@ -7,9 +7,9 @@ import { readFileSync, renameSync, writeFileSync } from "node:fs"
|
|
|
7
7
|
|
|
8
8
|
import type { Ctx } from "./index"
|
|
9
9
|
import { isObject, jqStringify, parseJson } from "./jq"
|
|
10
|
-
import { echo, err, log, warn } from "./output"
|
|
11
10
|
|
|
12
11
|
export function syncClaudeModel(ctx: Ctx, model: string): void {
|
|
12
|
+
const { change, echo, err, verbose, warn } = ctx.services.logger
|
|
13
13
|
const userSettings = p(ctx.home, ".claude", "settings.json")
|
|
14
14
|
|
|
15
15
|
if (model === "") return
|
|
@@ -42,7 +42,13 @@ export function syncClaudeModel(ctx: Ctx, model: string): void {
|
|
|
42
42
|
doc["model"] = model
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
|
|
45
|
+
const out = jqStringify(doc)
|
|
46
|
+
if (out === text) {
|
|
47
|
+
verbose(`Model: deployed settings model already ${model === "default" ? "unset (account default)" : model}`)
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
writeFileSync(`${userSettings}.tmp`, out)
|
|
46
51
|
renameSync(`${userSettings}.tmp`, userSettings)
|
|
47
|
-
|
|
52
|
+
change(`Model: deployed settings model set to ${model} (SoT unchanged; flag-less sync reverts)`)
|
|
53
|
+
ctx.nextStepTriggers.claudeRestart = true
|
|
48
54
|
}
|