@ryuenn3123/agentic-senior-core 4.1.0 → 4.2.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/.agent-context/prompts/compact-natural-mode.md +100 -0
- package/.agent-context/prompts/init-project.md +1 -0
- package/.agent-context/prompts/refactor.md +1 -0
- package/.agent-context/review-checklists/pr-checklist.md +1 -0
- package/.agent-context/rules/architecture.md +10 -0
- package/.agent-context/rules/naming-conv.md +6 -3
- package/AGENTS.md +5 -7
- package/README.md +95 -117
- package/benchmarks/README.md +40 -0
- package/benchmarks/compact-natural-mode/fixtures.mjs +359 -0
- package/benchmarks/compact-natural-mode/scorer.mjs +331 -0
- package/benchmarks/runtime-token-saver/fixtures.mjs +613 -0
- package/bin/agentic-senior-core.js +6 -0
- package/bin/ascx.js +23 -0
- package/lib/cli/adaptive-context/catalog.mjs +428 -0
- package/lib/cli/adaptive-context/file-signals.mjs +100 -0
- package/lib/cli/adaptive-context/implications.mjs +44 -0
- package/lib/cli/adaptive-context.mjs +365 -0
- package/lib/cli/ascx/adapters/git-diff.mjs +223 -0
- package/lib/cli/ascx/adapters/git-status.mjs +145 -0
- package/lib/cli/ascx/adapters/npm-test.mjs +120 -0
- package/lib/cli/ascx/fixture-evaluator.mjs +180 -0
- package/lib/cli/ascx/formatter.mjs +46 -0
- package/lib/cli/ascx/lexer.mjs +113 -0
- package/lib/cli/ascx/runtime.mjs +188 -0
- package/lib/cli/ascx/tee-writer.mjs +38 -0
- package/lib/cli/ascx/token-estimate.mjs +15 -0
- package/lib/cli/commands/context.mjs +140 -0
- package/lib/cli/commands/init.mjs +2 -1
- package/lib/cli/commands/optimize.mjs +143 -2
- package/lib/cli/commands/upgrade.mjs +2 -0
- package/lib/cli/compiler.mjs +9 -0
- package/lib/cli/token-optimization.mjs +161 -6
- package/lib/cli/utils.mjs +15 -1
- package/package.json +10 -3
- package/scripts/adaptive-context/fixtures.mjs +188 -0
- package/scripts/adaptive-context-benchmark.mjs +9 -0
- package/scripts/ascx-runtime-token-saver-benchmark.mjs +9 -0
- package/scripts/compact-natural-mode-benchmark.mjs +9 -0
- package/scripts/validate/config.mjs +1 -0
- package/scripts/validate.mjs +2 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
|
|
3
|
+
import { compressGitDiffOutput } from './adapters/git-diff.mjs';
|
|
4
|
+
import { compressGitStatusOutput } from './adapters/git-status.mjs';
|
|
5
|
+
import { compressNpmTestOutput } from './adapters/npm-test.mjs';
|
|
6
|
+
import { buildAscxFooter, shouldWriteSafetyTee } from './formatter.mjs';
|
|
7
|
+
import { classifyAscxInvocation, parseAscxCommand } from './lexer.mjs';
|
|
8
|
+
import { writeRawTeeFile } from './tee-writer.mjs';
|
|
9
|
+
|
|
10
|
+
const ADAPTERS = {
|
|
11
|
+
'git-diff': compressGitDiffOutput,
|
|
12
|
+
'git-status': compressGitStatusOutput,
|
|
13
|
+
'npm-test': compressNpmTestOutput,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function buildCommandEnvironment(baseEnvironment, parsedCommand) {
|
|
17
|
+
const commandEnvironment = { ...baseEnvironment };
|
|
18
|
+
|
|
19
|
+
for (const assignment of parsedCommand.environment) {
|
|
20
|
+
const separatorIndex = assignment.indexOf('=');
|
|
21
|
+
const variableName = assignment.slice(0, separatorIndex);
|
|
22
|
+
const variableValue = assignment.slice(separatorIndex + 1);
|
|
23
|
+
|
|
24
|
+
commandEnvironment[variableName] = variableValue;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return commandEnvironment;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function runSpawnedCommand(parsedCommand, options = {}) {
|
|
31
|
+
const {
|
|
32
|
+
cwd = process.cwd(),
|
|
33
|
+
env = process.env,
|
|
34
|
+
shell = false,
|
|
35
|
+
} = options;
|
|
36
|
+
|
|
37
|
+
return new Promise((resolve) => {
|
|
38
|
+
const useWindowsNpmShell = process.platform === 'win32'
|
|
39
|
+
&& parsedCommand.executable === 'npm'
|
|
40
|
+
&& shell === false;
|
|
41
|
+
const executable = shell
|
|
42
|
+
? parsedCommand.commandText
|
|
43
|
+
: parsedCommand.executable;
|
|
44
|
+
const args = shell ? [] : parsedCommand.args;
|
|
45
|
+
const childProcess = spawn(executable, args, {
|
|
46
|
+
cwd,
|
|
47
|
+
env: buildCommandEnvironment(env, parsedCommand),
|
|
48
|
+
shell: shell || useWindowsNpmShell,
|
|
49
|
+
windowsHide: true,
|
|
50
|
+
});
|
|
51
|
+
let stdout = '';
|
|
52
|
+
let stderr = '';
|
|
53
|
+
|
|
54
|
+
childProcess.stdout?.setEncoding('utf8');
|
|
55
|
+
childProcess.stderr?.setEncoding('utf8');
|
|
56
|
+
childProcess.stdout?.on('data', (chunk) => {
|
|
57
|
+
stdout += chunk;
|
|
58
|
+
});
|
|
59
|
+
childProcess.stderr?.on('data', (chunk) => {
|
|
60
|
+
stderr += chunk;
|
|
61
|
+
});
|
|
62
|
+
childProcess.on('error', (error) => {
|
|
63
|
+
stderr += `${error.name}: ${error.message}\n`;
|
|
64
|
+
});
|
|
65
|
+
childProcess.on('close', (exitCode) => {
|
|
66
|
+
resolve({
|
|
67
|
+
stdout,
|
|
68
|
+
stderr,
|
|
69
|
+
exitCode: typeof exitCode === 'number' ? exitCode : 1,
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function combineOutput(stdout, stderr) {
|
|
76
|
+
return [stdout, stderr].filter(Boolean).join('\n');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function formatCompressedResult({
|
|
80
|
+
adapterResult,
|
|
81
|
+
capture,
|
|
82
|
+
classification,
|
|
83
|
+
commandText,
|
|
84
|
+
cwd,
|
|
85
|
+
teeDirectoryPath,
|
|
86
|
+
}) {
|
|
87
|
+
const rawOutput = combineOutput(capture.stdout, capture.stderr);
|
|
88
|
+
const preliminaryFooter = buildAscxFooter({
|
|
89
|
+
classification: classification.kind,
|
|
90
|
+
commandText,
|
|
91
|
+
compactOutput: adapterResult.output,
|
|
92
|
+
exitCode: capture.exitCode,
|
|
93
|
+
filterName: adapterResult.filterName,
|
|
94
|
+
rawOutput,
|
|
95
|
+
rawTeePath: null,
|
|
96
|
+
});
|
|
97
|
+
const rawTeePath = shouldWriteSafetyTee({
|
|
98
|
+
adapterResult,
|
|
99
|
+
exitCode: capture.exitCode,
|
|
100
|
+
reductionPercent: preliminaryFooter.reductionPercent,
|
|
101
|
+
})
|
|
102
|
+
? await writeRawTeeFile({
|
|
103
|
+
commandText,
|
|
104
|
+
cwd,
|
|
105
|
+
exitCode: capture.exitCode,
|
|
106
|
+
rawOutput,
|
|
107
|
+
teeDirectoryPath,
|
|
108
|
+
})
|
|
109
|
+
: null;
|
|
110
|
+
const footer = buildAscxFooter({
|
|
111
|
+
classification: classification.kind,
|
|
112
|
+
commandText,
|
|
113
|
+
compactOutput: adapterResult.output,
|
|
114
|
+
exitCode: capture.exitCode,
|
|
115
|
+
filterName: adapterResult.filterName,
|
|
116
|
+
rawOutput,
|
|
117
|
+
rawTeePath,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
stdout: `${adapterResult.output}\n\n${footer.text}\n`,
|
|
122
|
+
stderr: '',
|
|
123
|
+
exitCode: capture.exitCode,
|
|
124
|
+
compressed: adapterResult.confident === true,
|
|
125
|
+
rawTeePath,
|
|
126
|
+
footer,
|
|
127
|
+
adapterResult,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export async function runAscx(commandArguments, options = {}) {
|
|
132
|
+
const {
|
|
133
|
+
cwd = process.cwd(),
|
|
134
|
+
executeCommand = runSpawnedCommand,
|
|
135
|
+
teeDirectoryPath,
|
|
136
|
+
} = options;
|
|
137
|
+
const parsedCommand = parseAscxCommand(commandArguments);
|
|
138
|
+
const classification = classifyAscxInvocation(parsedCommand);
|
|
139
|
+
|
|
140
|
+
if (!parsedCommand.executable) {
|
|
141
|
+
return {
|
|
142
|
+
stdout: '',
|
|
143
|
+
stderr: 'ascx: command is required\n',
|
|
144
|
+
exitCode: 1,
|
|
145
|
+
parsedCommand,
|
|
146
|
+
classification,
|
|
147
|
+
compressed: false,
|
|
148
|
+
rawTeePath: null,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const capture = await executeCommand(parsedCommand, {
|
|
153
|
+
cwd,
|
|
154
|
+
shell: classification.kind === 'unsafe-for-compression',
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (classification.kind !== 'compressible') {
|
|
158
|
+
return {
|
|
159
|
+
stdout: capture.stdout,
|
|
160
|
+
stderr: capture.stderr,
|
|
161
|
+
exitCode: capture.exitCode,
|
|
162
|
+
parsedCommand,
|
|
163
|
+
classification,
|
|
164
|
+
compressed: false,
|
|
165
|
+
rawTeePath: null,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const adapter = ADAPTERS[classification.adapterName];
|
|
170
|
+
const adapterResult = adapter({
|
|
171
|
+
stdout: capture.stdout,
|
|
172
|
+
stderr: capture.stderr,
|
|
173
|
+
exitCode: capture.exitCode,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
...await formatCompressedResult({
|
|
178
|
+
adapterResult,
|
|
179
|
+
capture,
|
|
180
|
+
classification,
|
|
181
|
+
commandText: parsedCommand.commandText,
|
|
182
|
+
cwd,
|
|
183
|
+
teeDirectoryPath,
|
|
184
|
+
}),
|
|
185
|
+
parsedCommand,
|
|
186
|
+
classification,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
function sanitizeFileNamePart(rawValue) {
|
|
5
|
+
return String(rawValue || 'command')
|
|
6
|
+
.toLowerCase()
|
|
7
|
+
.replace(/[^a-z0-9._-]+/g, '-')
|
|
8
|
+
.replace(/^-+|-+$/g, '')
|
|
9
|
+
.slice(0, 60) || 'command';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function getDefaultTeeDirectory(cwd = process.cwd()) {
|
|
13
|
+
return path.resolve(cwd, '.agent-context', 'state', 'token-saver', 'tee');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function writeRawTeeFile({
|
|
17
|
+
commandText,
|
|
18
|
+
cwd = process.cwd(),
|
|
19
|
+
exitCode,
|
|
20
|
+
rawOutput,
|
|
21
|
+
teeDirectoryPath = getDefaultTeeDirectory(cwd),
|
|
22
|
+
}) {
|
|
23
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
24
|
+
const commandName = sanitizeFileNamePart(commandText);
|
|
25
|
+
const teeFilePath = path.resolve(teeDirectoryPath, `${timestamp}-${commandName}.log`);
|
|
26
|
+
const fileContent = [
|
|
27
|
+
`[ascx raw output]`,
|
|
28
|
+
`command: ${commandText}`,
|
|
29
|
+
`exit: ${exitCode}`,
|
|
30
|
+
'',
|
|
31
|
+
rawOutput,
|
|
32
|
+
].join('\n');
|
|
33
|
+
|
|
34
|
+
await fs.mkdir(path.dirname(teeFilePath), { recursive: true });
|
|
35
|
+
await fs.writeFile(teeFilePath, fileContent, 'utf8');
|
|
36
|
+
|
|
37
|
+
return teeFilePath;
|
|
38
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const ASCX_TOKEN_ESTIMATE_METHOD = 'chars-div-4-local-estimate';
|
|
2
|
+
|
|
3
|
+
export function estimateOutputTokens(outputText) {
|
|
4
|
+
const textLength = String(outputText || '').length;
|
|
5
|
+
return Math.max(0, Math.ceil(textLength / 4));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function calculateReductionPercent(rawTokens, compactTokens) {
|
|
9
|
+
if (rawTokens <= 0) {
|
|
10
|
+
return 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const reducedTokens = Math.max(0, rawTokens - compactTokens);
|
|
14
|
+
return Number(((reducedTokens / rawTokens) * 100).toFixed(2));
|
|
15
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { stdin } from 'node:process';
|
|
2
|
+
|
|
3
|
+
import { buildSelectedContextManifest } from '../adaptive-context.mjs';
|
|
4
|
+
|
|
5
|
+
export function parseContextArguments(commandArguments) {
|
|
6
|
+
const parsedOptions = {
|
|
7
|
+
requestId: 'adhoc-request',
|
|
8
|
+
requestText: '',
|
|
9
|
+
contextFiles: [],
|
|
10
|
+
json: false,
|
|
11
|
+
readStdin: false,
|
|
12
|
+
};
|
|
13
|
+
const requestParts = [];
|
|
14
|
+
|
|
15
|
+
for (let argumentIndex = 0; argumentIndex < commandArguments.length; argumentIndex++) {
|
|
16
|
+
const currentArgument = commandArguments[argumentIndex];
|
|
17
|
+
|
|
18
|
+
if (currentArgument === '--json') {
|
|
19
|
+
parsedOptions.json = true;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (currentArgument === '--stdin') {
|
|
24
|
+
parsedOptions.readStdin = true;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (currentArgument === '--file') {
|
|
29
|
+
const contextFilePath = commandArguments[argumentIndex + 1];
|
|
30
|
+
if (!contextFilePath || contextFilePath.startsWith('--')) {
|
|
31
|
+
throw new Error('Missing value for --file');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
parsedOptions.contextFiles.push(contextFilePath);
|
|
35
|
+
argumentIndex++;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (currentArgument === '--files') {
|
|
40
|
+
const contextFileList = commandArguments[argumentIndex + 1];
|
|
41
|
+
if (!contextFileList || contextFileList.startsWith('--')) {
|
|
42
|
+
throw new Error('Missing value for --files');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
parsedOptions.contextFiles.push(
|
|
46
|
+
...contextFileList
|
|
47
|
+
.split(',')
|
|
48
|
+
.map((contextFilePath) => contextFilePath.trim())
|
|
49
|
+
.filter(Boolean)
|
|
50
|
+
);
|
|
51
|
+
argumentIndex++;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (currentArgument === '--request-id') {
|
|
56
|
+
const requestId = commandArguments[argumentIndex + 1];
|
|
57
|
+
if (!requestId || requestId.startsWith('--')) {
|
|
58
|
+
throw new Error('Missing value for --request-id');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
parsedOptions.requestId = requestId;
|
|
62
|
+
argumentIndex++;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (currentArgument.startsWith('--')) {
|
|
67
|
+
throw new Error(`Unknown option: ${currentArgument}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
requestParts.push(currentArgument);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
parsedOptions.requestText = requestParts.join(' ').trim();
|
|
74
|
+
return parsedOptions;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function readRequestFromStdin() {
|
|
78
|
+
return new Promise((resolve, reject) => {
|
|
79
|
+
let requestText = '';
|
|
80
|
+
|
|
81
|
+
stdin.setEncoding('utf8');
|
|
82
|
+
stdin.on('data', (chunk) => {
|
|
83
|
+
requestText += chunk;
|
|
84
|
+
});
|
|
85
|
+
stdin.on('error', reject);
|
|
86
|
+
stdin.on('end', () => {
|
|
87
|
+
resolve(requestText.trim());
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function formatList(label, values) {
|
|
93
|
+
if (values.length === 0) {
|
|
94
|
+
return [`${label}: none`];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return [
|
|
98
|
+
`${label}:`,
|
|
99
|
+
...values.map((value) => `- ${value}`),
|
|
100
|
+
];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function formatManifestText(manifest) {
|
|
104
|
+
return [
|
|
105
|
+
'Adaptive Context',
|
|
106
|
+
`requestId: ${manifest.requestId}`,
|
|
107
|
+
`labels: ${manifest.labels.length > 0 ? manifest.labels.join(', ') : 'none'}`,
|
|
108
|
+
`uncertainty: ${manifest.uncertainty}`,
|
|
109
|
+
`budget: ${manifest.budget.status} (${manifest.budget.selectedRuleCount}/${manifest.budget.maxRecommendedRuleCount} recommended rules)`,
|
|
110
|
+
`fallbackRequired: ${manifest.fallbackRequired}`,
|
|
111
|
+
...formatList('contextFiles', manifest.contextFiles),
|
|
112
|
+
...formatList('selectedRules', manifest.selectedRules),
|
|
113
|
+
...formatList('selectedPrompts', manifest.selectedPrompts),
|
|
114
|
+
...formatList('selectedDocs', manifest.selectedDocs),
|
|
115
|
+
].join('\n');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export async function runContextCommand(commandArguments) {
|
|
119
|
+
const contextOptions = parseContextArguments(commandArguments);
|
|
120
|
+
const requestText = contextOptions.readStdin
|
|
121
|
+
? await readRequestFromStdin()
|
|
122
|
+
: contextOptions.requestText;
|
|
123
|
+
|
|
124
|
+
if (!requestText) {
|
|
125
|
+
throw new Error('Context request text is required. Pass text as arguments or use --stdin.');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const manifest = buildSelectedContextManifest({
|
|
129
|
+
contextFiles: contextOptions.contextFiles,
|
|
130
|
+
requestId: contextOptions.requestId,
|
|
131
|
+
requestText,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
if (contextOptions.json) {
|
|
135
|
+
console.log(JSON.stringify(manifest, null, 2));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
console.log(formatManifestText(manifest));
|
|
140
|
+
}
|
|
@@ -565,6 +565,7 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
565
565
|
console.log(`- Review thresholds: ${formatBlockingSeverities(selectedPolicyProfile.blockingSeverities)}`);
|
|
566
566
|
console.log(`- Setup time: ${formatDuration(setupDurationMs)}`);
|
|
567
567
|
console.log('- Generated files: AGENTS.md, CLAUDE.md, GEMINI.md, .agent-context/, and .agent-context/state/onboarding-report.json');
|
|
568
|
+
console.log('- Default response mode: Compact Natural Mode enabled (.agent-context/prompts/compact-natural-mode.md)');
|
|
568
569
|
if (scaffoldingResult?.bootstrapMode === 'ai-synthesis') {
|
|
569
570
|
console.log(`- Bootstrap prompts: ${(scaffoldingResult.generatedPromptFileNames || []).length} files generated in .agent-context/prompts/`);
|
|
570
571
|
if ((scaffoldingResult.materializedFileNames || []).length > 0) {
|
|
@@ -587,7 +588,7 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
587
588
|
console.log('- Memory continuity policy: disabled (--no-memory-continuity)');
|
|
588
589
|
}
|
|
589
590
|
if (isTokenOptimizationEnabled) {
|
|
590
|
-
console.log(`- Token optimization policy: enabled for ${selectedTokenAgentName}`);
|
|
591
|
+
console.log(`- Token optimization policy: enabled for ${selectedTokenAgentName} (ASCX command guidance on)`);
|
|
591
592
|
} else {
|
|
592
593
|
console.log('- Token optimization policy: disabled (--no-token-optimize)');
|
|
593
594
|
}
|
|
@@ -7,6 +7,11 @@ import {
|
|
|
7
7
|
TOKEN_OPTIMIZATION_REPORT_FILE_NAME,
|
|
8
8
|
normalizeAgentName,
|
|
9
9
|
detectRtkBinary,
|
|
10
|
+
detectAscxRuntime,
|
|
11
|
+
checkAscxTeeReadiness,
|
|
12
|
+
resolveRuntimeTokenSaverMode,
|
|
13
|
+
buildRuntimeTokenSaverWarnings,
|
|
14
|
+
buildRuntimeTokenSaverNextAction,
|
|
10
15
|
buildRtkInstallHint,
|
|
11
16
|
buildRtkHookCommand,
|
|
12
17
|
createTokenOptimizationState,
|
|
@@ -19,12 +24,43 @@ export function parseOptimizeArguments(commandArguments) {
|
|
|
19
24
|
targetDirectory: '.',
|
|
20
25
|
agent: 'copilot',
|
|
21
26
|
enabled: true,
|
|
27
|
+
mode: 'configure',
|
|
22
28
|
show: false,
|
|
23
29
|
};
|
|
24
30
|
|
|
31
|
+
function setOptimizeMode(nextMode) {
|
|
32
|
+
if (parsedOptimizeOptions.mode !== 'configure' && parsedOptimizeOptions.mode !== nextMode) {
|
|
33
|
+
throw new Error(`Conflicting optimize modes: ${parsedOptimizeOptions.mode} and ${nextMode}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
parsedOptimizeOptions.mode = nextMode;
|
|
37
|
+
}
|
|
38
|
+
|
|
25
39
|
for (let argumentIndex = 0; argumentIndex < commandArguments.length; argumentIndex++) {
|
|
26
40
|
const currentArgument = commandArguments[argumentIndex];
|
|
27
41
|
|
|
42
|
+
if (currentArgument === 'install') {
|
|
43
|
+
setOptimizeMode('install');
|
|
44
|
+
parsedOptimizeOptions.enabled = true;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (currentArgument === 'off') {
|
|
49
|
+
setOptimizeMode('off');
|
|
50
|
+
parsedOptimizeOptions.enabled = false;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (currentArgument === 'status') {
|
|
55
|
+
setOptimizeMode('status');
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (currentArgument === 'doctor') {
|
|
60
|
+
setOptimizeMode('doctor');
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
|
|
28
64
|
if (!currentArgument.startsWith('--')) {
|
|
29
65
|
parsedOptimizeOptions.targetDirectory = currentArgument;
|
|
30
66
|
continue;
|
|
@@ -43,19 +79,36 @@ export function parseOptimizeArguments(commandArguments) {
|
|
|
43
79
|
|
|
44
80
|
if (currentArgument === '--enable') {
|
|
45
81
|
parsedOptimizeOptions.enabled = true;
|
|
82
|
+
if (parsedOptimizeOptions.mode === 'off') {
|
|
83
|
+
setOptimizeMode('install');
|
|
84
|
+
}
|
|
46
85
|
continue;
|
|
47
86
|
}
|
|
48
87
|
|
|
49
88
|
if (currentArgument === '--disable') {
|
|
50
89
|
parsedOptimizeOptions.enabled = false;
|
|
90
|
+
if (parsedOptimizeOptions.mode === 'install') {
|
|
91
|
+
setOptimizeMode('off');
|
|
92
|
+
}
|
|
51
93
|
continue;
|
|
52
94
|
}
|
|
53
95
|
|
|
54
96
|
if (currentArgument === '--show') {
|
|
97
|
+
setOptimizeMode('show');
|
|
55
98
|
parsedOptimizeOptions.show = true;
|
|
56
99
|
continue;
|
|
57
100
|
}
|
|
58
101
|
|
|
102
|
+
if (currentArgument === '--status') {
|
|
103
|
+
setOptimizeMode('status');
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (currentArgument === '--doctor') {
|
|
108
|
+
setOptimizeMode('doctor');
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
|
|
59
112
|
throw new Error(`Unknown option: ${currentArgument}`);
|
|
60
113
|
}
|
|
61
114
|
|
|
@@ -63,6 +116,78 @@ export function parseOptimizeArguments(commandArguments) {
|
|
|
63
116
|
return parsedOptimizeOptions;
|
|
64
117
|
}
|
|
65
118
|
|
|
119
|
+
function formatStatusLine(label, value) {
|
|
120
|
+
return `${label}: ${value}`;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function buildRuntimeTokenSaverStatus(resolvedTargetDirectoryPath, options = {}) {
|
|
124
|
+
const onboardingReport = await loadOnboardingReportIfExists(resolvedTargetDirectoryPath);
|
|
125
|
+
const existingOptimizationState = await readTokenOptimizationState(resolvedTargetDirectoryPath);
|
|
126
|
+
const ascxDetection = detectAscxRuntime();
|
|
127
|
+
const rtkDetection = detectRtkBinary();
|
|
128
|
+
const teeReadiness = await checkAscxTeeReadiness(resolvedTargetDirectoryPath, {
|
|
129
|
+
writeProbe: options.writeProbe === true,
|
|
130
|
+
});
|
|
131
|
+
const mode = resolveRuntimeTokenSaverMode({
|
|
132
|
+
tokenOptimizationState: existingOptimizationState,
|
|
133
|
+
ascxDetection,
|
|
134
|
+
rtkDetection,
|
|
135
|
+
});
|
|
136
|
+
const warnings = buildRuntimeTokenSaverWarnings({
|
|
137
|
+
mode,
|
|
138
|
+
onboardingReport,
|
|
139
|
+
ascxDetection,
|
|
140
|
+
teeReadiness,
|
|
141
|
+
rtkDetection,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
targetDirectory: resolvedTargetDirectoryPath,
|
|
146
|
+
initialized: Boolean(onboardingReport),
|
|
147
|
+
mode,
|
|
148
|
+
ascx: ascxDetection,
|
|
149
|
+
tee: teeReadiness,
|
|
150
|
+
rtk: rtkDetection,
|
|
151
|
+
nineRouter: {
|
|
152
|
+
status: 'not-checked',
|
|
153
|
+
reason: 'localhost probing is intentionally deferred',
|
|
154
|
+
},
|
|
155
|
+
warnings,
|
|
156
|
+
nextAction: buildRuntimeTokenSaverNextAction({ mode, warnings }),
|
|
157
|
+
tokenOptimizationState: existingOptimizationState,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function printRuntimeTokenSaverStatus(statusReport, options = {}) {
|
|
162
|
+
const title = options.title || 'Runtime token saver status';
|
|
163
|
+
const ascxStatus = statusReport.ascx.isAvailable
|
|
164
|
+
? `found (${statusReport.ascx.source})`
|
|
165
|
+
: 'missing';
|
|
166
|
+
const rtkStatus = statusReport.rtk.isAvailable
|
|
167
|
+
? `detected${statusReport.rtk.version ? ` (${statusReport.rtk.version})` : ''}`
|
|
168
|
+
: 'not-detected';
|
|
169
|
+
|
|
170
|
+
console.log(title);
|
|
171
|
+
console.log(formatStatusLine('target', statusReport.targetDirectory));
|
|
172
|
+
console.log(formatStatusLine('initialized', statusReport.initialized ? 'yes' : 'no'));
|
|
173
|
+
console.log(formatStatusLine('mode', statusReport.mode));
|
|
174
|
+
console.log(formatStatusLine('ascx', ascxStatus));
|
|
175
|
+
console.log(formatStatusLine('tee', `${statusReport.tee.status} (${statusReport.tee.path})`));
|
|
176
|
+
console.log(formatStatusLine('rtk', rtkStatus));
|
|
177
|
+
console.log(formatStatusLine('9router', statusReport.nineRouter.status));
|
|
178
|
+
|
|
179
|
+
if (statusReport.warnings.length > 0) {
|
|
180
|
+
console.log('warnings:');
|
|
181
|
+
for (const warning of statusReport.warnings) {
|
|
182
|
+
console.log(`- ${warning}`);
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
console.log('warnings: none');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
console.log(formatStatusLine('next_action', statusReport.nextAction));
|
|
189
|
+
}
|
|
190
|
+
|
|
66
191
|
export async function runOptimizeCommand(targetDirectoryArgument, optimizeOptions = {}) {
|
|
67
192
|
const optimizationStartedAt = Date.now();
|
|
68
193
|
const resolvedTargetDirectoryPath = path.resolve(targetDirectoryArgument || '.');
|
|
@@ -72,7 +197,23 @@ export async function runOptimizeCommand(targetDirectoryArgument, optimizeOption
|
|
|
72
197
|
const selectedAgentName = normalizeAgentName(optimizeOptions.agent || 'copilot');
|
|
73
198
|
const rtkDetection = detectRtkBinary();
|
|
74
199
|
|
|
75
|
-
if (optimizeOptions.
|
|
200
|
+
if (optimizeOptions.mode === 'status') {
|
|
201
|
+
const statusReport = await buildRuntimeTokenSaverStatus(resolvedTargetDirectoryPath);
|
|
202
|
+
printRuntimeTokenSaverStatus(statusReport);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (optimizeOptions.mode === 'doctor') {
|
|
207
|
+
const statusReport = await buildRuntimeTokenSaverStatus(resolvedTargetDirectoryPath, {
|
|
208
|
+
writeProbe: true,
|
|
209
|
+
});
|
|
210
|
+
printRuntimeTokenSaverStatus(statusReport, {
|
|
211
|
+
title: 'ASCX runtime token saver doctor',
|
|
212
|
+
});
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (optimizeOptions.show || optimizeOptions.mode === 'show') {
|
|
76
217
|
const existingOptimizationState = await readTokenOptimizationState(resolvedTargetDirectoryPath);
|
|
77
218
|
console.log(
|
|
78
219
|
JSON.stringify(
|
|
@@ -97,7 +238,7 @@ export async function runOptimizeCommand(targetDirectoryArgument, optimizeOption
|
|
|
97
238
|
}
|
|
98
239
|
|
|
99
240
|
const tokenOptimizationState = createTokenOptimizationState({
|
|
100
|
-
isEnabled: optimizeOptions.enabled,
|
|
241
|
+
isEnabled: optimizeOptions.mode === 'off' ? false : optimizeOptions.enabled,
|
|
101
242
|
selectedAgentName,
|
|
102
243
|
rtkDetection,
|
|
103
244
|
});
|
|
@@ -302,6 +302,7 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
|
|
|
302
302
|
}
|
|
303
303
|
console.log(`- CI/CD quality checks (guardrails): ${includeCiGuardrails ? 'enabled' : 'disabled'}`);
|
|
304
304
|
console.log('- Instruction surface: AGENTS.md canonical with CLAUDE.md and GEMINI.md import bridges');
|
|
305
|
+
console.log('- Default response mode: Compact Natural Mode enabled');
|
|
305
306
|
console.log(`- Managed surface stale files: ${managedSurfacePlan.staleFiles.length}`);
|
|
306
307
|
console.log(`- Managed surface stale directories: ${managedSurfacePlan.staleDirectories.length}`);
|
|
307
308
|
console.log(`- Managed surface sync mode: 1:1 (prune enabled)`);
|
|
@@ -464,6 +465,7 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
|
|
|
464
465
|
}
|
|
465
466
|
|
|
466
467
|
console.log('\nRefreshed files: AGENTS.md, CLAUDE.md, GEMINI.md, .agent-context/, and .agent-context/state/onboarding-report.json');
|
|
468
|
+
console.log('Default response mode remains Compact Natural Mode through .agent-context/prompts/compact-natural-mode.md.');
|
|
467
469
|
console.log('\nNext-step suggestion (UI scope): run `npx @ryuenn3123/agentic-senior-core audit:design-anti-repeat` to scan CSS, SCSS, SASS, LESS, Tailwind config, and design-token files in this project for typography or palette values that match the anti-repeat ledger in docs/design-intent.json. Add it to your CI alongside `npm test` once the design dossier is populated.');
|
|
468
470
|
} catch (error) {
|
|
469
471
|
console.error('\n[FATAL] An error occurred during upgrade. Attempting automatic rollback...');
|
package/lib/cli/compiler.mjs
CHANGED
|
@@ -202,6 +202,14 @@ export async function writeOnboardingReport({
|
|
|
202
202
|
containerizationStrategy: buildContainerizationStrategySnapshot(dockerStrategy),
|
|
203
203
|
tokenOptimization: resolvedTokenOptimization,
|
|
204
204
|
memoryContinuity: resolvedMemoryContinuity,
|
|
205
|
+
responseCompression: {
|
|
206
|
+
enabled: true,
|
|
207
|
+
mode: 'compact-natural-mode',
|
|
208
|
+
defaultOn: true,
|
|
209
|
+
promptFile: '.agent-context/prompts/compact-natural-mode.md',
|
|
210
|
+
appliesTo: 'agent-final-responses',
|
|
211
|
+
commandOutputBoundary: 'ASCX handles command-output compression separately',
|
|
212
|
+
},
|
|
205
213
|
autoDetection: {
|
|
206
214
|
detectedStack: projectDetection.detectedStackFileName,
|
|
207
215
|
detectedAdditionalStacks: projectDetection.secondaryStackFileNames || [],
|
|
@@ -383,6 +391,7 @@ export async function buildCompiledRulesContent({
|
|
|
383
391
|
[
|
|
384
392
|
'## LAYER 5: EXECUTION PROMPTS AND UI TRIGGERS',
|
|
385
393
|
'Load these prompt contracts only when their trigger matches the user request:',
|
|
394
|
+
'Default. .agent-context/prompts/compact-natural-mode.md -> final response shape and evidence-preserving compact prose',
|
|
386
395
|
'0. Documentation-first mode -> docs, documentation, dokumen, docs/*, architecture docs, flow docs, API docs, lengkapkan docs',
|
|
387
396
|
'1. .agent-context/prompts/init-project.md -> create, build, new project, scaffold',
|
|
388
397
|
'2. .agent-context/prompts/refactor.md -> refactor, improve, clean up, fix',
|