cc4pm 1.8.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/.claude-plugin/README.md +17 -0
- package/.claude-plugin/plugin.json +25 -0
- package/LICENSE +21 -0
- package/README.md +157 -0
- package/README.zh-CN.md +134 -0
- package/contexts/dev.md +20 -0
- package/contexts/research.md +26 -0
- package/contexts/review.md +22 -0
- package/examples/CLAUDE.md +100 -0
- package/examples/statusline.json +19 -0
- package/examples/user-CLAUDE.md +109 -0
- package/install.sh +17 -0
- package/manifests/install-components.json +173 -0
- package/manifests/install-modules.json +335 -0
- package/manifests/install-profiles.json +75 -0
- package/package.json +117 -0
- package/schemas/ecc-install-config.schema.json +58 -0
- package/schemas/hooks.schema.json +197 -0
- package/schemas/install-components.schema.json +56 -0
- package/schemas/install-modules.schema.json +105 -0
- package/schemas/install-profiles.schema.json +45 -0
- package/schemas/install-state.schema.json +210 -0
- package/schemas/package-manager.schema.json +23 -0
- package/schemas/plugin.schema.json +58 -0
- package/scripts/ci/catalog.js +83 -0
- package/scripts/ci/validate-agents.js +81 -0
- package/scripts/ci/validate-commands.js +135 -0
- package/scripts/ci/validate-hooks.js +239 -0
- package/scripts/ci/validate-install-manifests.js +211 -0
- package/scripts/ci/validate-no-personal-paths.js +63 -0
- package/scripts/ci/validate-rules.js +81 -0
- package/scripts/ci/validate-skills.js +54 -0
- package/scripts/claw.js +468 -0
- package/scripts/doctor.js +110 -0
- package/scripts/ecc.js +194 -0
- package/scripts/hooks/auto-tmux-dev.js +88 -0
- package/scripts/hooks/check-console-log.js +71 -0
- package/scripts/hooks/check-hook-enabled.js +12 -0
- package/scripts/hooks/cost-tracker.js +78 -0
- package/scripts/hooks/doc-file-warning.js +63 -0
- package/scripts/hooks/evaluate-session.js +100 -0
- package/scripts/hooks/insaits-security-monitor.py +269 -0
- package/scripts/hooks/insaits-security-wrapper.js +88 -0
- package/scripts/hooks/post-bash-build-complete.js +27 -0
- package/scripts/hooks/post-bash-pr-created.js +36 -0
- package/scripts/hooks/post-edit-console-warn.js +54 -0
- package/scripts/hooks/post-edit-format.js +109 -0
- package/scripts/hooks/post-edit-typecheck.js +96 -0
- package/scripts/hooks/pre-bash-dev-server-block.js +187 -0
- package/scripts/hooks/pre-bash-git-push-reminder.js +28 -0
- package/scripts/hooks/pre-bash-tmux-reminder.js +33 -0
- package/scripts/hooks/pre-compact.js +48 -0
- package/scripts/hooks/pre-write-doc-warn.js +9 -0
- package/scripts/hooks/quality-gate.js +168 -0
- package/scripts/hooks/run-with-flags-shell.sh +32 -0
- package/scripts/hooks/run-with-flags.js +120 -0
- package/scripts/hooks/session-end-marker.js +15 -0
- package/scripts/hooks/session-end.js +299 -0
- package/scripts/hooks/session-start.js +97 -0
- package/scripts/hooks/suggest-compact.js +80 -0
- package/scripts/install-apply.js +137 -0
- package/scripts/install-plan.js +254 -0
- package/scripts/lib/hook-flags.js +74 -0
- package/scripts/lib/install/apply.js +23 -0
- package/scripts/lib/install/config.js +82 -0
- package/scripts/lib/install/request.js +113 -0
- package/scripts/lib/install/runtime.js +42 -0
- package/scripts/lib/install-executor.js +605 -0
- package/scripts/lib/install-lifecycle.js +763 -0
- package/scripts/lib/install-manifests.js +305 -0
- package/scripts/lib/install-state.js +120 -0
- package/scripts/lib/install-targets/antigravity-project.js +9 -0
- package/scripts/lib/install-targets/claude-home.js +10 -0
- package/scripts/lib/install-targets/codex-home.js +10 -0
- package/scripts/lib/install-targets/cursor-project.js +10 -0
- package/scripts/lib/install-targets/helpers.js +89 -0
- package/scripts/lib/install-targets/opencode-home.js +10 -0
- package/scripts/lib/install-targets/registry.js +64 -0
- package/scripts/lib/orchestration-session.js +299 -0
- package/scripts/lib/package-manager.d.ts +119 -0
- package/scripts/lib/package-manager.js +431 -0
- package/scripts/lib/project-detect.js +428 -0
- package/scripts/lib/resolve-formatter.js +185 -0
- package/scripts/lib/session-adapters/canonical-session.js +138 -0
- package/scripts/lib/session-adapters/claude-history.js +149 -0
- package/scripts/lib/session-adapters/dmux-tmux.js +80 -0
- package/scripts/lib/session-adapters/registry.js +111 -0
- package/scripts/lib/session-aliases.d.ts +136 -0
- package/scripts/lib/session-aliases.js +481 -0
- package/scripts/lib/session-manager.d.ts +131 -0
- package/scripts/lib/session-manager.js +464 -0
- package/scripts/lib/shell-split.js +86 -0
- package/scripts/lib/skill-improvement/amendify.js +89 -0
- package/scripts/lib/skill-improvement/evaluate.js +59 -0
- package/scripts/lib/skill-improvement/health.js +118 -0
- package/scripts/lib/skill-improvement/observations.js +108 -0
- package/scripts/lib/tmux-worktree-orchestrator.js +491 -0
- package/scripts/lib/utils.d.ts +183 -0
- package/scripts/lib/utils.js +543 -0
- package/scripts/list-installed.js +90 -0
- package/scripts/orchestrate-codex-worker.sh +92 -0
- package/scripts/orchestrate-worktrees.js +108 -0
- package/scripts/orchestration-status.js +62 -0
- package/scripts/repair.js +97 -0
- package/scripts/session-inspect.js +150 -0
- package/scripts/setup-package-manager.js +204 -0
- package/scripts/skill-create-output.js +244 -0
- package/scripts/uninstall.js +96 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { spawnSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
function stripCodeTicks(value) {
|
|
8
|
+
if (typeof value !== 'string') {
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const trimmed = value.trim();
|
|
13
|
+
if (trimmed.startsWith('`') && trimmed.endsWith('`') && trimmed.length >= 2) {
|
|
14
|
+
return trimmed.slice(1, -1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return trimmed;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function parseSection(content, heading) {
|
|
21
|
+
if (typeof content !== 'string' || content.length === 0) {
|
|
22
|
+
return '';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const lines = content.split('\n');
|
|
26
|
+
const headingLines = new Set([`## ${heading}`, `**${heading}**`]);
|
|
27
|
+
const startIndex = lines.findIndex(line => headingLines.has(line.trim()));
|
|
28
|
+
|
|
29
|
+
if (startIndex === -1) {
|
|
30
|
+
return '';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const collected = [];
|
|
34
|
+
for (let index = startIndex + 1; index < lines.length; index += 1) {
|
|
35
|
+
const line = lines[index];
|
|
36
|
+
const trimmed = line.trim();
|
|
37
|
+
if (trimmed.startsWith('## ') || (/^\*\*.+\*\*$/.test(trimmed) && !headingLines.has(trimmed))) {
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
collected.push(line);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return collected.join('\n').trim();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function parseBullets(section) {
|
|
47
|
+
if (!section) {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return section
|
|
52
|
+
.split('\n')
|
|
53
|
+
.map(line => line.trim())
|
|
54
|
+
.filter(line => line.startsWith('- '))
|
|
55
|
+
.map(line => stripCodeTicks(line.replace(/^- /, '').trim()));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function parseWorkerStatus(content) {
|
|
59
|
+
const status = {
|
|
60
|
+
state: null,
|
|
61
|
+
updated: null,
|
|
62
|
+
branch: null,
|
|
63
|
+
worktree: null,
|
|
64
|
+
taskFile: null,
|
|
65
|
+
handoffFile: null
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
if (typeof content !== 'string' || content.length === 0) {
|
|
69
|
+
return status;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for (const line of content.split('\n')) {
|
|
73
|
+
const match = line.match(/^- ([A-Za-z ]+):\s*(.+)$/);
|
|
74
|
+
if (!match) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const key = match[1].trim().toLowerCase().replace(/\s+/g, '');
|
|
79
|
+
const value = stripCodeTicks(match[2]);
|
|
80
|
+
|
|
81
|
+
if (key === 'state') status.state = value;
|
|
82
|
+
if (key === 'updated') status.updated = value;
|
|
83
|
+
if (key === 'branch') status.branch = value;
|
|
84
|
+
if (key === 'worktree') status.worktree = value;
|
|
85
|
+
if (key === 'taskfile') status.taskFile = value;
|
|
86
|
+
if (key === 'handofffile') status.handoffFile = value;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return status;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function parseWorkerTask(content) {
|
|
93
|
+
return {
|
|
94
|
+
objective: parseSection(content, 'Objective'),
|
|
95
|
+
seedPaths: parseBullets(parseSection(content, 'Seeded Local Overlays'))
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function parseWorkerHandoff(content) {
|
|
100
|
+
return {
|
|
101
|
+
summary: parseBullets(parseSection(content, 'Summary')),
|
|
102
|
+
validation: parseBullets(parseSection(content, 'Validation')),
|
|
103
|
+
remainingRisks: parseBullets(parseSection(content, 'Remaining Risks'))
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function readTextIfExists(filePath) {
|
|
108
|
+
if (!filePath || !fs.existsSync(filePath)) {
|
|
109
|
+
return '';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return fs.readFileSync(filePath, 'utf8');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function listWorkerDirectories(coordinationDir) {
|
|
116
|
+
if (!coordinationDir || !fs.existsSync(coordinationDir)) {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return fs.readdirSync(coordinationDir, { withFileTypes: true })
|
|
121
|
+
.filter(entry => entry.isDirectory())
|
|
122
|
+
.filter(entry => {
|
|
123
|
+
const workerDir = path.join(coordinationDir, entry.name);
|
|
124
|
+
return ['status.md', 'task.md', 'handoff.md']
|
|
125
|
+
.some(filename => fs.existsSync(path.join(workerDir, filename)));
|
|
126
|
+
})
|
|
127
|
+
.map(entry => entry.name)
|
|
128
|
+
.sort();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function loadWorkerSnapshots(coordinationDir) {
|
|
132
|
+
return listWorkerDirectories(coordinationDir).map(workerSlug => {
|
|
133
|
+
const workerDir = path.join(coordinationDir, workerSlug);
|
|
134
|
+
const statusPath = path.join(workerDir, 'status.md');
|
|
135
|
+
const taskPath = path.join(workerDir, 'task.md');
|
|
136
|
+
const handoffPath = path.join(workerDir, 'handoff.md');
|
|
137
|
+
|
|
138
|
+
const status = parseWorkerStatus(readTextIfExists(statusPath));
|
|
139
|
+
const task = parseWorkerTask(readTextIfExists(taskPath));
|
|
140
|
+
const handoff = parseWorkerHandoff(readTextIfExists(handoffPath));
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
workerSlug,
|
|
144
|
+
workerDir,
|
|
145
|
+
status,
|
|
146
|
+
task,
|
|
147
|
+
handoff,
|
|
148
|
+
files: {
|
|
149
|
+
status: statusPath,
|
|
150
|
+
task: taskPath,
|
|
151
|
+
handoff: handoffPath
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function listTmuxPanes(sessionName, options = {}) {
|
|
158
|
+
const { spawnSyncImpl = spawnSync } = options;
|
|
159
|
+
const format = [
|
|
160
|
+
'#{pane_id}',
|
|
161
|
+
'#{window_index}',
|
|
162
|
+
'#{pane_index}',
|
|
163
|
+
'#{pane_title}',
|
|
164
|
+
'#{pane_current_command}',
|
|
165
|
+
'#{pane_current_path}',
|
|
166
|
+
'#{pane_active}',
|
|
167
|
+
'#{pane_dead}',
|
|
168
|
+
'#{pane_pid}'
|
|
169
|
+
].join('\t');
|
|
170
|
+
|
|
171
|
+
const result = spawnSyncImpl('tmux', ['list-panes', '-t', sessionName, '-F', format], {
|
|
172
|
+
encoding: 'utf8',
|
|
173
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
if (result.error) {
|
|
177
|
+
if (result.error.code === 'ENOENT') {
|
|
178
|
+
return [];
|
|
179
|
+
}
|
|
180
|
+
throw result.error;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (result.status !== 0) {
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return (result.stdout || '')
|
|
188
|
+
.split('\n')
|
|
189
|
+
.map(line => line.trim())
|
|
190
|
+
.filter(Boolean)
|
|
191
|
+
.map(line => {
|
|
192
|
+
const [
|
|
193
|
+
paneId,
|
|
194
|
+
windowIndex,
|
|
195
|
+
paneIndex,
|
|
196
|
+
title,
|
|
197
|
+
currentCommand,
|
|
198
|
+
currentPath,
|
|
199
|
+
active,
|
|
200
|
+
dead,
|
|
201
|
+
pid
|
|
202
|
+
] = line.split('\t');
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
paneId,
|
|
206
|
+
windowIndex: Number(windowIndex),
|
|
207
|
+
paneIndex: Number(paneIndex),
|
|
208
|
+
title,
|
|
209
|
+
currentCommand,
|
|
210
|
+
currentPath,
|
|
211
|
+
active: active === '1',
|
|
212
|
+
dead: dead === '1',
|
|
213
|
+
pid: pid ? Number(pid) : null
|
|
214
|
+
};
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function summarizeWorkerStates(workers) {
|
|
219
|
+
return workers.reduce((counts, worker) => {
|
|
220
|
+
const state = worker.status.state || 'unknown';
|
|
221
|
+
counts[state] = (counts[state] || 0) + 1;
|
|
222
|
+
return counts;
|
|
223
|
+
}, {});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function buildSessionSnapshot({ sessionName, coordinationDir, panes }) {
|
|
227
|
+
const workerSnapshots = loadWorkerSnapshots(coordinationDir);
|
|
228
|
+
const paneMap = new Map(panes.map(pane => [pane.title, pane]));
|
|
229
|
+
|
|
230
|
+
const workers = workerSnapshots.map(worker => ({
|
|
231
|
+
...worker,
|
|
232
|
+
pane: paneMap.get(worker.workerSlug) || null
|
|
233
|
+
}));
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
sessionName,
|
|
237
|
+
coordinationDir,
|
|
238
|
+
sessionActive: panes.length > 0,
|
|
239
|
+
paneCount: panes.length,
|
|
240
|
+
workerCount: workers.length,
|
|
241
|
+
workerStates: summarizeWorkerStates(workers),
|
|
242
|
+
panes,
|
|
243
|
+
workers
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function resolveSnapshotTarget(targetPath, cwd = process.cwd()) {
|
|
248
|
+
const absoluteTarget = path.resolve(cwd, targetPath);
|
|
249
|
+
|
|
250
|
+
if (fs.existsSync(absoluteTarget) && fs.statSync(absoluteTarget).isFile()) {
|
|
251
|
+
const config = JSON.parse(fs.readFileSync(absoluteTarget, 'utf8'));
|
|
252
|
+
const repoRoot = path.resolve(config.repoRoot || cwd);
|
|
253
|
+
const coordinationRoot = path.resolve(
|
|
254
|
+
config.coordinationRoot || path.join(repoRoot, '.orchestration')
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
return {
|
|
258
|
+
sessionName: config.sessionName,
|
|
259
|
+
coordinationDir: path.join(coordinationRoot, config.sessionName),
|
|
260
|
+
repoRoot,
|
|
261
|
+
targetType: 'plan'
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
sessionName: targetPath,
|
|
267
|
+
coordinationDir: path.join(cwd, '.claude', 'orchestration', targetPath),
|
|
268
|
+
repoRoot: cwd,
|
|
269
|
+
targetType: 'session'
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function collectSessionSnapshot(targetPath, cwd = process.cwd()) {
|
|
274
|
+
const target = resolveSnapshotTarget(targetPath, cwd);
|
|
275
|
+
const panes = listTmuxPanes(target.sessionName);
|
|
276
|
+
const snapshot = buildSessionSnapshot({
|
|
277
|
+
sessionName: target.sessionName,
|
|
278
|
+
coordinationDir: target.coordinationDir,
|
|
279
|
+
panes
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
...snapshot,
|
|
284
|
+
repoRoot: target.repoRoot,
|
|
285
|
+
targetType: target.targetType
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
module.exports = {
|
|
290
|
+
buildSessionSnapshot,
|
|
291
|
+
collectSessionSnapshot,
|
|
292
|
+
listTmuxPanes,
|
|
293
|
+
loadWorkerSnapshots,
|
|
294
|
+
normalizeText: stripCodeTicks,
|
|
295
|
+
parseWorkerHandoff,
|
|
296
|
+
parseWorkerStatus,
|
|
297
|
+
parseWorkerTask,
|
|
298
|
+
resolveSnapshotTarget
|
|
299
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package Manager Detection and Selection.
|
|
3
|
+
* Supports: npm, pnpm, yarn, bun.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/** Supported package manager names */
|
|
7
|
+
export type PackageManagerName = 'npm' | 'pnpm' | 'yarn' | 'bun';
|
|
8
|
+
|
|
9
|
+
/** Configuration for a single package manager */
|
|
10
|
+
export interface PackageManagerConfig {
|
|
11
|
+
name: PackageManagerName;
|
|
12
|
+
/** Lock file name (e.g., "package-lock.json", "pnpm-lock.yaml") */
|
|
13
|
+
lockFile: string;
|
|
14
|
+
/** Install command (e.g., "npm install") */
|
|
15
|
+
installCmd: string;
|
|
16
|
+
/** Run script command prefix (e.g., "npm run", "pnpm") */
|
|
17
|
+
runCmd: string;
|
|
18
|
+
/** Execute binary command (e.g., "npx", "pnpm dlx") */
|
|
19
|
+
execCmd: string;
|
|
20
|
+
/** Test command (e.g., "npm test") */
|
|
21
|
+
testCmd: string;
|
|
22
|
+
/** Build command (e.g., "npm run build") */
|
|
23
|
+
buildCmd: string;
|
|
24
|
+
/** Dev server command (e.g., "npm run dev") */
|
|
25
|
+
devCmd: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** How the package manager was detected */
|
|
29
|
+
export type DetectionSource =
|
|
30
|
+
| 'environment'
|
|
31
|
+
| 'project-config'
|
|
32
|
+
| 'package.json'
|
|
33
|
+
| 'lock-file'
|
|
34
|
+
| 'global-config'
|
|
35
|
+
| 'default';
|
|
36
|
+
|
|
37
|
+
/** Result from getPackageManager() */
|
|
38
|
+
export interface PackageManagerResult {
|
|
39
|
+
name: PackageManagerName;
|
|
40
|
+
config: PackageManagerConfig;
|
|
41
|
+
source: DetectionSource;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Map of all supported package managers keyed by name */
|
|
45
|
+
export const PACKAGE_MANAGERS: Record<PackageManagerName, PackageManagerConfig>;
|
|
46
|
+
|
|
47
|
+
/** Priority order for lock file detection */
|
|
48
|
+
export const DETECTION_PRIORITY: PackageManagerName[];
|
|
49
|
+
|
|
50
|
+
export interface GetPackageManagerOptions {
|
|
51
|
+
/** Project directory to detect from (default: process.cwd()) */
|
|
52
|
+
projectDir?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get the package manager to use for the current project.
|
|
57
|
+
*
|
|
58
|
+
* Detection priority:
|
|
59
|
+
* 1. CLAUDE_PACKAGE_MANAGER environment variable
|
|
60
|
+
* 2. Project-specific config (.claude/package-manager.json)
|
|
61
|
+
* 3. package.json `packageManager` field
|
|
62
|
+
* 4. Lock file detection
|
|
63
|
+
* 5. Global user preference (~/.claude/package-manager.json)
|
|
64
|
+
* 6. Default to npm (no child processes spawned)
|
|
65
|
+
*/
|
|
66
|
+
export function getPackageManager(options?: GetPackageManagerOptions): PackageManagerResult;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Set the user's globally preferred package manager.
|
|
70
|
+
* Saves to ~/.claude/package-manager.json.
|
|
71
|
+
* @throws If pmName is not a known package manager or if save fails
|
|
72
|
+
*/
|
|
73
|
+
export function setPreferredPackageManager(pmName: PackageManagerName): { packageManager: string; setAt: string };
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Set a project-specific preferred package manager.
|
|
77
|
+
* Saves to <projectDir>/.claude/package-manager.json.
|
|
78
|
+
* @throws If pmName is not a known package manager
|
|
79
|
+
*/
|
|
80
|
+
export function setProjectPackageManager(pmName: PackageManagerName, projectDir?: string): { packageManager: string; setAt: string };
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get package managers installed on the system.
|
|
84
|
+
* WARNING: Spawns child processes for each PM check.
|
|
85
|
+
* Do NOT call during session startup hooks.
|
|
86
|
+
*/
|
|
87
|
+
export function getAvailablePackageManagers(): PackageManagerName[];
|
|
88
|
+
|
|
89
|
+
/** Detect package manager from lock file in the given directory */
|
|
90
|
+
export function detectFromLockFile(projectDir?: string): PackageManagerName | null;
|
|
91
|
+
|
|
92
|
+
/** Detect package manager from package.json `packageManager` field */
|
|
93
|
+
export function detectFromPackageJson(projectDir?: string): PackageManagerName | null;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get the full command string to run a script.
|
|
97
|
+
* @param script - Script name: "install", "test", "build", "dev", or custom
|
|
98
|
+
*/
|
|
99
|
+
export function getRunCommand(script: string, options?: GetPackageManagerOptions): string;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get the full command string to execute a package binary.
|
|
103
|
+
* @param binary - Binary name (e.g., "prettier", "eslint")
|
|
104
|
+
* @param args - Arguments to pass to the binary
|
|
105
|
+
*/
|
|
106
|
+
export function getExecCommand(binary: string, args?: string, options?: GetPackageManagerOptions): string;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Get a message prompting the user to configure their package manager.
|
|
110
|
+
* Does NOT spawn child processes.
|
|
111
|
+
*/
|
|
112
|
+
export function getSelectionPrompt(): string;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Generate a regex pattern string that matches commands for all package managers.
|
|
116
|
+
* @param action - Action like "dev", "install", "test", "build", or custom
|
|
117
|
+
* @returns Parenthesized alternation regex string, e.g., "(npm run dev|pnpm( run)? dev|...)"
|
|
118
|
+
*/
|
|
119
|
+
export function getCommandPattern(action: string): string;
|