@ryuenn3123/agentic-senior-core 2.0.26 → 2.5.3
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/state/benchmark-evidence-bundle.json +672 -22
- package/.agent-context/state/benchmark-history.json +75 -0
- package/.agent-context/state/benchmark-trend-report.csv +5 -0
- package/.agent-context/state/benchmark-trend-report.json +140 -0
- package/.agent-context/state/benchmark-watchlist.json +3 -3
- package/.agent-context/state/memory-adapter-contract.json +52 -0
- package/.agent-context/state/memory-continuity-benchmark.json +132 -0
- package/.agent-context/state/memory-schema-v1.json +88 -0
- package/.cursorrules +1 -1
- package/.windsurfrules +1 -1
- package/README.md +43 -0
- package/lib/cli/commands/init.mjs +47 -1
- package/lib/cli/compiler.mjs +22 -0
- package/lib/cli/memory-continuity.mjs +395 -0
- package/lib/cli/utils.mjs +3 -1
- package/package.json +2 -1
- package/scripts/benchmark-evidence-bundle.mjs +493 -16
- package/scripts/memory-continuity-benchmark.mjs +322 -0
- package/scripts/validate.mjs +3 -0
|
@@ -56,6 +56,10 @@ import {
|
|
|
56
56
|
normalizeAgentName,
|
|
57
57
|
writeTokenOptimizationState,
|
|
58
58
|
} from '../token-optimization.mjs';
|
|
59
|
+
import {
|
|
60
|
+
createMemoryContinuityState,
|
|
61
|
+
writeMemoryContinuityState,
|
|
62
|
+
} from '../memory-continuity.mjs';
|
|
59
63
|
import { evaluateSkillDomainCompatibility } from '../compatibility.mjs';
|
|
60
64
|
|
|
61
65
|
export { REPO_ROOT } from '../constants.mjs';
|
|
@@ -71,6 +75,7 @@ export function parseInitArguments(commandArguments) {
|
|
|
71
75
|
ci: undefined,
|
|
72
76
|
newbie: false,
|
|
73
77
|
tokenOptimize: true,
|
|
78
|
+
memoryContinuity: true,
|
|
74
79
|
tokenAgent: 'copilot',
|
|
75
80
|
includeMcpTemplate: false,
|
|
76
81
|
scaffoldDocs: undefined,
|
|
@@ -166,6 +171,11 @@ export function parseInitArguments(commandArguments) {
|
|
|
166
171
|
continue;
|
|
167
172
|
}
|
|
168
173
|
|
|
174
|
+
if (currentArgument === '--memory-continuity') {
|
|
175
|
+
parsedInitOptions.memoryContinuity = true;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
|
|
169
179
|
if (currentArgument === '--token-agent') {
|
|
170
180
|
parsedInitOptions.tokenAgent = commandArguments[argumentIndex + 1] || 'copilot';
|
|
171
181
|
argumentIndex += 1;
|
|
@@ -182,6 +192,11 @@ export function parseInitArguments(commandArguments) {
|
|
|
182
192
|
continue;
|
|
183
193
|
}
|
|
184
194
|
|
|
195
|
+
if (currentArgument === '--no-memory-continuity') {
|
|
196
|
+
parsedInitOptions.memoryContinuity = false;
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
|
|
185
200
|
if (currentArgument === '--mcp-template') {
|
|
186
201
|
parsedInitOptions.includeMcpTemplate = true;
|
|
187
202
|
continue;
|
|
@@ -408,6 +423,9 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
408
423
|
const isTokenOptimizationEnabled = typeof initOptions.tokenOptimize === 'boolean'
|
|
409
424
|
? initOptions.tokenOptimize
|
|
410
425
|
: true;
|
|
426
|
+
const isMemoryContinuityEnabled = typeof initOptions.memoryContinuity === 'boolean'
|
|
427
|
+
? initOptions.memoryContinuity
|
|
428
|
+
: true;
|
|
411
429
|
const shouldIncludeMcpTemplate = initOptions.includeMcpTemplate === true;
|
|
412
430
|
const selectedTokenAgentName = normalizeAgentName(initOptions.tokenAgent || 'copilot');
|
|
413
431
|
const isInteractiveSession = Boolean(stdin.isTTY && stdout.isTTY);
|
|
@@ -729,9 +747,20 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
729
747
|
includeMcpTemplate: shouldIncludeMcpTemplate,
|
|
730
748
|
});
|
|
731
749
|
|
|
750
|
+
let memoryContinuityState = null;
|
|
751
|
+
if (isMemoryContinuityEnabled) {
|
|
752
|
+
memoryContinuityState = createMemoryContinuityState({
|
|
753
|
+
isEnabled: true,
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
await writeMemoryContinuityState(resolvedTargetDirectoryPath, memoryContinuityState);
|
|
757
|
+
console.log(`Memory continuity policy enabled (${memoryContinuityState.hydrationMode}).`);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
let tokenOptimizationState = null;
|
|
732
761
|
if (isTokenOptimizationEnabled) {
|
|
733
762
|
const detectedExternalProxy = detectRtkBinary();
|
|
734
|
-
|
|
763
|
+
tokenOptimizationState = createTokenOptimizationState({
|
|
735
764
|
isEnabled: true,
|
|
736
765
|
selectedAgentName: selectedTokenAgentName,
|
|
737
766
|
rtkDetection: detectedExternalProxy,
|
|
@@ -862,6 +891,18 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
862
891
|
detectionSource: detectedRuntimeEnvironment.source,
|
|
863
892
|
},
|
|
864
893
|
operationMode: 'init',
|
|
894
|
+
tokenOptimization: {
|
|
895
|
+
enabled: isTokenOptimizationEnabled,
|
|
896
|
+
selectedAgent: selectedTokenAgentName,
|
|
897
|
+
preferredShellProxy: tokenOptimizationState?.preferredShellProxy || null,
|
|
898
|
+
stateFile: isTokenOptimizationEnabled ? '.agent-context/state/token-optimization.json' : null,
|
|
899
|
+
},
|
|
900
|
+
memoryContinuity: {
|
|
901
|
+
enabled: isMemoryContinuityEnabled,
|
|
902
|
+
hydrationMode: memoryContinuityState?.hydrationMode || null,
|
|
903
|
+
adapters: memoryContinuityState?.adapters || [],
|
|
904
|
+
stateFile: isMemoryContinuityEnabled ? '.agent-context/state/memory-continuity.json' : null,
|
|
905
|
+
},
|
|
865
906
|
});
|
|
866
907
|
|
|
867
908
|
console.log('\nInitialization complete.');
|
|
@@ -892,6 +933,11 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
892
933
|
}
|
|
893
934
|
console.log(`- Repository workflows copied: no (workflows remain source-repo assets)`);
|
|
894
935
|
console.log(`- MCP template file: ${shouldIncludeMcpTemplate ? 'created (.vscode/mcp.json)' : 'not created by default (use --mcp-template)'}`);
|
|
936
|
+
if (isMemoryContinuityEnabled) {
|
|
937
|
+
console.log('- Memory continuity policy: enabled (index + selective hydration)');
|
|
938
|
+
} else {
|
|
939
|
+
console.log('- Memory continuity policy: disabled (--no-memory-continuity)');
|
|
940
|
+
}
|
|
895
941
|
if (isTokenOptimizationEnabled) {
|
|
896
942
|
console.log(`- Token optimization policy: enabled for ${selectedTokenAgentName}`);
|
|
897
943
|
} else {
|
package/lib/cli/compiler.mjs
CHANGED
|
@@ -25,6 +25,10 @@ import {
|
|
|
25
25
|
readTokenOptimizationState,
|
|
26
26
|
buildTokenOptimizationGuidanceBlock,
|
|
27
27
|
} from './token-optimization.mjs';
|
|
28
|
+
import {
|
|
29
|
+
readMemoryContinuityState,
|
|
30
|
+
buildMemoryContinuityGuidanceBlock,
|
|
31
|
+
} from './memory-continuity.mjs';
|
|
28
32
|
|
|
29
33
|
export async function writeSelectedPolicy(targetDirectoryPath, selectedProfileName) {
|
|
30
34
|
const policyFilePath = path.join(targetDirectoryPath, '.agent-context', 'policies', POLICY_FILE_NAME);
|
|
@@ -49,8 +53,16 @@ export async function writeOnboardingReport({
|
|
|
49
53
|
compatibilityWarnings = [],
|
|
50
54
|
runtimeEnvironment = null,
|
|
51
55
|
operationMode = 'init',
|
|
56
|
+
tokenOptimization = undefined,
|
|
57
|
+
memoryContinuity = undefined,
|
|
52
58
|
}) {
|
|
53
59
|
const onboardingReportPath = path.join(targetDirectoryPath, '.agent-context', 'state', 'onboarding-report.json');
|
|
60
|
+
const resolvedTokenOptimization = typeof tokenOptimization === 'undefined'
|
|
61
|
+
? await readTokenOptimizationState(targetDirectoryPath)
|
|
62
|
+
: tokenOptimization;
|
|
63
|
+
const resolvedMemoryContinuity = typeof memoryContinuity === 'undefined'
|
|
64
|
+
? await readMemoryContinuityState(targetDirectoryPath)
|
|
65
|
+
: memoryContinuity;
|
|
54
66
|
const onboardingReport = {
|
|
55
67
|
cliVersion: CLI_VERSION,
|
|
56
68
|
generatedAt: new Date().toISOString(),
|
|
@@ -72,6 +84,8 @@ export async function writeOnboardingReport({
|
|
|
72
84
|
selectedSkillDomains,
|
|
73
85
|
compatibilityWarnings,
|
|
74
86
|
runtimeEnvironment,
|
|
87
|
+
tokenOptimization: resolvedTokenOptimization,
|
|
88
|
+
memoryContinuity: resolvedMemoryContinuity,
|
|
75
89
|
autoDetection: {
|
|
76
90
|
recommendedStack: projectDetection.recommendedStackFileName,
|
|
77
91
|
recommendedAdditionalStacks: projectDetection.secondaryStackFileNames || [],
|
|
@@ -267,6 +281,14 @@ export async function buildCompiledRulesContent({
|
|
|
267
281
|
`## TOKEN OPTIMIZATION PROFILE\nSource: .agent-context/state/token-optimization.json\n\n${buildTokenOptimizationGuidanceBlock(tokenOptimizationState).trim()}`
|
|
268
282
|
);
|
|
269
283
|
}
|
|
284
|
+
|
|
285
|
+
const memoryContinuityState = await readMemoryContinuityState(resolvedTargetDirectoryPath);
|
|
286
|
+
if (memoryContinuityState?.enabled) {
|
|
287
|
+
contextBlocks.push(
|
|
288
|
+
`## MEMORY CONTINUITY PROFILE\nSource: .agent-context/state/memory-continuity.json\n\n${buildMemoryContinuityGuidanceBlock(memoryContinuityState).trim()}`
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
270
292
|
contextBlocks.push(
|
|
271
293
|
[
|
|
272
294
|
'## LAYER 7: STATE AWARENESS (MANDATORY)',
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-agent memory continuity utilities.
|
|
3
|
+
* Provides provider-agnostic observation normalization, privacy redaction,
|
|
4
|
+
* lightweight indexing, and selective hydration helpers.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from 'node:fs/promises';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
|
|
10
|
+
import { pathExists } from './utils.mjs';
|
|
11
|
+
|
|
12
|
+
const PRIVATE_BLOCK_PATTERN = /<private>[\s\S]*?<\/private>/gi;
|
|
13
|
+
|
|
14
|
+
const INLINE_SENSITIVE_PATTERNS = [
|
|
15
|
+
{
|
|
16
|
+
reason: 'api-key-like-value',
|
|
17
|
+
pattern: /\b(api[_-]?key)\b\s*[:=]\s*[^\s,;]+/gi,
|
|
18
|
+
replacer: (_match, fieldName) => `${fieldName}=[REDACTED]`,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
reason: 'token-like-value',
|
|
22
|
+
pattern: /\b(token)\b\s*[:=]\s*[^\s,;]+/gi,
|
|
23
|
+
replacer: (_match, fieldName) => `${fieldName}=[REDACTED]`,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
reason: 'password-like-value',
|
|
27
|
+
pattern: /\b(password|passwd|pwd)\b\s*[:=]\s*[^\s,;]+/gi,
|
|
28
|
+
replacer: (_match, fieldName) => `${fieldName}=[REDACTED]`,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
reason: 'bearer-token',
|
|
32
|
+
pattern: /\bBearer\s+[A-Za-z0-9._-]+/g,
|
|
33
|
+
replacer: () => 'Bearer [REDACTED]',
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
export const MEMORY_SCHEMA_VERSION = '1.0.0';
|
|
38
|
+
export const MEMORY_CONTINUITY_STATE_FILE_NAME = 'memory-continuity.json';
|
|
39
|
+
|
|
40
|
+
const MEMORY_CONTINUITY_STATE_SCHEMA_VERSION = 'memory-continuity-v1';
|
|
41
|
+
|
|
42
|
+
export const SUPPORTED_MEMORY_ADAPTER_IDS = Object.freeze([
|
|
43
|
+
'claude-code',
|
|
44
|
+
'gemini-cli',
|
|
45
|
+
'vscode-chat',
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
export const SUPPORTED_MEMORY_EVENT_TYPES = Object.freeze([
|
|
49
|
+
'prompt',
|
|
50
|
+
'tool-use',
|
|
51
|
+
'decision',
|
|
52
|
+
'summary',
|
|
53
|
+
'issue',
|
|
54
|
+
'context',
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
function toIsoTimestamp(rawValue) {
|
|
58
|
+
if (typeof rawValue !== 'string' || rawValue.trim().length === 0) {
|
|
59
|
+
return new Date().toISOString();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const parsedDate = new Date(rawValue);
|
|
63
|
+
if (Number.isNaN(parsedDate.getTime())) {
|
|
64
|
+
return new Date().toISOString();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return parsedDate.toISOString();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function toNonEmptyString(rawValue, fallbackValue = '') {
|
|
71
|
+
if (typeof rawValue !== 'string') {
|
|
72
|
+
return fallbackValue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const normalizedValue = rawValue.trim();
|
|
76
|
+
return normalizedValue.length > 0 ? normalizedValue : fallbackValue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function normalizeTags(rawTags) {
|
|
80
|
+
if (!Array.isArray(rawTags)) {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const tagSet = new Set();
|
|
85
|
+
for (const rawTag of rawTags) {
|
|
86
|
+
const normalizedTag = toNonEmptyString(String(rawTag || '')).toLowerCase();
|
|
87
|
+
if (normalizedTag) {
|
|
88
|
+
tagSet.add(normalizedTag);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return Array.from(tagSet);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function normalizeMemoryAdapterIds(rawAdapterIds) {
|
|
96
|
+
if (!Array.isArray(rawAdapterIds) || rawAdapterIds.length === 0) {
|
|
97
|
+
return [...SUPPORTED_MEMORY_ADAPTER_IDS];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const normalizedAdapterIdSet = new Set();
|
|
101
|
+
for (const rawAdapterId of rawAdapterIds) {
|
|
102
|
+
const normalizedAdapterId = toNonEmptyString(String(rawAdapterId || '')).toLowerCase();
|
|
103
|
+
if (!normalizedAdapterId) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!SUPPORTED_MEMORY_ADAPTER_IDS.includes(normalizedAdapterId)) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
normalizedAdapterIdSet.add(normalizedAdapterId);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (normalizedAdapterIdSet.size === 0) {
|
|
115
|
+
return [...SUPPORTED_MEMORY_ADAPTER_IDS];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return Array.from(normalizedAdapterIdSet);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function estimateTokenUsage(rawText = '') {
|
|
122
|
+
const normalizedText = String(rawText || '');
|
|
123
|
+
return Math.max(1, Math.ceil(normalizedText.length / 4));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function redactSensitiveMemoryText(rawText = '') {
|
|
127
|
+
let normalizedText = String(rawText || '');
|
|
128
|
+
const redactionReasons = new Set();
|
|
129
|
+
let privateTagRedactionCount = 0;
|
|
130
|
+
let inlineRedactionCount = 0;
|
|
131
|
+
|
|
132
|
+
normalizedText = normalizedText.replace(PRIVATE_BLOCK_PATTERN, () => {
|
|
133
|
+
privateTagRedactionCount += 1;
|
|
134
|
+
redactionReasons.add('private-tag');
|
|
135
|
+
return '[REDACTED_PRIVATE_BLOCK]';
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
for (const sensitivePattern of INLINE_SENSITIVE_PATTERNS) {
|
|
139
|
+
normalizedText = normalizedText.replace(sensitivePattern.pattern, (...replacerArguments) => {
|
|
140
|
+
inlineRedactionCount += 1;
|
|
141
|
+
redactionReasons.add(sensitivePattern.reason);
|
|
142
|
+
return sensitivePattern.replacer(...replacerArguments);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
redactedText: normalizedText,
|
|
148
|
+
wasRedacted: privateTagRedactionCount > 0 || inlineRedactionCount > 0,
|
|
149
|
+
privateTagRedactionCount,
|
|
150
|
+
inlineRedactionCount,
|
|
151
|
+
redactionReasons: Array.from(redactionReasons),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function normalizeMemoryObservation(rawObservation, options = {}) {
|
|
156
|
+
const fallbackAdapterId = options.fallbackAdapterId || 'unknown-adapter';
|
|
157
|
+
const observationId = toNonEmptyString(rawObservation?.id, `${fallbackAdapterId}-${Date.now()}`);
|
|
158
|
+
const adapterId = toNonEmptyString(rawObservation?.adapterId, fallbackAdapterId);
|
|
159
|
+
|
|
160
|
+
const eventTypeCandidate = toNonEmptyString(rawObservation?.eventType, 'context').toLowerCase();
|
|
161
|
+
const eventType = SUPPORTED_MEMORY_EVENT_TYPES.includes(eventTypeCandidate)
|
|
162
|
+
? eventTypeCandidate
|
|
163
|
+
: 'context';
|
|
164
|
+
|
|
165
|
+
const rawDetail = toNonEmptyString(rawObservation?.detail, '');
|
|
166
|
+
const detailRedaction = redactSensitiveMemoryText(rawDetail);
|
|
167
|
+
|
|
168
|
+
const rawSummary = toNonEmptyString(rawObservation?.summary, detailRedaction.redactedText.slice(0, 220));
|
|
169
|
+
const summaryRedaction = redactSensitiveMemoryText(rawSummary);
|
|
170
|
+
|
|
171
|
+
const title = toNonEmptyString(rawObservation?.title, `${eventType} from ${adapterId}`);
|
|
172
|
+
const tags = normalizeTags(rawObservation?.tags);
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
id: observationId,
|
|
176
|
+
projectId: toNonEmptyString(rawObservation?.projectId, 'default-project'),
|
|
177
|
+
sessionId: toNonEmptyString(rawObservation?.sessionId, 'default-session'),
|
|
178
|
+
adapterId,
|
|
179
|
+
eventType,
|
|
180
|
+
timestamp: toIsoTimestamp(rawObservation?.timestamp),
|
|
181
|
+
title,
|
|
182
|
+
summary: summaryRedaction.redactedText,
|
|
183
|
+
detail: detailRedaction.redactedText,
|
|
184
|
+
tags,
|
|
185
|
+
privacy: {
|
|
186
|
+
level: toNonEmptyString(rawObservation?.privacyLevel, 'internal'),
|
|
187
|
+
redactionApplied: detailRedaction.wasRedacted || summaryRedaction.wasRedacted,
|
|
188
|
+
redactionReasons: Array.from(new Set([
|
|
189
|
+
...detailRedaction.redactionReasons,
|
|
190
|
+
...summaryRedaction.redactionReasons,
|
|
191
|
+
])),
|
|
192
|
+
privateTagRedactionCount: detailRedaction.privateTagRedactionCount + summaryRedaction.privateTagRedactionCount,
|
|
193
|
+
inlineRedactionCount: detailRedaction.inlineRedactionCount + summaryRedaction.inlineRedactionCount,
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function scoreObservationRelevance(queryText, normalizedObservation) {
|
|
199
|
+
const normalizedQuery = toNonEmptyString(queryText, '').toLowerCase();
|
|
200
|
+
if (!normalizedQuery) {
|
|
201
|
+
return 0;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const queryTerms = normalizedQuery
|
|
205
|
+
.split(/\s+/)
|
|
206
|
+
.map((queryTerm) => queryTerm.trim())
|
|
207
|
+
.filter((queryTerm) => queryTerm.length > 2);
|
|
208
|
+
|
|
209
|
+
if (queryTerms.length === 0) {
|
|
210
|
+
return 0;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const searchableContent = [
|
|
214
|
+
normalizedObservation.title,
|
|
215
|
+
normalizedObservation.summary,
|
|
216
|
+
normalizedObservation.detail,
|
|
217
|
+
normalizedObservation.tags.join(' '),
|
|
218
|
+
normalizedObservation.eventType,
|
|
219
|
+
normalizedObservation.adapterId,
|
|
220
|
+
].join(' ').toLowerCase();
|
|
221
|
+
|
|
222
|
+
let matchCount = 0;
|
|
223
|
+
for (const queryTerm of queryTerms) {
|
|
224
|
+
if (searchableContent.includes(queryTerm)) {
|
|
225
|
+
matchCount += 1;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return Number((matchCount / queryTerms.length).toFixed(4));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function buildSessionStartIndex(normalizedObservations, options = {}) {
|
|
233
|
+
const queryText = toNonEmptyString(options.queryText, '');
|
|
234
|
+
const maxIndexEntries = Number.isFinite(Number(options.limit)) ? Math.max(1, Number(options.limit)) : 8;
|
|
235
|
+
|
|
236
|
+
const rankedEntries = normalizedObservations
|
|
237
|
+
.map((normalizedObservation) => {
|
|
238
|
+
const relevanceScore = scoreObservationRelevance(queryText, normalizedObservation);
|
|
239
|
+
const indexLine = `${normalizedObservation.id}|${normalizedObservation.adapterId}|${normalizedObservation.eventType}|${normalizedObservation.title}`;
|
|
240
|
+
const indexTokenEstimate = estimateTokenUsage(indexLine);
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
id: normalizedObservation.id,
|
|
244
|
+
adapterId: normalizedObservation.adapterId,
|
|
245
|
+
eventType: normalizedObservation.eventType,
|
|
246
|
+
timestamp: normalizedObservation.timestamp,
|
|
247
|
+
title: normalizedObservation.title,
|
|
248
|
+
summarySnippet: normalizedObservation.summary.slice(0, 120),
|
|
249
|
+
tags: normalizedObservation.tags,
|
|
250
|
+
relevanceScore,
|
|
251
|
+
indexTokenEstimate,
|
|
252
|
+
};
|
|
253
|
+
})
|
|
254
|
+
.sort((leftEntry, rightEntry) => {
|
|
255
|
+
if (rightEntry.relevanceScore !== leftEntry.relevanceScore) {
|
|
256
|
+
return rightEntry.relevanceScore - leftEntry.relevanceScore;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return rightEntry.timestamp.localeCompare(leftEntry.timestamp);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
const indexEntries = rankedEntries.slice(0, maxIndexEntries);
|
|
263
|
+
const totalTokenEstimate = indexEntries.reduce(
|
|
264
|
+
(tokenAccumulator, indexEntry) => tokenAccumulator + indexEntry.indexTokenEstimate,
|
|
265
|
+
0
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
indexEntries,
|
|
270
|
+
totalTokenEstimate,
|
|
271
|
+
totalCandidateCount: rankedEntries.length,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export function hydrateIndexedObservations(indexEntries, normalizedObservations, options = {}) {
|
|
276
|
+
const fullFetchLimit = Number.isFinite(Number(options.fullFetchLimit))
|
|
277
|
+
? Math.max(1, Number(options.fullFetchLimit))
|
|
278
|
+
: 2;
|
|
279
|
+
|
|
280
|
+
const observationLookup = new Map(normalizedObservations.map((normalizedObservation) => [
|
|
281
|
+
normalizedObservation.id,
|
|
282
|
+
normalizedObservation,
|
|
283
|
+
]));
|
|
284
|
+
|
|
285
|
+
const selectedIds = indexEntries.slice(0, fullFetchLimit).map((indexEntry) => indexEntry.id);
|
|
286
|
+
const hydratedObservations = selectedIds
|
|
287
|
+
.map((selectedId) => observationLookup.get(selectedId))
|
|
288
|
+
.filter(Boolean);
|
|
289
|
+
|
|
290
|
+
const hydrationTokenEstimate = hydratedObservations.reduce(
|
|
291
|
+
(tokenAccumulator, hydratedObservation) => tokenAccumulator + estimateTokenUsage(hydratedObservation.detail),
|
|
292
|
+
0
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
return {
|
|
296
|
+
selectedIds,
|
|
297
|
+
hydratedObservations,
|
|
298
|
+
hydrationTokenEstimate,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export function createMemoryContinuityState(options = {}) {
|
|
303
|
+
const isEnabled = options.isEnabled !== false;
|
|
304
|
+
const sessionStartIndexLimit = Number.isFinite(Number(options.sessionStartIndexLimit))
|
|
305
|
+
? Math.max(1, Number(options.sessionStartIndexLimit))
|
|
306
|
+
: 8;
|
|
307
|
+
const fullHydrationLimit = Number.isFinite(Number(options.fullHydrationLimit))
|
|
308
|
+
? Math.max(1, Number(options.fullHydrationLimit))
|
|
309
|
+
: 2;
|
|
310
|
+
|
|
311
|
+
return {
|
|
312
|
+
schemaVersion: MEMORY_CONTINUITY_STATE_SCHEMA_VERSION,
|
|
313
|
+
enabled: isEnabled,
|
|
314
|
+
hydrationMode: 'progressive-disclosure',
|
|
315
|
+
adapters: normalizeMemoryAdapterIds(options.adapterIds),
|
|
316
|
+
retrieval: {
|
|
317
|
+
sessionStartIndexLimit,
|
|
318
|
+
fullHydrationLimit,
|
|
319
|
+
},
|
|
320
|
+
privacy: {
|
|
321
|
+
redactPrivateTags: true,
|
|
322
|
+
redactInlineSensitivePatterns: true,
|
|
323
|
+
},
|
|
324
|
+
generatedAt: new Date().toISOString(),
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export async function readMemoryContinuityState(targetDirectoryPath) {
|
|
329
|
+
const stateFilePath = path.join(
|
|
330
|
+
targetDirectoryPath,
|
|
331
|
+
'.agent-context',
|
|
332
|
+
'state',
|
|
333
|
+
MEMORY_CONTINUITY_STATE_FILE_NAME
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
if (!(await pathExists(stateFilePath))) {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
try {
|
|
341
|
+
const stateContent = await fs.readFile(stateFilePath, 'utf8');
|
|
342
|
+
const parsedState = JSON.parse(stateContent);
|
|
343
|
+
if (typeof parsedState.enabled !== 'boolean') {
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
parsedState.adapters = normalizeMemoryAdapterIds(parsedState.adapters);
|
|
348
|
+
return parsedState;
|
|
349
|
+
} catch {
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
export async function writeMemoryContinuityState(targetDirectoryPath, memoryContinuityState) {
|
|
355
|
+
const stateDirectoryPath = path.join(targetDirectoryPath, '.agent-context', 'state');
|
|
356
|
+
const stateFilePath = path.join(stateDirectoryPath, MEMORY_CONTINUITY_STATE_FILE_NAME);
|
|
357
|
+
|
|
358
|
+
await fs.mkdir(stateDirectoryPath, { recursive: true });
|
|
359
|
+
await fs.writeFile(stateFilePath, JSON.stringify(memoryContinuityState, null, 2) + '\n', 'utf8');
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export function buildMemoryContinuityGuidanceBlock(memoryContinuityState) {
|
|
363
|
+
if (!memoryContinuityState?.enabled) {
|
|
364
|
+
return [
|
|
365
|
+
'Memory continuity mode is disabled for this repository.',
|
|
366
|
+
'Use explicit session summaries when handing off context across tools.',
|
|
367
|
+
].join('\n');
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const adapterGuidanceLine = memoryContinuityState.adapters?.length
|
|
371
|
+
? `Supported adapters: ${memoryContinuityState.adapters.join(', ')}.`
|
|
372
|
+
: `Supported adapters: ${SUPPORTED_MEMORY_ADAPTER_IDS.join(', ')}.`;
|
|
373
|
+
|
|
374
|
+
const sessionStartIndexLimit = Number.isFinite(Number(memoryContinuityState.retrieval?.sessionStartIndexLimit))
|
|
375
|
+
? Number(memoryContinuityState.retrieval.sessionStartIndexLimit)
|
|
376
|
+
: 8;
|
|
377
|
+
const fullHydrationLimit = Number.isFinite(Number(memoryContinuityState.retrieval?.fullHydrationLimit))
|
|
378
|
+
? Number(memoryContinuityState.retrieval.fullHydrationLimit)
|
|
379
|
+
: 2;
|
|
380
|
+
|
|
381
|
+
return [
|
|
382
|
+
'Memory continuity mode is enabled.',
|
|
383
|
+
'Hydration mode: progressive-disclosure.',
|
|
384
|
+
adapterGuidanceLine,
|
|
385
|
+
'',
|
|
386
|
+
'Session-start retrieval policy:',
|
|
387
|
+
`- Load compact index first (limit: ${sessionStartIndexLimit} entries).`,
|
|
388
|
+
`- Hydrate full detail only for highest-value entries (limit: ${fullHydrationLimit}).`,
|
|
389
|
+
'- Always redact sensitive text before persistence (<private> blocks and inline secret-like fields).',
|
|
390
|
+
'',
|
|
391
|
+
'Host compatibility scope:',
|
|
392
|
+
'- Works for local IDE, CLI, and cloud IDE chat hosts that implement the memory adapter contract or MCP retrieval path.',
|
|
393
|
+
'- Generic web chat sessions without repository tools cannot auto-hydrate runtime memory and should rely on manual summary export/import.',
|
|
394
|
+
].join('\n');
|
|
395
|
+
}
|
package/lib/cli/utils.mjs
CHANGED
|
@@ -28,7 +28,7 @@ export function printUsage() {
|
|
|
28
28
|
console.log('');
|
|
29
29
|
console.log('Usage:');
|
|
30
30
|
console.log(' agentic-senior-core launch');
|
|
31
|
-
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] [--no-token-optimize] [--token-agent <name>] [--scaffold-docs] [--no-scaffold-docs] [--docs-lang <en|id>] [--project-config <path>] [--runtime-env <auto|linux-wsl|linux|windows|macos>]');
|
|
31
|
+
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] [--no-token-optimize] [--token-agent <name>] [--memory-continuity] [--no-memory-continuity] [--scaffold-docs] [--no-scaffold-docs] [--docs-lang <en|id>] [--project-config <path>] [--runtime-env <auto|linux-wsl|linux|windows|macos>]');
|
|
32
32
|
console.log(' agentic-senior-core upgrade [target-directory] [--dry-run] [--yes] [--mcp-template]');
|
|
33
33
|
console.log(' agentic-senior-core optimize [target-directory] [--agent <copilot|claude|cursor|windsurf|gemini|codex|cline>] [--enable|--disable] [--show]');
|
|
34
34
|
console.log(' agentic-senior-core mcp');
|
|
@@ -49,6 +49,8 @@ export function printUsage() {
|
|
|
49
49
|
console.log(' --token-optimize Explicitly enable token optimization policy during init (default behavior)');
|
|
50
50
|
console.log(' --token-agent Set token optimization agent target (copilot, claude, cursor, windsurf, gemini, codex, cline)');
|
|
51
51
|
console.log(' --no-token-optimize Disable token optimization policy during init');
|
|
52
|
+
console.log(' --memory-continuity Explicitly enable cross-session memory continuity policy during init (default behavior)');
|
|
53
|
+
console.log(' --no-memory-continuity Disable memory continuity policy during init');
|
|
52
54
|
console.log(' --mcp-template Create .vscode/mcp.json workspace template (MCP trust/start remains manual in IDE)');
|
|
53
55
|
console.log(' --scaffold-docs Force project documentation scaffolding (architecture, database, API, flow)');
|
|
54
56
|
console.log(' --no-scaffold-docs Skip project documentation scaffolding');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ryuenn3123/agentic-senior-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Force your AI Agent to code like a Staff Engineer, not a Junior.",
|
|
6
6
|
"bin": {
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"benchmark:writer-judge": "node ./scripts/benchmark-writer-judge-matrix.mjs",
|
|
53
53
|
"benchmark:gate": "node ./scripts/benchmark-gate.mjs",
|
|
54
54
|
"benchmark:intelligence": "node ./scripts/benchmark-intelligence.mjs",
|
|
55
|
+
"benchmark:continuity": "node ./scripts/memory-continuity-benchmark.mjs",
|
|
55
56
|
"report:quality-trend": "node ./scripts/quality-trend-report.mjs",
|
|
56
57
|
"report:docs-quality-drift": "node ./scripts/docs-quality-drift-report.mjs",
|
|
57
58
|
"report:governance-weekly": "node ./scripts/governance-weekly-report.mjs",
|