claude-plugin-dsh 0.0.0-stage → 0.1.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.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -2
  3. package/dist/bin/cli.d.ts +3 -0
  4. package/dist/bin/cli.d.ts.map +1 -0
  5. package/dist/bin/cli.js +80 -0
  6. package/dist/bin/cli.js.map +1 -0
  7. package/dist/bin/inspect.d.ts +2 -0
  8. package/dist/bin/inspect.d.ts.map +1 -0
  9. package/dist/bin/inspect.js +45 -0
  10. package/dist/bin/inspect.js.map +1 -0
  11. package/dist/bin/runtime.d.ts +2 -0
  12. package/dist/bin/runtime.d.ts.map +1 -0
  13. package/dist/bin/runtime.js +4 -0
  14. package/dist/bin/runtime.js.map +1 -0
  15. package/dist/bin/scaffold.d.ts +2 -0
  16. package/dist/bin/scaffold.d.ts.map +1 -0
  17. package/dist/bin/scaffold.js +44 -0
  18. package/dist/bin/scaffold.js.map +1 -0
  19. package/dist/bin/sync.d.ts +2 -0
  20. package/dist/bin/sync.d.ts.map +1 -0
  21. package/dist/bin/sync.js +24 -0
  22. package/dist/bin/sync.js.map +1 -0
  23. package/dist/claude-compat.js +825 -0
  24. package/dist/src/claude-compat.d.ts +8 -0
  25. package/dist/src/claude-compat.d.ts.map +1 -0
  26. package/dist/src/claude-compat.js +7 -0
  27. package/dist/src/claude-compat.js.map +1 -0
  28. package/dist/src/dsh-types.d.ts +252 -0
  29. package/dist/src/dsh-types.d.ts.map +1 -0
  30. package/dist/src/dsh-types.js +6 -0
  31. package/dist/src/dsh-types.js.map +1 -0
  32. package/dist/src/hooks.d.ts +38 -0
  33. package/dist/src/hooks.d.ts.map +1 -0
  34. package/dist/src/hooks.js +136 -0
  35. package/dist/src/hooks.js.map +1 -0
  36. package/dist/src/plugin-files.d.ts +92 -0
  37. package/dist/src/plugin-files.d.ts.map +1 -0
  38. package/dist/src/plugin-files.js +198 -0
  39. package/dist/src/plugin-files.js.map +1 -0
  40. package/dist/src/plugin.d.ts +35 -0
  41. package/dist/src/plugin.d.ts.map +1 -0
  42. package/dist/src/plugin.js +422 -0
  43. package/dist/src/plugin.js.map +1 -0
  44. package/dist/src/transcript.d.ts +25 -0
  45. package/dist/src/transcript.d.ts.map +1 -0
  46. package/dist/src/transcript.js +198 -0
  47. package/dist/src/transcript.js.map +1 -0
  48. package/package.json +54 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mariusz Rakus
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,155 @@
1
- # Temporary Holding Version
1
+ # claude-plugin-dsh
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Run an unmodified [Claude Code](https://docs.claude.com/en/docs/claude-code) plugin inside
4
+ [DeepSeek Harness](https://github.com/deepseek-ai) (DSH).
5
+
6
+ You add a `dsh/` directory next to the plugin's `.claude-plugin/`. It holds a small DSH
7
+ bundle and a copy of `claude-compat.js`. The bundle reads the plugin's own skills, commands,
8
+ agents, hooks and instruction files and wires them into DSH. Claude Code never reads `dsh/`,
9
+ so the same tree keeps working in both harnesses. The vendored runtime is refreshed with
10
+ `sync`, not by hand.
11
+
12
+ TypeScript sources, compiled JavaScript and declarations. The vendored runtime is one file
13
+ with no runtime dependencies. Node 20 or newer; hooks require a POSIX shell.
14
+
15
+ Install the package:
16
+
17
+ ```sh
18
+ bun add claude-plugin-dsh
19
+ ```
20
+
21
+ `bun x claude-plugin-dsh` runs the CLI without installing it.
22
+ The old `claude-plugins-dsh` command name still works as an alias.
23
+
24
+ Adapters may import `createPlugin` and `rootFrom` directly, or vendor the built runtime as
25
+ shown below. Direct imports receive types; vendored copies stay self-contained and must be
26
+ updated with `sync`.
27
+
28
+ ## What maps to what
29
+
30
+ | Claude Code | DSH |
31
+ |---|---|
32
+ | `skills/<n>/SKILL.md` | skill at rank 450, so a same-named skill in `~/.dsh/skills` still wins |
33
+ | `commands/<n>.md` | `/<plugin>-<n>` slash command (prefix configurable); the body, with `$ARGUMENTS` and `$1` to `$9`, becomes the next turn |
34
+ | `agents/<n>.md` | skill `<plugin>-agent-<n>`: a role brief to pass to `subagent` or `spawn_teammate` |
35
+ | `CLAUDE.md`-style files you list | system prompt section, with `<!--harness:claude-only-->` blocks removed |
36
+ | `PreToolUse` hook | `tools/pre-execute`; `ask` becomes a DSH approval, `deny` or exit 2 denies, `updatedInput` is denied because DSH cannot rewrite arguments |
37
+ | `PostToolUse` hook | `tools/post-execute`; exit 2 blocks the result and its stderr becomes the feedback, `additionalContext` rides on the decision |
38
+ | `SessionStart` hook | `agent/created` of a root agent (subagents skipped, as in Claude Code) |
39
+ | `UserPromptSubmit` hook | a step carrying a user message; a block keeps the prompt from the model |
40
+ | `Stop`, `SubagentStop` hooks | `agent/turn-stopping`; `{"decision":"block"}` steers one more step |
41
+ | `SessionEnd` hook | `agent/disposed` |
42
+ | `.mcp.json` | not handled here: add `@deepseek-ai/dsh-mcp-client` rows to the bundle patch |
43
+
44
+ Hooks get Claude Code's stdin JSON: `session_id`, `cwd`, `hook_event_name`, `tool_name` using
45
+ Claude names such as `Bash`, `tool_input`, `stop_hook_active` and `transcript_path`.
46
+ `tool_response` uses Claude's per-tool shape: `stdout` and `stderr` for Bash, `file.content`
47
+ for Read, `filePath` plus edit strings for Write and Edit, and `filenames` for Glob. Their
48
+ environment has `CLAUDE_PLUGIN_ROOT` and `CLAUDE_PROJECT_DIR`, plus `CLAUDE_HARNESS=dsh` so a
49
+ script can tell the two harnesses apart. A hook with `args` runs in exec form, as in Claude Code: `command` is spawned directly with those arguments and no shell, and `${CLAUDE_PLUGIN_ROOT}` and `${CLAUDE_PROJECT_DIR}` are replaced inside each argument as plain text. `onFailure: "block"` makes a crash, a timeout or an exit code other than 0 and 2 count as a block. Matching hooks run in parallel, each in its own process
50
+ group. A timeout or a cancelled turn kills the whole group.
51
+
52
+ `transcript_path` points at a Claude-shaped JSONL export of the DSH session under
53
+ `$DSH_HOME/state/claude-compat/transcripts/`. It is mode 0600, grows by appending, and is
54
+ deleted when the agent is disposed.
55
+
56
+ Not mapped: function hooks (`hooks.json` `modules`), `PreCompact`, `Notification`, LSP
57
+ servers, and per-agent model pins.
58
+
59
+ ## Add it to a plugin
60
+
61
+ ```sh
62
+ bun x claude-plugin-dsh scaffold --scope @you /path/to/plugin
63
+ ```
64
+
65
+ `scaffold` writes `dsh/package.json` (package `@you/<plugin>-dsh`, or `<plugin>-dsh` without
66
+ `--scope`), `dsh/locale/en.json` and the runtime copy. You write two small files yourself.
67
+
68
+ `dsh/index.js`:
69
+
70
+ ```js
71
+ import { createPlugin, rootFrom } from './claude-compat.js'
72
+
73
+ const plugin = createPlugin({
74
+ root: rootFrom(import.meta.url),
75
+ // all optional:
76
+ instructions: ['CLAUDE.md'], // files to put in the system prompt
77
+ skills: { exclude: [], prefix: '' }, // prefix renames x to <prefix>-x; '' keeps x
78
+ commands: { exclude: [], prefix: '' },// default is the plugin name; '' gives /<n>
79
+ agents: { exclude: [], extraDirs: [] },
80
+ hooks: { events: ['PreToolUse'] }, // limit which hook events run
81
+ disableByDefault: [], // skills | commands | agents | instructions | hooks
82
+ })
83
+ export const { name, apply } = plugin
84
+ export default plugin
85
+ ```
86
+
87
+ `dsh/cordis.patch.yml`:
88
+
89
+ ```yaml
90
+ - insert:
91
+ - id: claude-compat-my-plugin
92
+ name: '@you/my-plugin-dsh' # the name in dsh/package.json
93
+ ```
94
+
95
+ Check what it registers without starting DSH:
96
+
97
+ ```sh
98
+ bun x claude-plugin-dsh inspect /path/to/plugin
99
+ ```
100
+
101
+ ## Install into DSH
102
+
103
+ Through DSH's plugin manager:
104
+
105
+ ```sh
106
+ dsh plugin --profile web add file:/abs/path/to/plugin/dsh
107
+ ```
108
+
109
+ Or for every profile, add a row to `~/.dsh/cordis.patch.yml`. DSH picks it up without a restart:
110
+
111
+ ```yaml
112
+ - insert:
113
+ - id: claude-compat-my-plugin
114
+ name: "file:///abs/path/to/plugin/dsh/index.js"
115
+ ```
116
+
117
+ A row config can turn parts off: `config: { disable: [hooks] }`.
118
+
119
+ ## Keeping vendored copies current
120
+
121
+ ```sh
122
+ bun x claude-plugin-dsh sync plugin-a plugin-b
123
+ bun x claude-plugin-dsh sync --check plugin-a plugin-b
124
+ ```
125
+
126
+ ## Development
127
+
128
+ ```sh
129
+ bun install --frozen-lockfile
130
+ bun run typecheck
131
+ bun run test
132
+ bun pm pack
133
+ ```
134
+
135
+ `bun run build` compiles the typed modules and CLI, emits declarations, and bundles
136
+ `dist/claude-compat.js` for existing adapters. Generated files are not committed.
137
+ `bun run test` runs the Node compatibility suite against the compiled runtime and CLI.
138
+ `prepack` builds before packaging.
139
+
140
+ Publishing requires npm access to the `claude-plugin-dsh` package:
141
+
142
+ ```sh
143
+ bun publish
144
+ ```
145
+
146
+ `prepublishOnly` runs type checking and tests before publication. Do not put registry tokens
147
+ in the repository. Run `inspect` only on trusted plugins: it imports their JavaScript.
148
+
149
+ ## Used by
150
+
151
+ The [kolezka](https://github.com/kolezka/marketplace) Claude Code plugins.
152
+
153
+ ## License
154
+
155
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":""}
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env node
2
+ import { inspect } from './inspect.js';
3
+ import { scaffold } from './scaffold.js';
4
+ import { sync } from './sync.js';
5
+ const usage = `Usage: claude-plugin-dsh <command> [options] <plugin-dir>...
6
+
7
+ Commands:
8
+ scaffold [--scope @you] <plugin-dir>... Generate manifest, locale and runtime
9
+ inspect <plugin-dir>... List plugin registrations (loads plugin code)
10
+ sync [--check] <plugin-dir>... Copy runtime, or check for drift
11
+
12
+ Options:
13
+ -h, --help Show help
14
+ `;
15
+ class UsageError extends Error {
16
+ }
17
+ async function main(args) {
18
+ const [command, ...rest] = args;
19
+ if ((command === '-h' || command === '--help') && rest.length === 0) {
20
+ console.log(usage);
21
+ return 0;
22
+ }
23
+ if (command !== 'scaffold' && command !== 'inspect' && command !== 'sync') {
24
+ throw new UsageError(command ? `Unknown command: ${command}` : 'A command is required');
25
+ }
26
+ if (rest.length === 1 && (rest[0] === '-h' || rest[0] === '--help')) {
27
+ console.log(usage);
28
+ return 0;
29
+ }
30
+ let scope;
31
+ let check = false;
32
+ let positional = false;
33
+ const directories = [];
34
+ for (let index = 0; index < rest.length; index++) {
35
+ const arg = rest[index];
36
+ if (arg === undefined)
37
+ continue;
38
+ if (!positional && arg === '--') {
39
+ positional = true;
40
+ }
41
+ else if (!positional && arg === '--scope' && command === 'scaffold') {
42
+ if (scope !== undefined)
43
+ throw new UsageError('--scope may only be supplied once');
44
+ scope = rest[++index];
45
+ if (scope === undefined || !/^@[a-z0-9][a-z0-9._-]*$/.test(scope)) {
46
+ throw new UsageError(`--scope must look like @name, got ${JSON.stringify(scope)}`);
47
+ }
48
+ }
49
+ else if (!positional && arg === '--check' && command === 'sync') {
50
+ if (check)
51
+ throw new UsageError('--check may only be supplied once');
52
+ check = true;
53
+ }
54
+ else if (!positional && arg.startsWith('-')) {
55
+ throw new UsageError(`Unknown option for ${command}: ${arg}`);
56
+ }
57
+ else {
58
+ directories.push(arg);
59
+ }
60
+ }
61
+ if (!directories.length)
62
+ throw new UsageError(`${command} requires at least one plugin directory`);
63
+ if (command === 'scaffold') {
64
+ scaffold(directories, scope ?? '');
65
+ return 0;
66
+ }
67
+ if (command === 'sync')
68
+ return sync(directories, check);
69
+ return inspect(directories);
70
+ }
71
+ try {
72
+ process.exitCode = await main(process.argv.slice(2));
73
+ }
74
+ catch (error) {
75
+ console.error(error instanceof Error ? error.message : String(error));
76
+ if (error instanceof UsageError)
77
+ console.error(usage);
78
+ process.exitCode = error instanceof UsageError ? 64 : 1;
79
+ }
80
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function inspect(directories: readonly string[]): Promise<number>;
2
+ //# sourceMappingURL=inspect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspect.d.ts","sourceRoot":"","sources":["../../bin/inspect.ts"],"names":[],"mappings":"AAIA,wBAAsB,OAAO,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAyC7E"}
@@ -0,0 +1,45 @@
1
+ import { resolve } from 'node:path';
2
+ import { pathToFileURL } from 'node:url';
3
+ export async function inspect(directories) {
4
+ let failed = false;
5
+ for (const directory of directories) {
6
+ const entry = pathToFileURL(resolve(directory, 'dsh', 'index.js')).href;
7
+ const plugin = await import(entry);
8
+ if (typeof plugin !== 'object' || plugin === null || !('apply' in plugin) || typeof plugin.apply !== 'function') {
9
+ throw new Error(`${entry}: expected a plugin exporting apply`);
10
+ }
11
+ const seen = {
12
+ skills: [], commands: [], sections: [], events: [],
13
+ };
14
+ const ctx = {
15
+ logger: { warn: (message) => console.warn(' warn:', message) },
16
+ skills: { registerProvider: (create) => seen.skills.push(create({ signal: new AbortController().signal, invalidate() { } })) },
17
+ commands: { register: (definition) => seen.commands.push(definition.name) },
18
+ systemPrompt: { section: (section) => seen.sections.push(section) },
19
+ workingDirectory: { get: () => process.cwd() },
20
+ inject: (_services, callback) => callback(ctx),
21
+ effect() { },
22
+ on: (event) => seen.events.push(event),
23
+ };
24
+ await plugin.apply(ctx, {});
25
+ const skills = [];
26
+ for (const provider of seen.skills) {
27
+ for (const candidate of await provider.list({})) {
28
+ const body = await provider.get(candidate, {});
29
+ if (!body?.content) {
30
+ failed = true;
31
+ console.error(` ${candidate.name}: empty body`);
32
+ }
33
+ skills.push(candidate.name);
34
+ }
35
+ }
36
+ const prompt = seen.sections.map((section) => typeof section.text === 'string' ? section.text : section.text({})).join('');
37
+ console.log('name' in plugin ? String(plugin.name) : directory);
38
+ console.log(` skills: ${skills.join(', ') || '-'}`);
39
+ console.log(` commands: ${seen.commands.map((command) => '/' + command).join(' ') || '-'}`);
40
+ console.log(` prompt: ${prompt ? `${prompt.length} chars, claude-only left: ${/harness:claude-only/.test(prompt)}` : '-'}`);
41
+ console.log(` events: ${[...new Set(seen.events)].join(', ') || '-'}`);
42
+ }
43
+ return failed ? 1 : 0;
44
+ }
45
+ //# sourceMappingURL=inspect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspect.js","sourceRoot":"","sources":["../../bin/inspect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const runtimePath: string;
2
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../bin/runtime.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,WAAW,QAAiE,CAAA"}
@@ -0,0 +1,4 @@
1
+ import { fileURLToPath } from 'node:url';
2
+ // The CLI lives in dist/bin; the vendorable bundle lives directly in dist.
3
+ export const runtimePath = fileURLToPath(new URL('../claude-compat.js', import.meta.url));
4
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../bin/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,2EAA2E;AAC3E,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,qBAAqB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare function scaffold(directories: readonly string[], scope: string): void;
2
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../bin/scaffold.ts"],"names":[],"mappings":"AAsBA,wBAAgB,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAyB5E"}
@@ -0,0 +1,44 @@
1
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import { runtimePath } from './runtime.js';
4
+ function readManifest(root) {
5
+ const value = JSON.parse(readFileSync(join(root, '.claude-plugin', 'plugin.json'), 'utf8'));
6
+ if (typeof value !== 'object' || value === null || !('name' in value) || typeof value.name !== 'string' || !value.name) {
7
+ throw new Error(`${root}: plugin manifest must contain a name`);
8
+ }
9
+ const version = 'version' in value ? value.version : undefined;
10
+ const description = 'description' in value ? value.description : undefined;
11
+ if (version !== undefined && typeof version !== 'string')
12
+ throw new Error(`${root}: plugin version must be a string`);
13
+ if (description !== undefined && typeof description !== 'string')
14
+ throw new Error(`${root}: plugin description must be a string`);
15
+ return { name: value.name, version: version ?? '0.0.0', description: description ?? '' };
16
+ }
17
+ export function scaffold(directories, scope) {
18
+ for (const directory of directories) {
19
+ const root = resolve(directory);
20
+ const manifest = readManifest(root);
21
+ const dsh = join(root, 'dsh');
22
+ mkdirSync(join(dsh, 'locale'), { recursive: true });
23
+ copyFileSync(runtimePath, join(dsh, 'claude-compat.js'));
24
+ const pkg = {
25
+ name: `${scope ? scope + '/' : ''}${manifest.name}-dsh`,
26
+ version: manifest.version,
27
+ private: true,
28
+ description: `DeepSeek Harness adapter for the ${manifest.name} Claude Code plugin`,
29
+ type: 'module',
30
+ exports: { '.': './index.js', './locale/*.json': './locale/*.json' },
31
+ files: ['index.js', 'claude-compat.js', 'cordis.patch.yml', 'locale/*.json'],
32
+ dsh: { bundle: { patch: './cordis.patch.yml' } },
33
+ };
34
+ writeFileSync(join(dsh, 'package.json'), JSON.stringify(pkg, null, 2) + '\n');
35
+ const locale = { meta: { title: manifest.name, description: manifest.description } };
36
+ writeFileSync(join(dsh, 'locale', 'en.json'), JSON.stringify(locale, null, 2) + '\n');
37
+ for (const required of ['index.js', 'cordis.patch.yml']) {
38
+ if (!existsSync(join(dsh, required)))
39
+ console.warn(`${manifest.name}: dsh/${required} is missing, write it by hand`);
40
+ }
41
+ console.log(`scaffolded ${dsh}`);
42
+ }
43
+ }
44
+ //# sourceMappingURL=scaffold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../bin/scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC1F,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAQ1C,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,KAAK,GAAY,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,gBAAgB,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC,CAAA;IACpG,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACvH,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,uCAAuC,CAAC,CAAA;IACjE,CAAC;IACD,MAAM,OAAO,GAAG,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAA;IAC9D,MAAM,WAAW,GAAG,aAAa,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAA;IAC1E,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,mCAAmC,CAAC,CAAA;IACrH,IAAI,WAAW,KAAK,SAAS,IAAI,OAAO,WAAW,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,uCAAuC,CAAC,CAAA;IACjI,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,WAAW,EAAE,WAAW,IAAI,EAAE,EAAE,CAAA;AAC1F,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,WAA8B,EAAE,KAAa;IACpE,KAAK,MAAM,SAAS,IAAI,WAAW,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;QAC/B,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;QACnC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAC7B,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACnD,YAAY,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC,CAAA;QACxD,MAAM,GAAG,GAAG;YACV,IAAI,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,QAAQ,CAAC,IAAI,MAAM;YACvD,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,oCAAoC,QAAQ,CAAC,IAAI,qBAAqB;YACnF,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE;YACpE,KAAK,EAAE,CAAC,UAAU,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,eAAe,CAAC;YAC5E,GAAG,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE;SACjD,CAAA;QACD,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;QAC7E,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAA;QACpF,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;QACrF,KAAK,MAAM,QAAQ,IAAI,CAAC,UAAU,EAAE,kBAAkB,CAAC,EAAE,CAAC;YACxD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,SAAS,QAAQ,+BAA+B,CAAC,CAAA;QACtH,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,EAAE,CAAC,CAAA;IAClC,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function sync(directories: readonly string[], check: boolean): number;
2
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../bin/sync.ts"],"names":[],"mappings":"AAIA,wBAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAkB3E"}
@@ -0,0 +1,24 @@
1
+ import { copyFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import { runtimePath } from './runtime.js';
4
+ export function sync(directories, check) {
5
+ const canonical = readFileSync(runtimePath);
6
+ let status = 0;
7
+ for (const directory of directories) {
8
+ const dsh = resolve(directory, 'dsh');
9
+ const destination = join(dsh, 'claude-compat.js');
10
+ if (check) {
11
+ if (!existsSync(destination) || !canonical.equals(readFileSync(destination))) {
12
+ console.log(`drift: ${destination}`);
13
+ status = 1;
14
+ }
15
+ }
16
+ else {
17
+ mkdirSync(dsh, { recursive: true });
18
+ copyFileSync(runtimePath, destination);
19
+ console.log(`synced: ${destination}`);
20
+ }
21
+ }
22
+ return status;
23
+ }
24
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../bin/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAC3E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE1C,MAAM,UAAU,IAAI,CAAC,WAA8B,EAAE,KAAc;IACjE,MAAM,SAAS,GAAG,YAAY,CAAC,WAAW,CAAC,CAAA;IAC3C,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,KAAK,MAAM,SAAS,IAAI,WAAW,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;QACrC,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAA;QACjD,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC;gBAC7E,OAAO,CAAC,GAAG,CAAC,UAAU,WAAW,EAAE,CAAC,CAAA;gBACpC,MAAM,GAAG,CAAC,CAAA;YACZ,CAAC;QACH,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YACnC,YAAY,CAAC,WAAW,EAAE,WAAW,CAAC,CAAA;YACtC,OAAO,CAAC,GAAG,CAAC,WAAW,WAAW,EAAE,CAAC,CAAA;QACvC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC"}