docks-kit 0.17.0 → 0.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +37 -33
- package/README.md +1 -0
- package/cli/docs/omp-models.md +114 -58
- package/cli/src/argv.ts +38 -469
- package/cli/src/argvSurface.ts +371 -0
- package/cli/src/argvValidate.ts +122 -0
- package/cli/src/commands/docs.ts +57 -42
- package/cli/src/commands/harnesses.ts +38 -45
- package/cli/src/commands/model.ts +48 -53
- package/cli/src/commands/models.ts +24 -26
- package/cli/src/commands/omp.ts +178 -88
- package/cli/src/commands/plugins.ts +20 -20
- package/cli/src/commands/skills.ts +22 -20
- package/cli/src/commands/status.ts +87 -80
- package/cli/src/commands/sync.ts +113 -87
- package/cli/src/commands/toolchain.ts +21 -21
- package/cli/src/commands/update.ts +139 -117
- package/cli/src/efforts.ts +35 -34
- package/cli/src/engine-native/DESIGN.md +30 -30
- package/cli/src/engine-native/bun.ts +77 -55
- package/cli/src/engine-native/claudeLsp.ts +154 -0
- package/cli/src/engine-native/claudeOptionalPlugins.ts +113 -0
- package/cli/src/engine-native/claudePluginPasses.ts +348 -0
- package/cli/src/engine-native/claudeRemovals.ts +195 -0
- package/cli/src/engine-native/claudeRetired.ts +4 -4
- package/cli/src/engine-native/claudeRuntime.ts +94 -68
- package/cli/src/engine-native/claudeSettings.ts +174 -0
- package/cli/src/engine-native/claudeSettingsModifiers.ts +50 -54
- package/cli/src/engine-native/claudeSync.ts +176 -456
- package/cli/src/engine-native/codexConfig.ts +158 -0
- package/cli/src/engine-native/codexHooks.ts +91 -0
- package/cli/src/engine-native/codexPlugins.ts +290 -0
- package/cli/src/engine-native/codexStatus.ts +24 -0
- package/cli/src/engine-native/codexSync.ts +110 -568
- package/cli/src/engine-native/codexToml.ts +140 -138
- package/cli/src/engine-native/deps.ts +144 -107
- package/cli/src/engine-native/engineCtx.ts +126 -0
- package/cli/src/engine-native/exec.ts +98 -87
- package/cli/src/engine-native/failures.ts +3 -3
- package/cli/src/engine-native/harnesses.ts +62 -72
- package/cli/src/engine-native/index.ts +34 -315
- package/cli/src/engine-native/jq.ts +25 -24
- package/cli/src/engine-native/logger.ts +98 -100
- package/cli/src/engine-native/models.ts +50 -45
- package/cli/src/engine-native/modes.ts +83 -80
- package/cli/src/engine-native/ompFileDeploy.ts +111 -0
- package/cli/src/engine-native/ompMarketplace.ts +136 -0
- package/cli/src/engine-native/ompOverlay.ts +93 -53
- package/cli/src/engine-native/ompPaths.ts +49 -38
- package/cli/src/engine-native/ompPlugins.ts +170 -0
- package/cli/src/engine-native/ompSync.ts +64 -408
- package/cli/src/engine-native/ompYaml.ts +43 -41
- package/cli/src/engine-native/os/darwin.ts +5 -5
- package/cli/src/engine-native/os/index.ts +15 -15
- package/cli/src/engine-native/os/linux.ts +5 -5
- package/cli/src/engine-native/os/posix.ts +28 -24
- package/cli/src/engine-native/os/targets.ts +17 -17
- package/cli/src/engine-native/os/types.ts +31 -31
- package/cli/src/engine-native/os/windows.ts +61 -61
- package/cli/src/engine-native/parseArgs.ts +122 -372
- package/cli/src/engine-native/parseHelp.ts +66 -0
- package/cli/src/engine-native/parseModifiers.ts +222 -0
- package/cli/src/engine-native/services.ts +34 -34
- package/cli/src/engine-native/settings.ts +15 -15
- package/cli/src/engine-native/sharedTypes.d.ts +46 -0
- package/cli/src/engine-native/skillsInstall.ts +105 -0
- package/cli/src/engine-native/skillsLinks.ts +203 -0
- package/cli/src/engine-native/skillsManifest.ts +16 -0
- package/cli/src/engine-native/skillsPrune.ts +108 -0
- package/cli/src/engine-native/skillsSync.ts +28 -362
- package/cli/src/engine-native/syncConcurrency.ts +55 -0
- package/cli/src/engine-native/syncDispatch.ts +141 -0
- package/cli/src/engine-native/toolchain.ts +65 -62
- package/cli/src/engine.ts +65 -57
- package/cli/src/generated/sotPayload.ts +7 -7
- package/cli/src/kitHome.ts +44 -40
- package/cli/src/main.ts +63 -56
- package/cli/src/manifests.ts +53 -54
- package/cli/src/md.d.ts +2 -2
- package/cli/src/payload.ts +9 -9
- package/cli/src/services.ts +21 -13
- package/cli/tsconfig.json +4 -1
- package/package.json +9 -2
- package/cli/src/engine-native/claudePlugins.ts +0 -510
package/cli/src/kitHome.ts
CHANGED
|
@@ -1,41 +1,45 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs"
|
|
2
|
-
import { dirname, join, resolve } from "node:path"
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
|
|
4
4
|
const isKitHome = (dir: string): boolean => {
|
|
5
5
|
try {
|
|
6
|
-
const manifest = JSON.parse(readFileSync(join(dir, "package.json"), "utf8")) as {
|
|
7
|
-
|
|
6
|
+
const manifest = JSON.parse(readFileSync(join(dir, "package.json"), "utf8")) as {
|
|
7
|
+
name?: unknown;
|
|
8
|
+
};
|
|
9
|
+
return manifest.name === "docks-kit";
|
|
8
10
|
} catch {
|
|
9
|
-
return false
|
|
11
|
+
return false;
|
|
10
12
|
}
|
|
11
|
-
}
|
|
13
|
+
};
|
|
12
14
|
|
|
13
15
|
const explicitKitHome = (dir: string, source: string): string => {
|
|
14
|
-
const packageJson = join(dir, "package.json")
|
|
15
|
-
let text: string
|
|
16
|
+
const packageJson = join(dir, "package.json");
|
|
17
|
+
let text: string;
|
|
16
18
|
try {
|
|
17
|
-
text = readFileSync(packageJson, "utf8")
|
|
19
|
+
text = readFileSync(packageJson, "utf8");
|
|
18
20
|
} catch (error) {
|
|
19
21
|
const code =
|
|
20
22
|
typeof error === "object" && error !== null && "code" in error
|
|
21
23
|
? String(error.code)
|
|
22
|
-
: undefined
|
|
24
|
+
: undefined;
|
|
23
25
|
if (code === "ENOENT") {
|
|
24
|
-
throw new Error(`DOCKS_KIT_HOME=${source} does not contain package.json
|
|
26
|
+
throw new Error(`DOCKS_KIT_HOME=${source} does not contain package.json`, { cause: error });
|
|
25
27
|
}
|
|
26
|
-
const detail = error instanceof Error ? error.message : String(error)
|
|
27
|
-
const category = code === undefined ? "" : ` (${code})
|
|
28
|
-
throw new Error(
|
|
29
|
-
|
|
30
|
-
)
|
|
28
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
29
|
+
const category = code === undefined ? "" : ` (${code})`;
|
|
30
|
+
throw new Error(`DOCKS_KIT_HOME=${source} package.json cannot be read${category}: ${detail}`, {
|
|
31
|
+
cause: error,
|
|
32
|
+
});
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
let manifest: unknown
|
|
35
|
+
let manifest: unknown;
|
|
34
36
|
try {
|
|
35
|
-
manifest = JSON.parse(text)
|
|
37
|
+
manifest = JSON.parse(text);
|
|
36
38
|
} catch (error) {
|
|
37
|
-
const detail = error instanceof Error ? error.message : String(error)
|
|
38
|
-
throw new Error(`DOCKS_KIT_HOME=${source} package.json contains invalid JSON: ${detail}
|
|
39
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
40
|
+
throw new Error(`DOCKS_KIT_HOME=${source} package.json contains invalid JSON: ${detail}`, {
|
|
41
|
+
cause: error,
|
|
42
|
+
});
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
if (
|
|
@@ -45,29 +49,29 @@ const explicitKitHome = (dir: string, source: string): string => {
|
|
|
45
49
|
manifest.name !== "docks-kit"
|
|
46
50
|
) {
|
|
47
51
|
throw new Error(
|
|
48
|
-
`DOCKS_KIT_HOME=${source} is not a docks-kit package root (package.json name must be "docks-kit")
|
|
49
|
-
)
|
|
52
|
+
`DOCKS_KIT_HOME=${source} is not a docks-kit package root (package.json name must be "docks-kit")`,
|
|
53
|
+
);
|
|
50
54
|
}
|
|
51
|
-
return dir
|
|
52
|
-
}
|
|
55
|
+
return dir;
|
|
56
|
+
};
|
|
53
57
|
|
|
54
58
|
const findKitHome = (start: string | undefined): string | undefined => {
|
|
55
|
-
if (start === undefined || start === "") return undefined
|
|
56
|
-
let dir = resolve(start)
|
|
59
|
+
if (start === undefined || start === "") return undefined;
|
|
60
|
+
let dir = resolve(start);
|
|
57
61
|
for (;;) {
|
|
58
|
-
if (isKitHome(dir)) return dir
|
|
59
|
-
const parent = dirname(dir)
|
|
60
|
-
if (parent === dir) return undefined
|
|
61
|
-
dir = parent
|
|
62
|
+
if (isKitHome(dir)) return dir;
|
|
63
|
+
const parent = dirname(dir);
|
|
64
|
+
if (parent === dir) return undefined;
|
|
65
|
+
dir = parent;
|
|
62
66
|
}
|
|
63
|
-
}
|
|
67
|
+
};
|
|
64
68
|
|
|
65
69
|
export interface KitHomeSources {
|
|
66
|
-
readonly env: string | undefined
|
|
70
|
+
readonly env: string | undefined;
|
|
67
71
|
/** `import.meta.dir` is a Bun extension, so a non-Bun loader leaves it undefined. */
|
|
68
|
-
readonly moduleDir: string | undefined
|
|
69
|
-
readonly execPath: string
|
|
70
|
-
readonly cwd: string
|
|
72
|
+
readonly moduleDir: string | undefined;
|
|
73
|
+
readonly execPath: string;
|
|
74
|
+
readonly cwd: string;
|
|
71
75
|
}
|
|
72
76
|
|
|
73
77
|
/**
|
|
@@ -78,7 +82,7 @@ export interface KitHomeSources {
|
|
|
78
82
|
*/
|
|
79
83
|
export const resolveKitHome = (sources: KitHomeSources): string => {
|
|
80
84
|
if (sources.env !== undefined && sources.env !== "") {
|
|
81
|
-
return explicitKitHome(resolve(sources.env), sources.env)
|
|
85
|
+
return explicitKitHome(resolve(sources.env), sources.env);
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
return (
|
|
@@ -86,13 +90,13 @@ export const resolveKitHome = (sources: KitHomeSources): string => {
|
|
|
86
90
|
findKitHome(dirname(sources.execPath)) ??
|
|
87
91
|
findKitHome(sources.cwd) ??
|
|
88
92
|
dirname(sources.execPath)
|
|
89
|
-
)
|
|
90
|
-
}
|
|
93
|
+
);
|
|
94
|
+
};
|
|
91
95
|
|
|
92
96
|
export const kitHome = (): string =>
|
|
93
97
|
resolveKitHome({
|
|
94
98
|
env: process.env["DOCKS_KIT_HOME"],
|
|
95
99
|
moduleDir: import.meta.dir,
|
|
96
100
|
execPath: process.execPath,
|
|
97
|
-
cwd: process.cwd()
|
|
98
|
-
})
|
|
101
|
+
cwd: process.cwd(),
|
|
102
|
+
});
|
package/cli/src/main.ts
CHANGED
|
@@ -1,46 +1,53 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { Command, CliOutput } from "effect/unstable/cli"
|
|
3
|
-
import { BunRuntime, BunServices } from "@effect/platform-bun"
|
|
4
|
-
import { Console, Effect, Layer } from "effect"
|
|
5
|
-
import { EngineServicesLive } from "./services"
|
|
6
|
-
import { docsCommand } from "./commands/docs"
|
|
7
|
-
import { harnessesCommand } from "./commands/harnesses"
|
|
8
|
-
import { modelCommand } from "./commands/model"
|
|
9
|
-
import { modelsCommand } from "./commands/models"
|
|
10
|
-
import { ompCommand } from "./commands/omp"
|
|
11
|
-
import { pluginsCommand } from "./commands/plugins"
|
|
12
|
-
import { skillsCommand } from "./commands/skills"
|
|
13
|
-
import { statusCommand } from "./commands/status"
|
|
14
|
-
import { syncCommand } from "./commands/sync"
|
|
15
|
-
import { toolchainCommand } from "./commands/toolchain"
|
|
16
|
-
import { updateCommand } from "./commands/update"
|
|
17
|
-
import { GENERATED_PACKAGE_VERSION } from "./generated/sotPayload"
|
|
18
|
-
import { prepareArgv } from "./argv"
|
|
19
|
-
import { runEngineNative } from "./engine-native"
|
|
20
|
-
|
|
2
|
+
import { Command, CliOutput } from "effect/unstable/cli";
|
|
3
|
+
import { BunRuntime, BunServices } from "@effect/platform-bun";
|
|
4
|
+
import { Console, Effect, Layer } from "effect";
|
|
5
|
+
import { EngineServicesLive } from "./services";
|
|
6
|
+
import { docsCommand } from "./commands/docs";
|
|
7
|
+
import { harnessesCommand } from "./commands/harnesses";
|
|
8
|
+
import { modelCommand } from "./commands/model";
|
|
9
|
+
import { modelsCommand } from "./commands/models";
|
|
10
|
+
import { ompCommand } from "./commands/omp";
|
|
11
|
+
import { pluginsCommand } from "./commands/plugins";
|
|
12
|
+
import { skillsCommand } from "./commands/skills";
|
|
13
|
+
import { statusCommand } from "./commands/status";
|
|
14
|
+
import { syncCommand } from "./commands/sync";
|
|
15
|
+
import { toolchainCommand } from "./commands/toolchain";
|
|
16
|
+
import { updateCommand } from "./commands/update";
|
|
17
|
+
import { GENERATED_PACKAGE_VERSION } from "./generated/sotPayload";
|
|
18
|
+
import { prepareArgv } from "./argv";
|
|
19
|
+
import { runEngineNative } from "./engine-native";
|
|
21
20
|
|
|
22
21
|
const root = Command.make("docks-kit", {}, () =>
|
|
23
22
|
Effect.gen(function* () {
|
|
24
|
-
yield* Console.log("docks-kit — portable AI coding agent config kit")
|
|
25
|
-
yield* Console.log("")
|
|
26
|
-
yield* Console.log(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
yield* Console.log(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
yield* Console.log(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
yield* Console.log(" docks-kit
|
|
36
|
-
yield* Console.log(" docks-kit
|
|
37
|
-
yield* Console.log("")
|
|
38
|
-
yield* Console.log("
|
|
39
|
-
yield* Console.log("
|
|
40
|
-
|
|
23
|
+
yield* Console.log("docks-kit — portable AI coding agent config kit");
|
|
24
|
+
yield* Console.log("");
|
|
25
|
+
yield* Console.log(
|
|
26
|
+
" docks-kit sync [claude|codex|agents|omp] deploy the SoT to this machine",
|
|
27
|
+
);
|
|
28
|
+
yield* Console.log(
|
|
29
|
+
" docks-kit harnesses choose the flag-less sync selection",
|
|
30
|
+
);
|
|
31
|
+
yield* Console.log(
|
|
32
|
+
" docks-kit update [--no-sync] self-update the kit, then sync",
|
|
33
|
+
);
|
|
34
|
+
yield* Console.log(" docks-kit model <claude|codex> [value] get/set the deployed model");
|
|
35
|
+
yield* Console.log(" docks-kit models [tool] kit-verified model catalog");
|
|
36
|
+
yield* Console.log(" docks-kit toolchain [check|ensure <tool>] verified-version floors");
|
|
37
|
+
yield* Console.log(" docks-kit status deployed-vs-SoT doctor view");
|
|
38
|
+
yield* Console.log(" docks-kit plugins list plugin tri-state");
|
|
39
|
+
yield* Console.log(" docks-kit skills list universal skills");
|
|
40
|
+
yield* Console.log(" docks-kit docs [topic] self-documentation");
|
|
41
|
+
yield* Console.log(" docks-kit omp [--model|--pick] [...] free-model omp session");
|
|
42
|
+
yield* Console.log("");
|
|
43
|
+
yield* Console.log(
|
|
44
|
+
"Run 'docks-kit --help' for full option listings (also: --wizard, --completions).",
|
|
45
|
+
);
|
|
46
|
+
yield* Console.log("No-Bun recovery path: use a platform release binary.");
|
|
47
|
+
}),
|
|
41
48
|
).pipe(
|
|
42
49
|
Command.withDescription(
|
|
43
|
-
"Portable AI coding agent config kit — SoT sync engine + helpers for Claude Code, Codex, and universal agent skills."
|
|
50
|
+
"Portable AI coding agent config kit — SoT sync engine + helpers for Claude Code, Codex, and universal agent skills.",
|
|
44
51
|
),
|
|
45
52
|
Command.withSubcommands([
|
|
46
53
|
syncCommand,
|
|
@@ -53,17 +60,17 @@ const root = Command.make("docks-kit", {}, () =>
|
|
|
53
60
|
pluginsCommand,
|
|
54
61
|
skillsCommand,
|
|
55
62
|
docsCommand,
|
|
56
|
-
ompCommand
|
|
57
|
-
])
|
|
58
|
-
)
|
|
63
|
+
ompCommand,
|
|
64
|
+
]),
|
|
65
|
+
);
|
|
59
66
|
|
|
60
67
|
// v4's default formatter renders `name vversion`, but the `docks-kit` launcher
|
|
61
68
|
// compares `--version` against the bare `package.json` version. The trailing
|
|
62
69
|
// newline reproduces the characterized byte-for-byte output of the v3 CLI.
|
|
63
70
|
const bareVersionFormatter: CliOutput.Formatter = {
|
|
64
71
|
...CliOutput.defaultFormatter(),
|
|
65
|
-
formatVersion: (_name, version) => `${version}\n
|
|
66
|
-
}
|
|
72
|
+
formatVersion: (_name, version) => `${version}\n`,
|
|
73
|
+
};
|
|
67
74
|
|
|
68
75
|
// Harness-private raw channel:
|
|
69
76
|
// `DOCKS_KIT_ENGINE=native-raw` bypasses effect/unstable/cli and hands the raw engine
|
|
@@ -71,31 +78,31 @@ const bareVersionFormatter: CliOutput.Formatter = {
|
|
|
71
78
|
// PUBLIC engine execution lives at the engine.ts seam after the CLI has
|
|
72
79
|
// parsed/normalized pickers, --flag value forms, and non-engine commands.
|
|
73
80
|
if (process.env["DOCKS_KIT_ENGINE"] === "native-raw") {
|
|
74
|
-
const rawArgs = process.argv.slice(2)
|
|
75
|
-
const rawOperation = rawArgs.join(" ") || "default"
|
|
81
|
+
const rawArgs = process.argv.slice(2);
|
|
82
|
+
const rawOperation = rawArgs.join(" ") || "default";
|
|
76
83
|
try {
|
|
77
|
-
process.exit(await runEngineNative(rawArgs))
|
|
84
|
+
process.exit(await runEngineNative(rawArgs));
|
|
78
85
|
} catch (error) {
|
|
79
|
-
let detail = "unknown error"
|
|
80
|
-
if (error instanceof Error && error.message !== "") detail = error.message
|
|
81
|
-
else if (typeof error === "string" && error !== "") detail = error
|
|
82
|
-
process.stderr.write(`docks-kit raw operation '${rawOperation}' failed: ${detail}\n`)
|
|
83
|
-
process.exit(1)
|
|
86
|
+
let detail = "unknown error";
|
|
87
|
+
if (error instanceof Error && error.message !== "") detail = error.message;
|
|
88
|
+
else if (typeof error === "string" && error !== "") detail = error;
|
|
89
|
+
process.stderr.write(`docks-kit raw operation '${rawOperation}' failed: ${detail}\n`);
|
|
90
|
+
process.exit(1);
|
|
84
91
|
}
|
|
85
92
|
}
|
|
86
93
|
|
|
87
94
|
// Validate and normalize before parsing because the kit refuses to guess at unrecognized
|
|
88
95
|
// or duplicated flags, and Effect 4 would otherwise negate `--no-<flag>` into a real
|
|
89
96
|
// mutating run. This seam owns argument normalization.
|
|
90
|
-
const prepared = prepareArgv(process.argv.slice(2))
|
|
97
|
+
const prepared = prepareArgv(process.argv.slice(2));
|
|
91
98
|
if (prepared.kind === "reject") {
|
|
92
|
-
process.stderr.write(`${prepared.message}\n`)
|
|
93
|
-
process.exit(prepared.exitCode)
|
|
99
|
+
process.stderr.write(`${prepared.message}\n`);
|
|
100
|
+
process.exit(prepared.exitCode);
|
|
94
101
|
}
|
|
95
102
|
|
|
96
103
|
Command.runWith(root, { version: GENERATED_PACKAGE_VERSION })(prepared.args).pipe(
|
|
97
104
|
Effect.provide(
|
|
98
|
-
Layer.mergeAll(BunServices.layer, EngineServicesLive, CliOutput.layer(bareVersionFormatter))
|
|
105
|
+
Layer.mergeAll(BunServices.layer, EngineServicesLive, CliOutput.layer(bareVersionFormatter)),
|
|
99
106
|
),
|
|
100
|
-
BunRuntime.runMain
|
|
101
|
-
)
|
|
107
|
+
BunRuntime.runMain,
|
|
108
|
+
);
|
package/cli/src/manifests.ts
CHANGED
|
@@ -1,99 +1,98 @@
|
|
|
1
|
-
import { existsSync, lstatSync, readFileSync, readdirSync, readlinkSync } from "node:fs"
|
|
2
|
-
import { homedir } from "node:os"
|
|
3
|
-
import { dirname, join, resolve } from "node:path"
|
|
4
|
-
import { pluginUserScopeInstalled } from "./engine-native/
|
|
5
|
-
import { COPY_MARKER } from "./engine-native/skillsSync"
|
|
6
|
-
import { payloadText } from "./payload"
|
|
1
|
+
import { existsSync, lstatSync, readFileSync, readdirSync, readlinkSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { pluginUserScopeInstalled } from "./engine-native/claudePluginPasses";
|
|
5
|
+
import { COPY_MARKER } from "./engine-native/skillsSync";
|
|
6
|
+
import { payloadText } from "./payload";
|
|
7
7
|
|
|
8
|
-
export { homedir }
|
|
8
|
+
export { homedir };
|
|
9
9
|
|
|
10
|
-
export type Tool = "claude" | "codex"
|
|
10
|
+
export type Tool = "claude" | "codex";
|
|
11
11
|
|
|
12
|
-
const readJson = (path: string): any => JSON.parse(readFileSync(path, "utf8"))
|
|
13
|
-
const readJsonText = (text: string): any => JSON.parse(text)
|
|
12
|
+
const readJson = (path: string): any => JSON.parse(readFileSync(path, "utf8"));
|
|
13
|
+
const readJsonText = (text: string): any => JSON.parse(text);
|
|
14
14
|
|
|
15
15
|
/** SoT settings (claude) — model/effort/env for drift display. */
|
|
16
|
-
export const sotClaudeSettings = (): any =>
|
|
17
|
-
readJsonText(payloadText("SoT/.claude/settings.json"))
|
|
16
|
+
export const sotClaudeSettings = (): any => readJsonText(payloadText("SoT/.claude/settings.json"));
|
|
18
17
|
|
|
19
18
|
export const deployedClaudeSettings = (): any | undefined => {
|
|
20
|
-
const p = join(homedir(), ".claude", "settings.json")
|
|
21
|
-
return existsSync(p) ? readJson(p) : undefined
|
|
22
|
-
}
|
|
19
|
+
const p = join(homedir(), ".claude", "settings.json");
|
|
20
|
+
return existsSync(p) ? readJson(p) : undefined;
|
|
21
|
+
};
|
|
23
22
|
|
|
24
23
|
export function topLevelTomlString(text: string, setting: string): string | undefined {
|
|
25
24
|
for (const line of text.split(/\r?\n/)) {
|
|
26
|
-
if (/^\s*\[/.test(line)) return undefined
|
|
27
|
-
const assignment = line.match(/^\s*([A-Za-z0-9_-]+)\s*=\s*"([^"]+)"/)
|
|
28
|
-
if (assignment?.[1] === setting) return assignment[2]
|
|
25
|
+
if (/^\s*\[/.test(line)) return undefined;
|
|
26
|
+
const assignment = line.match(/^\s*([A-Za-z0-9_-]+)\s*=\s*"([^"]+)"/);
|
|
27
|
+
if (assignment?.[1] === setting) return assignment[2];
|
|
29
28
|
}
|
|
30
|
-
return undefined
|
|
29
|
+
return undefined;
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
const tomlModel = (path: string): string | undefined => {
|
|
34
|
-
if (!existsSync(path)) return undefined
|
|
35
|
-
return topLevelTomlString(readFileSync(path, "utf8"), "model")
|
|
36
|
-
}
|
|
33
|
+
if (!existsSync(path)) return undefined;
|
|
34
|
+
return topLevelTomlString(readFileSync(path, "utf8"), "model");
|
|
35
|
+
};
|
|
37
36
|
|
|
38
37
|
export const sotCodexModel = (): string | undefined =>
|
|
39
|
-
topLevelTomlString(payloadText("SoT/.codex/config.toml"), "model")
|
|
38
|
+
topLevelTomlString(payloadText("SoT/.codex/config.toml"), "model");
|
|
40
39
|
|
|
41
40
|
export const deployedCodexModel = (): string | undefined =>
|
|
42
|
-
tomlModel(join(homedir(), ".codex", "config.toml"))
|
|
41
|
+
tomlModel(join(homedir(), ".codex", "config.toml"));
|
|
43
42
|
|
|
44
43
|
/** Installed plugins (user scope) vs SoT enabledPlugins tri-state. */
|
|
45
44
|
export const pluginsView = (): Array<{
|
|
46
|
-
plugin: string
|
|
47
|
-
sot: "true" | "false" | "absent"
|
|
48
|
-
installed: boolean
|
|
45
|
+
plugin: string;
|
|
46
|
+
sot: "true" | "false" | "absent";
|
|
47
|
+
installed: boolean;
|
|
49
48
|
}> => {
|
|
50
|
-
const sot: Record<string, boolean> = sotClaudeSettings().enabledPlugins ?? {}
|
|
51
|
-
const installedPath = join(homedir(), ".claude", "plugins", "installed_plugins.json")
|
|
49
|
+
const sot: Record<string, boolean> = sotClaudeSettings().enabledPlugins ?? {};
|
|
50
|
+
const installedPath = join(homedir(), ".claude", "plugins", "installed_plugins.json");
|
|
52
51
|
const installed: Record<string, unknown> = existsSync(installedPath)
|
|
53
|
-
? readJson(installedPath).plugins ?? {}
|
|
54
|
-
: {}
|
|
55
|
-
const names = new Set([...Object.keys(sot), ...Object.keys(installed)])
|
|
52
|
+
? (readJson(installedPath).plugins ?? {})
|
|
53
|
+
: {};
|
|
54
|
+
const names = new Set([...Object.keys(sot), ...Object.keys(installed)]);
|
|
56
55
|
return [...names].sort().map((plugin) => ({
|
|
57
56
|
plugin,
|
|
58
57
|
sot: plugin in sot ? (sot[plugin] ? "true" : "false") : "absent",
|
|
59
|
-
installed: pluginUserScopeInstalled(installedPath, plugin)
|
|
60
|
-
}))
|
|
61
|
-
}
|
|
58
|
+
installed: pluginUserScopeInstalled(installedPath, plugin),
|
|
59
|
+
}));
|
|
60
|
+
};
|
|
62
61
|
|
|
63
62
|
/** Universal skills: SoT manifest slugs vs ~/.agents/skills contents. */
|
|
64
63
|
export const skillsView = (): Array<{
|
|
65
|
-
skill: string
|
|
66
|
-
declared: boolean
|
|
67
|
-
installed: boolean
|
|
64
|
+
skill: string;
|
|
65
|
+
declared: boolean;
|
|
66
|
+
installed: boolean;
|
|
68
67
|
/** Claude entry resolves to the canonical skill by symlink, junction, or kit-created copy. */
|
|
69
|
-
claudeSymlink: boolean
|
|
68
|
+
claudeSymlink: boolean;
|
|
70
69
|
}> => {
|
|
71
70
|
const declared = payloadText("SoT/.agents/skills.txt")
|
|
72
71
|
.split("\n")
|
|
73
72
|
.map((l) => l.replace(/#.*$/, "").trim())
|
|
74
73
|
.filter((l) => l.length > 0)
|
|
75
|
-
.map((slug) => slug.split("/").pop() as string)
|
|
76
|
-
const home = homedir()
|
|
77
|
-
const skillsDir = join(home, ".agents", "skills")
|
|
74
|
+
.map((slug) => slug.split("/").pop() as string);
|
|
75
|
+
const home = homedir();
|
|
76
|
+
const skillsDir = join(home, ".agents", "skills");
|
|
78
77
|
const installed = existsSync(skillsDir)
|
|
79
78
|
? readdirSync(skillsDir, { withFileTypes: true })
|
|
80
79
|
.filter((e) => e.isDirectory())
|
|
81
80
|
.map((e) => e.name)
|
|
82
|
-
: []
|
|
83
|
-
const names = new Set([...declared, ...installed])
|
|
81
|
+
: [];
|
|
82
|
+
const names = new Set([...declared, ...installed]);
|
|
84
83
|
return [...names].sort().map((skill) => {
|
|
85
|
-
const link = join(home, ".claude", "skills", skill)
|
|
86
|
-
const canonical = resolve(skillsDir, skill)
|
|
87
|
-
let claudeSymlink = false
|
|
84
|
+
const link = join(home, ".claude", "skills", skill);
|
|
85
|
+
const canonical = resolve(skillsDir, skill);
|
|
86
|
+
let claudeSymlink = false;
|
|
88
87
|
try {
|
|
89
|
-
const target = resolve(dirname(link), readlinkSync(link))
|
|
90
|
-
claudeSymlink = target === canonical && existsSync(target)
|
|
88
|
+
const target = resolve(dirname(link), readlinkSync(link));
|
|
89
|
+
claudeSymlink = target === canonical && existsSync(target);
|
|
91
90
|
} catch {
|
|
92
91
|
/* not a symlink or missing */
|
|
93
92
|
}
|
|
94
93
|
if (!claudeSymlink && installed.includes(skill)) {
|
|
95
94
|
try {
|
|
96
|
-
claudeSymlink = lstatSync(link).isDirectory() && existsSync(join(link, COPY_MARKER))
|
|
95
|
+
claudeSymlink = lstatSync(link).isDirectory() && existsSync(join(link, COPY_MARKER));
|
|
97
96
|
} catch {
|
|
98
97
|
/* missing Claude entry */
|
|
99
98
|
}
|
|
@@ -102,7 +101,7 @@ export const skillsView = (): Array<{
|
|
|
102
101
|
skill,
|
|
103
102
|
declared: declared.includes(skill),
|
|
104
103
|
installed: installed.includes(skill),
|
|
105
|
-
claudeSymlink
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
}
|
|
104
|
+
claudeSymlink,
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
};
|
package/cli/src/md.d.ts
CHANGED
package/cli/src/payload.ts
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
2
|
GENERATED_PAYLOAD_BASE64,
|
|
3
3
|
GENERATED_PAYLOAD_PATHS,
|
|
4
|
-
GENERATED_PAYLOAD_TEXT
|
|
5
|
-
} from "./generated/sotPayload"
|
|
4
|
+
GENERATED_PAYLOAD_TEXT,
|
|
5
|
+
} from "./generated/sotPayload";
|
|
6
6
|
|
|
7
|
-
export type PayloadPath = typeof GENERATED_PAYLOAD_PATHS[number]
|
|
8
|
-
type TextPayloadPath = Exclude<PayloadPath, "notification.mp3"
|
|
7
|
+
export type PayloadPath = (typeof GENERATED_PAYLOAD_PATHS)[number];
|
|
8
|
+
type TextPayloadPath = Exclude<PayloadPath, "notification.mp3">;
|
|
9
9
|
|
|
10
10
|
export function payloadText(path: TextPayloadPath): string {
|
|
11
|
-
return GENERATED_PAYLOAD_TEXT[path]
|
|
11
|
+
return GENERATED_PAYLOAD_TEXT[path];
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export function payloadBytes(path: PayloadPath): Buffer {
|
|
15
|
-
if (path === "notification.mp3") return Buffer.from(GENERATED_PAYLOAD_BASE64[path], "base64")
|
|
16
|
-
return Buffer.from(payloadText(path))
|
|
15
|
+
if (path === "notification.mp3") return Buffer.from(GENERATED_PAYLOAD_BASE64[path], "base64");
|
|
16
|
+
return Buffer.from(payloadText(path));
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export function payloadPaths(prefix: string): ReadonlyArray<PayloadPath> {
|
|
20
|
-
return GENERATED_PAYLOAD_PATHS.filter((path) => path.startsWith(prefix))
|
|
20
|
+
return GENERATED_PAYLOAD_PATHS.filter((path) => path.startsWith(prefix));
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export function payloadDisplayPath(path: PayloadPath): string {
|
|
24
|
-
return `embedded:${path}
|
|
24
|
+
return `embedded:${path}`;
|
|
25
25
|
}
|
package/cli/src/services.ts
CHANGED
|
@@ -4,9 +4,14 @@
|
|
|
4
4
|
* named test-layer constructors. Composed ONCE at main.ts — command code
|
|
5
5
|
* accesses services via `yield*`, never by re-providing.
|
|
6
6
|
*/
|
|
7
|
-
import { Context, Layer } from "effect"
|
|
8
|
-
import { makeLogger, type Logger, type LoggerSinks } from "./engine-native/logger"
|
|
9
|
-
import {
|
|
7
|
+
import { Context, Layer } from "effect";
|
|
8
|
+
import { makeLogger, type Logger, type LoggerSinks } from "./engine-native/logger";
|
|
9
|
+
import {
|
|
10
|
+
makeEngineServices,
|
|
11
|
+
makePlatform,
|
|
12
|
+
type DependencyManager,
|
|
13
|
+
type Platform,
|
|
14
|
+
} from "./engine-native/services";
|
|
10
15
|
|
|
11
16
|
export class LoggerService extends Context.Service<LoggerService, Logger>()("docks-kit/Logger") {}
|
|
12
17
|
|
|
@@ -15,20 +20,23 @@ export class DependencyManagerService extends Context.Service<
|
|
|
15
20
|
DependencyManager
|
|
16
21
|
>()("docks-kit/DependencyManager") {}
|
|
17
22
|
|
|
18
|
-
export class PlatformService extends Context.Service<PlatformService, Platform>()(
|
|
23
|
+
export class PlatformService extends Context.Service<PlatformService, Platform>()(
|
|
24
|
+
"docks-kit/Platform",
|
|
25
|
+
) {}
|
|
19
26
|
|
|
20
|
-
const live = makeEngineServices()
|
|
27
|
+
const live = makeEngineServices();
|
|
21
28
|
|
|
22
|
-
export const LoggerLive = Layer.succeed(LoggerService, live.logger)
|
|
23
|
-
export const DependencyManagerLive = Layer.succeed(DependencyManagerService, live.deps)
|
|
24
|
-
export const PlatformLive = Layer.succeed(PlatformService, live.platform)
|
|
25
|
-
export const EngineServicesLive = Layer.mergeAll(LoggerLive, DependencyManagerLive, PlatformLive)
|
|
29
|
+
export const LoggerLive = Layer.succeed(LoggerService, live.logger);
|
|
30
|
+
export const DependencyManagerLive = Layer.succeed(DependencyManagerService, live.deps);
|
|
31
|
+
export const PlatformLive = Layer.succeed(PlatformService, live.platform);
|
|
32
|
+
export const EngineServicesLive = Layer.mergeAll(LoggerLive, DependencyManagerLive, PlatformLive);
|
|
26
33
|
|
|
27
34
|
export const LoggerTest = (sinks: LoggerSinks): Layer.Layer<LoggerService> =>
|
|
28
|
-
Layer.succeed(LoggerService, makeLogger(sinks))
|
|
35
|
+
Layer.succeed(LoggerService, makeLogger(sinks));
|
|
29
36
|
|
|
30
37
|
export const PlatformTest = (pf: NodeJS.Platform): Layer.Layer<PlatformService> =>
|
|
31
|
-
Layer.succeed(PlatformService, makePlatform(pf))
|
|
38
|
+
Layer.succeed(PlatformService, makePlatform(pf));
|
|
32
39
|
|
|
33
|
-
export const DependencyManagerTest = (
|
|
34
|
-
|
|
40
|
+
export const DependencyManagerTest = (
|
|
41
|
+
impl: DependencyManager,
|
|
42
|
+
): Layer.Layer<DependencyManagerService> => Layer.succeed(DependencyManagerService, impl);
|
package/cli/tsconfig.json
CHANGED
|
@@ -6,9 +6,12 @@
|
|
|
6
6
|
"types": ["bun"],
|
|
7
7
|
"strict": true,
|
|
8
8
|
"noEmit": true,
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
"checkJs": true,
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
9
12
|
"skipLibCheck": true,
|
|
10
13
|
"forceConsistentCasingInFileNames": true,
|
|
11
14
|
"verbatimModuleSyntax": true
|
|
12
15
|
},
|
|
13
|
-
"include": ["src/**/*.ts", "src/**/*.d.ts", "test/**/*.ts", "scripts/**/*.ts"]
|
|
16
|
+
"include": ["src/**/*.ts", "src/**/*.d.ts", "test/**/*.ts", "scripts/**/*.ts", "test/statusline-runtime-smoke.mjs", "../SoT/.claude/bin/*.mjs"]
|
|
14
17
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docks-kit",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.2",
|
|
4
4
|
"description": "Portable AI coding agent config kit — SoT sync engine + typed CLI for Claude Code, Codex, and universal agent skills",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,7 +37,12 @@
|
|
|
37
37
|
"test:unit": "vitest run",
|
|
38
38
|
"test:runtime:posix": "bun cli/test/statusline-runtime-smoke.mjs posix",
|
|
39
39
|
"test:runtime:windows": "bun cli/test/statusline-runtime-smoke.mjs windows",
|
|
40
|
-
"test:ci": "bun run check:generated && bun run --parallel typecheck test:unit golden:dryrun golden:mutation && bun run test:runtime:posix"
|
|
40
|
+
"test:ci": "bun run check:generated && bun run --parallel typecheck test:unit golden:dryrun golden:mutation && bun run test:runtime:posix",
|
|
41
|
+
"test:integration": "bun run --parallel golden:dryrun golden:mutation",
|
|
42
|
+
"test": "bun run --parallel test:unit test:integration",
|
|
43
|
+
"lint": "oxlint",
|
|
44
|
+
"format": "oxfmt --write cli/src cli/test cli/scripts vitest.config.ts",
|
|
45
|
+
"check": "bun run --parallel lint typecheck test"
|
|
41
46
|
},
|
|
42
47
|
"dependencies": {
|
|
43
48
|
"@effect/platform-bun": "4.0.0-rc.115",
|
|
@@ -48,6 +53,8 @@
|
|
|
48
53
|
"devDependencies": {
|
|
49
54
|
"@effect/vitest": "4.0.0-rc.115",
|
|
50
55
|
"@types/bun": "^1.4.0",
|
|
56
|
+
"oxfmt": "0.67.0",
|
|
57
|
+
"oxlint": "1.82.0",
|
|
51
58
|
"typescript": "7.0.2",
|
|
52
59
|
"vitest": "5.0.0"
|
|
53
60
|
}
|