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,92 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
if [[ $# -ne 3 ]]; then
|
|
5
|
+
echo "Usage: bash scripts/orchestrate-codex-worker.sh <task-file> <handoff-file> <status-file>" >&2
|
|
6
|
+
exit 1
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
task_file="$1"
|
|
10
|
+
handoff_file="$2"
|
|
11
|
+
status_file="$3"
|
|
12
|
+
|
|
13
|
+
timestamp() {
|
|
14
|
+
date -u +"%Y-%m-%dT%H:%M:%SZ"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
write_status() {
|
|
18
|
+
local state="$1"
|
|
19
|
+
local details="$2"
|
|
20
|
+
|
|
21
|
+
cat > "$status_file" <<EOF
|
|
22
|
+
# Status
|
|
23
|
+
|
|
24
|
+
- State: $state
|
|
25
|
+
- Updated: $(timestamp)
|
|
26
|
+
- Branch: $(git rev-parse --abbrev-ref HEAD)
|
|
27
|
+
- Worktree: \`$(pwd)\`
|
|
28
|
+
|
|
29
|
+
$details
|
|
30
|
+
EOF
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
mkdir -p "$(dirname "$handoff_file")" "$(dirname "$status_file")"
|
|
34
|
+
write_status "running" "- Task file: \`$task_file\`"
|
|
35
|
+
|
|
36
|
+
prompt_file="$(mktemp)"
|
|
37
|
+
output_file="$(mktemp)"
|
|
38
|
+
cleanup() {
|
|
39
|
+
rm -f "$prompt_file" "$output_file"
|
|
40
|
+
}
|
|
41
|
+
trap cleanup EXIT
|
|
42
|
+
|
|
43
|
+
cat > "$prompt_file" <<EOF
|
|
44
|
+
You are one worker in an cc4pm tmux/worktree swarm.
|
|
45
|
+
|
|
46
|
+
Rules:
|
|
47
|
+
- Work only in the current git worktree.
|
|
48
|
+
- Do not touch sibling worktrees or the parent repo checkout.
|
|
49
|
+
- Complete the task from the task file below.
|
|
50
|
+
- Do not spawn subagents or external agents for this task.
|
|
51
|
+
- Report progress and final results in stdout only.
|
|
52
|
+
- Do not write handoff or status files yourself; the launcher manages those artifacts.
|
|
53
|
+
- If you change code or docs, keep the scope narrow and defensible.
|
|
54
|
+
- In your final response, include exactly these sections:
|
|
55
|
+
1. Summary
|
|
56
|
+
2. Files Changed
|
|
57
|
+
3. Validation
|
|
58
|
+
4. Remaining Risks
|
|
59
|
+
|
|
60
|
+
Task file: $task_file
|
|
61
|
+
|
|
62
|
+
$(cat "$task_file")
|
|
63
|
+
EOF
|
|
64
|
+
|
|
65
|
+
if codex exec -p yolo -m gpt-5.4 --color never -C "$(pwd)" -o "$output_file" - < "$prompt_file"; then
|
|
66
|
+
{
|
|
67
|
+
echo "# Handoff"
|
|
68
|
+
echo
|
|
69
|
+
echo "- Completed: $(timestamp)"
|
|
70
|
+
echo "- Branch: \`$(git rev-parse --abbrev-ref HEAD)\`"
|
|
71
|
+
echo "- Worktree: \`$(pwd)\`"
|
|
72
|
+
echo
|
|
73
|
+
cat "$output_file"
|
|
74
|
+
echo
|
|
75
|
+
echo "## Git Status"
|
|
76
|
+
echo
|
|
77
|
+
git status --short
|
|
78
|
+
} > "$handoff_file"
|
|
79
|
+
write_status "completed" "- Handoff file: \`$handoff_file\`"
|
|
80
|
+
else
|
|
81
|
+
{
|
|
82
|
+
echo "# Handoff"
|
|
83
|
+
echo
|
|
84
|
+
echo "- Failed: $(timestamp)"
|
|
85
|
+
echo "- Branch: \`$(git rev-parse --abbrev-ref HEAD)\`"
|
|
86
|
+
echo "- Worktree: \`$(pwd)\`"
|
|
87
|
+
echo
|
|
88
|
+
echo "The Codex worker exited with a non-zero status."
|
|
89
|
+
} > "$handoff_file"
|
|
90
|
+
write_status "failed" "- Handoff file: \`$handoff_file\`"
|
|
91
|
+
exit 1
|
|
92
|
+
fi
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
buildOrchestrationPlan,
|
|
9
|
+
executePlan,
|
|
10
|
+
materializePlan
|
|
11
|
+
} = require('./lib/tmux-worktree-orchestrator');
|
|
12
|
+
|
|
13
|
+
function usage() {
|
|
14
|
+
console.log([
|
|
15
|
+
'Usage:',
|
|
16
|
+
' node scripts/orchestrate-worktrees.js <plan.json> [--execute]',
|
|
17
|
+
' node scripts/orchestrate-worktrees.js <plan.json> [--write-only]',
|
|
18
|
+
'',
|
|
19
|
+
'Placeholders supported in launcherCommand:',
|
|
20
|
+
' {worker_name} {worker_slug} {session_name} {repo_root}',
|
|
21
|
+
' {worktree_path} {branch_name} {task_file} {handoff_file} {status_file}',
|
|
22
|
+
'',
|
|
23
|
+
'Without flags the script prints a dry-run plan only.'
|
|
24
|
+
].join('\n'));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function parseArgs(argv) {
|
|
28
|
+
const args = argv.slice(2);
|
|
29
|
+
const planPath = args.find(arg => !arg.startsWith('--'));
|
|
30
|
+
return {
|
|
31
|
+
execute: args.includes('--execute'),
|
|
32
|
+
planPath,
|
|
33
|
+
writeOnly: args.includes('--write-only')
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function loadPlanConfig(planPath) {
|
|
38
|
+
const absolutePath = path.resolve(planPath);
|
|
39
|
+
const raw = fs.readFileSync(absolutePath, 'utf8');
|
|
40
|
+
const config = JSON.parse(raw);
|
|
41
|
+
config.repoRoot = config.repoRoot || process.cwd();
|
|
42
|
+
return { absolutePath, config };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function printDryRun(plan, absolutePath) {
|
|
46
|
+
const preview = {
|
|
47
|
+
planFile: absolutePath,
|
|
48
|
+
sessionName: plan.sessionName,
|
|
49
|
+
repoRoot: plan.repoRoot,
|
|
50
|
+
coordinationDir: plan.coordinationDir,
|
|
51
|
+
workers: plan.workerPlans.map(worker => ({
|
|
52
|
+
workerName: worker.workerName,
|
|
53
|
+
branchName: worker.branchName,
|
|
54
|
+
worktreePath: worker.worktreePath,
|
|
55
|
+
seedPaths: worker.seedPaths,
|
|
56
|
+
taskFilePath: worker.taskFilePath,
|
|
57
|
+
handoffFilePath: worker.handoffFilePath,
|
|
58
|
+
launchCommand: worker.launchCommand
|
|
59
|
+
})),
|
|
60
|
+
commands: [
|
|
61
|
+
...plan.workerPlans.map(worker => worker.gitCommand),
|
|
62
|
+
...plan.tmuxCommands.map(command => [command.cmd, ...command.args].join(' '))
|
|
63
|
+
]
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
console.log(JSON.stringify(preview, null, 2));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function main() {
|
|
70
|
+
const { execute, planPath, writeOnly } = parseArgs(process.argv);
|
|
71
|
+
|
|
72
|
+
if (!planPath) {
|
|
73
|
+
usage();
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const { absolutePath, config } = loadPlanConfig(planPath);
|
|
78
|
+
const plan = buildOrchestrationPlan(config);
|
|
79
|
+
|
|
80
|
+
if (writeOnly) {
|
|
81
|
+
materializePlan(plan);
|
|
82
|
+
console.log(`Wrote orchestration files to ${plan.coordinationDir}`);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!execute) {
|
|
87
|
+
printDryRun(plan, absolutePath);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const result = executePlan(plan);
|
|
92
|
+
console.log([
|
|
93
|
+
`Started tmux session '${result.sessionName}' with ${result.workerCount} worker panes.`,
|
|
94
|
+
`Coordination files: ${result.coordinationDir}`,
|
|
95
|
+
`Attach with: tmux attach -t ${result.sessionName}`
|
|
96
|
+
].join('\n'));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (require.main === module) {
|
|
100
|
+
try {
|
|
101
|
+
main();
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error(`[orchestrate-worktrees] ${error.message}`);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
module.exports = { main };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const { inspectSessionTarget } = require('./lib/session-adapters/registry');
|
|
8
|
+
|
|
9
|
+
function usage() {
|
|
10
|
+
console.log([
|
|
11
|
+
'Usage:',
|
|
12
|
+
' node scripts/orchestration-status.js <session-name|plan.json> [--write <output.json>]',
|
|
13
|
+
'',
|
|
14
|
+
'Examples:',
|
|
15
|
+
' node scripts/orchestration-status.js workflow-visual-proof',
|
|
16
|
+
' node scripts/orchestration-status.js .claude/plan/workflow-visual-proof.json',
|
|
17
|
+
' node scripts/orchestration-status.js .claude/plan/workflow-visual-proof.json --write /tmp/snapshot.json'
|
|
18
|
+
].join('\n'));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function parseArgs(argv) {
|
|
22
|
+
const args = argv.slice(2);
|
|
23
|
+
const target = args.find(arg => !arg.startsWith('--'));
|
|
24
|
+
const writeIndex = args.indexOf('--write');
|
|
25
|
+
const writePath = writeIndex >= 0 ? args[writeIndex + 1] : null;
|
|
26
|
+
|
|
27
|
+
return { target, writePath };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function main() {
|
|
31
|
+
const { target, writePath } = parseArgs(process.argv);
|
|
32
|
+
|
|
33
|
+
if (!target) {
|
|
34
|
+
usage();
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const snapshot = inspectSessionTarget(target, {
|
|
39
|
+
cwd: process.cwd(),
|
|
40
|
+
adapterId: 'dmux-tmux'
|
|
41
|
+
});
|
|
42
|
+
const json = JSON.stringify(snapshot, null, 2);
|
|
43
|
+
|
|
44
|
+
if (writePath) {
|
|
45
|
+
const absoluteWritePath = path.resolve(writePath);
|
|
46
|
+
fs.mkdirSync(path.dirname(absoluteWritePath), { recursive: true });
|
|
47
|
+
fs.writeFileSync(absoluteWritePath, json + '\n', 'utf8');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log(json);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (require.main === module) {
|
|
54
|
+
try {
|
|
55
|
+
main();
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error(`[orchestration-status] ${error.message}`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = { main };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { repairInstalledStates } = require('./lib/install-lifecycle');
|
|
4
|
+
const { SUPPORTED_INSTALL_TARGETS } = require('./lib/install-manifests');
|
|
5
|
+
|
|
6
|
+
function showHelp(exitCode = 0) {
|
|
7
|
+
console.log(`
|
|
8
|
+
Usage: node scripts/repair.js [--target <${SUPPORTED_INSTALL_TARGETS.join('|')}>] [--dry-run] [--json]
|
|
9
|
+
|
|
10
|
+
Rebuild ECC-managed files recorded in install-state for the current context.
|
|
11
|
+
`);
|
|
12
|
+
process.exit(exitCode);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function parseArgs(argv) {
|
|
16
|
+
const args = argv.slice(2);
|
|
17
|
+
const parsed = {
|
|
18
|
+
targets: [],
|
|
19
|
+
dryRun: false,
|
|
20
|
+
json: false,
|
|
21
|
+
help: false,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
25
|
+
const arg = args[index];
|
|
26
|
+
|
|
27
|
+
if (arg === '--target') {
|
|
28
|
+
parsed.targets.push(args[index + 1] || null);
|
|
29
|
+
index += 1;
|
|
30
|
+
} else if (arg === '--dry-run') {
|
|
31
|
+
parsed.dryRun = true;
|
|
32
|
+
} else if (arg === '--json') {
|
|
33
|
+
parsed.json = true;
|
|
34
|
+
} else if (arg === '--help' || arg === '-h') {
|
|
35
|
+
parsed.help = true;
|
|
36
|
+
} else {
|
|
37
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return parsed;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function printHuman(result) {
|
|
45
|
+
if (result.results.length === 0) {
|
|
46
|
+
console.log('No cc4pm install-state files found for the current home/project context.');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log('Repair summary:\n');
|
|
51
|
+
for (const entry of result.results) {
|
|
52
|
+
console.log(`- ${entry.adapter.id}`);
|
|
53
|
+
console.log(` Status: ${entry.status.toUpperCase()}`);
|
|
54
|
+
console.log(` Install-state: ${entry.installStatePath}`);
|
|
55
|
+
|
|
56
|
+
if (entry.error) {
|
|
57
|
+
console.log(` Error: ${entry.error}`);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const paths = result.dryRun ? entry.plannedRepairs : entry.repairedPaths;
|
|
62
|
+
console.log(` ${result.dryRun ? 'Planned repairs' : 'Repaired paths'}: ${paths.length}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log(`\nSummary: checked=${result.summary.checkedCount}, ${result.dryRun ? 'planned' : 'repaired'}=${result.dryRun ? result.summary.plannedRepairCount : result.summary.repairedCount}, errors=${result.summary.errorCount}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function main() {
|
|
69
|
+
try {
|
|
70
|
+
const options = parseArgs(process.argv);
|
|
71
|
+
if (options.help) {
|
|
72
|
+
showHelp(0);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const result = repairInstalledStates({
|
|
76
|
+
repoRoot: require('path').join(__dirname, '..'),
|
|
77
|
+
homeDir: process.env.HOME,
|
|
78
|
+
projectRoot: process.cwd(),
|
|
79
|
+
targets: options.targets,
|
|
80
|
+
dryRun: options.dryRun,
|
|
81
|
+
});
|
|
82
|
+
const hasErrors = result.summary.errorCount > 0;
|
|
83
|
+
|
|
84
|
+
if (options.json) {
|
|
85
|
+
console.log(JSON.stringify(result, null, 2));
|
|
86
|
+
} else {
|
|
87
|
+
printHuman(result);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
process.exitCode = hasErrors ? 1 : 0;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error(`Error: ${error.message}`);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
main();
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const { createAdapterRegistry, inspectSessionTarget } = require('./lib/session-adapters/registry');
|
|
8
|
+
const { readSkillObservations } = require('./lib/skill-improvement/observations');
|
|
9
|
+
const { buildSkillHealthReport } = require('./lib/skill-improvement/health');
|
|
10
|
+
const { proposeSkillAmendment } = require('./lib/skill-improvement/amendify');
|
|
11
|
+
const { buildSkillEvaluationScaffold } = require('./lib/skill-improvement/evaluate');
|
|
12
|
+
|
|
13
|
+
function usage() {
|
|
14
|
+
console.log([
|
|
15
|
+
'Usage:',
|
|
16
|
+
' node scripts/session-inspect.js <target> [--adapter <id>] [--target-type <type>] [--write <output.json>]',
|
|
17
|
+
' node scripts/session-inspect.js --list-adapters',
|
|
18
|
+
'',
|
|
19
|
+
'Targets:',
|
|
20
|
+
' <plan.json> Dmux/orchestration plan file',
|
|
21
|
+
' <session-name> Dmux session name when the coordination directory exists',
|
|
22
|
+
' claude:latest Most recent Claude session history entry',
|
|
23
|
+
' claude:<id|alias> Specific Claude session or alias',
|
|
24
|
+
' <session.tmp> Direct path to a Claude session file',
|
|
25
|
+
' skills:health Inspect skill failure/success patterns from observations',
|
|
26
|
+
' skills:amendify Propose a SKILL.md patch from failure evidence',
|
|
27
|
+
' skills:evaluate Compare baseline vs amended skill outcomes',
|
|
28
|
+
'',
|
|
29
|
+
'Examples:',
|
|
30
|
+
' node scripts/session-inspect.js .claude/plan/workflow.json',
|
|
31
|
+
' node scripts/session-inspect.js workflow-visual-proof',
|
|
32
|
+
' node scripts/session-inspect.js claude:latest',
|
|
33
|
+
' node scripts/session-inspect.js latest --target-type claude-history',
|
|
34
|
+
' node scripts/session-inspect.js skills:health',
|
|
35
|
+
' node scripts/session-inspect.js skills:amendify --skill api-design',
|
|
36
|
+
' node scripts/session-inspect.js claude:a1b2c3d4 --write /tmp/session.json'
|
|
37
|
+
].join('\n'));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function parseArgs(argv) {
|
|
41
|
+
const args = argv.slice(2);
|
|
42
|
+
const target = args.find(argument => !argument.startsWith('--'));
|
|
43
|
+
const listAdapters = args.includes('--list-adapters');
|
|
44
|
+
|
|
45
|
+
const adapterIndex = args.indexOf('--adapter');
|
|
46
|
+
const adapterId = adapterIndex >= 0 ? args[adapterIndex + 1] : null;
|
|
47
|
+
|
|
48
|
+
const targetTypeIndex = args.indexOf('--target-type');
|
|
49
|
+
const targetType = targetTypeIndex >= 0 ? args[targetTypeIndex + 1] : null;
|
|
50
|
+
|
|
51
|
+
const skillIndex = args.indexOf('--skill');
|
|
52
|
+
const skillId = skillIndex >= 0 ? args[skillIndex + 1] : null;
|
|
53
|
+
|
|
54
|
+
const amendmentIndex = args.indexOf('--amendment-id');
|
|
55
|
+
const amendmentId = amendmentIndex >= 0 ? args[amendmentIndex + 1] : null;
|
|
56
|
+
|
|
57
|
+
const observationsIndex = args.indexOf('--observations');
|
|
58
|
+
const observationsPath = observationsIndex >= 0 ? args[observationsIndex + 1] : null;
|
|
59
|
+
|
|
60
|
+
const writeIndex = args.indexOf('--write');
|
|
61
|
+
const writePath = writeIndex >= 0 ? args[writeIndex + 1] : null;
|
|
62
|
+
|
|
63
|
+
return { target, adapterId, targetType, writePath, listAdapters, skillId, amendmentId, observationsPath };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function inspectSkillLoopTarget(target, options = {}) {
|
|
67
|
+
const observations = readSkillObservations({
|
|
68
|
+
cwd: options.cwd,
|
|
69
|
+
projectRoot: options.cwd,
|
|
70
|
+
observationsPath: options.observationsPath
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
if (target === 'skills:health') {
|
|
74
|
+
return buildSkillHealthReport(observations, {
|
|
75
|
+
skillId: options.skillId || null
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (target === 'skills:amendify') {
|
|
80
|
+
if (!options.skillId) {
|
|
81
|
+
throw new Error('skills:amendify requires --skill <id>');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return proposeSkillAmendment(options.skillId, observations);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (target === 'skills:evaluate') {
|
|
88
|
+
if (!options.skillId) {
|
|
89
|
+
throw new Error('skills:evaluate requires --skill <id>');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return buildSkillEvaluationScaffold(options.skillId, observations, {
|
|
93
|
+
amendmentId: options.amendmentId || null
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function main() {
|
|
101
|
+
const { target, adapterId, targetType, writePath, listAdapters, skillId, amendmentId, observationsPath } = parseArgs(process.argv);
|
|
102
|
+
|
|
103
|
+
if (listAdapters) {
|
|
104
|
+
const registry = createAdapterRegistry();
|
|
105
|
+
console.log(JSON.stringify({ adapters: registry.listAdapters() }, null, 2));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (!target) {
|
|
110
|
+
usage();
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const skillLoopPayload = inspectSkillLoopTarget(target, {
|
|
115
|
+
cwd: process.cwd(),
|
|
116
|
+
skillId,
|
|
117
|
+
amendmentId,
|
|
118
|
+
observationsPath
|
|
119
|
+
});
|
|
120
|
+
const payloadObject = skillLoopPayload || inspectSessionTarget(
|
|
121
|
+
targetType ? { type: targetType, value: target } : target,
|
|
122
|
+
{
|
|
123
|
+
cwd: process.cwd(),
|
|
124
|
+
adapterId
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
const payload = JSON.stringify(payloadObject, null, 2);
|
|
128
|
+
|
|
129
|
+
if (writePath) {
|
|
130
|
+
const absoluteWritePath = path.resolve(writePath);
|
|
131
|
+
fs.mkdirSync(path.dirname(absoluteWritePath), { recursive: true });
|
|
132
|
+
fs.writeFileSync(absoluteWritePath, payload + '\n', 'utf8');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
console.log(payload);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (require.main === module) {
|
|
139
|
+
try {
|
|
140
|
+
main();
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error(`[session-inspect] ${error.message}`);
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = {
|
|
148
|
+
main,
|
|
149
|
+
parseArgs
|
|
150
|
+
};
|