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.
Files changed (108) hide show
  1. package/.claude-plugin/README.md +17 -0
  2. package/.claude-plugin/plugin.json +25 -0
  3. package/LICENSE +21 -0
  4. package/README.md +157 -0
  5. package/README.zh-CN.md +134 -0
  6. package/contexts/dev.md +20 -0
  7. package/contexts/research.md +26 -0
  8. package/contexts/review.md +22 -0
  9. package/examples/CLAUDE.md +100 -0
  10. package/examples/statusline.json +19 -0
  11. package/examples/user-CLAUDE.md +109 -0
  12. package/install.sh +17 -0
  13. package/manifests/install-components.json +173 -0
  14. package/manifests/install-modules.json +335 -0
  15. package/manifests/install-profiles.json +75 -0
  16. package/package.json +117 -0
  17. package/schemas/ecc-install-config.schema.json +58 -0
  18. package/schemas/hooks.schema.json +197 -0
  19. package/schemas/install-components.schema.json +56 -0
  20. package/schemas/install-modules.schema.json +105 -0
  21. package/schemas/install-profiles.schema.json +45 -0
  22. package/schemas/install-state.schema.json +210 -0
  23. package/schemas/package-manager.schema.json +23 -0
  24. package/schemas/plugin.schema.json +58 -0
  25. package/scripts/ci/catalog.js +83 -0
  26. package/scripts/ci/validate-agents.js +81 -0
  27. package/scripts/ci/validate-commands.js +135 -0
  28. package/scripts/ci/validate-hooks.js +239 -0
  29. package/scripts/ci/validate-install-manifests.js +211 -0
  30. package/scripts/ci/validate-no-personal-paths.js +63 -0
  31. package/scripts/ci/validate-rules.js +81 -0
  32. package/scripts/ci/validate-skills.js +54 -0
  33. package/scripts/claw.js +468 -0
  34. package/scripts/doctor.js +110 -0
  35. package/scripts/ecc.js +194 -0
  36. package/scripts/hooks/auto-tmux-dev.js +88 -0
  37. package/scripts/hooks/check-console-log.js +71 -0
  38. package/scripts/hooks/check-hook-enabled.js +12 -0
  39. package/scripts/hooks/cost-tracker.js +78 -0
  40. package/scripts/hooks/doc-file-warning.js +63 -0
  41. package/scripts/hooks/evaluate-session.js +100 -0
  42. package/scripts/hooks/insaits-security-monitor.py +269 -0
  43. package/scripts/hooks/insaits-security-wrapper.js +88 -0
  44. package/scripts/hooks/post-bash-build-complete.js +27 -0
  45. package/scripts/hooks/post-bash-pr-created.js +36 -0
  46. package/scripts/hooks/post-edit-console-warn.js +54 -0
  47. package/scripts/hooks/post-edit-format.js +109 -0
  48. package/scripts/hooks/post-edit-typecheck.js +96 -0
  49. package/scripts/hooks/pre-bash-dev-server-block.js +187 -0
  50. package/scripts/hooks/pre-bash-git-push-reminder.js +28 -0
  51. package/scripts/hooks/pre-bash-tmux-reminder.js +33 -0
  52. package/scripts/hooks/pre-compact.js +48 -0
  53. package/scripts/hooks/pre-write-doc-warn.js +9 -0
  54. package/scripts/hooks/quality-gate.js +168 -0
  55. package/scripts/hooks/run-with-flags-shell.sh +32 -0
  56. package/scripts/hooks/run-with-flags.js +120 -0
  57. package/scripts/hooks/session-end-marker.js +15 -0
  58. package/scripts/hooks/session-end.js +299 -0
  59. package/scripts/hooks/session-start.js +97 -0
  60. package/scripts/hooks/suggest-compact.js +80 -0
  61. package/scripts/install-apply.js +137 -0
  62. package/scripts/install-plan.js +254 -0
  63. package/scripts/lib/hook-flags.js +74 -0
  64. package/scripts/lib/install/apply.js +23 -0
  65. package/scripts/lib/install/config.js +82 -0
  66. package/scripts/lib/install/request.js +113 -0
  67. package/scripts/lib/install/runtime.js +42 -0
  68. package/scripts/lib/install-executor.js +605 -0
  69. package/scripts/lib/install-lifecycle.js +763 -0
  70. package/scripts/lib/install-manifests.js +305 -0
  71. package/scripts/lib/install-state.js +120 -0
  72. package/scripts/lib/install-targets/antigravity-project.js +9 -0
  73. package/scripts/lib/install-targets/claude-home.js +10 -0
  74. package/scripts/lib/install-targets/codex-home.js +10 -0
  75. package/scripts/lib/install-targets/cursor-project.js +10 -0
  76. package/scripts/lib/install-targets/helpers.js +89 -0
  77. package/scripts/lib/install-targets/opencode-home.js +10 -0
  78. package/scripts/lib/install-targets/registry.js +64 -0
  79. package/scripts/lib/orchestration-session.js +299 -0
  80. package/scripts/lib/package-manager.d.ts +119 -0
  81. package/scripts/lib/package-manager.js +431 -0
  82. package/scripts/lib/project-detect.js +428 -0
  83. package/scripts/lib/resolve-formatter.js +185 -0
  84. package/scripts/lib/session-adapters/canonical-session.js +138 -0
  85. package/scripts/lib/session-adapters/claude-history.js +149 -0
  86. package/scripts/lib/session-adapters/dmux-tmux.js +80 -0
  87. package/scripts/lib/session-adapters/registry.js +111 -0
  88. package/scripts/lib/session-aliases.d.ts +136 -0
  89. package/scripts/lib/session-aliases.js +481 -0
  90. package/scripts/lib/session-manager.d.ts +131 -0
  91. package/scripts/lib/session-manager.js +464 -0
  92. package/scripts/lib/shell-split.js +86 -0
  93. package/scripts/lib/skill-improvement/amendify.js +89 -0
  94. package/scripts/lib/skill-improvement/evaluate.js +59 -0
  95. package/scripts/lib/skill-improvement/health.js +118 -0
  96. package/scripts/lib/skill-improvement/observations.js +108 -0
  97. package/scripts/lib/tmux-worktree-orchestrator.js +491 -0
  98. package/scripts/lib/utils.d.ts +183 -0
  99. package/scripts/lib/utils.js +543 -0
  100. package/scripts/list-installed.js +90 -0
  101. package/scripts/orchestrate-codex-worker.sh +92 -0
  102. package/scripts/orchestrate-worktrees.js +108 -0
  103. package/scripts/orchestration-status.js +62 -0
  104. package/scripts/repair.js +97 -0
  105. package/scripts/session-inspect.js +150 -0
  106. package/scripts/setup-package-manager.js +204 -0
  107. package/scripts/skill-create-output.js +244 -0
  108. package/scripts/uninstall.js +96 -0
@@ -0,0 +1,211 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Validate selective-install manifests and profile/module relationships.
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const Ajv = require('ajv');
9
+
10
+ const REPO_ROOT = path.join(__dirname, '../..');
11
+ const MODULES_MANIFEST_PATH = path.join(REPO_ROOT, 'manifests/install-modules.json');
12
+ const PROFILES_MANIFEST_PATH = path.join(REPO_ROOT, 'manifests/install-profiles.json');
13
+ const COMPONENTS_MANIFEST_PATH = path.join(REPO_ROOT, 'manifests/install-components.json');
14
+ const MODULES_SCHEMA_PATH = path.join(REPO_ROOT, 'schemas/install-modules.schema.json');
15
+ const PROFILES_SCHEMA_PATH = path.join(REPO_ROOT, 'schemas/install-profiles.schema.json');
16
+ const COMPONENTS_SCHEMA_PATH = path.join(REPO_ROOT, 'schemas/install-components.schema.json');
17
+ const COMPONENT_FAMILY_PREFIXES = {
18
+ baseline: 'baseline:',
19
+ language: 'lang:',
20
+ framework: 'framework:',
21
+ capability: 'capability:',
22
+ };
23
+
24
+ function readJson(filePath, label) {
25
+ try {
26
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
27
+ } catch (error) {
28
+ throw new Error(`Invalid JSON in ${label}: ${error.message}`);
29
+ }
30
+ }
31
+
32
+ function normalizeRelativePath(relativePath) {
33
+ return String(relativePath).replace(/\\/g, '/').replace(/\/+$/, '');
34
+ }
35
+
36
+ function validateSchema(ajv, schemaPath, data, label) {
37
+ const schema = readJson(schemaPath, `${label} schema`);
38
+ const validate = ajv.compile(schema);
39
+ const valid = validate(data);
40
+
41
+ if (!valid) {
42
+ for (const error of validate.errors) {
43
+ console.error(
44
+ `ERROR: ${label} schema: ${error.instancePath || '/'} ${error.message}`
45
+ );
46
+ }
47
+ return true;
48
+ }
49
+
50
+ return false;
51
+ }
52
+
53
+ function validateInstallManifests() {
54
+ if (!fs.existsSync(MODULES_MANIFEST_PATH) || !fs.existsSync(PROFILES_MANIFEST_PATH)) {
55
+ console.log('Install manifests not found, skipping validation');
56
+ process.exit(0);
57
+ }
58
+
59
+ let hasErrors = false;
60
+ let modulesData;
61
+ let profilesData;
62
+ let componentsData = { version: null, components: [] };
63
+
64
+ try {
65
+ modulesData = readJson(MODULES_MANIFEST_PATH, 'install-modules.json');
66
+ profilesData = readJson(PROFILES_MANIFEST_PATH, 'install-profiles.json');
67
+ if (fs.existsSync(COMPONENTS_MANIFEST_PATH)) {
68
+ componentsData = readJson(COMPONENTS_MANIFEST_PATH, 'install-components.json');
69
+ }
70
+ } catch (error) {
71
+ console.error(`ERROR: ${error.message}`);
72
+ process.exit(1);
73
+ }
74
+
75
+ const ajv = new Ajv({ allErrors: true });
76
+ hasErrors = validateSchema(ajv, MODULES_SCHEMA_PATH, modulesData, 'install-modules.json') || hasErrors;
77
+ hasErrors = validateSchema(ajv, PROFILES_SCHEMA_PATH, profilesData, 'install-profiles.json') || hasErrors;
78
+ if (fs.existsSync(COMPONENTS_MANIFEST_PATH)) {
79
+ hasErrors = validateSchema(ajv, COMPONENTS_SCHEMA_PATH, componentsData, 'install-components.json') || hasErrors;
80
+ }
81
+
82
+ if (hasErrors) {
83
+ process.exit(1);
84
+ }
85
+
86
+ const modules = Array.isArray(modulesData.modules) ? modulesData.modules : [];
87
+ const moduleIds = new Set();
88
+ const claimedPaths = new Map();
89
+
90
+ for (const module of modules) {
91
+ if (moduleIds.has(module.id)) {
92
+ console.error(`ERROR: Duplicate install module id: ${module.id}`);
93
+ hasErrors = true;
94
+ }
95
+ moduleIds.add(module.id);
96
+
97
+ for (const dependency of module.dependencies) {
98
+ if (!moduleIds.has(dependency) && !modules.some(candidate => candidate.id === dependency)) {
99
+ console.error(`ERROR: Module ${module.id} depends on unknown module ${dependency}`);
100
+ hasErrors = true;
101
+ }
102
+ if (dependency === module.id) {
103
+ console.error(`ERROR: Module ${module.id} cannot depend on itself`);
104
+ hasErrors = true;
105
+ }
106
+ }
107
+
108
+ for (const relativePath of module.paths) {
109
+ const normalizedPath = normalizeRelativePath(relativePath);
110
+ const absolutePath = path.join(REPO_ROOT, normalizedPath);
111
+
112
+ if (!fs.existsSync(absolutePath)) {
113
+ console.error(
114
+ `ERROR: Module ${module.id} references missing path: ${normalizedPath}`
115
+ );
116
+ hasErrors = true;
117
+ }
118
+
119
+ if (claimedPaths.has(normalizedPath)) {
120
+ console.error(
121
+ `ERROR: Install path ${normalizedPath} is claimed by both ${claimedPaths.get(normalizedPath)} and ${module.id}`
122
+ );
123
+ hasErrors = true;
124
+ } else {
125
+ claimedPaths.set(normalizedPath, module.id);
126
+ }
127
+ }
128
+ }
129
+
130
+ const profiles = profilesData.profiles || {};
131
+ const components = Array.isArray(componentsData.components) ? componentsData.components : [];
132
+ const expectedProfileIds = ['core', 'developer', 'security', 'research', 'full'];
133
+
134
+ for (const profileId of expectedProfileIds) {
135
+ if (!profiles[profileId]) {
136
+ console.error(`ERROR: Missing required install profile: ${profileId}`);
137
+ hasErrors = true;
138
+ }
139
+ }
140
+
141
+ for (const [profileId, profile] of Object.entries(profiles)) {
142
+ const seenModules = new Set();
143
+ for (const moduleId of profile.modules) {
144
+ if (!moduleIds.has(moduleId)) {
145
+ console.error(
146
+ `ERROR: Profile ${profileId} references unknown module ${moduleId}`
147
+ );
148
+ hasErrors = true;
149
+ }
150
+
151
+ if (seenModules.has(moduleId)) {
152
+ console.error(
153
+ `ERROR: Profile ${profileId} contains duplicate module ${moduleId}`
154
+ );
155
+ hasErrors = true;
156
+ }
157
+ seenModules.add(moduleId);
158
+ }
159
+ }
160
+
161
+ if (profiles.full) {
162
+ const fullModules = new Set(profiles.full.modules);
163
+ for (const moduleId of moduleIds) {
164
+ if (!fullModules.has(moduleId)) {
165
+ console.error(`ERROR: full profile is missing module ${moduleId}`);
166
+ hasErrors = true;
167
+ }
168
+ }
169
+ }
170
+
171
+ const componentIds = new Set();
172
+ for (const component of components) {
173
+ if (componentIds.has(component.id)) {
174
+ console.error(`ERROR: Duplicate install component id: ${component.id}`);
175
+ hasErrors = true;
176
+ }
177
+ componentIds.add(component.id);
178
+
179
+ const expectedPrefix = COMPONENT_FAMILY_PREFIXES[component.family];
180
+ if (expectedPrefix && !component.id.startsWith(expectedPrefix)) {
181
+ console.error(
182
+ `ERROR: Component ${component.id} does not match expected ${component.family} prefix ${expectedPrefix}`
183
+ );
184
+ hasErrors = true;
185
+ }
186
+
187
+ const seenModules = new Set();
188
+ for (const moduleId of component.modules) {
189
+ if (!moduleIds.has(moduleId)) {
190
+ console.error(`ERROR: Component ${component.id} references unknown module ${moduleId}`);
191
+ hasErrors = true;
192
+ }
193
+
194
+ if (seenModules.has(moduleId)) {
195
+ console.error(`ERROR: Component ${component.id} contains duplicate module ${moduleId}`);
196
+ hasErrors = true;
197
+ }
198
+ seenModules.add(moduleId);
199
+ }
200
+ }
201
+
202
+ if (hasErrors) {
203
+ process.exit(1);
204
+ }
205
+
206
+ console.log(
207
+ `Validated ${modules.length} install modules, ${components.length} install components, and ${Object.keys(profiles).length} profiles`
208
+ );
209
+ }
210
+
211
+ validateInstallManifests();
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Prevent shipping user-specific absolute paths in public docs/skills/commands.
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ const ROOT = path.join(__dirname, '../..');
12
+ const TARGETS = [
13
+ 'README.md',
14
+ 'skills',
15
+ 'commands',
16
+ 'agents',
17
+ 'docs',
18
+ '.opencode/commands',
19
+ ];
20
+
21
+ const BLOCK_PATTERNS = [
22
+ /\/Users\/affoon\b/g,
23
+ /C:\\Users\\affoon\b/gi,
24
+ ];
25
+
26
+ function collectFiles(targetPath, out) {
27
+ if (!fs.existsSync(targetPath)) return;
28
+ const stat = fs.statSync(targetPath);
29
+ if (stat.isFile()) {
30
+ out.push(targetPath);
31
+ return;
32
+ }
33
+
34
+ for (const entry of fs.readdirSync(targetPath)) {
35
+ if (entry === 'node_modules' || entry === '.git') continue;
36
+ collectFiles(path.join(targetPath, entry), out);
37
+ }
38
+ }
39
+
40
+ const files = [];
41
+ for (const target of TARGETS) {
42
+ collectFiles(path.join(ROOT, target), files);
43
+ }
44
+
45
+ let failures = 0;
46
+ for (const file of files) {
47
+ if (!/\.(md|json|js|ts|sh|toml|yml|yaml)$/i.test(file)) continue;
48
+ const content = fs.readFileSync(file, 'utf8');
49
+ for (const pattern of BLOCK_PATTERNS) {
50
+ const match = content.match(pattern);
51
+ if (match) {
52
+ console.error(`ERROR: personal path detected in ${path.relative(ROOT, file)}`);
53
+ failures += match.length;
54
+ break;
55
+ }
56
+ }
57
+ }
58
+
59
+ if (failures > 0) {
60
+ process.exit(1);
61
+ }
62
+
63
+ console.log('Validated: no personal absolute paths in shipped docs/skills/commands');
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Validate rule markdown files
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ const RULES_DIR = path.join(__dirname, '../../rules');
10
+
11
+ /**
12
+ * Recursively collect markdown rule files.
13
+ * Uses explicit traversal for portability across Node versions.
14
+ * @param {string} dir - Directory to scan
15
+ * @returns {string[]} Relative file paths from RULES_DIR
16
+ */
17
+ function collectRuleFiles(dir) {
18
+ const files = [];
19
+
20
+ let entries;
21
+ try {
22
+ entries = fs.readdirSync(dir, { withFileTypes: true });
23
+ } catch {
24
+ return files;
25
+ }
26
+
27
+ for (const entry of entries) {
28
+ const absolute = path.join(dir, entry.name);
29
+
30
+ if (entry.isDirectory()) {
31
+ files.push(...collectRuleFiles(absolute));
32
+ continue;
33
+ }
34
+
35
+ if (entry.name.endsWith('.md')) {
36
+ files.push(path.relative(RULES_DIR, absolute));
37
+ }
38
+
39
+ // Non-markdown files are ignored.
40
+ }
41
+
42
+ return files;
43
+ }
44
+
45
+ function validateRules() {
46
+ if (!fs.existsSync(RULES_DIR)) {
47
+ console.log('No rules directory found, skipping validation');
48
+ process.exit(0);
49
+ }
50
+
51
+ const files = collectRuleFiles(RULES_DIR);
52
+ let hasErrors = false;
53
+ let validatedCount = 0;
54
+
55
+ for (const file of files) {
56
+ const filePath = path.join(RULES_DIR, file);
57
+ try {
58
+ const stat = fs.statSync(filePath);
59
+ if (!stat.isFile()) continue;
60
+
61
+ const content = fs.readFileSync(filePath, 'utf-8');
62
+ if (content.trim().length === 0) {
63
+ console.error(`ERROR: ${file} - Empty rule file`);
64
+ hasErrors = true;
65
+ continue;
66
+ }
67
+ validatedCount++;
68
+ } catch (err) {
69
+ console.error(`ERROR: ${file} - ${err.message}`);
70
+ hasErrors = true;
71
+ }
72
+ }
73
+
74
+ if (hasErrors) {
75
+ process.exit(1);
76
+ }
77
+
78
+ console.log(`Validated ${validatedCount} rule files`);
79
+ }
80
+
81
+ validateRules();
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Validate skill directories have SKILL.md with required structure
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ const SKILLS_DIR = path.join(__dirname, '../../skills');
10
+
11
+ function validateSkills() {
12
+ if (!fs.existsSync(SKILLS_DIR)) {
13
+ console.log('No skills directory found, skipping validation');
14
+ process.exit(0);
15
+ }
16
+
17
+ const entries = fs.readdirSync(SKILLS_DIR, { withFileTypes: true });
18
+ const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
19
+ let hasErrors = false;
20
+ let validCount = 0;
21
+
22
+ for (const dir of dirs) {
23
+ const skillMd = path.join(SKILLS_DIR, dir, 'SKILL.md');
24
+ if (!fs.existsSync(skillMd)) {
25
+ console.error(`ERROR: ${dir}/ - Missing SKILL.md`);
26
+ hasErrors = true;
27
+ continue;
28
+ }
29
+
30
+ let content;
31
+ try {
32
+ content = fs.readFileSync(skillMd, 'utf-8');
33
+ } catch (err) {
34
+ console.error(`ERROR: ${dir}/SKILL.md - ${err.message}`);
35
+ hasErrors = true;
36
+ continue;
37
+ }
38
+ if (content.trim().length === 0) {
39
+ console.error(`ERROR: ${dir}/SKILL.md - Empty file`);
40
+ hasErrors = true;
41
+ continue;
42
+ }
43
+
44
+ validCount++;
45
+ }
46
+
47
+ if (hasErrors) {
48
+ process.exit(1);
49
+ }
50
+
51
+ console.log(`Validated ${validCount} skill directories`);
52
+ }
53
+
54
+ validateSkills();