@slats/claude-assets-sync 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 +111 -587
- package/bin/claude-sync.mjs +24 -0
- package/dist/claude-hashes.json +20 -0
- package/dist/commands/index.d.ts +1 -112
- package/dist/commands/runCli/index.d.ts +2 -0
- package/dist/commands/runCli/runCli.cjs +31 -0
- package/dist/commands/runCli/runCli.d.ts +10 -0
- package/dist/commands/runCli/runCli.mjs +29 -0
- package/dist/commands/runCli/type.d.ts +28 -0
- package/dist/commands/runCli/utils/injectOne.cjs +48 -0
- package/dist/commands/runCli/utils/injectOne.d.ts +3 -0
- package/dist/commands/runCli/utils/injectOne.mjs +46 -0
- package/dist/commands/runCli/utils/resolveScopeFlag.cjs +28 -0
- package/dist/commands/runCli/utils/resolveScopeFlag.d.ts +2 -0
- package/dist/commands/runCli/utils/resolveScopeFlag.mjs +26 -0
- package/dist/commands/runCli/utils/runInject.cjs +36 -0
- package/dist/commands/runCli/utils/runInject.d.ts +2 -0
- package/dist/commands/runCli/utils/runInject.mjs +34 -0
- package/dist/core/buildPlan/buildPlan.cjs +42 -0
- package/dist/core/buildPlan/buildPlan.d.ts +2 -0
- package/dist/core/buildPlan/buildPlan.mjs +40 -0
- package/dist/core/buildPlan/index.d.ts +2 -0
- package/dist/core/buildPlan/type.d.ts +32 -0
- package/dist/core/buildPlan/utils/toPosix.cjs +9 -0
- package/dist/core/buildPlan/utils/toPosix.d.ts +1 -0
- package/dist/core/buildPlan/utils/toPosix.mjs +7 -0
- package/dist/core/buildPlan/utils/walkFiles.cjs +25 -0
- package/dist/core/buildPlan/utils/walkFiles.d.ts +1 -0
- package/dist/core/buildPlan/utils/walkFiles.mjs +23 -0
- package/dist/core/hash/hash.cjs +30 -0
- package/dist/core/hash/hash.d.ts +4 -0
- package/dist/core/hash/hash.mjs +26 -0
- package/dist/core/hash/index.d.ts +1 -0
- package/dist/core/hashManifest/hashManifest.cjs +27 -0
- package/dist/core/hashManifest/hashManifest.d.ts +17 -0
- package/dist/core/hashManifest/hashManifest.mjs +23 -0
- package/dist/core/hashManifest/index.d.ts +1 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/injectDocs/index.d.ts +2 -0
- package/dist/core/injectDocs/injectDocs.cjs +43 -0
- package/dist/core/injectDocs/injectDocs.d.ts +2 -0
- package/dist/core/injectDocs/injectDocs.mjs +41 -0
- package/dist/core/injectDocs/type.d.ts +30 -0
- package/dist/core/injectDocs/utils/applyAction.cjs +21 -0
- package/dist/core/injectDocs/utils/applyAction.d.ts +2 -0
- package/dist/core/injectDocs/utils/applyAction.mjs +19 -0
- package/dist/core/injectDocs/utils/emitCiForceList.cjs +10 -0
- package/dist/core/injectDocs/utils/emitCiForceList.d.ts +2 -0
- package/dist/core/injectDocs/utils/emitCiForceList.mjs +8 -0
- package/dist/core/injectDocs/utils/printPlan.cjs +20 -0
- package/dist/core/injectDocs/utils/printPlan.d.ts +2 -0
- package/dist/core/injectDocs/utils/printPlan.mjs +18 -0
- package/dist/core/injectDocs/utils/summarize.cjs +27 -0
- package/dist/core/injectDocs/utils/summarize.d.ts +3 -0
- package/dist/core/injectDocs/utils/summarize.mjs +25 -0
- package/dist/core/scope/index.d.ts +1 -0
- package/dist/core/scope/scope.cjs +46 -0
- package/dist/core/scope/scope.d.ts +16 -0
- package/dist/core/scope/scope.mjs +41 -0
- package/dist/core/scope/utils/isDirectory.cjs +14 -0
- package/dist/core/scope/utils/isDirectory.d.ts +1 -0
- package/dist/core/scope/utils/isDirectory.mjs +12 -0
- package/dist/index.cjs +15 -9
- package/dist/index.d.ts +3 -5
- package/dist/index.mjs +7 -3
- package/dist/prompts/confirmForce.cjs +27 -0
- package/dist/prompts/confirmForce.d.ts +1 -0
- package/dist/prompts/confirmForce.mjs +25 -0
- package/dist/prompts/index.d.ts +2 -0
- package/dist/prompts/selectScope.cjs +30 -0
- package/dist/prompts/selectScope.d.ts +2 -0
- package/dist/prompts/selectScope.mjs +28 -0
- package/dist/utils/heartbeat.cjs +25 -0
- package/dist/utils/heartbeat.d.ts +16 -0
- package/dist/utils/heartbeat.mjs +23 -0
- package/dist/utils/logger.cjs +7 -0
- package/dist/utils/logger.d.ts +8 -0
- package/dist/utils/logger.mjs +7 -0
- package/dist/utils/types.d.ts +1 -252
- package/dist/utils/version.cjs +2 -14
- package/dist/utils/version.d.ts +3 -53
- package/dist/utils/version.mjs +2 -13
- package/docs/bundle-size-decision.md +36 -0
- package/docs/claude/skills/claude-sync-applier/SKILL.md +195 -0
- package/docs/claude/skills/claude-sync-applier/knowledge/claude-md-template.md +77 -0
- package/docs/claude/skills/claude-sync-applier/knowledge/dependency-cruiser.md +126 -0
- package/docs/claude/skills/claude-sync-applier/knowledge/gotchas.md +139 -0
- package/docs/claude/skills/claude-sync-applier/knowledge/package-json-patches.md +130 -0
- package/docs/claude/skills/claude-sync-applier/knowledge/reference-files.md +120 -0
- package/docs/claude/skills/claude-sync-applier/knowledge/smoke-tests.md +102 -0
- package/docs/consumer-integration.md +153 -0
- package/package.json +24 -16
- package/scripts/build-hashes.mjs +30 -0
- package/scripts/buildHashes.d.mts +15 -0
- package/scripts/buildHashes.mjs +82 -0
- package/scripts/claude-build-hashes.mjs +42 -0
- package/scripts/inject-version.js +112 -0
- package/dist/cli.cjs +0 -8
- package/dist/cli.d.ts +0 -1
- package/dist/cli.mjs +0 -7
- package/dist/commands/add.cjs +0 -80
- package/dist/commands/add.d.ts +0 -8
- package/dist/commands/add.mjs +0 -78
- package/dist/commands/list.cjs +0 -94
- package/dist/commands/list.d.ts +0 -15
- package/dist/commands/list.mjs +0 -91
- package/dist/commands/migrate.cjs +0 -9
- package/dist/commands/migrate.d.ts +0 -6
- package/dist/commands/migrate.mjs +0 -7
- package/dist/commands/remove.cjs +0 -127
- package/dist/commands/remove.d.ts +0 -6
- package/dist/commands/remove.mjs +0 -105
- package/dist/commands/status.cjs +0 -193
- package/dist/commands/status.d.ts +0 -6
- package/dist/commands/status.mjs +0 -171
- package/dist/commands/sync.cjs +0 -28
- package/dist/commands/sync.d.ts +0 -6
- package/dist/commands/sync.mjs +0 -26
- package/dist/commands/types.d.ts +0 -89
- package/dist/commands/update.cjs +0 -209
- package/dist/commands/update.d.ts +0 -29
- package/dist/commands/update.mjs +0 -206
- package/dist/components/add/AddCommand.cjs +0 -103
- package/dist/components/add/AddCommand.d.ts +0 -14
- package/dist/components/add/AddCommand.mjs +0 -101
- package/dist/components/add/BulkAddView.cjs +0 -165
- package/dist/components/add/BulkAddView.d.ts +0 -11
- package/dist/components/add/BulkAddView.mjs +0 -163
- package/dist/components/add/index.d.ts +0 -2
- package/dist/components/index.d.ts +0 -2
- package/dist/components/list/EditableTreeItem.d.ts +0 -13
- package/dist/components/list/ListCommand.cjs +0 -651
- package/dist/components/list/ListCommand.d.ts +0 -5
- package/dist/components/list/ListCommand.mjs +0 -649
- package/dist/components/list/SyncedPackageTree.d.ts +0 -14
- package/dist/components/list/index.d.ts +0 -10
- package/dist/components/list/types.d.ts +0 -14
- package/dist/components/primitives/Box.d.ts +0 -4
- package/dist/components/primitives/Spinner.d.ts +0 -6
- package/dist/components/primitives/Text.d.ts +0 -4
- package/dist/components/primitives/index.d.ts +0 -3
- package/dist/components/remove/RemoveConfirm.cjs +0 -18
- package/dist/components/remove/RemoveConfirm.d.ts +0 -11
- package/dist/components/remove/RemoveConfirm.mjs +0 -16
- package/dist/components/shared/Confirm.cjs +0 -30
- package/dist/components/shared/Confirm.d.ts +0 -8
- package/dist/components/shared/Confirm.mjs +0 -28
- package/dist/components/shared/MenuItem.cjs +0 -18
- package/dist/components/shared/MenuItem.d.ts +0 -7
- package/dist/components/shared/MenuItem.mjs +0 -16
- package/dist/components/shared/ProgressBar.d.ts +0 -7
- package/dist/components/shared/StepRunner.cjs +0 -58
- package/dist/components/shared/StepRunner.d.ts +0 -15
- package/dist/components/shared/StepRunner.mjs +0 -56
- package/dist/components/shared/Table.cjs +0 -19
- package/dist/components/shared/Table.d.ts +0 -8
- package/dist/components/shared/Table.mjs +0 -17
- package/dist/components/shared/index.d.ts +0 -6
- package/dist/components/status/PackageStatusCard.d.ts +0 -10
- package/dist/components/status/StatusDisplay.cjs +0 -26
- package/dist/components/status/StatusDisplay.d.ts +0 -23
- package/dist/components/status/StatusDisplay.mjs +0 -24
- package/dist/components/status/StatusTreeNode.cjs +0 -40
- package/dist/components/status/StatusTreeNode.d.ts +0 -15
- package/dist/components/status/StatusTreeNode.mjs +0 -38
- package/dist/components/status/index.d.ts +0 -6
- package/dist/components/tree/AssetTreeNode.cjs +0 -54
- package/dist/components/tree/AssetTreeNode.d.ts +0 -12
- package/dist/components/tree/AssetTreeNode.mjs +0 -52
- package/dist/components/tree/TreeSelect.cjs +0 -129
- package/dist/components/tree/TreeSelect.d.ts +0 -12
- package/dist/components/tree/TreeSelect.mjs +0 -127
- package/dist/components/tree/index.d.ts +0 -4
- package/dist/core/assetStructure.cjs +0 -30
- package/dist/core/assetStructure.d.ts +0 -36
- package/dist/core/assetStructure.mjs +0 -27
- package/dist/core/cli.cjs +0 -106
- package/dist/core/cli.d.ts +0 -9
- package/dist/core/cli.mjs +0 -103
- package/dist/core/constants.cjs +0 -28
- package/dist/core/constants.d.ts +0 -94
- package/dist/core/constants.mjs +0 -21
- package/dist/core/filesystem.cjs +0 -98
- package/dist/core/filesystem.d.ts +0 -94
- package/dist/core/filesystem.mjs +0 -88
- package/dist/core/github.cjs +0 -115
- package/dist/core/github.d.ts +0 -61
- package/dist/core/github.mjs +0 -107
- package/dist/core/io.cjs +0 -46
- package/dist/core/io.d.ts +0 -40
- package/dist/core/io.mjs +0 -39
- package/dist/core/listOperations.cjs +0 -228
- package/dist/core/listOperations.d.ts +0 -43
- package/dist/core/listOperations.mjs +0 -205
- package/dist/core/localSource.cjs +0 -126
- package/dist/core/localSource.d.ts +0 -33
- package/dist/core/localSource.mjs +0 -120
- package/dist/core/migration.cjs +0 -201
- package/dist/core/migration.d.ts +0 -57
- package/dist/core/migration.mjs +0 -198
- package/dist/core/packageScanner.cjs +0 -360
- package/dist/core/packageScanner.d.ts +0 -22
- package/dist/core/packageScanner.mjs +0 -356
- package/dist/core/sync.cjs +0 -400
- package/dist/core/sync.d.ts +0 -21
- package/dist/core/sync.mjs +0 -397
- package/dist/core/syncMeta.cjs +0 -242
- package/dist/core/syncMeta.d.ts +0 -75
- package/dist/core/syncMeta.mjs +0 -229
- package/dist/utils/dependencies.cjs +0 -57
- package/dist/utils/dependencies.d.ts +0 -10
- package/dist/utils/dependencies.mjs +0 -34
- package/dist/utils/nameTransform.cjs +0 -13
- package/dist/utils/nameTransform.d.ts +0 -65
- package/dist/utils/nameTransform.mjs +0 -11
- package/dist/utils/package.cjs +0 -170
- package/dist/utils/package.d.ts +0 -105
- package/dist/utils/package.mjs +0 -157
- package/dist/utils/packageName.cjs +0 -24
- package/dist/utils/packageName.d.ts +0 -32
- package/dist/utils/packageName.mjs +0 -21
- package/dist/utils/paths.cjs +0 -18
- package/dist/utils/paths.d.ts +0 -55
- package/dist/utils/paths.mjs +0 -15
- package/dist/version.cjs +0 -5
- package/dist/version.d.ts +0 -5
- package/dist/version.mjs +0 -3
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var promises = require('node:fs/promises');
|
|
4
|
+
var node_path = require('node:path');
|
|
5
|
+
|
|
6
|
+
async function* walkFiles(root) {
|
|
7
|
+
let entries;
|
|
8
|
+
try {
|
|
9
|
+
entries = await promises.readdir(root, { withFileTypes: true });
|
|
10
|
+
}
|
|
11
|
+
catch (err) {
|
|
12
|
+
if (err.code === 'ENOENT')
|
|
13
|
+
return;
|
|
14
|
+
throw err;
|
|
15
|
+
}
|
|
16
|
+
for (const entry of entries) {
|
|
17
|
+
const abs = node_path.join(root, entry.name);
|
|
18
|
+
if (entry.isDirectory())
|
|
19
|
+
yield* walkFiles(abs);
|
|
20
|
+
else if (entry.isFile())
|
|
21
|
+
yield abs;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
exports.walkFiles = walkFiles;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function walkFiles(root: string): AsyncGenerator<string>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { readdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
async function* walkFiles(root) {
|
|
5
|
+
let entries;
|
|
6
|
+
try {
|
|
7
|
+
entries = await readdir(root, { withFileTypes: true });
|
|
8
|
+
}
|
|
9
|
+
catch (err) {
|
|
10
|
+
if (err.code === 'ENOENT')
|
|
11
|
+
return;
|
|
12
|
+
throw err;
|
|
13
|
+
}
|
|
14
|
+
for (const entry of entries) {
|
|
15
|
+
const abs = join(root, entry.name);
|
|
16
|
+
if (entry.isDirectory())
|
|
17
|
+
yield* walkFiles(abs);
|
|
18
|
+
else if (entry.isFile())
|
|
19
|
+
yield abs;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { walkFiles };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var node_crypto = require('node:crypto');
|
|
4
|
+
var promises = require('node:fs/promises');
|
|
5
|
+
|
|
6
|
+
function hashContent(buffer) {
|
|
7
|
+
return node_crypto.createHash('sha256').update(buffer).digest('hex');
|
|
8
|
+
}
|
|
9
|
+
async function hashFile(absPath) {
|
|
10
|
+
try {
|
|
11
|
+
const buf = await promises.readFile(absPath);
|
|
12
|
+
return hashContent(buf);
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
if (err.code === 'ENOENT')
|
|
16
|
+
return null;
|
|
17
|
+
throw err;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function hashEquals(a, b) {
|
|
21
|
+
if (a === null || b === null)
|
|
22
|
+
return false;
|
|
23
|
+
if (a.length !== b.length)
|
|
24
|
+
return false;
|
|
25
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
exports.hashContent = hashContent;
|
|
29
|
+
exports.hashEquals = hashEquals;
|
|
30
|
+
exports.hashFile = hashFile;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type Sha256Hex = string;
|
|
2
|
+
export declare function hashContent(buffer: Buffer | string): Sha256Hex;
|
|
3
|
+
export declare function hashFile(absPath: string): Promise<Sha256Hex | null>;
|
|
4
|
+
export declare function hashEquals(a: Sha256Hex | null, b: Sha256Hex | null): boolean;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
|
|
4
|
+
function hashContent(buffer) {
|
|
5
|
+
return createHash('sha256').update(buffer).digest('hex');
|
|
6
|
+
}
|
|
7
|
+
async function hashFile(absPath) {
|
|
8
|
+
try {
|
|
9
|
+
const buf = await readFile(absPath);
|
|
10
|
+
return hashContent(buf);
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
if (err.code === 'ENOENT')
|
|
14
|
+
return null;
|
|
15
|
+
throw err;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function hashEquals(a, b) {
|
|
19
|
+
if (a === null || b === null)
|
|
20
|
+
return false;
|
|
21
|
+
if (a.length !== b.length)
|
|
22
|
+
return false;
|
|
23
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { hashContent, hashEquals, hashFile };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { hashContent, hashFile, hashEquals, type Sha256Hex } from './hash.js';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var promises = require('node:fs/promises');
|
|
4
|
+
var node_path = require('node:path');
|
|
5
|
+
|
|
6
|
+
const HASH_MANIFEST_FILENAME = 'claude-hashes.json';
|
|
7
|
+
async function readHashManifest(packageRoot) {
|
|
8
|
+
const primary = node_path.join(packageRoot, 'dist', HASH_MANIFEST_FILENAME);
|
|
9
|
+
const raw = await promises.readFile(primary, 'utf-8');
|
|
10
|
+
const parsed = JSON.parse(raw);
|
|
11
|
+
if (parsed.schemaVersion !== 1)
|
|
12
|
+
throw new Error(`[claude-assets-sync] Unsupported manifest schemaVersion: ${parsed.schemaVersion}`);
|
|
13
|
+
return parsed;
|
|
14
|
+
}
|
|
15
|
+
function computeNamespacePrefixes(manifest) {
|
|
16
|
+
const prefixes = new Set();
|
|
17
|
+
for (const relPath of Object.keys(manifest.files)) {
|
|
18
|
+
const parts = relPath.split('/');
|
|
19
|
+
if (parts.length >= 3 && parts[0] === 'skills')
|
|
20
|
+
prefixes.add(`${parts[0]}/${parts[1]}/`);
|
|
21
|
+
}
|
|
22
|
+
return [...prefixes];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
exports.HASH_MANIFEST_FILENAME = HASH_MANIFEST_FILENAME;
|
|
26
|
+
exports.computeNamespacePrefixes = computeNamespacePrefixes;
|
|
27
|
+
exports.readHashManifest = readHashManifest;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Sha256Hex } from '../hash/index.js';
|
|
2
|
+
export interface HashManifest {
|
|
3
|
+
schemaVersion: 1;
|
|
4
|
+
package: {
|
|
5
|
+
name: string;
|
|
6
|
+
version: string;
|
|
7
|
+
};
|
|
8
|
+
generatedAt: string;
|
|
9
|
+
algorithm: 'sha256';
|
|
10
|
+
assetRoot: string;
|
|
11
|
+
files: Record<string, Sha256Hex>;
|
|
12
|
+
previousVersions: Record<string, never>;
|
|
13
|
+
}
|
|
14
|
+
export declare const HASH_MANIFEST_FILENAME = "claude-hashes.json";
|
|
15
|
+
export declare function readHashManifest(packageRoot: string): Promise<HashManifest>;
|
|
16
|
+
/** Derive the set of managed namespace prefixes (e.g., "skills/<expert>/") from manifest file paths. */
|
|
17
|
+
export declare function computeNamespacePrefixes(manifest: HashManifest): string[];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
const HASH_MANIFEST_FILENAME = 'claude-hashes.json';
|
|
5
|
+
async function readHashManifest(packageRoot) {
|
|
6
|
+
const primary = join(packageRoot, 'dist', HASH_MANIFEST_FILENAME);
|
|
7
|
+
const raw = await readFile(primary, 'utf-8');
|
|
8
|
+
const parsed = JSON.parse(raw);
|
|
9
|
+
if (parsed.schemaVersion !== 1)
|
|
10
|
+
throw new Error(`[claude-assets-sync] Unsupported manifest schemaVersion: ${parsed.schemaVersion}`);
|
|
11
|
+
return parsed;
|
|
12
|
+
}
|
|
13
|
+
function computeNamespacePrefixes(manifest) {
|
|
14
|
+
const prefixes = new Set();
|
|
15
|
+
for (const relPath of Object.keys(manifest.files)) {
|
|
16
|
+
const parts = relPath.split('/');
|
|
17
|
+
if (parts.length >= 3 && parts[0] === 'skills')
|
|
18
|
+
prefixes.add(`${parts[0]}/${parts[1]}/`);
|
|
19
|
+
}
|
|
20
|
+
return [...prefixes];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { HASH_MANIFEST_FILENAME, computeNamespacePrefixes, readHashManifest };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { HASH_MANIFEST_FILENAME, computeNamespacePrefixes, readHashManifest, type HashManifest, } from './hashManifest.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { hashContent, hashEquals, hashFile, type Sha256Hex, } from './hash/index.js';
|
|
2
|
+
export { HASH_MANIFEST_FILENAME, computeNamespacePrefixes, readHashManifest, type HashManifest, } from './hashManifest/index.js';
|
|
3
|
+
export { injectDocs, type InjectOptions, type InjectReport, } from './injectDocs/index.js';
|
|
4
|
+
export { buildPlan, type Action, type InjectPlan, type PlanInput, } from './buildPlan/index.js';
|
|
5
|
+
export { findNearestDotClaudeAncestor, isInteractive, isValidScope, resolveScope, type Scope, type ScopeResolution, } from './scope/index.js';
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var asyncPool = require('../../utils/asyncPool.cjs');
|
|
4
|
+
var logger = require('../../utils/logger.cjs');
|
|
5
|
+
var buildPlan = require('../buildPlan/buildPlan.cjs');
|
|
6
|
+
var hashManifest = require('../hashManifest/hashManifest.cjs');
|
|
7
|
+
var scope = require('../scope/scope.cjs');
|
|
8
|
+
var applyAction = require('./utils/applyAction.cjs');
|
|
9
|
+
var emitCiForceList = require('./utils/emitCiForceList.cjs');
|
|
10
|
+
var printPlan = require('./utils/printPlan.cjs');
|
|
11
|
+
var summarize = require('./utils/summarize.cjs');
|
|
12
|
+
|
|
13
|
+
async function injectDocs(opts) {
|
|
14
|
+
const manifest = await hashManifest.readHashManifest(opts.packageRoot);
|
|
15
|
+
const resolution = scope.resolveScope(opts.scope, opts.originCwd ?? process.cwd());
|
|
16
|
+
const plan = await buildPlan.buildPlan({
|
|
17
|
+
sourceHashes: manifest.files,
|
|
18
|
+
targetRoot: resolution.targetRoot,
|
|
19
|
+
namespacePrefixes: hashManifest.computeNamespacePrefixes(manifest),
|
|
20
|
+
force: opts.force,
|
|
21
|
+
});
|
|
22
|
+
logger.logger.info(`${opts.packageName}@${opts.packageVersion} → ${resolution.description}`);
|
|
23
|
+
printPlan.printPlan(plan);
|
|
24
|
+
if (plan.requiresForce && !opts.force) {
|
|
25
|
+
logger.logger.error('Re-run with --force to proceed, or inspect with --dry-run.');
|
|
26
|
+
return summarize.summarize(plan, 2);
|
|
27
|
+
}
|
|
28
|
+
if (opts.force &&
|
|
29
|
+
plan.actions.some((a) => a.kind === 'warn-diverged' || a.kind === 'warn-orphan')) {
|
|
30
|
+
if (!scope.isInteractive())
|
|
31
|
+
emitCiForceList.emitCiForceList(plan);
|
|
32
|
+
else if (opts.confirmForce && !(await opts.confirmForce(plan)))
|
|
33
|
+
return summarize.summarize(plan, 2);
|
|
34
|
+
}
|
|
35
|
+
if (opts.dryRun) {
|
|
36
|
+
logger.logger.warn('[DRY RUN] No files will be created, overwritten, or deleted.');
|
|
37
|
+
return summarize.summarize(plan, 0);
|
|
38
|
+
}
|
|
39
|
+
await asyncPool.asyncPool(8, plan.actions, (action) => applyAction.applyAction(action, opts.assetRoot));
|
|
40
|
+
return summarize.summarize(plan, 0);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
exports.injectDocs = injectDocs;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { asyncPool } from '../../utils/asyncPool.mjs';
|
|
2
|
+
import { logger } from '../../utils/logger.mjs';
|
|
3
|
+
import { buildPlan } from '../buildPlan/buildPlan.mjs';
|
|
4
|
+
import { readHashManifest, computeNamespacePrefixes } from '../hashManifest/hashManifest.mjs';
|
|
5
|
+
import { resolveScope, isInteractive } from '../scope/scope.mjs';
|
|
6
|
+
import { applyAction } from './utils/applyAction.mjs';
|
|
7
|
+
import { emitCiForceList } from './utils/emitCiForceList.mjs';
|
|
8
|
+
import { printPlan } from './utils/printPlan.mjs';
|
|
9
|
+
import { summarize } from './utils/summarize.mjs';
|
|
10
|
+
|
|
11
|
+
async function injectDocs(opts) {
|
|
12
|
+
const manifest = await readHashManifest(opts.packageRoot);
|
|
13
|
+
const resolution = resolveScope(opts.scope, opts.originCwd ?? process.cwd());
|
|
14
|
+
const plan = await buildPlan({
|
|
15
|
+
sourceHashes: manifest.files,
|
|
16
|
+
targetRoot: resolution.targetRoot,
|
|
17
|
+
namespacePrefixes: computeNamespacePrefixes(manifest),
|
|
18
|
+
force: opts.force,
|
|
19
|
+
});
|
|
20
|
+
logger.info(`${opts.packageName}@${opts.packageVersion} → ${resolution.description}`);
|
|
21
|
+
printPlan(plan);
|
|
22
|
+
if (plan.requiresForce && !opts.force) {
|
|
23
|
+
logger.error('Re-run with --force to proceed, or inspect with --dry-run.');
|
|
24
|
+
return summarize(plan, 2);
|
|
25
|
+
}
|
|
26
|
+
if (opts.force &&
|
|
27
|
+
plan.actions.some((a) => a.kind === 'warn-diverged' || a.kind === 'warn-orphan')) {
|
|
28
|
+
if (!isInteractive())
|
|
29
|
+
emitCiForceList(plan);
|
|
30
|
+
else if (opts.confirmForce && !(await opts.confirmForce(plan)))
|
|
31
|
+
return summarize(plan, 2);
|
|
32
|
+
}
|
|
33
|
+
if (opts.dryRun) {
|
|
34
|
+
logger.warn('[DRY RUN] No files will be created, overwritten, or deleted.');
|
|
35
|
+
return summarize(plan, 0);
|
|
36
|
+
}
|
|
37
|
+
await asyncPool(8, plan.actions, (action) => applyAction(action, opts.assetRoot));
|
|
38
|
+
return summarize(plan, 0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { injectDocs };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { InjectPlan } from '../buildPlan/index.js';
|
|
2
|
+
import type { Scope } from '../scope/index.js';
|
|
3
|
+
export interface InjectOptions {
|
|
4
|
+
packageName: string;
|
|
5
|
+
packageVersion: string;
|
|
6
|
+
packageRoot: string;
|
|
7
|
+
assetRoot: string;
|
|
8
|
+
scope: Scope;
|
|
9
|
+
dryRun: boolean;
|
|
10
|
+
force: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Origin directory used to resolve project/local scope targets. When set,
|
|
13
|
+
* `resolveScope` walks up from this path to find the nearest existing
|
|
14
|
+
* `.claude` ancestor. Defaults to `process.cwd()`.
|
|
15
|
+
*/
|
|
16
|
+
originCwd?: string;
|
|
17
|
+
/** Called AFTER plan is built but BEFORE apply. Return false to abort. */
|
|
18
|
+
confirmForce?: (plan: InjectPlan) => Promise<boolean>;
|
|
19
|
+
}
|
|
20
|
+
export interface InjectReport {
|
|
21
|
+
created: string[];
|
|
22
|
+
updated: string[];
|
|
23
|
+
skipped: string[];
|
|
24
|
+
warnings: {
|
|
25
|
+
relPath: string;
|
|
26
|
+
reason: string;
|
|
27
|
+
}[];
|
|
28
|
+
deleted: string[];
|
|
29
|
+
exitCode: 0 | 1 | 2;
|
|
30
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var promises = require('node:fs/promises');
|
|
4
|
+
var node_path = require('node:path');
|
|
5
|
+
var logger = require('../../../utils/logger.cjs');
|
|
6
|
+
|
|
7
|
+
async function applyAction(action, assetRoot) {
|
|
8
|
+
if (action.kind === 'copy') {
|
|
9
|
+
const srcAbs = node_path.join(assetRoot, action.relPath);
|
|
10
|
+
await promises.mkdir(node_path.dirname(action.dstAbs), { recursive: true });
|
|
11
|
+
await promises.copyFile(srcAbs, action.dstAbs);
|
|
12
|
+
}
|
|
13
|
+
else if (action.kind === 'delete')
|
|
14
|
+
await promises.unlink(action.dstAbs).catch((error) => {
|
|
15
|
+
if (error?.code !== 'ENOENT') {
|
|
16
|
+
logger.logger.warn(`[claude-sync] unlink failed: ${action.dstAbs} (${error?.code ?? error})`);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
exports.applyAction = applyAction;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { mkdir, copyFile, unlink } from 'node:fs/promises';
|
|
2
|
+
import { join, dirname } from 'node:path';
|
|
3
|
+
import { logger } from '../../../utils/logger.mjs';
|
|
4
|
+
|
|
5
|
+
async function applyAction(action, assetRoot) {
|
|
6
|
+
if (action.kind === 'copy') {
|
|
7
|
+
const srcAbs = join(assetRoot, action.relPath);
|
|
8
|
+
await mkdir(dirname(action.dstAbs), { recursive: true });
|
|
9
|
+
await copyFile(srcAbs, action.dstAbs);
|
|
10
|
+
}
|
|
11
|
+
else if (action.kind === 'delete')
|
|
12
|
+
await unlink(action.dstAbs).catch((error) => {
|
|
13
|
+
if (error?.code !== 'ENOENT') {
|
|
14
|
+
logger.warn(`[claude-sync] unlink failed: ${action.dstAbs} (${error?.code ?? error})`);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export { applyAction };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function emitCiForceList(plan) {
|
|
4
|
+
const divergent = plan.actions.filter((a) => a.kind === 'warn-diverged' || a.kind === 'warn-orphan');
|
|
5
|
+
process.stderr.write(`[claude-assets-sync] --force overwriting ${divergent.length} file(s) in non-TTY mode:\n`);
|
|
6
|
+
for (const a of divergent)
|
|
7
|
+
process.stderr.write(` ${a.relPath}\n`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
exports.emitCiForceList = emitCiForceList;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
function emitCiForceList(plan) {
|
|
2
|
+
const divergent = plan.actions.filter((a) => a.kind === 'warn-diverged' || a.kind === 'warn-orphan');
|
|
3
|
+
process.stderr.write(`[claude-assets-sync] --force overwriting ${divergent.length} file(s) in non-TTY mode:\n`);
|
|
4
|
+
for (const a of divergent)
|
|
5
|
+
process.stderr.write(` ${a.relPath}\n`);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export { emitCiForceList };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var logger = require('../../../utils/logger.cjs');
|
|
4
|
+
|
|
5
|
+
function printPlan(plan) {
|
|
6
|
+
for (const a of plan.actions) {
|
|
7
|
+
if (a.kind === 'copy')
|
|
8
|
+
logger.logger.file('create', a.relPath);
|
|
9
|
+
else if (a.kind === 'skip-uptodate')
|
|
10
|
+
logger.logger.file('skip', `${a.relPath} (up-to-date)`);
|
|
11
|
+
else if (a.kind === 'warn-diverged')
|
|
12
|
+
logger.logger.warn(`${a.relPath} — local differs from source (user edit or version change)`);
|
|
13
|
+
else if (a.kind === 'warn-orphan')
|
|
14
|
+
logger.logger.warn(`${a.relPath} — present locally, absent in source`);
|
|
15
|
+
else if (a.kind === 'delete')
|
|
16
|
+
logger.logger.file('update', `${a.relPath} (deleting)`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
exports.printPlan = printPlan;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { logger } from '../../../utils/logger.mjs';
|
|
2
|
+
|
|
3
|
+
function printPlan(plan) {
|
|
4
|
+
for (const a of plan.actions) {
|
|
5
|
+
if (a.kind === 'copy')
|
|
6
|
+
logger.file('create', a.relPath);
|
|
7
|
+
else if (a.kind === 'skip-uptodate')
|
|
8
|
+
logger.file('skip', `${a.relPath} (up-to-date)`);
|
|
9
|
+
else if (a.kind === 'warn-diverged')
|
|
10
|
+
logger.warn(`${a.relPath} — local differs from source (user edit or version change)`);
|
|
11
|
+
else if (a.kind === 'warn-orphan')
|
|
12
|
+
logger.warn(`${a.relPath} — present locally, absent in source`);
|
|
13
|
+
else if (a.kind === 'delete')
|
|
14
|
+
logger.file('update', `${a.relPath} (deleting)`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { printPlan };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function summarize(plan, exitCode) {
|
|
4
|
+
const report = {
|
|
5
|
+
created: [],
|
|
6
|
+
updated: [],
|
|
7
|
+
skipped: [],
|
|
8
|
+
warnings: [],
|
|
9
|
+
deleted: [],
|
|
10
|
+
exitCode,
|
|
11
|
+
};
|
|
12
|
+
for (const a of plan.actions) {
|
|
13
|
+
if (a.kind === 'copy')
|
|
14
|
+
report.created.push(a.relPath);
|
|
15
|
+
else if (a.kind === 'skip-uptodate')
|
|
16
|
+
report.skipped.push(a.relPath);
|
|
17
|
+
else if (a.kind === 'warn-diverged')
|
|
18
|
+
report.warnings.push({ relPath: a.relPath, reason: 'diverged' });
|
|
19
|
+
else if (a.kind === 'warn-orphan')
|
|
20
|
+
report.warnings.push({ relPath: a.relPath, reason: 'orphan' });
|
|
21
|
+
else if (a.kind === 'delete')
|
|
22
|
+
report.deleted.push(a.relPath);
|
|
23
|
+
}
|
|
24
|
+
return report;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
exports.summarize = summarize;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
function summarize(plan, exitCode) {
|
|
2
|
+
const report = {
|
|
3
|
+
created: [],
|
|
4
|
+
updated: [],
|
|
5
|
+
skipped: [],
|
|
6
|
+
warnings: [],
|
|
7
|
+
deleted: [],
|
|
8
|
+
exitCode,
|
|
9
|
+
};
|
|
10
|
+
for (const a of plan.actions) {
|
|
11
|
+
if (a.kind === 'copy')
|
|
12
|
+
report.created.push(a.relPath);
|
|
13
|
+
else if (a.kind === 'skip-uptodate')
|
|
14
|
+
report.skipped.push(a.relPath);
|
|
15
|
+
else if (a.kind === 'warn-diverged')
|
|
16
|
+
report.warnings.push({ relPath: a.relPath, reason: 'diverged' });
|
|
17
|
+
else if (a.kind === 'warn-orphan')
|
|
18
|
+
report.warnings.push({ relPath: a.relPath, reason: 'orphan' });
|
|
19
|
+
else if (a.kind === 'delete')
|
|
20
|
+
report.deleted.push(a.relPath);
|
|
21
|
+
}
|
|
22
|
+
return report;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { summarize };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { findNearestDotClaudeAncestor, isInteractive, isValidScope, resolveScope, type Scope, type ScopeResolution, } from './scope.js';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var node_os = require('node:os');
|
|
4
|
+
var node_path = require('node:path');
|
|
5
|
+
var isDirectory = require('./utils/isDirectory.cjs');
|
|
6
|
+
|
|
7
|
+
function isValidScope(value) {
|
|
8
|
+
return value === 'user' || value === 'project';
|
|
9
|
+
}
|
|
10
|
+
function findNearestDotClaudeAncestor(start) {
|
|
11
|
+
let current = start;
|
|
12
|
+
while (true) {
|
|
13
|
+
if (isDirectory.isDirectory(node_path.join(current, '.claude')))
|
|
14
|
+
return current;
|
|
15
|
+
const parent = node_path.dirname(current);
|
|
16
|
+
if (parent === current)
|
|
17
|
+
return null;
|
|
18
|
+
current = parent;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function resolveScope(scope, cwd = process.cwd()) {
|
|
22
|
+
if (scope === 'user') {
|
|
23
|
+
return {
|
|
24
|
+
scope,
|
|
25
|
+
targetRoot: node_path.join(node_os.homedir(), '.claude'),
|
|
26
|
+
description: '~/.claude (user)',
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const ancestor = findNearestDotClaudeAncestor(cwd);
|
|
30
|
+
const base = ancestor ?? cwd;
|
|
31
|
+
return {
|
|
32
|
+
scope,
|
|
33
|
+
targetRoot: node_path.join(base, '.claude'),
|
|
34
|
+
description: ancestor !== null
|
|
35
|
+
? `${base}/.claude (project, auto-located)`
|
|
36
|
+
: `${base}/.claude (project)`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function isInteractive() {
|
|
40
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
exports.findNearestDotClaudeAncestor = findNearestDotClaudeAncestor;
|
|
44
|
+
exports.isInteractive = isInteractive;
|
|
45
|
+
exports.isValidScope = isValidScope;
|
|
46
|
+
exports.resolveScope = resolveScope;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type Scope = 'user' | 'project';
|
|
2
|
+
export interface ScopeResolution {
|
|
3
|
+
scope: Scope;
|
|
4
|
+
targetRoot: string;
|
|
5
|
+
description: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function isValidScope(value: unknown): value is Scope;
|
|
8
|
+
/**
|
|
9
|
+
* Walk parent directories of `start` and return the first ancestor that
|
|
10
|
+
* already contains a `.claude` directory. Returns the ancestor path itself
|
|
11
|
+
* (not `/.claude`), or `null` when no such ancestor exists up to the
|
|
12
|
+
* filesystem root. `start` itself is considered as the first candidate.
|
|
13
|
+
*/
|
|
14
|
+
export declare function findNearestDotClaudeAncestor(start: string): string | null;
|
|
15
|
+
export declare function resolveScope(scope: Scope, cwd?: string): ScopeResolution;
|
|
16
|
+
export declare function isInteractive(): boolean;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { join, dirname } from 'node:path';
|
|
3
|
+
import { isDirectory } from './utils/isDirectory.mjs';
|
|
4
|
+
|
|
5
|
+
function isValidScope(value) {
|
|
6
|
+
return value === 'user' || value === 'project';
|
|
7
|
+
}
|
|
8
|
+
function findNearestDotClaudeAncestor(start) {
|
|
9
|
+
let current = start;
|
|
10
|
+
while (true) {
|
|
11
|
+
if (isDirectory(join(current, '.claude')))
|
|
12
|
+
return current;
|
|
13
|
+
const parent = dirname(current);
|
|
14
|
+
if (parent === current)
|
|
15
|
+
return null;
|
|
16
|
+
current = parent;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function resolveScope(scope, cwd = process.cwd()) {
|
|
20
|
+
if (scope === 'user') {
|
|
21
|
+
return {
|
|
22
|
+
scope,
|
|
23
|
+
targetRoot: join(homedir(), '.claude'),
|
|
24
|
+
description: '~/.claude (user)',
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const ancestor = findNearestDotClaudeAncestor(cwd);
|
|
28
|
+
const base = ancestor ?? cwd;
|
|
29
|
+
return {
|
|
30
|
+
scope,
|
|
31
|
+
targetRoot: join(base, '.claude'),
|
|
32
|
+
description: ancestor !== null
|
|
33
|
+
? `${base}/.claude (project, auto-located)`
|
|
34
|
+
: `${base}/.claude (project)`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function isInteractive() {
|
|
38
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { findNearestDotClaudeAncestor, isInteractive, isValidScope, resolveScope };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isDirectory(path: string): boolean;
|