@slats/claude-assets-sync 0.3.2 → 0.3.3
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 +29 -6
- package/dist/claude-hashes.json +2 -2
- package/dist/commands/runCli/runCli.mjs +11 -1
- package/dist/commands/runCli/utils/resolvePackage.d.ts +1 -1
- package/dist/commands/runCli/utils/resolvePackage.mjs +11 -4
- package/dist/commands/runCli/utils/resolveScopeAlias.mjs +1 -1
- package/dist/commands/runCli/utils/resolveTargets.mjs +1 -3
- package/dist/utils/version.d.ts +1 -1
- package/dist/utils/version.mjs +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Engine + dispatcher CLI that lets any npm package ship its own Claude Code docs
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
A consumer package declares `claude.assetPath` in `package.json` and runs `claude-build-hashes` during build to emit `dist/claude-hashes.json`. End users run `npx
|
|
7
|
+
A consumer package declares `claude.assetPath` in `package.json` and runs `claude-build-hashes` during build to emit `dist/claude-hashes.json`. End users run `npx @slats/claude-assets-sync --package=<name>` and this engine resolves each consumer's metadata, compares its hash manifest against the target `.claude/`, and copies only what is out of date.
|
|
8
8
|
|
|
9
9
|
`--package` accepts a scoped name (`@scope/pkg`), an unscoped name (`pkg`), or a **scope alias** (`@scope` with no slash) that fans out to every installed `node_modules/@scope/*` package declaring `claude.assetPath`. Single-target resolution uses `createRequire`; scope-alias enumeration walks ancestor `node_modules/@<scope>/` directories from `cwd` upward and is isolated to `runCli/utils/resolveScopeAlias.ts`.
|
|
10
10
|
|
|
@@ -21,22 +21,45 @@ yarn add -D @slats/claude-assets-sync
|
|
|
21
21
|
## CLI Surface
|
|
22
22
|
|
|
23
23
|
```
|
|
24
|
-
|
|
24
|
+
<bin> --package=<name> [--scope=user|project] [--dry-run] [--force] [--root=<cwd>]
|
|
25
25
|
claude-build-hashes
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
`<bin>` is one of three entry points that all dispatch to the same engine:
|
|
29
|
+
|
|
30
|
+
| Bin | Use when |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `claude-assets-sync` | invoking via `npx` — matches the package's unscoped name so `npx @slats/claude-assets-sync ...` works directly |
|
|
33
|
+
| `inject-claude-settings` | the engine is installed (`yarn add -D` / `npm i -g`) and you prefer a descriptive command name |
|
|
34
|
+
| `claude-build-hashes` | build-time helper for consumer packages (run from `package.json` scripts) |
|
|
35
|
+
|
|
28
36
|
### End-user invocation
|
|
29
37
|
|
|
30
|
-
The engine is not shipped as a runtime dependency of consumers.
|
|
38
|
+
The engine is not shipped as a runtime dependency of consumers. The canonical npx form is:
|
|
31
39
|
|
|
32
40
|
```bash
|
|
33
41
|
# Single consumer:
|
|
34
|
-
npx
|
|
42
|
+
npx @slats/claude-assets-sync --package=@canard/schema-form --scope=user
|
|
35
43
|
|
|
36
44
|
# Scope alias — every installed @winglet/* that declares claude.assetPath:
|
|
37
|
-
npx
|
|
45
|
+
npx @slats/claude-assets-sync --package=@winglet --scope=user
|
|
38
46
|
```
|
|
39
47
|
|
|
48
|
+
The dispatcher walks `node_modules` from the current working directory (or `--root <path>`) up to the filesystem root, so it works as long as the target package is installed somewhere in the host project's hoisting chain.
|
|
49
|
+
|
|
50
|
+
#### Installed CLI (alternative)
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
yarn add -D @slats/claude-assets-sync
|
|
54
|
+
yarn inject-claude-settings --package=@canard/schema-form --scope=user
|
|
55
|
+
|
|
56
|
+
# or globally:
|
|
57
|
+
npm i -g @slats/claude-assets-sync
|
|
58
|
+
inject-claude-settings --package=@canard/schema-form --scope=user
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The legacy explicit form `npx -p @slats/claude-assets-sync inject-claude-settings ...` continues to work for backward compatibility.
|
|
62
|
+
|
|
40
63
|
| Flag | Meaning |
|
|
41
64
|
|---|---|
|
|
42
65
|
| `--package <name>` | **Required.** Repeatable/comma-separable. Accepts `@scope/pkg`, `pkg`, or a scope alias `@scope` (fans out to every installed `node_modules/@scope/*` with `claude.assetPath`). |
|
|
@@ -89,7 +112,7 @@ Ship the resulting `dist/` (including `claude-hashes.json`) alongside `docs/` wh
|
|
|
89
112
|
- The engine is used at two moments only: (1) the consumer's own build, where `claude-build-hashes` produces `dist/claude-hashes.json`, and (2) the end user's one-off `inject-claude-settings` invocation. Neither is runtime behaviour of the consumer library.
|
|
90
113
|
- Putting the engine in `dependencies` would force every downstream installer of the consumer to pull `commander`, `@inquirer/prompts`, and their transitive trees into their production `node_modules` — dead weight for anyone who never sets up Claude Code assets.
|
|
91
114
|
- The workspace build chain still resolves `.bin/claude-build-hashes` from `devDependencies` at `yarn install` time; yarn workspaces link devDeps and deps identically for workspace-local builds.
|
|
92
|
-
- End users never rely on a hoisted `inject-claude-settings` bin. The canonical invocation is `npx
|
|
115
|
+
- End users never rely on a hoisted `inject-claude-settings` bin. The canonical invocation is `npx @slats/claude-assets-sync --package=<THIS>`, which fetches the engine on demand and caches it.
|
|
93
116
|
- Bundle isolation is enforced by the import graph (`src/**` in the consumer never references the engine), not by dependency-type.
|
|
94
117
|
|
|
95
118
|
## Authoring `docs/claude/`
|
package/dist/claude-hashes.json
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"package": {
|
|
4
4
|
"name": "@slats/claude-assets-sync",
|
|
5
|
-
"version": "0.3.
|
|
5
|
+
"version": "0.3.3"
|
|
6
6
|
},
|
|
7
|
-
"generatedAt": "2026-04-
|
|
7
|
+
"generatedAt": "2026-04-26T11:57:30.854Z",
|
|
8
8
|
"algorithm": "sha256",
|
|
9
9
|
"assetRoot": "docs/claude",
|
|
10
10
|
"files": {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { basename } from 'node:path';
|
|
1
2
|
import { Command } from 'commander';
|
|
2
3
|
import { logger } from '../../utils/logger.mjs';
|
|
3
4
|
import { VERSION } from '../../utils/version.mjs';
|
|
@@ -5,10 +6,11 @@ import { renderOrFallback } from './utils/renderOrFallback.mjs';
|
|
|
5
6
|
import { resolveTargets } from './utils/resolveTargets.mjs';
|
|
6
7
|
import { toConsumerPackages } from './utils/toConsumerPackages.mjs';
|
|
7
8
|
|
|
9
|
+
const FALLBACK_PROGRAM_NAME = 'inject-claude-settings';
|
|
8
10
|
async function runCli(argv = process.argv) {
|
|
9
11
|
const cmd = new Command();
|
|
10
12
|
cmd
|
|
11
|
-
.name(
|
|
13
|
+
.name(deriveProgramName(argv))
|
|
12
14
|
.description("Inject target consumer(s)' Claude assets into the selected .claude directory")
|
|
13
15
|
.version(VERSION)
|
|
14
16
|
.option('--package <name...>', 'Target(s). "@<scope>" = whole npm scope; "@<scope>/<name>" or "<name>" = one package. Repeat the flag or comma-separate values.', collectPackageValues, [])
|
|
@@ -52,5 +54,13 @@ function collectPackageValues(value, previous = []) {
|
|
|
52
54
|
.filter(Boolean),
|
|
53
55
|
];
|
|
54
56
|
}
|
|
57
|
+
function deriveProgramName(argv) {
|
|
58
|
+
const argv1 = argv[1];
|
|
59
|
+
if (typeof argv1 !== 'string' || argv1.length === 0) {
|
|
60
|
+
return FALLBACK_PROGRAM_NAME;
|
|
61
|
+
}
|
|
62
|
+
const base = basename(argv1).replace(/\.(mjs|cjs|js)$/, '');
|
|
63
|
+
return base.length > 0 ? base : FALLBACK_PROGRAM_NAME;
|
|
64
|
+
}
|
|
55
65
|
|
|
56
66
|
export { runCli };
|
|
@@ -13,4 +13,4 @@ export interface ResolvePackageOptions {
|
|
|
13
13
|
*/
|
|
14
14
|
skipMissingAsset?: boolean;
|
|
15
15
|
}
|
|
16
|
-
export declare function resolvePackage(name: string, options?: ResolvePackageOptions): Promise<ResolvedMetadata | null>;
|
|
16
|
+
export declare function resolvePackage(name: string, options?: ResolvePackageOptions, originCwd?: string): Promise<ResolvedMetadata | null>;
|
|
@@ -2,10 +2,11 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { createRequire } from 'node:module';
|
|
4
4
|
import { dirname, resolve } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
5
6
|
import { logger } from '../../../utils/logger.mjs';
|
|
6
7
|
|
|
7
|
-
async function resolvePackage(name, options = {}) {
|
|
8
|
-
const pkgJsonPath = resolvePackageJsonPath(name);
|
|
8
|
+
async function resolvePackage(name, options = {}, originCwd = process.cwd()) {
|
|
9
|
+
const pkgJsonPath = resolvePackageJsonPath(name, originCwd);
|
|
9
10
|
if (!pkgJsonPath) {
|
|
10
11
|
logger.error(`cannot resolve package "${name}". Install it in the current project or pass the correct name.`);
|
|
11
12
|
process.exit(2);
|
|
@@ -37,8 +38,14 @@ async function resolvePackage(name, options = {}) {
|
|
|
37
38
|
assetPath,
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
|
-
function resolvePackageJsonPath(name) {
|
|
41
|
-
const
|
|
41
|
+
function resolvePackageJsonPath(name, originCwd) {
|
|
42
|
+
const fromCwd = tryResolveFrom(name, resolve(originCwd, '__resolve-base__'));
|
|
43
|
+
if (fromCwd)
|
|
44
|
+
return fromCwd;
|
|
45
|
+
return tryResolveFrom(name, fileURLToPath(import.meta.url));
|
|
46
|
+
}
|
|
47
|
+
function tryResolveFrom(name, baseFilename) {
|
|
48
|
+
const require = createRequire(baseFilename);
|
|
42
49
|
try {
|
|
43
50
|
return require.resolve(`${name}/package.json`);
|
|
44
51
|
}
|
|
@@ -23,7 +23,7 @@ async function resolveScopeAlias(scope, rootCwd) {
|
|
|
23
23
|
}
|
|
24
24
|
const resolved = [];
|
|
25
25
|
for (const name of matchedNames) {
|
|
26
|
-
const meta = await resolvePackage(name, { skipMissingAsset: true });
|
|
26
|
+
const meta = await resolvePackage(name, { skipMissingAsset: true }, rootCwd);
|
|
27
27
|
if (meta)
|
|
28
28
|
resolved.push(meta);
|
|
29
29
|
}
|
|
@@ -20,9 +20,7 @@ async function resolveTargets(targets, rootCwd) {
|
|
|
20
20
|
candidates = await resolveScopeAlias(classification.scope, rootCwd);
|
|
21
21
|
}
|
|
22
22
|
else {
|
|
23
|
-
const meta = await resolvePackage(classification.name, {
|
|
24
|
-
skipMissingAsset: !isSingleTarget,
|
|
25
|
-
});
|
|
23
|
+
const meta = await resolvePackage(classification.name, { skipMissingAsset: !isSingleTarget }, rootCwd);
|
|
26
24
|
candidates = meta ? [meta] : [];
|
|
27
25
|
}
|
|
28
26
|
for (const meta of candidates) {
|
package/dist/utils/version.d.ts
CHANGED
package/dist/utils/version.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slats/claude-assets-sync",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Shared CLI engine that lets consumer packages inject their Claude docs (skills, rules, commands) into a user's .claude directory via a thin bin/inject-docs wrapper.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"module": "dist/index.mjs",
|
|
37
37
|
"types": "dist/index.d.ts",
|
|
38
38
|
"bin": {
|
|
39
|
+
"claude-assets-sync": "./bin/inject-claude-settings.mjs",
|
|
39
40
|
"claude-build-hashes": "./scripts/claude-build-hashes.mjs",
|
|
40
41
|
"inject-claude-settings": "./bin/inject-claude-settings.mjs"
|
|
41
42
|
},
|