@deskwork/cli 0.10.0 → 0.10.1
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.
|
@@ -1,60 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* deskwork repair-install — recover from Claude Code
|
|
3
|
-
*
|
|
2
|
+
* deskwork repair-install — recover from Claude Code plugin-cache eviction
|
|
3
|
+
* (issues #89, #125, #131).
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* accumulates entries pointing at cache directories that no longer
|
|
8
|
-
* exist on disk. Claude Code wires PATH from these stale entries, so
|
|
9
|
-
* `command -v deskwork` returns nothing even though the marketplace
|
|
10
|
-
* clone at ~/.claude/plugins/marketplaces/deskwork/ is intact.
|
|
5
|
+
* Thin wrapper around the marketplace-clone-resident bash script at
|
|
6
|
+
* `~/.claude/plugins/marketplaces/deskwork/scripts/repair-install.sh`.
|
|
11
7
|
*
|
|
12
|
-
* The
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
8
|
+
* The actual repair logic lives in bash because the deskwork CLI itself
|
|
9
|
+
* is unreachable when the cache is wiped — the hook that auto-runs the
|
|
10
|
+
* repair (configured per-adopter in their `.claude/settings.json`) needs
|
|
11
|
+
* to operate without depending on `deskwork` being on PATH. The wrapper
|
|
12
|
+
* exists so `deskwork repair-install` continues to work as an
|
|
13
|
+
* operator-driven recovery path AFTER the cache has been restored.
|
|
17
14
|
*
|
|
18
|
-
* Argv shape:
|
|
15
|
+
* Argv shape: forwards all flags to the bash script. Common flags:
|
|
19
16
|
*
|
|
20
|
-
* --
|
|
21
|
-
* --
|
|
17
|
+
* --quiet Silent on healthy state. Used by SessionStart hooks.
|
|
18
|
+
* --check Read-only — report state without modifying.
|
|
22
19
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* 0 Registry was already clean OR pruned cleanly.
|
|
28
|
-
* 1 Registry not found, malformed, or unrecognized version.
|
|
20
|
+
* Exit codes follow the bash script's contract:
|
|
21
|
+
* 0 Healthy or repaired successfully.
|
|
22
|
+
* 1 Repair failed (marketplace clone missing, fs error, etc.).
|
|
23
|
+
* 2 Usage error.
|
|
29
24
|
*/
|
|
30
|
-
interface InstallEntry {
|
|
31
|
-
readonly scope: string;
|
|
32
|
-
readonly installPath: string;
|
|
33
|
-
readonly version: string;
|
|
34
|
-
readonly installedAt?: string;
|
|
35
|
-
readonly lastUpdated?: string;
|
|
36
|
-
readonly gitCommitSha?: string;
|
|
37
|
-
readonly projectPath?: string;
|
|
38
|
-
}
|
|
39
|
-
interface Registry {
|
|
40
|
-
readonly version: number;
|
|
41
|
-
plugins: Record<string, InstallEntry[]>;
|
|
42
|
-
}
|
|
43
|
-
interface PruneReport {
|
|
44
|
-
readonly registryPath: string;
|
|
45
|
-
readonly marketplaceClonePresent: boolean;
|
|
46
|
-
readonly pruned: ReadonlyArray<{
|
|
47
|
-
readonly key: string;
|
|
48
|
-
readonly entry: InstallEntry;
|
|
49
|
-
}>;
|
|
50
|
-
readonly kept: ReadonlyArray<{
|
|
51
|
-
readonly key: string;
|
|
52
|
-
readonly entry: InstallEntry;
|
|
53
|
-
}>;
|
|
54
|
-
readonly missingAfterPrune: ReadonlyArray<string>;
|
|
55
|
-
readonly registryWritten: boolean;
|
|
56
|
-
}
|
|
57
25
|
export declare function run(argv: string[]): Promise<void>;
|
|
58
|
-
export declare function pruneRegistry(registry: Registry, dryRun: boolean): PruneReport;
|
|
59
|
-
export {};
|
|
60
26
|
//# sourceMappingURL=repair-install.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repair-install.d.ts","sourceRoot":"","sources":["../../src/commands/repair-install.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"repair-install.d.ts","sourceRoot":"","sources":["../../src/commands/repair-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAYH,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBvD"}
|
|
@@ -1,164 +1,50 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* deskwork repair-install — recover from Claude Code
|
|
3
|
-
*
|
|
2
|
+
* deskwork repair-install — recover from Claude Code plugin-cache eviction
|
|
3
|
+
* (issues #89, #125, #131).
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* accumulates entries pointing at cache directories that no longer
|
|
8
|
-
* exist on disk. Claude Code wires PATH from these stale entries, so
|
|
9
|
-
* `command -v deskwork` returns nothing even though the marketplace
|
|
10
|
-
* clone at ~/.claude/plugins/marketplaces/deskwork/ is intact.
|
|
5
|
+
* Thin wrapper around the marketplace-clone-resident bash script at
|
|
6
|
+
* `~/.claude/plugins/marketplaces/deskwork/scripts/repair-install.sh`.
|
|
11
7
|
*
|
|
12
|
-
* The
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
8
|
+
* The actual repair logic lives in bash because the deskwork CLI itself
|
|
9
|
+
* is unreachable when the cache is wiped — the hook that auto-runs the
|
|
10
|
+
* repair (configured per-adopter in their `.claude/settings.json`) needs
|
|
11
|
+
* to operate without depending on `deskwork` being on PATH. The wrapper
|
|
12
|
+
* exists so `deskwork repair-install` continues to work as an
|
|
13
|
+
* operator-driven recovery path AFTER the cache has been restored.
|
|
17
14
|
*
|
|
18
|
-
* Argv shape:
|
|
15
|
+
* Argv shape: forwards all flags to the bash script. Common flags:
|
|
19
16
|
*
|
|
20
|
-
* --
|
|
21
|
-
* --
|
|
17
|
+
* --quiet Silent on healthy state. Used by SessionStart hooks.
|
|
18
|
+
* --check Read-only — report state without modifying.
|
|
22
19
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* 0 Registry was already clean OR pruned cleanly.
|
|
28
|
-
* 1 Registry not found, malformed, or unrecognized version.
|
|
20
|
+
* Exit codes follow the bash script's contract:
|
|
21
|
+
* 0 Healthy or repaired successfully.
|
|
22
|
+
* 1 Repair failed (marketplace clone missing, fs error, etc.).
|
|
23
|
+
* 2 Usage error.
|
|
29
24
|
*/
|
|
30
|
-
import {
|
|
25
|
+
import { spawnSync } from 'node:child_process';
|
|
26
|
+
import { existsSync } from 'node:fs';
|
|
31
27
|
import { homedir } from 'node:os';
|
|
32
28
|
import { join } from 'node:path';
|
|
33
|
-
const
|
|
34
|
-
const MARKETPLACE_CLONE = join(homedir(), '.claude/plugins/marketplaces/deskwork');
|
|
35
|
-
const DESKWORK_PLUGINS = ['deskwork', 'deskwork-studio', 'dw-lifecycle'];
|
|
36
|
-
const DESKWORK_KEYS = DESKWORK_PLUGINS.map((p) => `${p}@deskwork`);
|
|
29
|
+
const SCRIPT_PATH = join(homedir(), '.claude/plugins/marketplaces/deskwork/scripts/repair-install.sh');
|
|
37
30
|
export async function run(argv) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
registry = JSON.parse(readFileSync(REGISTRY_PATH, 'utf8'));
|
|
47
|
-
}
|
|
48
|
-
catch (err) {
|
|
49
|
-
const reason = err instanceof Error ? err.message : String(err);
|
|
50
|
-
process.stderr.write(`failed to parse ${REGISTRY_PATH}: ${reason}\n`);
|
|
51
|
-
process.exit(1);
|
|
52
|
-
}
|
|
53
|
-
if (typeof registry.version !== 'number' || registry.version > 2) {
|
|
54
|
-
process.stderr.write(`unrecognized installed_plugins.json version: ${String(registry.version)}\n` +
|
|
55
|
-
`this command was written for version 2 — bail out and edit the file by hand if you trust the change.\n`);
|
|
56
|
-
process.exit(1);
|
|
57
|
-
}
|
|
58
|
-
if (!registry.plugins || typeof registry.plugins !== 'object') {
|
|
59
|
-
process.stderr.write(`installed_plugins.json missing 'plugins' object\n`);
|
|
31
|
+
// The CLI dispatcher injects process.cwd() as args[0] when no
|
|
32
|
+
// path-like arg is present. Drop anything that doesn't look like a
|
|
33
|
+
// flag — only `--*` and `-x` reach the bash script.
|
|
34
|
+
const flags = argv.filter((arg) => arg.startsWith('-'));
|
|
35
|
+
if (!existsSync(SCRIPT_PATH)) {
|
|
36
|
+
process.stderr.write(`repair-install script missing at ${SCRIPT_PATH}\n` +
|
|
37
|
+
`the marketplace clone may not be present. In Claude Code, run:\n` +
|
|
38
|
+
` /plugin marketplace add audiocontrol-org/deskwork\n`);
|
|
60
39
|
process.exit(1);
|
|
61
40
|
}
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
process.exit(0);
|
|
65
|
-
}
|
|
66
|
-
export function pruneRegistry(registry, dryRun) {
|
|
67
|
-
const pruned = [];
|
|
68
|
-
const kept = [];
|
|
69
|
-
for (const key of DESKWORK_KEYS) {
|
|
70
|
-
const entries = registry.plugins[key];
|
|
71
|
-
if (!Array.isArray(entries))
|
|
72
|
-
continue;
|
|
73
|
-
const live = [];
|
|
74
|
-
for (const entry of entries) {
|
|
75
|
-
if (entry.installPath && existsSync(entry.installPath)) {
|
|
76
|
-
live.push(entry);
|
|
77
|
-
kept.push({ key, entry });
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
pruned.push({ key, entry });
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
if (live.length > 0) {
|
|
84
|
-
registry.plugins[key] = live;
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
delete registry.plugins[key];
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
let registryWritten = false;
|
|
91
|
-
if (!dryRun && pruned.length > 0) {
|
|
92
|
-
writeFileSync(REGISTRY_PATH, `${JSON.stringify(registry, null, 2)}\n`, 'utf8');
|
|
93
|
-
registryWritten = true;
|
|
94
|
-
}
|
|
95
|
-
const missingAfterPrune = DESKWORK_PLUGINS.filter((p) => {
|
|
96
|
-
const liveEntries = registry.plugins[`${p}@deskwork`];
|
|
97
|
-
return !liveEntries || liveEntries.length === 0;
|
|
41
|
+
const result = spawnSync('bash', [SCRIPT_PATH, ...flags], {
|
|
42
|
+
stdio: 'inherit',
|
|
98
43
|
});
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
pruned,
|
|
103
|
-
kept,
|
|
104
|
-
missingAfterPrune,
|
|
105
|
-
registryWritten,
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
function emit(report, opts) {
|
|
109
|
-
if (opts.json) {
|
|
110
|
-
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
if (report.pruned.length === 0) {
|
|
114
|
-
process.stdout.write('Registry has no stale deskwork entries — install state looks consistent.\n');
|
|
115
|
-
if (report.missingAfterPrune.length > 0) {
|
|
116
|
-
process.stdout.write(`\nNote: no entries registered for: ${report.missingAfterPrune.join(', ')}.\n`);
|
|
117
|
-
process.stdout.write('If you need any of these, install via Claude Code:\n');
|
|
118
|
-
for (const name of report.missingAfterPrune) {
|
|
119
|
-
process.stdout.write(` /plugin install ${name}@deskwork\n`);
|
|
120
|
-
}
|
|
121
|
-
process.stdout.write(' /reload-plugins\n');
|
|
122
|
-
}
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
const verb = report.registryWritten ? 'Pruned' : 'Would prune';
|
|
126
|
-
const count = report.pruned.length;
|
|
127
|
-
process.stdout.write(`${verb} ${count} stale entr${count === 1 ? 'y' : 'ies'} pointing at non-existent paths:\n`);
|
|
128
|
-
for (const { key, entry } of report.pruned) {
|
|
129
|
-
process.stdout.write(` ${key} scope=${entry.scope} version=${entry.version}\n`);
|
|
130
|
-
process.stdout.write(` ${entry.installPath}\n`);
|
|
131
|
-
}
|
|
132
|
-
if (report.kept.length > 0) {
|
|
133
|
-
process.stdout.write(`\nKept ${report.kept.length} live entr${report.kept.length === 1 ? 'y' : 'ies'}:\n`);
|
|
134
|
-
for (const { key, entry } of report.kept) {
|
|
135
|
-
process.stdout.write(` ${key} scope=${entry.scope} version=${entry.version}\n`);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (report.registryWritten) {
|
|
139
|
-
process.stdout.write(`\nWrote cleaned registry to ${report.registryPath}\n`);
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
process.stdout.write('\n(dry-run: registry not modified — re-run without --dry-run to apply.)\n');
|
|
143
|
-
}
|
|
144
|
-
if (report.missingAfterPrune.length > 0) {
|
|
145
|
-
process.stdout.write('\nNext steps to restore the bin(s) on PATH:\n');
|
|
146
|
-
process.stdout.write(' In Claude Code, run:\n');
|
|
147
|
-
for (const name of report.missingAfterPrune) {
|
|
148
|
-
process.stdout.write(` /plugin install ${name}@deskwork\n`);
|
|
149
|
-
}
|
|
150
|
-
process.stdout.write(' /reload-plugins\n');
|
|
151
|
-
process.stdout.write('\n Verify with:\n');
|
|
152
|
-
for (const name of report.missingAfterPrune) {
|
|
153
|
-
process.stdout.write(` command -v ${name}\n`);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
if (!report.marketplaceClonePresent) {
|
|
157
|
-
process.stdout.write('\nWarning: marketplace clone at ');
|
|
158
|
-
process.stdout.write(MARKETPLACE_CLONE);
|
|
159
|
-
process.stdout.write(` is missing.\n`);
|
|
160
|
-
process.stdout.write('You may need to re-add the marketplace before /plugin install will work:\n');
|
|
161
|
-
process.stdout.write(' /plugin marketplace add audiocontrol-org/deskwork\n');
|
|
44
|
+
if (result.error) {
|
|
45
|
+
process.stderr.write(`failed to invoke repair-install script: ${result.error.message}\n`);
|
|
46
|
+
process.exit(1);
|
|
162
47
|
}
|
|
48
|
+
process.exit(result.status ?? 1);
|
|
163
49
|
}
|
|
164
50
|
//# sourceMappingURL=repair-install.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repair-install.js","sourceRoot":"","sources":["../../src/commands/repair-install.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"repair-install.js","sourceRoot":"","sources":["../../src/commands/repair-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,WAAW,GAAG,IAAI,CACtB,OAAO,EAAE,EACT,iEAAiE,CAClE,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAc;IACtC,8DAA8D;IAC9D,mEAAmE;IACnE,oDAAoD;IACpD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAExD,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,oCAAoC,WAAW,IAAI;YACjD,kEAAkE;YAClE,uDAAuD,CAC1D,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,EAAE;QACxD,KAAK,EAAE,SAAS;KACjB,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2CAA2C,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;QAC1F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;AACnC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deskwork/cli",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Editorial calendar + review CLI for the deskwork plugin",
|
|
6
6
|
"homepage": "https://github.com/audiocontrol-org/deskwork#readme",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"typecheck": "tsc --noEmit"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@deskwork/core": "0.10.
|
|
36
|
+
"@deskwork/core": "0.10.1"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/node": "^22.10.0",
|