@ryuenn3123/agentic-senior-core 2.0.0 → 2.0.2

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.
@@ -0,0 +1,8 @@
1
+ {
2
+ "schemaVersion": "compatibility-manifest-v1",
3
+ "artifactType": "skill-domain",
4
+ "domain": "backend",
5
+ "ides": ["cursor", "windsurf", "copilot", "gemini", "claude", "codex", "cline"],
6
+ "nodeMin": "18",
7
+ "platforms": ["windows", "linux", "macos"]
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "schemaVersion": "compatibility-manifest-v1",
3
+ "artifactType": "skill-domain",
4
+ "domain": "cli",
5
+ "ides": ["cursor", "windsurf", "copilot", "gemini", "claude", "codex", "cline"],
6
+ "nodeMin": "18",
7
+ "platforms": ["windows", "linux", "macos"]
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "schemaVersion": "compatibility-manifest-v1",
3
+ "artifactType": "skill-domain",
4
+ "domain": "distribution",
5
+ "ides": ["cursor", "windsurf", "copilot", "gemini", "claude", "codex", "cline"],
6
+ "nodeMin": "18",
7
+ "platforms": ["windows", "linux", "macos"]
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "schemaVersion": "compatibility-manifest-v1",
3
+ "artifactType": "skill-domain",
4
+ "domain": "frontend",
5
+ "ides": ["cursor", "windsurf", "copilot", "gemini", "claude", "codex", "cline"],
6
+ "nodeMin": "18",
7
+ "platforms": ["windows", "linux", "macos"]
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "schemaVersion": "compatibility-manifest-v1",
3
+ "artifactType": "skill-domain",
4
+ "domain": "fullstack",
5
+ "ides": ["cursor", "windsurf", "copilot", "gemini", "claude", "codex", "cline"],
6
+ "nodeMin": "18",
7
+ "platforms": ["windows", "linux", "macos"]
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "schemaVersion": "compatibility-manifest-v1",
3
+ "artifactType": "skill-domain",
4
+ "domain": "review-quality",
5
+ "ides": ["cursor", "windsurf", "copilot", "gemini", "claude", "codex", "cline"],
6
+ "nodeMin": "18",
7
+ "platforms": ["windows", "linux", "macos"]
8
+ }
@@ -1,13 +1,13 @@
1
1
  {
2
- "cliVersion": "2.0.0",
3
- "generatedAt": "2026-04-08T03:56:54.149Z",
2
+ "cliVersion": "2.0.1",
3
+ "generatedAt": "2026-04-08T14:58:53.636Z",
4
4
  "operationMode": "upgrade",
5
5
  "selectedProfile": "beginner",
6
6
  "selectedProfilePack": null,
7
7
  "selectedStack": "typescript.md",
8
8
  "selectedBlueprint": "api-nextjs.md",
9
9
  "ciGuardrailsEnabled": true,
10
- "setupDurationMs": 86,
10
+ "setupDurationMs": 106,
11
11
  "selectedSkillDomains": [],
12
12
  "autoDetection": {
13
13
  "recommendedStack": "typescript.md",
package/.cursorrules CHANGED
@@ -1,7 +1,7 @@
1
1
  # AGENTIC-SENIOR-CORE DYNAMIC GOVERNANCE RULESET
2
2
 
3
- Generated by Agentic-Senior-Core CLI v2.0.0
4
- Timestamp: 2026-04-08T03:56:54.094Z
3
+ Generated by Agentic-Senior-Core CLI v2.0.2
4
+ Timestamp: 2026-04-08T14:58:53.570Z
5
5
  Selected profile: beginner
6
6
  Selected policy file: .agent-context/policies/llm-judge-threshold.json
7
7
 
package/.windsurfrules CHANGED
@@ -1,7 +1,7 @@
1
1
  # AGENTIC-SENIOR-CORE DYNAMIC GOVERNANCE RULESET
2
2
 
3
- Generated by Agentic-Senior-Core CLI v2.0.0
4
- Timestamp: 2026-04-08T03:56:54.094Z
3
+ Generated by Agentic-Senior-Core CLI v2.0.2
4
+ Timestamp: 2026-04-08T14:58:53.570Z
5
5
  Selected profile: beginner
6
6
  Selected policy file: .agent-context/policies/llm-judge-threshold.json
7
7
 
package/README.md CHANGED
@@ -103,7 +103,7 @@ If you have an existing project and want to infuse it with Staff-level context:
103
103
  npx @ryuenn3123/agentic-senior-core init
104
104
  ```
105
105
 
106
- Use team defaults (V1.8 track) with profile packs:
106
+ Use team defaults (V2.0 track) with profile packs:
107
107
 
108
108
  ```bash
109
109
  npx @ryuenn3123/agentic-senior-core init --profile-pack startup
@@ -128,6 +128,27 @@ agentic-senior-core skill fullstack --json
128
128
 
129
129
  When you run `init`, the CLI now auto-activates the matching skill packs for the chosen stack and blueprint, so the compiled governance context includes the relevant frontend, backend, fullstack, and CLI guidance by default.
130
130
 
131
+ ### Token Optimization Mode (Optional and User-Friendly)
132
+
133
+ Use this mode when your AI session is shell-heavy and context usage is high.
134
+ It is optional by design and works in two modes:
135
+ - Native fallback mode (no external dependency required)
136
+ - External proxy mode (auto-detected when available)
137
+
138
+ Quick start:
139
+
140
+ ```bash
141
+ agentic-senior-core optimize . --agent copilot --enable
142
+ agentic-senior-core optimize . --show
143
+ agentic-senior-core optimize . --disable
144
+
145
+ # Auto-enable during project initialization
146
+ npx @ryuenn3123/agentic-senior-core init --token-optimize --token-agent copilot
147
+ ```
148
+
149
+ When enabled, the CLI writes `.agent-context/state/token-optimization.json`, regenerates compiled rules, and adds compact command guidance to `.cursorrules` and `.windsurfrules`.
150
+ If an external token proxy is available, the CLI prints setup hints. If not, native fallback guidance stays active, so outside users are not forced to install extra tooling.
151
+
131
152
  ### Install and Setup Choices
132
153
 
133
154
  The CLI now supports a smaller decision surface for first-time setup:
@@ -139,6 +160,7 @@ The CLI now supports a smaller decision surface for first-time setup:
139
160
  | npm exec / npx | One-off setup on an existing repo |
140
161
  | npm install -g | Repeated local use from the shell |
141
162
  | `--preset` | Fast bootstrap with a curated stack and blueprint |
163
+ | `optimize` | Optional token-aware shell output guidance with native fallback |
142
164
 
143
165
  ### Supported Stack Map
144
166
 
@@ -170,7 +192,7 @@ Use the stack that matches the project you are actually starting:
170
192
  ### Option 4: Clone and Play
171
193
  Want to poke around under the hood? Just clone the repo and `npx @ryuenn3123/agentic-senior-core init` locally. No runtime dependencies needed — everything uses native Node.js!
172
194
 
173
- ### Upgrade Existing Governance Packs (V1.8)
195
+ ### Upgrade Existing Governance Packs (V1.x to V2.x)
174
196
 
175
197
  Yes, the upgrade flow still works. Use `--dry-run` first to preview changes, then apply with `--yes` when you are ready.
176
198
 
@@ -201,7 +223,8 @@ Our documentation has shifted into dedicated tracks to keep this README light:
201
223
 
202
224
  ## Core Capabilities
203
225
 
204
- - **Delivery Engine (CLI):** Interactive setup via GitHub source, bootstrap scripts, or `npx` after publish.
226
+ - **Delivery Engine (CLI):** Interactive setup via GitHub source, bootstrap scripts, or `npx` after publish. Supported by a robust transactional installer with rollback protection.
227
+ - **Verified Skill Marketplace:** Distribute and validate plugins securely with automated 4-dimension Trust Scoring and Evidence Bundles constraint validation.
205
228
  - **Dynamic Context Compiler:** Merges universal rules + selected stack + selected blueprint + optional CI guardrails into one dense, indexed rule file.
206
229
  - **Codebase Intelligence:** `.agent-context/state/` gives architecture/dependency boundaries so the agent understands high-risk areas.
207
230
  - **Override System:** `.agent-override.md` allows controlled enterprise exceptions without forking core rules.
@@ -11,6 +11,7 @@ import { CLI_VERSION } from '../lib/cli/constants.mjs';
11
11
  import { printUsage } from '../lib/cli/utils.mjs';
12
12
  import { runLaunchCommand } from '../lib/cli/commands/launch.mjs';
13
13
  import { runRollbackCommand } from '../lib/cli/commands/rollback.mjs';
14
+ import { runOptimizeCommand, parseOptimizeArguments } from '../lib/cli/commands/optimize.mjs';
14
15
  import { runInitCommand, parseInitArguments } from '../lib/cli/commands/init.mjs';
15
16
  import { runUpgradeCommand, parseUpgradeArguments } from '../lib/cli/commands/upgrade.mjs';
16
17
  import { runSkillCommand } from '../lib/cli/skill-selector.mjs';
@@ -45,6 +46,12 @@ async function main() {
45
46
  return;
46
47
  }
47
48
 
49
+ if (commandArgument === 'optimize') {
50
+ const optimizeOptions = parseOptimizeArguments(commandArguments);
51
+ await runOptimizeCommand(optimizeOptions.targetDirectory, optimizeOptions);
52
+ return;
53
+ }
54
+
48
55
  if (commandArgument === 'init') {
49
56
  const initOptions = parseInitArguments(commandArguments);
50
57
  await runInitCommand(initOptions.targetDirectory, initOptions);
@@ -35,6 +35,13 @@ import { compileDynamicContext, writeSelectedPolicy, writeOnboardingReport } fro
35
35
  import { runPreflightChecks } from '../preflight.mjs';
36
36
  import { createBackup } from '../backup.mjs';
37
37
  import { performRollback } from '../rollback.mjs';
38
+ import {
39
+ createTokenOptimizationState,
40
+ detectRtkBinary,
41
+ normalizeAgentName,
42
+ writeTokenOptimizationState,
43
+ } from '../token-optimization.mjs';
44
+ import { evaluateSkillDomainCompatibility } from '../compatibility.mjs';
38
45
 
39
46
  export { REPO_ROOT } from '../constants.mjs';
40
47
 
@@ -48,6 +55,8 @@ export function parseInitArguments(commandArguments) {
48
55
  blueprint: undefined,
49
56
  ci: undefined,
50
57
  newbie: false,
58
+ tokenOptimize: false,
59
+ tokenAgent: 'copilot',
51
60
  };
52
61
 
53
62
  for (let argumentIndex = 0; argumentIndex < commandArguments.length; argumentIndex++) {
@@ -130,6 +139,29 @@ export function parseInitArguments(commandArguments) {
130
139
  continue;
131
140
  }
132
141
 
142
+ if (currentArgument === '--token-optimize') {
143
+ parsedInitOptions.tokenOptimize = true;
144
+ continue;
145
+ }
146
+
147
+ if (currentArgument === '--token-agent') {
148
+ parsedInitOptions.tokenAgent = commandArguments[argumentIndex + 1] || 'copilot';
149
+ parsedInitOptions.tokenOptimize = true;
150
+ argumentIndex += 1;
151
+ continue;
152
+ }
153
+
154
+ if (currentArgument.startsWith('--token-agent=')) {
155
+ parsedInitOptions.tokenAgent = currentArgument.split('=')[1] || 'copilot';
156
+ parsedInitOptions.tokenOptimize = true;
157
+ continue;
158
+ }
159
+
160
+ if (currentArgument === '--no-token-optimize') {
161
+ parsedInitOptions.tokenOptimize = false;
162
+ continue;
163
+ }
164
+
133
165
  throw new Error(`Unknown option: ${currentArgument}`);
134
166
  }
135
167
 
@@ -137,11 +169,21 @@ export function parseInitArguments(commandArguments) {
137
169
  throw new Error('--newbie can only be combined with --profile beginner');
138
170
  }
139
171
 
172
+ parsedInitOptions.tokenAgent = normalizeAgentName(parsedInitOptions.tokenAgent);
173
+
140
174
  return parsedInitOptions;
141
175
  }
142
176
 
143
177
  export async function runInitCommand(targetDirectoryArgument, initOptions = {}) {
144
178
  const resolvedTargetDirectoryPath = path.resolve(targetDirectoryArgument || '.');
179
+
180
+ if (resolvedTargetDirectoryPath.toLowerCase() === 'c:\\windows' || resolvedTargetDirectoryPath.toLowerCase() === 'c:\\windows\\system32') {
181
+ console.error('\n[FATAL] Target directory resolved to a Windows system folder (C:\\Windows).');
182
+ console.error('If you are running Windows npm from inside WSL, this is caused by cmd.exe lacking UNC path support.');
183
+ console.error('Please install and use a native Linux Node.js/npm directly inside WSL to setup your project.');
184
+ process.exit(1);
185
+ }
186
+
145
187
  const setupStartedAt = Date.now();
146
188
  await ensureDirectory(resolvedTargetDirectoryPath);
147
189
 
@@ -287,6 +329,11 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
287
329
  )
288
330
  ];
289
331
 
332
+ const selectedSkillDomainNames = inferSkillDomainNamesFromSelection(
333
+ selectedResolvedStackFileName,
334
+ selectedResolvedBlueprintFileName
335
+ );
336
+
290
337
  const includeCiGuardrails = typeof initOptions.ci === 'boolean'
291
338
  ? initOptions.ci
292
339
  : typeof selectedPreset?.ci === 'boolean'
@@ -301,6 +348,33 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
301
348
 
302
349
  await copyGovernanceAssetsToTarget(resolvedTargetDirectoryPath);
303
350
 
351
+ if (initOptions.tokenOptimize) {
352
+ const detectedExternalProxy = detectRtkBinary();
353
+ const tokenOptimizationState = createTokenOptimizationState({
354
+ isEnabled: true,
355
+ selectedAgentName: initOptions.tokenAgent,
356
+ rtkDetection: detectedExternalProxy,
357
+ });
358
+
359
+ await writeTokenOptimizationState(resolvedTargetDirectoryPath, tokenOptimizationState);
360
+ console.log(
361
+ `Token optimization policy enabled for agent ${tokenOptimizationState.selectedAgent} (${tokenOptimizationState.preferredShellProxy}).`
362
+ );
363
+ }
364
+
365
+ const compatibilityWarnings = await evaluateSkillDomainCompatibility(
366
+ resolvedTargetDirectoryPath,
367
+ selectedSkillDomainNames
368
+ );
369
+
370
+ if (compatibilityWarnings.length > 0) {
371
+ console.log('\n[WARN] Compatibility checks reported potential issues for this environment:');
372
+ for (const compatibilityWarning of compatibilityWarnings) {
373
+ console.log(`- ${compatibilityWarning}`);
374
+ }
375
+ console.log('Installation will continue, but review these warnings before production use.');
376
+ }
377
+
304
378
  await compileDynamicContext({
305
379
  targetDirectoryPath: resolvedTargetDirectoryPath,
306
380
  selectedProfileName,
@@ -323,7 +397,8 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
323
397
  includeCiGuardrails,
324
398
  setupDurationMs,
325
399
  projectDetection,
326
- selectedSkillDomains: inferSkillDomainNamesFromSelection(selectedResolvedStackFileName, selectedResolvedBlueprintFileName),
400
+ selectedSkillDomains: selectedSkillDomainNames,
401
+ compatibilityWarnings,
327
402
  operationMode: 'init',
328
403
  });
329
404
 
@@ -342,6 +417,9 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
342
417
  console.log(`- Blocking severities: ${formatBlockingSeverities(selectedProfile.blockingSeverities)}`);
343
418
  console.log(`- Setup time: ${formatDuration(setupDurationMs)}`);
344
419
  console.log('- Generated files: .cursorrules, .windsurfrules, and .agent-context/state/onboarding-report.json');
420
+ if (initOptions.tokenOptimize) {
421
+ console.log(`- Token optimization policy: enabled for ${initOptions.tokenAgent}`);
422
+ }
345
423
  console.log('\nPlain-language summary:');
346
424
  console.log(`I prepared a ${selectedProfile.displayName.toLowerCase()} governance pack for a ${toTitleCase(selectedResolvedStackFileName)} project using the ${toTitleCase(selectedResolvedBlueprintFileName)} blueprint.`);
347
425
  console.log('Your AI tools will now receive one compiled rulebook plus the original source rules, and your review threshold is stored in .agent-context/policies/llm-judge-threshold.json.');
@@ -9,6 +9,7 @@ import { CLI_VERSION, INIT_PRESETS } from '../constants.mjs';
9
9
  import { askChoice, normalizeChoiceInput } from '../utils.mjs';
10
10
  import { runInitCommand } from './init.mjs';
11
11
  import { runSkillCommand } from '../skill-selector.mjs';
12
+ import { runOptimizeCommand } from './optimize.mjs';
12
13
 
13
14
  export async function runLaunchCommand() {
14
15
  const userInterface = createInterface({ input: stdin, output: stdout });
@@ -25,6 +26,7 @@ export async function runLaunchCommand() {
25
26
  'Bootstrap scripts',
26
27
  'Preset starter',
27
28
  'Interactive init wizard',
29
+ 'Enable token optimization',
28
30
  'Skill selector',
29
31
  'Exit',
30
32
  ],
@@ -69,6 +71,21 @@ export async function runLaunchCommand() {
69
71
  return;
70
72
  }
71
73
 
74
+ if (launchChoice === 'Enable token optimization') {
75
+ const selectedAgent = await askChoice(
76
+ 'Choose your primary agent integration:',
77
+ ['copilot', 'claude', 'cursor', 'windsurf', 'gemini', 'codex', 'cline'],
78
+ userInterface
79
+ );
80
+
81
+ await runOptimizeCommand('.', {
82
+ targetDirectory: '.',
83
+ agent: selectedAgent,
84
+ enabled: true,
85
+ });
86
+ return;
87
+ }
88
+
72
89
  if (launchChoice === 'Skill selector') {
73
90
  await runSkillCommand([]);
74
91
  return;
@@ -0,0 +1,171 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
4
+ import { ensureDirectory, formatDuration } from '../utils.mjs';
5
+ import { compileDynamicContext, loadOnboardingReportIfExists } from '../compiler.mjs';
6
+ import {
7
+ TOKEN_OPTIMIZATION_REPORT_FILE_NAME,
8
+ normalizeAgentName,
9
+ detectRtkBinary,
10
+ buildRtkInstallHint,
11
+ buildRtkHookCommand,
12
+ createTokenOptimizationState,
13
+ readTokenOptimizationState,
14
+ writeTokenOptimizationState,
15
+ } from '../token-optimization.mjs';
16
+
17
+ function normalizeMarkdownFileName(rawFileName, fallbackFileName) {
18
+ if (typeof rawFileName !== 'string' || rawFileName.trim().length === 0) {
19
+ return fallbackFileName;
20
+ }
21
+
22
+ const normalizedFileName = rawFileName.trim();
23
+ return normalizedFileName.endsWith('.md')
24
+ ? normalizedFileName
25
+ : `${normalizedFileName}.md`;
26
+ }
27
+
28
+ export function parseOptimizeArguments(commandArguments) {
29
+ const parsedOptimizeOptions = {
30
+ targetDirectory: '.',
31
+ agent: 'copilot',
32
+ enabled: true,
33
+ show: false,
34
+ };
35
+
36
+ for (let argumentIndex = 0; argumentIndex < commandArguments.length; argumentIndex++) {
37
+ const currentArgument = commandArguments[argumentIndex];
38
+
39
+ if (!currentArgument.startsWith('--')) {
40
+ parsedOptimizeOptions.targetDirectory = currentArgument;
41
+ continue;
42
+ }
43
+
44
+ if (currentArgument === '--agent') {
45
+ parsedOptimizeOptions.agent = commandArguments[argumentIndex + 1] || 'copilot';
46
+ argumentIndex += 1;
47
+ continue;
48
+ }
49
+
50
+ if (currentArgument.startsWith('--agent=')) {
51
+ parsedOptimizeOptions.agent = currentArgument.split('=')[1] || 'copilot';
52
+ continue;
53
+ }
54
+
55
+ if (currentArgument === '--enable') {
56
+ parsedOptimizeOptions.enabled = true;
57
+ continue;
58
+ }
59
+
60
+ if (currentArgument === '--disable') {
61
+ parsedOptimizeOptions.enabled = false;
62
+ continue;
63
+ }
64
+
65
+ if (currentArgument === '--show') {
66
+ parsedOptimizeOptions.show = true;
67
+ continue;
68
+ }
69
+
70
+ throw new Error(`Unknown option: ${currentArgument}`);
71
+ }
72
+
73
+ parsedOptimizeOptions.agent = normalizeAgentName(parsedOptimizeOptions.agent);
74
+ return parsedOptimizeOptions;
75
+ }
76
+
77
+ export async function runOptimizeCommand(targetDirectoryArgument, optimizeOptions = {}) {
78
+ const optimizationStartedAt = Date.now();
79
+ const resolvedTargetDirectoryPath = path.resolve(targetDirectoryArgument || '.');
80
+
81
+ await ensureDirectory(resolvedTargetDirectoryPath);
82
+
83
+ const selectedAgentName = normalizeAgentName(optimizeOptions.agent || 'copilot');
84
+ const rtkDetection = detectRtkBinary();
85
+
86
+ if (optimizeOptions.show) {
87
+ const existingOptimizationState = await readTokenOptimizationState(resolvedTargetDirectoryPath);
88
+ console.log(
89
+ JSON.stringify(
90
+ {
91
+ targetDirectory: resolvedTargetDirectoryPath,
92
+ selectedAgent: selectedAgentName,
93
+ externalProxy: rtkDetection,
94
+ tokenOptimizationState: existingOptimizationState,
95
+ },
96
+ null,
97
+ 2
98
+ )
99
+ );
100
+ return;
101
+ }
102
+
103
+ const onboardingReport = await loadOnboardingReportIfExists(resolvedTargetDirectoryPath);
104
+ if (!onboardingReport) {
105
+ throw new Error(
106
+ 'Token optimization requires an initialized repository. Run "agentic-senior-core init" first.'
107
+ );
108
+ }
109
+
110
+ const tokenOptimizationState = createTokenOptimizationState({
111
+ isEnabled: optimizeOptions.enabled,
112
+ selectedAgentName,
113
+ rtkDetection,
114
+ });
115
+
116
+ await writeTokenOptimizationState(resolvedTargetDirectoryPath, tokenOptimizationState);
117
+
118
+ const selectedProfileName = typeof onboardingReport.selectedProfile === 'string'
119
+ ? onboardingReport.selectedProfile
120
+ : 'balanced';
121
+ const selectedStackFileName = normalizeMarkdownFileName(onboardingReport.selectedStack, 'typescript.md');
122
+ const selectedBlueprintFileName = normalizeMarkdownFileName(onboardingReport.selectedBlueprint, 'api-nextjs.md');
123
+ const includeCiGuardrails = typeof onboardingReport.ciGuardrailsEnabled === 'boolean'
124
+ ? onboardingReport.ciGuardrailsEnabled
125
+ : true;
126
+
127
+ await compileDynamicContext({
128
+ targetDirectoryPath: resolvedTargetDirectoryPath,
129
+ selectedProfileName,
130
+ selectedStackFileName,
131
+ selectedBlueprintFileName,
132
+ includeCiGuardrails,
133
+ });
134
+
135
+ const optimizationDurationMs = Date.now() - optimizationStartedAt;
136
+ const tokenOptimizationReport = {
137
+ generatedAt: new Date().toISOString(),
138
+ targetDirectory: resolvedTargetDirectoryPath,
139
+ enabled: tokenOptimizationState.enabled,
140
+ selectedAgent: tokenOptimizationState.selectedAgent,
141
+ preferredShellProxy: tokenOptimizationState.preferredShellProxy,
142
+ externalProxy: tokenOptimizationState.externalProxy,
143
+ setupDurationMs: optimizationDurationMs,
144
+ };
145
+
146
+ const reportFilePath = path.join(
147
+ resolvedTargetDirectoryPath,
148
+ '.agent-context',
149
+ 'state',
150
+ TOKEN_OPTIMIZATION_REPORT_FILE_NAME
151
+ );
152
+ await fs.writeFile(reportFilePath, JSON.stringify(tokenOptimizationReport, null, 2) + '\n', 'utf8');
153
+
154
+ console.log(`\nToken optimization ${tokenOptimizationState.enabled ? 'enabled' : 'disabled'}.`);
155
+ console.log(`- Target directory: ${resolvedTargetDirectoryPath}`);
156
+ console.log(`- Agent profile: ${tokenOptimizationState.selectedAgent}`);
157
+ console.log(`- Preferred shell proxy: ${tokenOptimizationState.preferredShellProxy}`);
158
+ console.log(`- Setup time: ${formatDuration(optimizationDurationMs)}`);
159
+ console.log('- Updated files: .cursorrules, .windsurfrules, .agent-context/state/token-optimization.json');
160
+
161
+ if (tokenOptimizationState.enabled) {
162
+ if (rtkDetection.isAvailable) {
163
+ console.log(`- External proxy detected: ${rtkDetection.version ? `v${rtkDetection.version}` : 'yes'}`);
164
+ console.log('- Recommended hook command:');
165
+ console.log(` ${buildRtkHookCommand(tokenOptimizationState.selectedAgent)}`);
166
+ } else {
167
+ console.log('- External proxy not detected. Native fallback mode has been activated.');
168
+ console.log(`- Install hint: ${buildRtkInstallHint()}`);
169
+ }
170
+ }
171
+ }
@@ -15,6 +15,13 @@ export async function runRollbackCommand(commandArguments) {
15
15
  }
16
16
 
17
17
  const resolvedTargetDirectoryPath = path.resolve(targetDirectoryArgument);
18
+
19
+ if (resolvedTargetDirectoryPath.toLowerCase() === 'c:\\windows' || resolvedTargetDirectoryPath.toLowerCase() === 'c:\\windows\\system32') {
20
+ console.error('\n[FATAL] Target directory resolved to a Windows system folder (C:\\Windows).');
21
+ console.error('If you are running Windows npm from inside WSL, this is caused by cmd.exe lacking UNC path support.');
22
+ console.error('Please install and use a native Linux Node.js/npm directly inside WSL to setup your project.');
23
+ process.exit(1);
24
+ }
18
25
 
19
26
  try {
20
27
  await ensureDirectory(resolvedTargetDirectoryPath);
@@ -35,6 +35,8 @@ import {
35
35
  import { runPreflightChecks } from '../preflight.mjs';
36
36
  import { createBackup } from '../backup.mjs';
37
37
  import { performRollback } from '../rollback.mjs';
38
+ import { inferSkillDomainNamesFromSelection } from '../skill-selector.mjs';
39
+ import { evaluateSkillDomainCompatibility } from '../compatibility.mjs';
38
40
 
39
41
  export function parseUpgradeArguments(commandArguments) {
40
42
  const parsedUpgradeOptions = {
@@ -69,6 +71,14 @@ export function parseUpgradeArguments(commandArguments) {
69
71
 
70
72
  export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions = {}) {
71
73
  const resolvedTargetDirectoryPath = path.resolve(targetDirectoryArgument || '.');
74
+
75
+ if (resolvedTargetDirectoryPath.toLowerCase() === 'c:\\windows' || resolvedTargetDirectoryPath.toLowerCase() === 'c:\\windows\\system32') {
76
+ console.error('\n[FATAL] Target directory resolved to a Windows system folder (C:\\Windows).');
77
+ console.error('If you are running Windows npm from inside WSL, this is caused by cmd.exe lacking UNC path support.');
78
+ console.error('Please install and use a native Linux Node.js/npm directly inside WSL to setup your project.');
79
+ process.exit(1);
80
+ }
81
+
72
82
  const setupStartedAt = Date.now();
73
83
  await ensureDirectory(resolvedTargetDirectoryPath);
74
84
 
@@ -108,6 +118,23 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
108
118
  ? existingOnboardingReport.ciGuardrailsEnabled
109
119
  : true;
110
120
 
121
+ const selectedSkillDomainNames = inferSkillDomainNamesFromSelection(
122
+ selectedStackFileName,
123
+ selectedBlueprintFileName
124
+ );
125
+ const compatibilityWarnings = await evaluateSkillDomainCompatibility(
126
+ resolvedTargetDirectoryPath,
127
+ selectedSkillDomainNames
128
+ );
129
+
130
+ if (compatibilityWarnings.length > 0) {
131
+ console.log('\n[WARN] Compatibility checks reported potential issues for this environment:');
132
+ for (const compatibilityWarning of compatibilityWarnings) {
133
+ console.log(`- ${compatibilityWarning}`);
134
+ }
135
+ console.log('Upgrade will continue, but review these warnings before production use.');
136
+ }
137
+
111
138
  const currentRulesPath = path.join(resolvedTargetDirectoryPath, '.cursorrules');
112
139
  const currentRulesContent = await pathExists(currentRulesPath)
113
140
  ? await fs.readFile(currentRulesPath, 'utf8')
@@ -166,6 +193,8 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
166
193
  includeCiGuardrails,
167
194
  setupDurationMs,
168
195
  projectDetection,
196
+ selectedSkillDomains: selectedSkillDomainNames,
197
+ compatibilityWarnings,
169
198
  operationMode: 'upgrade',
170
199
  });
171
200
 
@@ -0,0 +1,124 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { platform, version } from 'node:process';
4
+
5
+ import { pathExists } from './utils.mjs';
6
+
7
+ export const SKILL_COMPATIBILITY_MANIFEST_FILE_NAME = 'compatibility-manifest.json';
8
+
9
+ export function getCurrentPlatformLabel() {
10
+ if (platform === 'win32') {
11
+ return 'windows';
12
+ }
13
+
14
+ if (platform === 'darwin') {
15
+ return 'macos';
16
+ }
17
+
18
+ return 'linux';
19
+ }
20
+
21
+ export function parseNodeMajorVersion(rawVersionString = version) {
22
+ const normalizedVersionString = String(rawVersionString || '').trim();
23
+ const numericVersion = normalizedVersionString.startsWith('v')
24
+ ? normalizedVersionString.slice(1)
25
+ : normalizedVersionString;
26
+
27
+ const majorSegment = numericVersion.split('.')[0];
28
+ const parsedMajorVersion = Number.parseInt(majorSegment, 10);
29
+ return Number.isNaN(parsedMajorVersion) ? null : parsedMajorVersion;
30
+ }
31
+
32
+ export function parseNodeMinimumMajor(rawNodeMinimum) {
33
+ const normalizedNodeMinimum = String(rawNodeMinimum || '').trim();
34
+ if (!normalizedNodeMinimum) {
35
+ return null;
36
+ }
37
+
38
+ const majorSegment = normalizedNodeMinimum.split('.')[0];
39
+ const parsedMajorVersion = Number.parseInt(majorSegment, 10);
40
+ return Number.isNaN(parsedMajorVersion) ? null : parsedMajorVersion;
41
+ }
42
+
43
+ export async function readSkillDomainCompatibilityManifest(targetDirectoryPath, skillDomainName) {
44
+ const compatibilityManifestPath = path.join(
45
+ targetDirectoryPath,
46
+ '.agent-context',
47
+ 'skills',
48
+ skillDomainName,
49
+ SKILL_COMPATIBILITY_MANIFEST_FILE_NAME
50
+ );
51
+
52
+ if (!(await pathExists(compatibilityManifestPath))) {
53
+ return {
54
+ exists: false,
55
+ compatibilityManifestPath,
56
+ parsedManifest: null,
57
+ };
58
+ }
59
+
60
+ try {
61
+ const compatibilityManifestContent = await fs.readFile(compatibilityManifestPath, 'utf8');
62
+ return {
63
+ exists: true,
64
+ compatibilityManifestPath,
65
+ parsedManifest: JSON.parse(compatibilityManifestContent),
66
+ };
67
+ } catch (error) {
68
+ return {
69
+ exists: true,
70
+ compatibilityManifestPath,
71
+ parsedManifest: null,
72
+ parseError: error instanceof Error ? error.message : String(error),
73
+ };
74
+ }
75
+ }
76
+
77
+ export async function evaluateSkillDomainCompatibility(targetDirectoryPath, skillDomainNames) {
78
+ const uniqueSkillDomainNames = Array.from(new Set(skillDomainNames || []));
79
+ const compatibilityWarnings = [];
80
+
81
+ const currentPlatformLabel = getCurrentPlatformLabel();
82
+ const currentNodeMajorVersion = parseNodeMajorVersion(version);
83
+
84
+ for (const skillDomainName of uniqueSkillDomainNames) {
85
+ const manifestResult = await readSkillDomainCompatibilityManifest(targetDirectoryPath, skillDomainName);
86
+
87
+ if (!manifestResult.exists) {
88
+ compatibilityWarnings.push(
89
+ `Domain ${skillDomainName} has no ${SKILL_COMPATIBILITY_MANIFEST_FILE_NAME}; compatibility cannot be verified.`
90
+ );
91
+ continue;
92
+ }
93
+
94
+ if (!manifestResult.parsedManifest) {
95
+ compatibilityWarnings.push(
96
+ `Domain ${skillDomainName} has invalid ${SKILL_COMPATIBILITY_MANIFEST_FILE_NAME}: ${manifestResult.parseError || 'Unknown parse error'}.`
97
+ );
98
+ continue;
99
+ }
100
+
101
+ const manifestPlatforms = Array.isArray(manifestResult.parsedManifest.platforms)
102
+ ? manifestResult.parsedManifest.platforms
103
+ : [];
104
+
105
+ if (manifestPlatforms.length > 0 && !manifestPlatforms.includes(currentPlatformLabel)) {
106
+ compatibilityWarnings.push(
107
+ `Domain ${skillDomainName} does not list platform ${currentPlatformLabel} in ${SKILL_COMPATIBILITY_MANIFEST_FILE_NAME}.`
108
+ );
109
+ }
110
+
111
+ const minimumNodeMajorVersion = parseNodeMinimumMajor(manifestResult.parsedManifest.nodeMin);
112
+ if (
113
+ typeof minimumNodeMajorVersion === 'number'
114
+ && typeof currentNodeMajorVersion === 'number'
115
+ && currentNodeMajorVersion < minimumNodeMajorVersion
116
+ ) {
117
+ compatibilityWarnings.push(
118
+ `Domain ${skillDomainName} requires Node.js >= ${minimumNodeMajorVersion}, current major version is ${currentNodeMajorVersion}.`
119
+ );
120
+ }
121
+ }
122
+
123
+ return compatibilityWarnings;
124
+ }
@@ -21,6 +21,11 @@ import {
21
21
  buildSkillPackSection,
22
22
  } from './skill-selector.mjs';
23
23
 
24
+ import {
25
+ readTokenOptimizationState,
26
+ buildTokenOptimizationGuidanceBlock,
27
+ } from './token-optimization.mjs';
28
+
24
29
  export async function writeSelectedPolicy(targetDirectoryPath, selectedProfileName) {
25
30
  const policyFilePath = path.join(targetDirectoryPath, '.agent-context', 'policies', POLICY_FILE_NAME);
26
31
  const parsedPolicy = JSON.parse(await fs.readFile(policyFilePath, 'utf8'));
@@ -39,6 +44,7 @@ export async function writeOnboardingReport({
39
44
  setupDurationMs,
40
45
  projectDetection,
41
46
  selectedSkillDomains = [],
47
+ compatibilityWarnings = [],
42
48
  operationMode = 'init',
43
49
  }) {
44
50
  const onboardingReportPath = path.join(targetDirectoryPath, '.agent-context', 'state', 'onboarding-report.json');
@@ -59,6 +65,7 @@ export async function writeOnboardingReport({
59
65
  ciGuardrailsEnabled: includeCiGuardrails,
60
66
  setupDurationMs,
61
67
  selectedSkillDomains,
68
+ compatibilityWarnings,
62
69
  autoDetection: {
63
70
  recommendedStack: projectDetection.recommendedStackFileName,
64
71
  recommendedBlueprint: projectDetection.recommendedBlueprintFileName,
@@ -136,6 +143,13 @@ export async function buildCompiledRulesContent({
136
143
  );
137
144
  }
138
145
 
146
+ const tokenOptimizationState = await readTokenOptimizationState(resolvedTargetDirectoryPath);
147
+ if (tokenOptimizationState?.enabled) {
148
+ contextBlocks.push(
149
+ `## TOKEN OPTIMIZATION PROFILE\nSource: .agent-context/state/token-optimization.json\n\n${buildTokenOptimizationGuidanceBlock(tokenOptimizationState).trim()}`
150
+ );
151
+ }
152
+
139
153
  for (const selectedSkillDomainName of selectedSkillDomainNames) {
140
154
  const skillDomainEntry = skillPlatformIndex.domains?.[selectedSkillDomainName];
141
155
  if (!skillDomainEntry) {
@@ -0,0 +1,275 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { spawnSync } from 'node:child_process';
4
+ import { platform } from 'node:process';
5
+
6
+ import { pathExists } from './utils.mjs';
7
+
8
+ export const TOKEN_OPTIMIZATION_STATE_FILE_NAME = 'token-optimization.json';
9
+ export const TOKEN_OPTIMIZATION_REPORT_FILE_NAME = 'token-optimization-report.json';
10
+
11
+ const TOKEN_OPTIMIZATION_SCHEMA_VERSION = 'token-optimization-v1';
12
+ const FALLBACK_AGENT_NAME = 'copilot';
13
+
14
+ const SUPPORTED_AGENT_NAMES = new Set([
15
+ 'copilot',
16
+ 'claude',
17
+ 'cursor',
18
+ 'windsurf',
19
+ 'gemini',
20
+ 'codex',
21
+ 'cline',
22
+ ]);
23
+
24
+ const COMMAND_REWRITE_MAPPINGS = [
25
+ {
26
+ rawCommand: 'ls -la',
27
+ optimizedCommand: 'rtk ls .',
28
+ reason: 'Directory listings are grouped and compacted before entering the model context.',
29
+ },
30
+ {
31
+ rawCommand: 'tree',
32
+ optimizedCommand: 'rtk ls .',
33
+ reason: 'Large trees are summarized without losing high-signal structure.',
34
+ },
35
+ {
36
+ rawCommand: 'cat file.ext',
37
+ optimizedCommand: 'rtk read file.ext',
38
+ reason: 'File reads keep signatures and relevant lines while trimming boilerplate.',
39
+ },
40
+ {
41
+ rawCommand: 'rg pattern .',
42
+ optimizedCommand: 'rtk grep "pattern" .',
43
+ reason: 'Search hits are grouped and deduplicated for faster reasoning.',
44
+ },
45
+ {
46
+ rawCommand: 'git status',
47
+ optimizedCommand: 'rtk git status',
48
+ reason: 'Status output is condensed to actionable file changes.',
49
+ },
50
+ {
51
+ rawCommand: 'git diff',
52
+ optimizedCommand: 'rtk git diff',
53
+ reason: 'Diff noise is trimmed while preserving code-review context.',
54
+ },
55
+ {
56
+ rawCommand: 'git log -n 10',
57
+ optimizedCommand: 'rtk git log -n 10',
58
+ reason: 'History is converted to compact one-line summaries.',
59
+ },
60
+ {
61
+ rawCommand: 'npm test',
62
+ optimizedCommand: 'rtk test npm test',
63
+ reason: 'Test results emphasize failures and suppress repetitive pass logs.',
64
+ },
65
+ {
66
+ rawCommand: 'npm run build',
67
+ optimizedCommand: 'rtk err npm run build',
68
+ reason: 'Build runs return errors and warnings only for quicker remediation.',
69
+ },
70
+ {
71
+ rawCommand: 'tsc --noEmit',
72
+ optimizedCommand: 'rtk tsc',
73
+ reason: 'TypeScript diagnostics are grouped by file with less repetition.',
74
+ },
75
+ {
76
+ rawCommand: 'eslint .',
77
+ optimizedCommand: 'rtk lint',
78
+ reason: 'Lint output is grouped by rule and location to reduce token churn.',
79
+ },
80
+ {
81
+ rawCommand: 'docker ps',
82
+ optimizedCommand: 'rtk docker ps',
83
+ reason: 'Container state is summarized into compact rows.',
84
+ },
85
+ {
86
+ rawCommand: 'kubectl get pods',
87
+ optimizedCommand: 'rtk kubectl pods',
88
+ reason: 'Kubernetes output is condensed and stable for agent consumption.',
89
+ },
90
+ ];
91
+
92
+ function parseRtkVersion(versionOutput) {
93
+ const versionMatch = versionOutput.match(/\d+\.\d+\.\d+/);
94
+ return versionMatch ? versionMatch[0] : null;
95
+ }
96
+
97
+ export function normalizeAgentName(rawAgentName = FALLBACK_AGENT_NAME) {
98
+ const normalizedAgentName = String(rawAgentName || '')
99
+ .trim()
100
+ .toLowerCase();
101
+
102
+ if (!normalizedAgentName) {
103
+ return FALLBACK_AGENT_NAME;
104
+ }
105
+
106
+ if (!SUPPORTED_AGENT_NAMES.has(normalizedAgentName)) {
107
+ throw new Error(
108
+ `Unsupported agent "${rawAgentName}". Supported values: ${Array.from(SUPPORTED_AGENT_NAMES).join(', ')}`
109
+ );
110
+ }
111
+
112
+ return normalizedAgentName;
113
+ }
114
+
115
+ export function detectRtkBinary() {
116
+ try {
117
+ const versionResult = spawnSync('rtk', ['--version'], {
118
+ encoding: 'utf8',
119
+ stdio: ['ignore', 'pipe', 'pipe'],
120
+ });
121
+
122
+ if (versionResult.status !== 0) {
123
+ return {
124
+ isAvailable: false,
125
+ version: null,
126
+ detectionError: (versionResult.stderr || versionResult.stdout || 'Unknown external proxy detection error').trim(),
127
+ };
128
+ }
129
+
130
+ const detectedVersion = parseRtkVersion(versionResult.stdout || '');
131
+ return {
132
+ isAvailable: true,
133
+ version: detectedVersion,
134
+ detectionError: null,
135
+ };
136
+ } catch (detectionError) {
137
+ return {
138
+ isAvailable: false,
139
+ version: null,
140
+ detectionError: detectionError instanceof Error ? detectionError.message : String(detectionError),
141
+ };
142
+ }
143
+ }
144
+
145
+ export function buildRtkInstallHint() {
146
+ if (platform === 'win32') {
147
+ return 'Install the external token optimizer binary for Windows, extract it, and ensure the executable is on PATH.';
148
+ }
149
+
150
+ if (platform === 'darwin') {
151
+ return 'Install the external token optimizer with Homebrew, then verify the executable is available in your shell.';
152
+ }
153
+
154
+ return 'Install the external token optimizer with the vendor installer, then verify it is available in your shell PATH.';
155
+ }
156
+
157
+ export function buildRtkHookCommand(selectedAgentName) {
158
+ const normalizedAgentName = normalizeAgentName(selectedAgentName);
159
+
160
+ if (normalizedAgentName === 'copilot') {
161
+ return 'rtk init -g --copilot';
162
+ }
163
+
164
+ if (normalizedAgentName === 'claude') {
165
+ return 'rtk init -g';
166
+ }
167
+
168
+ if (normalizedAgentName === 'cursor') {
169
+ return 'rtk init -g --agent cursor';
170
+ }
171
+
172
+ if (normalizedAgentName === 'windsurf') {
173
+ return 'rtk init --agent windsurf';
174
+ }
175
+
176
+ if (normalizedAgentName === 'gemini') {
177
+ return 'rtk init -g --gemini';
178
+ }
179
+
180
+ if (normalizedAgentName === 'codex') {
181
+ return 'rtk init -g --codex';
182
+ }
183
+
184
+ if (normalizedAgentName === 'cline') {
185
+ return 'rtk init --agent cline';
186
+ }
187
+
188
+ return 'rtk init -g --copilot';
189
+ }
190
+
191
+ export function createTokenOptimizationState({
192
+ isEnabled,
193
+ selectedAgentName,
194
+ rtkDetection,
195
+ }) {
196
+ return {
197
+ schemaVersion: TOKEN_OPTIMIZATION_SCHEMA_VERSION,
198
+ enabled: Boolean(isEnabled),
199
+ selectedAgent: normalizeAgentName(selectedAgentName),
200
+ preferredShellProxy: rtkDetection.isAvailable ? 'external-proxy' : 'native-fallback',
201
+ externalProxy: {
202
+ detected: Boolean(rtkDetection.isAvailable),
203
+ version: rtkDetection.version,
204
+ detectionError: rtkDetection.detectionError,
205
+ },
206
+ commandRewriteMappings: COMMAND_REWRITE_MAPPINGS.map((mapping) => ({ ...mapping })),
207
+ generatedAt: new Date().toISOString(),
208
+ };
209
+ }
210
+
211
+ export async function readTokenOptimizationState(targetDirectoryPath) {
212
+ const stateFilePath = path.join(
213
+ targetDirectoryPath,
214
+ '.agent-context',
215
+ 'state',
216
+ TOKEN_OPTIMIZATION_STATE_FILE_NAME
217
+ );
218
+
219
+ if (!(await pathExists(stateFilePath))) {
220
+ return null;
221
+ }
222
+
223
+ try {
224
+ const stateContent = await fs.readFile(stateFilePath, 'utf8');
225
+ const parsedState = JSON.parse(stateContent);
226
+ if (typeof parsedState.enabled !== 'boolean') {
227
+ return null;
228
+ }
229
+ return parsedState;
230
+ } catch {
231
+ return null;
232
+ }
233
+ }
234
+
235
+ export async function writeTokenOptimizationState(targetDirectoryPath, tokenOptimizationState) {
236
+ const stateDirectoryPath = path.join(targetDirectoryPath, '.agent-context', 'state');
237
+ const stateFilePath = path.join(stateDirectoryPath, TOKEN_OPTIMIZATION_STATE_FILE_NAME);
238
+
239
+ await fs.mkdir(stateDirectoryPath, { recursive: true });
240
+ await fs.writeFile(stateFilePath, JSON.stringify(tokenOptimizationState, null, 2) + '\n', 'utf8');
241
+ }
242
+
243
+ export function buildTokenOptimizationGuidanceBlock(tokenOptimizationState) {
244
+ if (!tokenOptimizationState?.enabled) {
245
+ return [
246
+ 'Token optimization mode is disabled for this repository.',
247
+ 'Use native shell commands with manual output limiting when needed.',
248
+ ].join('\n');
249
+ }
250
+
251
+ const rewriteLines = (tokenOptimizationState.commandRewriteMappings || []).map(
252
+ (mapping) => `- ${mapping.rawCommand} => ${mapping.optimizedCommand} (${mapping.reason})`
253
+ );
254
+
255
+ const fallbackGuidance = [
256
+ '- Prefer command variants with bounded output (for example: git diff --stat, rg --max-count, and npm test -- --reporter=dot).',
257
+ '- Request only the lines or sections required for the current decision.',
258
+ '- If shell output is still large, summarize and continue iteratively instead of dumping full logs.',
259
+ ];
260
+
261
+ return [
262
+ `Token optimization mode is enabled for agent: ${tokenOptimizationState.selectedAgent}.`,
263
+ `Preferred shell proxy: ${tokenOptimizationState.preferredShellProxy}.`,
264
+ '',
265
+ 'Apply command rewrites before running verbose shell commands:',
266
+ ...rewriteLines,
267
+ '',
268
+ 'Important scope note:',
269
+ '- Shell rewrite hooks affect shell tool calls only.',
270
+ '- Built-in read/grep/glob style tools may bypass shell rewrites, so explicit compact shell commands should be preferred in high-volume sessions.',
271
+ '',
272
+ 'Fallback behavior when external proxy is unavailable:',
273
+ ...fallbackGuidance,
274
+ ].join('\n');
275
+ }
package/lib/cli/utils.mjs CHANGED
@@ -25,8 +25,9 @@ export function printUsage() {
25
25
  console.log('');
26
26
  console.log('Usage:');
27
27
  console.log(' agentic-senior-core launch');
28
- console.log(' agentic-senior-core init [target-directory] [--preset <name>] [--profile <beginner|balanced|strict>] [--profile-pack <name>] [--stack <name>] [--blueprint <name>] [--ci <true|false>] [--newbie]');
28
+ console.log(' agentic-senior-core init [target-directory] [--preset <name>] [--profile <beginner|balanced|strict>] [--profile-pack <name>] [--stack <name>] [--blueprint <name>] [--ci <true|false>] [--newbie] [--token-optimize] [--token-agent <name>]');
29
29
  console.log(' agentic-senior-core upgrade [target-directory] [--dry-run] [--yes]');
30
+ console.log(' agentic-senior-core optimize [target-directory] [--agent <copilot|claude|cursor|windsurf|gemini|codex|cline>] [--enable|--disable] [--show]');
30
31
  console.log(' agentic-senior-core rollback [target-directory]');
31
32
  console.log(' agentic-senior-core skill [domain] [--tier <standard|advance|expert|above>] [--json]');
32
33
  console.log(' agentic-senior-core --version');
@@ -41,8 +42,15 @@ export function printUsage() {
41
42
  console.log(' --stack Override stack selection');
42
43
  console.log(' --blueprint Override blueprint selection');
43
44
  console.log(' --ci Override CI/CD guardrails (true|false)');
45
+ console.log(' --token-optimize Enable token optimization policy during init');
46
+ console.log(' --token-agent Set token optimization agent target (copilot, claude, cursor, windsurf, gemini, codex, cline)');
47
+ console.log(' --no-token-optimize Disable token optimization even if token-agent is provided');
44
48
  console.log(' --dry-run Preview upgrade without writing files');
45
49
  console.log(' --yes Skip confirmation prompts for upgrade');
50
+ console.log(' --agent Target agent integration for token optimization mode');
51
+ console.log(' --enable Enable token optimization policy and rebuild compiled rules');
52
+ console.log(' --disable Disable token optimization policy and rebuild compiled rules');
53
+ console.log(' --show Print current token optimization state as JSON');
46
54
  console.log(' --tier Choose a skill tier for the skill selector');
47
55
  console.log(' --json Emit machine-readable skill selection output');
48
56
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryuenn3123/agentic-senior-core",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "type": "module",
5
5
  "description": "Force your AI Agent to code like a Staff Engineer, not a Junior.",
6
6
  "bin": {
@@ -16,6 +16,16 @@ const __dirname = dirname(__filename);
16
16
  const REPOSITORY_ROOT = resolve(__dirname, '..');
17
17
 
18
18
  const VERSION_PATTERN = /^\d+\.\d+\.\d+$/;
19
+ const NODE_MIN_PATTERN = /^\d+(\.\d+)?$/;
20
+ const SUPPORTED_COMPATIBILITY_PLATFORMS = new Set(['windows', 'linux', 'macos']);
21
+ const REQUIRED_SKILL_DOMAINS = [
22
+ 'backend',
23
+ 'frontend',
24
+ 'fullstack',
25
+ 'cli',
26
+ 'distribution',
27
+ 'review-quality',
28
+ ];
19
29
 
20
30
  function readText(relativeFilePath) {
21
31
  const absolutePath = resolve(REPOSITORY_ROOT, relativeFilePath);
@@ -34,6 +44,32 @@ function pushResult(results, isPassed, checkName, details) {
34
44
  });
35
45
  }
36
46
 
47
+ function validateCompatibilityManifestShape(parsedManifest, skillDomainName) {
48
+ const validationErrors = [];
49
+
50
+ if (!Array.isArray(parsedManifest.ides) || parsedManifest.ides.length === 0) {
51
+ validationErrors.push(`Domain ${skillDomainName} must define non-empty ides[]`);
52
+ }
53
+
54
+ if (!Array.isArray(parsedManifest.platforms) || parsedManifest.platforms.length === 0) {
55
+ validationErrors.push(`Domain ${skillDomainName} must define non-empty platforms[]`);
56
+ } else {
57
+ const unsupportedPlatformName = parsedManifest.platforms.find(
58
+ (platformName) => !SUPPORTED_COMPATIBILITY_PLATFORMS.has(platformName)
59
+ );
60
+
61
+ if (unsupportedPlatformName) {
62
+ validationErrors.push(`Domain ${skillDomainName} has unsupported platform: ${unsupportedPlatformName}`);
63
+ }
64
+ }
65
+
66
+ if (typeof parsedManifest.nodeMin !== 'string' || !NODE_MIN_PATTERN.test(parsedManifest.nodeMin)) {
67
+ validationErrors.push(`Domain ${skillDomainName} must define nodeMin as "18" or "18.0" style string`);
68
+ }
69
+
70
+ return validationErrors;
71
+ }
72
+
37
73
  function runReleaseGate() {
38
74
  const results = [];
39
75
  const packageJsonPath = 'package.json';
@@ -100,6 +136,58 @@ function runReleaseGate() {
100
136
  pushResult(results, true, 'required-enterprise-file', `${requiredEnterpriseFile} is present`);
101
137
  }
102
138
 
139
+ let validatedCompatibilityManifestCount = 0;
140
+
141
+ for (const skillDomainName of REQUIRED_SKILL_DOMAINS) {
142
+ const compatibilityManifestPath = `.agent-context/skills/${skillDomainName}/compatibility-manifest.json`;
143
+ const compatibilityManifestContent = readText(compatibilityManifestPath);
144
+
145
+ if (!compatibilityManifestContent) {
146
+ pushResult(results, false, 'compatibility-manifest', `Missing ${compatibilityManifestPath}`);
147
+ continue;
148
+ }
149
+
150
+ let parsedCompatibilityManifest;
151
+ try {
152
+ parsedCompatibilityManifest = JSON.parse(compatibilityManifestContent);
153
+ } catch (compatibilityManifestParseError) {
154
+ const parseErrorMessage = compatibilityManifestParseError instanceof Error
155
+ ? compatibilityManifestParseError.message
156
+ : 'Unknown parse error';
157
+ pushResult(results, false, 'compatibility-manifest', `Invalid JSON in ${compatibilityManifestPath}: ${parseErrorMessage}`);
158
+ continue;
159
+ }
160
+
161
+ const compatibilityValidationErrors = validateCompatibilityManifestShape(
162
+ parsedCompatibilityManifest,
163
+ skillDomainName
164
+ );
165
+
166
+ if (compatibilityValidationErrors.length > 0) {
167
+ pushResult(results, false, 'compatibility-manifest', compatibilityValidationErrors.join('; '));
168
+ continue;
169
+ }
170
+
171
+ validatedCompatibilityManifestCount += 1;
172
+ pushResult(results, true, 'compatibility-manifest', `${compatibilityManifestPath} is valid`);
173
+ }
174
+
175
+ if (validatedCompatibilityManifestCount === REQUIRED_SKILL_DOMAINS.length) {
176
+ pushResult(
177
+ results,
178
+ true,
179
+ 'compatibility-manifest-coverage',
180
+ `Validated ${validatedCompatibilityManifestCount}/${REQUIRED_SKILL_DOMAINS.length} required skill compatibility manifests`
181
+ );
182
+ } else {
183
+ pushResult(
184
+ results,
185
+ false,
186
+ 'compatibility-manifest-coverage',
187
+ `Validated ${validatedCompatibilityManifestCount}/${REQUIRED_SKILL_DOMAINS.length} required skill compatibility manifests`
188
+ );
189
+ }
190
+
103
191
  const failureCount = results.filter((checkResult) => !checkResult.passed).length;
104
192
  const releaseGateReport = {
105
193
  generatedAt: new Date().toISOString(),
@@ -31,6 +31,7 @@ const SKILLS_DIR = join(AGENT_CONTEXT_DIR, 'skills');
31
31
  const GENERATED_RULE_FILES = ['.cursorrules', '.windsurfrules'];
32
32
  const ALLOWED_SEVERITIES = new Set(['critical', 'high', 'medium', 'low']);
33
33
  const OVERRIDE_WARNING_WINDOW_DAYS = 30;
34
+ const SUPPORTED_COMPATIBILITY_PLATFORMS = new Set(['windows', 'linux', 'macos']);
34
35
 
35
36
  const validationResult = {
36
37
  passed: 0,
@@ -59,7 +60,12 @@ async function collectFiles(directoryPath, fileExtensionMatcher) {
59
60
  const directoryEntries = await readdir(currentDirectoryPath, { withFileTypes: true });
60
61
 
61
62
  for (const directoryEntry of directoryEntries) {
62
- if (directoryEntry.name === '.git' || directoryEntry.name === 'node_modules') {
63
+ if (
64
+ directoryEntry.name === '.git'
65
+ || directoryEntry.name === 'node_modules'
66
+ || directoryEntry.name === '.agentic-backup'
67
+ || directoryEntry.name === '.benchmarks'
68
+ ) {
63
69
  continue;
64
70
  }
65
71
 
@@ -313,6 +319,75 @@ async function validateSkillTierQuality() {
313
319
  }
314
320
  }
315
321
 
322
+ async function validateSkillCompatibilityManifests() {
323
+ console.log('\nChecking skill compatibility manifests...');
324
+
325
+ const skillDomainEntries = await readdir(SKILLS_DIR, { withFileTypes: true });
326
+ const skillDomainDirectoryNames = skillDomainEntries
327
+ .filter((entry) => entry.isDirectory())
328
+ .map((entry) => entry.name)
329
+ .sort((leftName, rightName) => leftName.localeCompare(rightName));
330
+
331
+ let validManifestCount = 0;
332
+
333
+ for (const skillDomainDirectoryName of skillDomainDirectoryNames) {
334
+ const compatibilityManifestPath = join(
335
+ SKILLS_DIR,
336
+ skillDomainDirectoryName,
337
+ 'compatibility-manifest.json'
338
+ );
339
+
340
+ if (!(await fileExists(compatibilityManifestPath))) {
341
+ fail(`Missing compatibility manifest: .agent-context/skills/${skillDomainDirectoryName}/compatibility-manifest.json`);
342
+ continue;
343
+ }
344
+
345
+ let parsedCompatibilityManifest;
346
+ try {
347
+ parsedCompatibilityManifest = JSON.parse(await readTextFile(compatibilityManifestPath));
348
+ } catch (error) {
349
+ fail(`Invalid JSON compatibility manifest for ${skillDomainDirectoryName}: ${error.message}`);
350
+ continue;
351
+ }
352
+
353
+ if (!Array.isArray(parsedCompatibilityManifest.ides) || parsedCompatibilityManifest.ides.length === 0) {
354
+ fail(`Compatibility manifest for ${skillDomainDirectoryName} must include non-empty "ides" array`);
355
+ continue;
356
+ }
357
+
358
+ if (!Array.isArray(parsedCompatibilityManifest.platforms) || parsedCompatibilityManifest.platforms.length === 0) {
359
+ fail(`Compatibility manifest for ${skillDomainDirectoryName} must include non-empty "platforms" array`);
360
+ continue;
361
+ }
362
+
363
+ const unsupportedPlatform = parsedCompatibilityManifest.platforms.find(
364
+ (platformName) => !SUPPORTED_COMPATIBILITY_PLATFORMS.has(platformName)
365
+ );
366
+
367
+ if (unsupportedPlatform) {
368
+ fail(`Compatibility manifest for ${skillDomainDirectoryName} has unsupported platform: ${unsupportedPlatform}`);
369
+ continue;
370
+ }
371
+
372
+ if (
373
+ typeof parsedCompatibilityManifest.nodeMin !== 'string'
374
+ || !/^\d+(\.\d+)?$/.test(parsedCompatibilityManifest.nodeMin)
375
+ ) {
376
+ fail(`Compatibility manifest for ${skillDomainDirectoryName} must include string nodeMin (for example "18" or "18.0")`);
377
+ continue;
378
+ }
379
+
380
+ validManifestCount += 1;
381
+ pass(`Compatibility manifest validated: .agent-context/skills/${skillDomainDirectoryName}/compatibility-manifest.json`);
382
+ }
383
+
384
+ if (validManifestCount >= 6) {
385
+ pass(`Compatibility manifest coverage is valid (${validManifestCount} skill domains)`);
386
+ } else {
387
+ fail(`Compatibility manifest coverage is insufficient (${validManifestCount}/6 skill domains)`);
388
+ }
389
+ }
390
+
316
391
  function stripMarkdownCodeBlocks(markdownText) {
317
392
  return markdownText.replace(/```[\s\S]*?```/g, '');
318
393
  }
@@ -702,6 +777,7 @@ async function main() {
702
777
  await validateMarkdownFiles();
703
778
  await validateRuleFiles();
704
779
  await validateSkillTierQuality();
780
+ await validateSkillCompatibilityManifests();
705
781
  await validateOverrideGovernance();
706
782
  await validateAgentsManifest();
707
783
  await validateCrossReferences();