@ryuenn3123/agentic-senior-core 5.8.14 → 5.8.16

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.
@@ -48,6 +48,18 @@
48
48
  "statusMessage": "ASC Pre-tool dependency check (Write)..."
49
49
  }
50
50
  ]
51
+ },
52
+ {
53
+ "matcher": "Bash",
54
+ "hooks": [
55
+ {
56
+ "type": "command",
57
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/pre-tool-dependency-gate.js\"; exit 0",
58
+ "commandWindows": "if (Get-Command node -ErrorAction SilentlyContinue) { node \"$env:CLAUDE_PLUGIN_ROOT\\hooks\\pre-tool-dependency-gate.js\" }",
59
+ "timeout": 5,
60
+ "statusMessage": "ASC Pre-tool dependency check (Bash)..."
61
+ }
62
+ ]
51
63
  }
52
64
  ],
53
65
  "PostToolUse": [
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // Agentic Senior Core — PreToolUse dependency gate hook
3
- // Hard-blocks edits/writes to package.json if new dependencies duplicate stdlib/platform features.
3
+ // Hard-blocks edits/writes to package.json AND shell commands (npm install/yarn add)
4
+ // if new dependencies duplicate stdlib/platform features.
4
5
  // Supports Claude Code hookSpecificOutput permissionDecision deny response format.
5
6
 
6
7
  const fs = require('fs');
@@ -28,21 +29,27 @@ process.stdin.on('end', function () {
28
29
  const data = JSON.parse(inputBuffer);
29
30
  const toolName = data.tool_name || '';
30
31
  const toolInput = data.tool_input || {};
31
- const filePath = toolInput.file_path || '';
32
+ let added = [];
32
33
 
33
- if (!filePath.endsWith('package.json')) {
34
- process.exit(0);
35
- return;
36
- }
34
+ if (toolName === 'Bash') {
35
+ const command = toolInput.command || '';
36
+ added = extractCommandDeps(command);
37
+ } else if (toolName === 'Edit' || toolName === 'Write') {
38
+ const filePath = toolInput.file_path || '';
39
+ if (!filePath.endsWith('package.json')) {
40
+ process.exit(0);
41
+ return;
42
+ }
43
+ const target = toolName === 'Edit' ? (toolInput.new_string || '') : (toolInput.content || '');
44
+ const baseline = toolName === 'Edit' ? (toolInput.old_string || '') : '';
37
45
 
38
- const target = toolName === 'Edit' ? (toolInput.new_string || '') : (toolInput.content || '');
39
- const baseline = toolName === 'Edit' ? (toolInput.old_string || '') : '';
46
+ const depPattern = /"([^"]+)"\s*:\s*"[~^>=<*]?\d/g;
47
+ const newDeps = extractDeps(target, depPattern);
48
+ const oldDeps = extractDeps(baseline, depPattern);
40
49
 
41
- const depPattern = /"([^"]+)"\s*:\s*"[~^>=<*]?\d/g;
42
- const newDeps = extractDeps(target, depPattern);
43
- const oldDeps = extractDeps(baseline, depPattern);
50
+ added = newDeps.filter(function (d) { return oldDeps.indexOf(d) === -1; });
51
+ }
44
52
 
45
- const added = newDeps.filter(function (d) { return oldDeps.indexOf(d) === -1; });
46
53
  if (added.length === 0) {
47
54
  process.exit(0);
48
55
  return;
@@ -84,6 +91,37 @@ function extractDeps(text, pattern) {
84
91
  return matches;
85
92
  }
86
93
 
94
+ function extractCommandDeps(command) {
95
+ const installRegex = /(?:npm|yarn|pnpm|bun|ascx)\s+(?:install|i|add)(?:\s+[^\s]+)*/i;
96
+ if (!installRegex.test(command)) return [];
97
+
98
+ const parts = command.split(/\s+/);
99
+ const pkgIndex = parts.findIndex(p => ['install', 'i', 'add'].includes(p.toLowerCase()));
100
+ if (pkgIndex === -1 || pkgIndex >= parts.length - 1) return [];
101
+
102
+ const rawArgs = parts.slice(pkgIndex + 1);
103
+ const deps = [];
104
+ for (let arg of rawArgs) {
105
+ if (arg.startsWith('-')) continue; // Skip flags like -D, --save-dev
106
+ if (arg.startsWith('http://') || arg.startsWith('https://') || arg.startsWith('git+')) continue;
107
+
108
+ // Remove scope/version if any, e.g. lodash@^4.17 -> lodash, @types/node@18 -> @types/node
109
+ let name = arg;
110
+ if (name.startsWith('@')) {
111
+ const slashIndex = name.indexOf('/');
112
+ if (slashIndex !== -1) {
113
+ const atIndex = name.indexOf('@', slashIndex);
114
+ if (atIndex !== -1) name = name.substring(0, atIndex);
115
+ }
116
+ } else {
117
+ const atIndex = name.indexOf('@');
118
+ if (atIndex !== -1) name = name.substring(0, atIndex);
119
+ }
120
+ if (name) deps.push(name);
121
+ }
122
+ return deps;
123
+ }
124
+
87
125
  function loadAllowlist() {
88
126
  const allowed = new Set();
89
127
  const candidates = [
@@ -1,3 +1,9 @@
1
1
  {
2
- "name": "agentic-senior-core"
2
+ "name": "agentic-senior-core",
3
+ "version": "5.8.16",
4
+ "description": "Universal AI coding rules. Write code like a staff engineer.",
5
+ "contextFileName": "AGENTS.md",
6
+ "commands": ["commands/"],
7
+ "skills": ["skills/"],
8
+ "hooks": "hooks/hooks.json"
3
9
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-senior-core",
3
- "version": "5.8.14",
3
+ "version": "5.8.16",
4
4
  "displayName": "Agentic Senior Core",
5
5
  "description": "Universal AI coding rules. Write code like a staff engineer.",
6
6
  "author": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-senior-core",
3
- "version": "5.8.14",
3
+ "version": "5.8.16",
4
4
  "description": "Universal AI coding rules. Write code like a staff engineer.",
5
5
  "author": {
6
6
  "name": "fatidaprilian",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-senior-core",
3
- "version": "5.8.14",
3
+ "version": "5.8.16",
4
4
  "description": "Universal AI coding rules. Write code like a staff engineer.",
5
5
  "author": {
6
6
  "name": "fatidaprilian",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agentic-senior-core",
3
3
  "description": "Universal AI coding rules. Write code like a staff engineer.",
4
- "version": "5.8.14",
4
+ "version": "5.8.16",
5
5
  "author": {
6
6
  "name": "fatidaprilian",
7
7
  "url": "https://github.com/fatidaprilian"
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "agentic-senior-core",
3
- "version": "5.8.14",
3
+ "version": "5.8.16",
4
4
  "description": "Universal AI coding rules. Write code like a staff engineer.",
5
5
  "author": "fatidaprilian",
6
6
  "license": "MIT",
7
7
  "contextFileName": "AGENTS.md",
8
8
  "commands": ["commands/"],
9
- "skills": ["skills/"]
9
+ "skills": ["skills/"],
10
+ "hooks": "hooks/hooks.json"
10
11
  }
package/hooks/hooks.json CHANGED
@@ -48,6 +48,18 @@
48
48
  "statusMessage": "ASC Pre-tool dependency check (Write)..."
49
49
  }
50
50
  ]
51
+ },
52
+ {
53
+ "matcher": "Bash",
54
+ "hooks": [
55
+ {
56
+ "type": "command",
57
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/pre-tool-dependency-gate.js\"; exit 0",
58
+ "commandWindows": "if (Get-Command node -ErrorAction SilentlyContinue) { node \"$env:CLAUDE_PLUGIN_ROOT\\hooks\\pre-tool-dependency-gate.js\" }",
59
+ "timeout": 5,
60
+ "statusMessage": "ASC Pre-tool dependency check (Bash)..."
61
+ }
62
+ ]
51
63
  }
52
64
  ],
53
65
  "PostToolUse": [
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // Agentic Senior Core — PreToolUse dependency gate hook
3
- // Hard-blocks edits/writes to package.json if new dependencies duplicate stdlib/platform features.
3
+ // Hard-blocks edits/writes to package.json AND shell commands (npm install/yarn add)
4
+ // if new dependencies duplicate stdlib/platform features.
4
5
  // Supports Claude Code hookSpecificOutput permissionDecision deny response format.
5
6
 
6
7
  const fs = require('fs');
@@ -28,21 +29,27 @@ process.stdin.on('end', function () {
28
29
  const data = JSON.parse(inputBuffer);
29
30
  const toolName = data.tool_name || '';
30
31
  const toolInput = data.tool_input || {};
31
- const filePath = toolInput.file_path || '';
32
+ let added = [];
32
33
 
33
- if (!filePath.endsWith('package.json')) {
34
- process.exit(0);
35
- return;
36
- }
34
+ if (toolName === 'Bash') {
35
+ const command = toolInput.command || '';
36
+ added = extractCommandDeps(command);
37
+ } else if (toolName === 'Edit' || toolName === 'Write') {
38
+ const filePath = toolInput.file_path || '';
39
+ if (!filePath.endsWith('package.json')) {
40
+ process.exit(0);
41
+ return;
42
+ }
43
+ const target = toolName === 'Edit' ? (toolInput.new_string || '') : (toolInput.content || '');
44
+ const baseline = toolName === 'Edit' ? (toolInput.old_string || '') : '';
37
45
 
38
- const target = toolName === 'Edit' ? (toolInput.new_string || '') : (toolInput.content || '');
39
- const baseline = toolName === 'Edit' ? (toolInput.old_string || '') : '';
46
+ const depPattern = /"([^"]+)"\s*:\s*"[~^>=<*]?\d/g;
47
+ const newDeps = extractDeps(target, depPattern);
48
+ const oldDeps = extractDeps(baseline, depPattern);
40
49
 
41
- const depPattern = /"([^"]+)"\s*:\s*"[~^>=<*]?\d/g;
42
- const newDeps = extractDeps(target, depPattern);
43
- const oldDeps = extractDeps(baseline, depPattern);
50
+ added = newDeps.filter(function (d) { return oldDeps.indexOf(d) === -1; });
51
+ }
44
52
 
45
- const added = newDeps.filter(function (d) { return oldDeps.indexOf(d) === -1; });
46
53
  if (added.length === 0) {
47
54
  process.exit(0);
48
55
  return;
@@ -84,6 +91,37 @@ function extractDeps(text, pattern) {
84
91
  return matches;
85
92
  }
86
93
 
94
+ function extractCommandDeps(command) {
95
+ const installRegex = /(?:npm|yarn|pnpm|bun|ascx)\s+(?:install|i|add)(?:\s+[^\s]+)*/i;
96
+ if (!installRegex.test(command)) return [];
97
+
98
+ const parts = command.split(/\s+/);
99
+ const pkgIndex = parts.findIndex(p => ['install', 'i', 'add'].includes(p.toLowerCase()));
100
+ if (pkgIndex === -1 || pkgIndex >= parts.length - 1) return [];
101
+
102
+ const rawArgs = parts.slice(pkgIndex + 1);
103
+ const deps = [];
104
+ for (let arg of rawArgs) {
105
+ if (arg.startsWith('-')) continue; // Skip flags like -D, --save-dev
106
+ if (arg.startsWith('http://') || arg.startsWith('https://') || arg.startsWith('git+')) continue;
107
+
108
+ // Remove scope/version if any, e.g. lodash@^4.17 -> lodash, @types/node@18 -> @types/node
109
+ let name = arg;
110
+ if (name.startsWith('@')) {
111
+ const slashIndex = name.indexOf('/');
112
+ if (slashIndex !== -1) {
113
+ const atIndex = name.indexOf('@', slashIndex);
114
+ if (atIndex !== -1) name = name.substring(0, atIndex);
115
+ }
116
+ } else {
117
+ const atIndex = name.indexOf('@');
118
+ if (atIndex !== -1) name = name.substring(0, atIndex);
119
+ }
120
+ if (name) deps.push(name);
121
+ }
122
+ return deps;
123
+ }
124
+
87
125
  function loadAllowlist() {
88
126
  const allowed = new Set();
89
127
  const candidates = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryuenn3123/agentic-senior-core",
3
- "version": "5.8.14",
3
+ "version": "5.8.16",
4
4
  "type": "module",
5
5
  "description": "Agentic Senior Core: Universal AI coding rules and workflows. Write code like a staff engineer, not a junior.",
6
6
  "bin": {
package/plugin.yaml CHANGED
@@ -1,5 +1,5 @@
1
1
  name: agentic-senior-core
2
- version: 5.8.14
2
+ version: 5.8.16
3
3
  description: Universal AI coding rules. Write code like a staff engineer.
4
4
  author: fatidaprilian
5
5
  provides_hooks:
@@ -8,11 +8,17 @@ provides_commands:
8
8
  - asc-refactor
9
9
  - asc-review
10
10
  - asc-audit
11
+ - asc-new-project
12
+ - asc-add-feature
13
+ - asc-adapter
11
14
  - asc-help
12
15
  provides_skills:
13
16
  - asc
14
- - asc-refactor
15
- - asc-review
17
+ - asc-adapter
18
+ - asc-add-feature
16
19
  - asc-audit
17
20
  - asc-debt
21
+ - asc-new-project
22
+ - asc-refactor
18
23
  - asc-reference
24
+ - asc-review