@ryuenn3123/agentic-senior-core 4.1.0 → 4.2.1
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/.agent-context/state/README.md +2 -1
- package/AGENTS.md +6 -8
- package/README.md +95 -117
- package/benchmarks/README.md +60 -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 +714 -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-run-build.mjs +99 -0
- package/lib/cli/ascx/adapters/npm-test.mjs +120 -0
- package/lib/cli/ascx/adapters/rg.mjs +39 -0
- package/lib/cli/ascx/fixture-evaluator.mjs +180 -0
- package/lib/cli/ascx/formatter.mjs +47 -0
- package/lib/cli/ascx/lexer.mjs +129 -0
- package/lib/cli/ascx/runtime.mjs +192 -0
- package/lib/cli/ascx/tee-writer.mjs +63 -0
- package/lib/cli/ascx/token-estimate.mjs +15 -0
- package/lib/cli/backup.mjs +37 -4
- package/lib/cli/commands/context.mjs +140 -0
- package/lib/cli/commands/init.mjs +14 -2
- package/lib/cli/commands/optimize.mjs +143 -2
- package/lib/cli/commands/upgrade/design-intent-seed.mjs +46 -0
- package/lib/cli/commands/upgrade/token-optimization-state.mjs +51 -0
- package/lib/cli/commands/upgrade.mjs +34 -45
- package/lib/cli/compiler.mjs +9 -0
- package/lib/cli/project-scaffolder/prompt-builders.mjs +1 -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/build-release-benchmark-bundle.mjs +1 -3
- package/scripts/clean-local-artifacts.mjs +2 -0
- package/scripts/compact-natural-mode-benchmark.mjs +9 -0
- package/scripts/validate/config.mjs +6 -0
- package/scripts/validate.mjs +2 -0
|
@@ -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
|
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
|
|
3
|
+
import { buildDesignIntentSeedFromSignals } from '../../project-scaffolder.mjs';
|
|
4
|
+
|
|
5
|
+
export function buildUpgradeDesignIntentSeed({
|
|
6
|
+
targetDirectoryPath,
|
|
7
|
+
packageManifest,
|
|
8
|
+
selectedStackFileName,
|
|
9
|
+
selectedBlueprintFileName,
|
|
10
|
+
uiScopeSignals,
|
|
11
|
+
}) {
|
|
12
|
+
const projectName = String(packageManifest?.name || path.basename(targetDirectoryPath)).trim()
|
|
13
|
+
|| 'existing-ui-project';
|
|
14
|
+
const isMobileUiProject = String(selectedStackFileName || '').toLowerCase().includes('react-native')
|
|
15
|
+
|| String(selectedStackFileName || '').toLowerCase().includes('flutter')
|
|
16
|
+
|| uiScopeSignals.signalReasons.some((signalReason) => {
|
|
17
|
+
return signalReason.includes('android') || signalReason.includes('ios');
|
|
18
|
+
});
|
|
19
|
+
const resolvedDomain = isMobileUiProject ? 'Mobile app' : 'Web application';
|
|
20
|
+
const projectDescription = String(packageManifest?.description || '').trim()
|
|
21
|
+
|| `Existing ${resolvedDomain.toLowerCase()} detected during upgrade. Create a project-specific dynamic design contract before shipping new UI work.`;
|
|
22
|
+
|
|
23
|
+
return buildDesignIntentSeedFromSignals({
|
|
24
|
+
projectName,
|
|
25
|
+
projectDescription,
|
|
26
|
+
primaryDomain: resolvedDomain,
|
|
27
|
+
features: [],
|
|
28
|
+
initContext: {
|
|
29
|
+
stackFileName: selectedStackFileName,
|
|
30
|
+
blueprintFileName: selectedBlueprintFileName,
|
|
31
|
+
},
|
|
32
|
+
status: 'seed-generated-during-upgrade',
|
|
33
|
+
supplementalFields: {
|
|
34
|
+
upgradeSignals: {
|
|
35
|
+
detectedFrom: uiScopeSignals.signalReasons,
|
|
36
|
+
generatedBy: 'upgrade-seed',
|
|
37
|
+
},
|
|
38
|
+
repoEvidence: {
|
|
39
|
+
uiSignalReasons: uiScopeSignals.signalReasons,
|
|
40
|
+
frontendMetrics: uiScopeSignals.frontendEvidenceMetrics || null,
|
|
41
|
+
designEvidenceSummary: uiScopeSignals.designEvidenceSummary || null,
|
|
42
|
+
workspaceUiEntries: uiScopeSignals.workspaceUiEntries || [],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createTokenOptimizationState,
|
|
3
|
+
detectRtkBinary,
|
|
4
|
+
normalizeAgentName,
|
|
5
|
+
readTokenOptimizationState,
|
|
6
|
+
writeTokenOptimizationState,
|
|
7
|
+
} from '../../token-optimization.mjs';
|
|
8
|
+
|
|
9
|
+
export async function resolveUpgradeTokenOptimizationPlan(targetDirectoryPath, existingOnboardingReport) {
|
|
10
|
+
const existingState = await readTokenOptimizationState(targetDirectoryPath);
|
|
11
|
+
const optedOut = existingOnboardingReport?.tokenOptimization?.enabled === false;
|
|
12
|
+
const selectedAgentName = normalizeAgentName(
|
|
13
|
+
existingOnboardingReport?.tokenOptimization?.selectedAgent || 'copilot'
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
existingState,
|
|
18
|
+
optedOut,
|
|
19
|
+
selectedAgentName,
|
|
20
|
+
shouldSeed: !existingState && !optedOut,
|
|
21
|
+
previewLabel: optedOut
|
|
22
|
+
? 'disabled (preserved opt-out)'
|
|
23
|
+
: existingState
|
|
24
|
+
? 'enabled'
|
|
25
|
+
: 'enabled (will seed missing ASCX state)',
|
|
26
|
+
reportState: existingState
|
|
27
|
+
|| (optedOut ? existingOnboardingReport?.tokenOptimization || { enabled: false } : null),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function applyUpgradeTokenOptimizationPlan(targetDirectoryPath, plan) {
|
|
32
|
+
if (!plan.shouldSeed) {
|
|
33
|
+
return {
|
|
34
|
+
createdFileName: null,
|
|
35
|
+
reportState: plan.reportState,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const tokenOptimizationState = createTokenOptimizationState({
|
|
40
|
+
isEnabled: true,
|
|
41
|
+
selectedAgentName: plan.selectedAgentName,
|
|
42
|
+
rtkDetection: detectRtkBinary(),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
await writeTokenOptimizationState(targetDirectoryPath, tokenOptimizationState);
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
createdFileName: '.agent-context/state/token-optimization.json',
|
|
49
|
+
reportState: tokenOptimizationState,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -39,15 +39,21 @@ import {
|
|
|
39
39
|
} from '../compiler.mjs';
|
|
40
40
|
|
|
41
41
|
import { runPreflightChecks } from '../preflight.mjs';
|
|
42
|
-
import { createBackup, ensureBackupGitignoreEntry } from '../backup.mjs';
|
|
43
|
-
import { performRollback } from '../rollback.mjs';
|
|
44
42
|
import {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
createBackup,
|
|
44
|
+
ensureBackupGitignoreEntry,
|
|
45
|
+
ensureRuntimeArtifactGitignoreEntries,
|
|
46
|
+
} from '../backup.mjs';
|
|
47
|
+
import { performRollback } from '../rollback.mjs';
|
|
48
|
+
import { detectProjectDocTemplateStaleness } from '../project-scaffolder.mjs';
|
|
48
49
|
import { migrateExistingDesignIntentToResearchDossierSchema } from '../project-scaffolder/design-contract/research-dossier-migration.mjs';
|
|
49
50
|
import { ensureActiveMemorySnapshot } from '../memory-continuity.mjs';
|
|
50
51
|
import { buildExistingProjectMajorConstraints } from '../init-detection-flow.mjs';
|
|
52
|
+
import { buildUpgradeDesignIntentSeed } from './upgrade/design-intent-seed.mjs';
|
|
53
|
+
import {
|
|
54
|
+
applyUpgradeTokenOptimizationPlan,
|
|
55
|
+
resolveUpgradeTokenOptimizationPlan,
|
|
56
|
+
} from './upgrade/token-optimization-state.mjs';
|
|
51
57
|
|
|
52
58
|
export function parseUpgradeArguments(commandArguments) {
|
|
53
59
|
const parsedUpgradeOptions = {
|
|
@@ -102,46 +108,6 @@ export function parseUpgradeArguments(commandArguments) {
|
|
|
102
108
|
return parsedUpgradeOptions;
|
|
103
109
|
}
|
|
104
110
|
|
|
105
|
-
function buildUpgradeDesignIntentSeed({
|
|
106
|
-
targetDirectoryPath,
|
|
107
|
-
packageManifest,
|
|
108
|
-
selectedStackFileName,
|
|
109
|
-
selectedBlueprintFileName,
|
|
110
|
-
uiScopeSignals,
|
|
111
|
-
}) {
|
|
112
|
-
const projectName = String(packageManifest?.name || path.basename(targetDirectoryPath)).trim() || 'existing-ui-project';
|
|
113
|
-
const isMobileUiProject = String(selectedStackFileName || '').toLowerCase().includes('react-native')
|
|
114
|
-
|| String(selectedStackFileName || '').toLowerCase().includes('flutter')
|
|
115
|
-
|| uiScopeSignals.signalReasons.some((signalReason) => signalReason.includes('android') || signalReason.includes('ios'));
|
|
116
|
-
const resolvedDomain = isMobileUiProject ? 'Mobile app' : 'Web application';
|
|
117
|
-
const projectDescription = String(packageManifest?.description || '').trim()
|
|
118
|
-
|| `Existing ${resolvedDomain.toLowerCase()} detected during upgrade. Create a project-specific dynamic design contract before shipping new UI work.`;
|
|
119
|
-
|
|
120
|
-
return buildDesignIntentSeedFromSignals({
|
|
121
|
-
projectName,
|
|
122
|
-
projectDescription,
|
|
123
|
-
primaryDomain: resolvedDomain,
|
|
124
|
-
features: [],
|
|
125
|
-
initContext: {
|
|
126
|
-
stackFileName: selectedStackFileName,
|
|
127
|
-
blueprintFileName: selectedBlueprintFileName,
|
|
128
|
-
},
|
|
129
|
-
status: 'seed-generated-during-upgrade',
|
|
130
|
-
supplementalFields: {
|
|
131
|
-
upgradeSignals: {
|
|
132
|
-
detectedFrom: uiScopeSignals.signalReasons,
|
|
133
|
-
generatedBy: 'upgrade-seed',
|
|
134
|
-
},
|
|
135
|
-
repoEvidence: {
|
|
136
|
-
uiSignalReasons: uiScopeSignals.signalReasons,
|
|
137
|
-
frontendMetrics: uiScopeSignals.frontendEvidenceMetrics || null,
|
|
138
|
-
designEvidenceSummary: uiScopeSignals.designEvidenceSummary || null,
|
|
139
|
-
workspaceUiEntries: uiScopeSignals.workspaceUiEntries || [],
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
111
|
export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions = {}) {
|
|
146
112
|
const resolvedTargetDirectoryPath = path.resolve(targetDirectoryArgument || '.');
|
|
147
113
|
|
|
@@ -175,6 +141,10 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
|
|
|
175
141
|
const stackFileNames = await collectFileNames(path.join(AGENT_CONTEXT_DIR, 'stacks'));
|
|
176
142
|
const blueprintFileNames = await collectFileNames(path.join(AGENT_CONTEXT_DIR, 'blueprints'));
|
|
177
143
|
const existingOnboardingReport = await loadOnboardingReportIfExists(resolvedTargetDirectoryPath);
|
|
144
|
+
const tokenOptimizationPlan = await resolveUpgradeTokenOptimizationPlan(
|
|
145
|
+
resolvedTargetDirectoryPath,
|
|
146
|
+
existingOnboardingReport
|
|
147
|
+
);
|
|
178
148
|
const projectDetection = await detectProjectContext(resolvedTargetDirectoryPath);
|
|
179
149
|
const selectedProfileName = PROFILE_PRESETS[existingOnboardingReport?.selectedProfile]
|
|
180
150
|
? existingOnboardingReport.selectedProfile
|
|
@@ -302,6 +272,9 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
|
|
|
302
272
|
}
|
|
303
273
|
console.log(`- CI/CD quality checks (guardrails): ${includeCiGuardrails ? 'enabled' : 'disabled'}`);
|
|
304
274
|
console.log('- Instruction surface: AGENTS.md canonical with CLAUDE.md and GEMINI.md import bridges');
|
|
275
|
+
console.log('- Default activation cues: Adaptive Context bootstrap, ASCX wrappers, Compact Natural replies');
|
|
276
|
+
console.log(`- Token optimization policy: ${tokenOptimizationPlan.previewLabel}`);
|
|
277
|
+
console.log('- Default response mode: Compact Natural Mode enabled');
|
|
305
278
|
console.log(`- Managed surface stale files: ${managedSurfacePlan.staleFiles.length}`);
|
|
306
279
|
console.log(`- Managed surface stale directories: ${managedSurfacePlan.staleDirectories.length}`);
|
|
307
280
|
console.log(`- Managed surface sync mode: 1:1 (prune enabled)`);
|
|
@@ -373,6 +346,12 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
|
|
|
373
346
|
if (backupGitignoreResult.status !== 'unchanged') {
|
|
374
347
|
console.log(`Local backup artifacts ignored in .gitignore (${backupGitignoreResult.entry}).`);
|
|
375
348
|
}
|
|
349
|
+
const runtimeArtifactGitignoreResult = await ensureRuntimeArtifactGitignoreEntries(resolvedTargetDirectoryPath);
|
|
350
|
+
if (runtimeArtifactGitignoreResult.status !== 'unchanged') {
|
|
351
|
+
console.log(
|
|
352
|
+
`Local runtime artifacts ignored in .gitignore (${runtimeArtifactGitignoreResult.addedEntries.join(', ')}).`
|
|
353
|
+
);
|
|
354
|
+
}
|
|
376
355
|
|
|
377
356
|
try {
|
|
378
357
|
const governanceSyncResult = await copyGovernanceAssetsToTarget(resolvedTargetDirectoryPath, {
|
|
@@ -382,6 +361,13 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
|
|
|
382
361
|
});
|
|
383
362
|
const supplementalCreatedFileNames = [];
|
|
384
363
|
const shouldEnsureActiveMemorySnapshot = existingOnboardingReport?.memoryContinuity?.enabled !== false;
|
|
364
|
+
const tokenOptimizationApplyResult = await applyUpgradeTokenOptimizationPlan(
|
|
365
|
+
resolvedTargetDirectoryPath,
|
|
366
|
+
tokenOptimizationPlan
|
|
367
|
+
);
|
|
368
|
+
if (tokenOptimizationApplyResult.createdFileName) {
|
|
369
|
+
supplementalCreatedFileNames.push(tokenOptimizationApplyResult.createdFileName);
|
|
370
|
+
}
|
|
385
371
|
|
|
386
372
|
if (shouldSeedDesignIntentOnApply && designIntentSeedContent) {
|
|
387
373
|
const docsDirectoryPath = path.join(resolvedTargetDirectoryPath, 'docs');
|
|
@@ -427,6 +413,7 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
|
|
|
427
413
|
projectDetection,
|
|
428
414
|
runtimeEnvironment: existingOnboardingReport?.runtimeEnvironment || null,
|
|
429
415
|
operationMode: 'upgrade',
|
|
416
|
+
tokenOptimization: tokenOptimizationApplyResult.reportState,
|
|
430
417
|
detectionTransparency,
|
|
431
418
|
uiScopeSignals,
|
|
432
419
|
});
|
|
@@ -464,6 +451,8 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
|
|
|
464
451
|
}
|
|
465
452
|
|
|
466
453
|
console.log('\nRefreshed files: AGENTS.md, CLAUDE.md, GEMINI.md, .agent-context/, and .agent-context/state/onboarding-report.json');
|
|
454
|
+
console.log('Default activation cues remain Adaptive Context bootstrap, ASCX command wrappers, and Compact Natural final replies.');
|
|
455
|
+
console.log('Default response mode remains Compact Natural Mode through .agent-context/prompts/compact-natural-mode.md.');
|
|
467
456
|
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
457
|
} catch (error) {
|
|
469
458
|
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',
|
|
@@ -31,6 +31,7 @@ function buildDockerStrategyExecutionBlock(dockerStrategy) {
|
|
|
31
31
|
'- Required asset floor: ' + requiredAssetFloor + '.',
|
|
32
32
|
'- Keep development and production lanes separate when both are selected.',
|
|
33
33
|
'- If the user asks to create files without commands, write the files and documented commands, but do not execute Docker build, Compose, or registry commands.',
|
|
34
|
+
'- If Docker is enabled for development, local development setup and first-build instructions in the README must use Docker (e.g., `docker compose up`) rather than fallback local commands like `npm run dev`.',
|
|
34
35
|
];
|
|
35
36
|
}
|
|
36
37
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
1
2
|
import fs from 'node:fs/promises';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { spawnSync } from 'node:child_process';
|
|
4
5
|
import { platform } from 'node:process';
|
|
5
6
|
|
|
7
|
+
import { REPOSITORY_ROOT } from './constants.mjs';
|
|
6
8
|
import { pathExists } from './utils.mjs';
|
|
7
9
|
|
|
8
10
|
export const TOKEN_OPTIMIZATION_STATE_FILE_NAME = 'token-optimization.json';
|
|
@@ -44,13 +46,13 @@ const COMMAND_REWRITE_MAPPINGS = [
|
|
|
44
46
|
},
|
|
45
47
|
{
|
|
46
48
|
rawCommand: 'git status',
|
|
47
|
-
optimizedCommand: '
|
|
48
|
-
reason: '
|
|
49
|
+
optimizedCommand: 'ascx git status',
|
|
50
|
+
reason: 'ASCX condenses status output while preserving changed-file evidence and raw tee safety.',
|
|
49
51
|
},
|
|
50
52
|
{
|
|
51
53
|
rawCommand: 'git diff',
|
|
52
|
-
optimizedCommand: '
|
|
53
|
-
reason: '
|
|
54
|
+
optimizedCommand: 'ascx git diff',
|
|
55
|
+
reason: 'ASCX preserves changed files, hunk anchors, binary/deleted markers, truncation notes, and raw tee safety.',
|
|
54
56
|
},
|
|
55
57
|
{
|
|
56
58
|
rawCommand: 'git log -n 10',
|
|
@@ -59,8 +61,8 @@ const COMMAND_REWRITE_MAPPINGS = [
|
|
|
59
61
|
},
|
|
60
62
|
{
|
|
61
63
|
rawCommand: 'npm test',
|
|
62
|
-
optimizedCommand: '
|
|
63
|
-
reason: '
|
|
64
|
+
optimizedCommand: 'ascx npm test',
|
|
65
|
+
reason: 'ASCX preserves exit code, failing tests, assertions, file paths, and raw tee safety.',
|
|
64
66
|
},
|
|
65
67
|
{
|
|
66
68
|
rawCommand: 'npm run build',
|
|
@@ -179,6 +181,157 @@ export function detectRtkBinary() {
|
|
|
179
181
|
}
|
|
180
182
|
}
|
|
181
183
|
|
|
184
|
+
export function detectAscxRuntime() {
|
|
185
|
+
const localBinPath = path.join(REPOSITORY_ROOT, 'bin', 'ascx.js');
|
|
186
|
+
const pathDetection = spawnSync('ascx', [], {
|
|
187
|
+
encoding: 'utf8',
|
|
188
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
189
|
+
});
|
|
190
|
+
const pathBinaryLooksAvailable = pathDetection.error == null
|
|
191
|
+
&& typeof pathDetection.status === 'number'
|
|
192
|
+
&& /command is required/i.test(`${pathDetection.stdout || ''}\n${pathDetection.stderr || ''}`);
|
|
193
|
+
|
|
194
|
+
if (pathBinaryLooksAvailable) {
|
|
195
|
+
return {
|
|
196
|
+
isAvailable: true,
|
|
197
|
+
source: 'path',
|
|
198
|
+
command: 'ascx',
|
|
199
|
+
localBinPath,
|
|
200
|
+
detectionError: null,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (existsSync(localBinPath)) {
|
|
205
|
+
return {
|
|
206
|
+
isAvailable: true,
|
|
207
|
+
source: 'package-bin',
|
|
208
|
+
command: `node ${localBinPath}`,
|
|
209
|
+
localBinPath,
|
|
210
|
+
detectionError: pathDetection.error ? pathDetection.error.message : null,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
isAvailable: false,
|
|
216
|
+
source: 'missing',
|
|
217
|
+
command: null,
|
|
218
|
+
localBinPath,
|
|
219
|
+
detectionError: pathDetection.error
|
|
220
|
+
? pathDetection.error.message
|
|
221
|
+
: (pathDetection.stderr || pathDetection.stdout || 'ascx binary was not detected').trim(),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export async function checkAscxTeeReadiness(targetDirectoryPath, options = {}) {
|
|
226
|
+
const shouldWriteProbe = options.writeProbe === true;
|
|
227
|
+
const stateDirectoryPath = path.join(targetDirectoryPath, '.agent-context', 'state');
|
|
228
|
+
const teeDirectoryPath = path.join(stateDirectoryPath, 'token-saver', 'tee');
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
if (shouldWriteProbe) {
|
|
232
|
+
await fs.mkdir(teeDirectoryPath, { recursive: true });
|
|
233
|
+
const probeFilePath = path.join(teeDirectoryPath, `.ascx-probe-${process.pid}.tmp`);
|
|
234
|
+
await fs.writeFile(probeFilePath, 'ascx tee probe\n', 'utf8');
|
|
235
|
+
await fs.rm(probeFilePath, { force: true });
|
|
236
|
+
} else {
|
|
237
|
+
await fs.access(stateDirectoryPath);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
status: 'writable',
|
|
242
|
+
path: teeDirectoryPath,
|
|
243
|
+
error: null,
|
|
244
|
+
};
|
|
245
|
+
} catch (readinessError) {
|
|
246
|
+
return {
|
|
247
|
+
status: 'not-writable',
|
|
248
|
+
path: teeDirectoryPath,
|
|
249
|
+
error: readinessError instanceof Error ? readinessError.message : String(readinessError),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export function resolveRuntimeTokenSaverMode({
|
|
255
|
+
tokenOptimizationState,
|
|
256
|
+
ascxDetection,
|
|
257
|
+
rtkDetection,
|
|
258
|
+
}) {
|
|
259
|
+
const stateEnabled = tokenOptimizationState?.enabled === true;
|
|
260
|
+
const rtkDetected = rtkDetection?.isAvailable === true;
|
|
261
|
+
|
|
262
|
+
if (stateEnabled && ascxDetection?.isAvailable && rtkDetected) {
|
|
263
|
+
return 'conflict-risk';
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (stateEnabled && ascxDetection?.isAvailable) {
|
|
267
|
+
return 'runtime-on';
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (stateEnabled) {
|
|
271
|
+
return 'policy-only';
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (rtkDetected) {
|
|
275
|
+
return 'external-runtime-detected';
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return 'runtime-off';
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export function buildRuntimeTokenSaverWarnings({
|
|
282
|
+
mode,
|
|
283
|
+
onboardingReport,
|
|
284
|
+
ascxDetection,
|
|
285
|
+
teeReadiness,
|
|
286
|
+
rtkDetection,
|
|
287
|
+
}) {
|
|
288
|
+
const warnings = [];
|
|
289
|
+
|
|
290
|
+
if (!onboardingReport) {
|
|
291
|
+
warnings.push('project is not initialized; run init before enabling runtime token saving');
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (!ascxDetection?.isAvailable) {
|
|
295
|
+
warnings.push('ascx binary is missing; supported commands will not be compressed');
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (teeReadiness?.status !== 'writable') {
|
|
299
|
+
warnings.push('raw tee folder is not writable; failing commands may lose safety logs');
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (mode === 'conflict-risk') {
|
|
303
|
+
warnings.push('ASCX and an external runtime compressor both appear active; avoid double compression');
|
|
304
|
+
} else if (rtkDetection?.isAvailable) {
|
|
305
|
+
warnings.push('external runtime compressor detected; keep only one runtime compressor enabled by default');
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return warnings;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export function buildRuntimeTokenSaverNextAction({ mode, warnings }) {
|
|
312
|
+
if (warnings.some((warning) => warning.includes('not initialized'))) {
|
|
313
|
+
return 'Run agentic-senior-core init before enabling ASCX runtime saving.';
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (warnings.some((warning) => warning.includes('tee folder'))) {
|
|
317
|
+
return 'Fix .agent-context/state write access, then rerun optimize doctor.';
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (mode === 'conflict-risk') {
|
|
321
|
+
return 'Disable either ASCX runtime saving or the external compressor before using compressed command output.';
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (mode === 'runtime-on') {
|
|
325
|
+
return 'Use ascx git status, ascx git diff, and ascx npm test for supported high-volume command output.';
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (mode === 'policy-only') {
|
|
329
|
+
return 'Install or expose the ascx binary, then rerun optimize doctor.';
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return 'Run agentic-senior-core optimize install to enable ASCX guidance for this repository.';
|
|
333
|
+
}
|
|
334
|
+
|
|
182
335
|
export function buildRtkInstallHint() {
|
|
183
336
|
if (platform === 'win32') {
|
|
184
337
|
return 'Install the external token optimizer binary for Windows, extract it, and ensure the executable is on PATH.';
|
|
@@ -298,6 +451,7 @@ export function buildTokenOptimizationGuidanceBlock(tokenOptimizationState) {
|
|
|
298
451
|
);
|
|
299
452
|
|
|
300
453
|
const fallbackGuidance = [
|
|
454
|
+
'- Use ascx git status, ascx git diff, and ascx npm test when the ascx binary is available.',
|
|
301
455
|
'- Use command variants with bounded output such as git diff --stat, rg --max-count, and npm test -- --reporter=dot.',
|
|
302
456
|
'- Request only the lines or sections required for the current decision.',
|
|
303
457
|
'- If shell output is still large, summarize and continue iteratively instead of dumping full logs.',
|
|
@@ -319,6 +473,7 @@ export function buildTokenOptimizationGuidanceBlock(tokenOptimizationState) {
|
|
|
319
473
|
...rewriteLines,
|
|
320
474
|
'',
|
|
321
475
|
'Important scope note:',
|
|
476
|
+
'- ASCX wrappers are explicit local command wrappers, not provider gateways.',
|
|
322
477
|
'- Shell rewrite hooks affect shell tool calls only.',
|
|
323
478
|
'- Built-in read/grep/glob style tools may bypass shell rewrites, so explicit compact shell commands should be preferred in high-volume sessions.',
|
|
324
479
|
'',
|