@ryuenn3123/agentic-senior-core 4.3.15 → 5.1.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.
Files changed (198) hide show
  1. package/.agents/plugins/marketplace.json +21 -0
  2. package/.agents/rules/agentic-senior-core.md +126 -0
  3. package/.claude-plugin/marketplace.json +17 -0
  4. package/.claude-plugin/plugin.json +17 -0
  5. package/.clinerules/agentic-senior-core.md +94 -0
  6. package/.codex-plugin/plugin.json +24 -0
  7. package/.cursor/rules/agentic-senior-core.mdc +99 -0
  8. package/.devin-plugin/plugin.json +13 -0
  9. package/.github/copilot-instructions.md +94 -0
  10. package/.github/plugin/marketplace.json +20 -0
  11. package/.github/plugin/plugin.json +16 -0
  12. package/.kiro/steering/agentic-senior-core.md +94 -0
  13. package/.openclaw/skills/asc/SKILL.md +23 -0
  14. package/.openclaw/skills/asc-audit/SKILL.md +28 -0
  15. package/.openclaw/skills/asc-review/SKILL.md +54 -0
  16. package/.opencode/plugins/agentic-senior-core.mjs +31 -0
  17. package/.windsurf/rules/agentic-senior-core.md +94 -0
  18. package/AGENTS.md +126 -179
  19. package/CONTRIBUTING.md +93 -63
  20. package/README.md +160 -111
  21. package/__init__.py +61 -0
  22. package/bin/agentic-senior-core.js +41 -43
  23. package/commands/asc-audit.md +1 -0
  24. package/commands/asc-audit.toml +2 -0
  25. package/commands/asc-help.md +9 -0
  26. package/commands/asc-help.toml +2 -0
  27. package/commands/asc-refactor.md +1 -0
  28. package/commands/asc-refactor.toml +2 -0
  29. package/commands/asc-review.md +1 -0
  30. package/commands/asc-review.toml +2 -0
  31. package/gemini-extension.json +10 -0
  32. package/hooks/copilot-hooks.json +21 -0
  33. package/hooks/hooks.json +31 -0
  34. package/hooks/session-start.js +36 -0
  35. package/hooks/subagent-start.js +38 -0
  36. package/lib/cli/commands/adapter.mjs +109 -0
  37. package/lib/cli/commands/clean.mjs +63 -0
  38. package/lib/cli/commands/status.mjs +94 -0
  39. package/package.json +43 -67
  40. package/plugin.yaml +16 -0
  41. package/scripts/uninstall.js +38 -0
  42. package/skills/asc/SKILL.md +16 -0
  43. package/skills/asc-audit/SKILL.md +28 -0
  44. package/skills/asc-refactor/SKILL.md +35 -0
  45. package/skills/asc-review/SKILL.md +54 -0
  46. package/.agent-context/policies/llm-judge-threshold.json +0 -29
  47. package/.agent-context/prompts/bootstrap-design.md +0 -63
  48. package/.agent-context/prompts/compact-natural-mode.md +0 -100
  49. package/.agent-context/prompts/init-project.md +0 -60
  50. package/.agent-context/prompts/refactor.md +0 -38
  51. package/.agent-context/prompts/review-code.md +0 -31
  52. package/.agent-context/review-checklists/architecture-review.md +0 -57
  53. package/.agent-context/review-checklists/pr-checklist.md +0 -136
  54. package/.agent-context/rules/api-docs.md +0 -24
  55. package/.agent-context/rules/api-versioning.md +0 -16
  56. package/.agent-context/rules/architecture.md +0 -33
  57. package/.agent-context/rules/background-jobs.md +0 -17
  58. package/.agent-context/rules/config-and-flags.md +0 -16
  59. package/.agent-context/rules/database-design.md +0 -18
  60. package/.agent-context/rules/docker-runtime.md +0 -17
  61. package/.agent-context/rules/error-handling.md +0 -16
  62. package/.agent-context/rules/event-driven.md +0 -16
  63. package/.agent-context/rules/frontend-architecture.md +0 -54
  64. package/.agent-context/rules/microservices.md +0 -16
  65. package/.agent-context/rules/migrations.md +0 -16
  66. package/.agent-context/rules/observability.md +0 -16
  67. package/.agent-context/rules/performance.md +0 -16
  68. package/.agent-context/rules/realtime.md +0 -16
  69. package/.agent-context/rules/resilience.md +0 -18
  70. package/.agent-context/rules/security.md +0 -18
  71. package/.agent-context/rules/testing.md +0 -16
  72. package/.agent-context/state/README.md +0 -25
  73. package/.agent-context/state/architecture-map.md +0 -40
  74. package/.agent-context/state/benchmark-comparison-schema.json +0 -181
  75. package/.agent-context/state/benchmark-reproducibility.json +0 -87
  76. package/.agent-context/state/benchmark-thresholds.json +0 -10
  77. package/.agent-context/state/benchmark-writer-judge-config.json +0 -58
  78. package/.agent-context/state/dependency-map.md +0 -41
  79. package/.agent-context/state/memory-adapter-contract.json +0 -52
  80. package/.agent-context/state/memory-schema-v1.json +0 -88
  81. package/GEMINI.md +0 -1
  82. package/benchmarks/README.md +0 -60
  83. package/benchmarks/compact-natural-mode/fixtures.mjs +0 -359
  84. package/benchmarks/compact-natural-mode/scorer.mjs +0 -331
  85. package/benchmarks/runtime-token-saver/fixtures.mjs +0 -836
  86. package/lib/cli/adaptive-context/catalog.mjs +0 -390
  87. package/lib/cli/adaptive-context/file-signals.mjs +0 -100
  88. package/lib/cli/adaptive-context/implications.mjs +0 -44
  89. package/lib/cli/adaptive-context.mjs +0 -365
  90. package/lib/cli/audits/typography-palette-anti-repeat/color-utils.mjs +0 -156
  91. package/lib/cli/audits/typography-palette-anti-repeat/file-scanner.mjs +0 -103
  92. package/lib/cli/audits/typography-palette-anti-repeat/typography-utils.mjs +0 -70
  93. package/lib/cli/audits/typography-palette-anti-repeat-audit.mjs +0 -239
  94. package/lib/cli/backup.mjs +0 -210
  95. package/lib/cli/commands/audit-design-anti-repeat.mjs +0 -39
  96. package/lib/cli/commands/context.mjs +0 -140
  97. package/lib/cli/commands/init/project-context.mjs +0 -60
  98. package/lib/cli/commands/init/runtime-environment.mjs +0 -59
  99. package/lib/cli/commands/init/setup-decisions.mjs +0 -83
  100. package/lib/cli/commands/init.mjs +0 -654
  101. package/lib/cli/commands/launch.mjs +0 -76
  102. package/lib/cli/commands/optimize.mjs +0 -284
  103. package/lib/cli/commands/rollback.mjs +0 -64
  104. package/lib/cli/commands/upgrade/token-optimization-state.mjs +0 -51
  105. package/lib/cli/commands/upgrade.mjs +0 -451
  106. package/lib/cli/compiler.mjs +0 -570
  107. package/lib/cli/constants.mjs +0 -136
  108. package/lib/cli/detector/constants.mjs +0 -135
  109. package/lib/cli/detector/design-evidence/collector.mjs +0 -256
  110. package/lib/cli/detector/design-evidence/constants.mjs +0 -39
  111. package/lib/cli/detector/design-evidence/file-traversal.mjs +0 -83
  112. package/lib/cli/detector/design-evidence/structured-attribute-evidence.mjs +0 -117
  113. package/lib/cli/detector/design-evidence/summary.mjs +0 -109
  114. package/lib/cli/detector/design-evidence/utility-helpers.mjs +0 -122
  115. package/lib/cli/detector/design-evidence.mjs +0 -25
  116. package/lib/cli/detector/stack-detection.mjs +0 -243
  117. package/lib/cli/detector/ui-signals.mjs +0 -150
  118. package/lib/cli/detector/workspace-scan.mjs +0 -177
  119. package/lib/cli/detector.mjs +0 -23
  120. package/lib/cli/init-detection-flow.mjs +0 -48
  121. package/lib/cli/init-options.mjs +0 -237
  122. package/lib/cli/init-selection.mjs +0 -29
  123. package/lib/cli/memory-continuity.mjs +0 -537
  124. package/lib/cli/preflight.mjs +0 -76
  125. package/lib/cli/project-scaffolder/constants.mjs +0 -69
  126. package/lib/cli/project-scaffolder/discovery.mjs +0 -272
  127. package/lib/cli/project-scaffolder/prompt-builders.mjs +0 -171
  128. package/lib/cli/project-scaffolder/storage.mjs +0 -144
  129. package/lib/cli/project-scaffolder/ui-scope-detection.mjs +0 -36
  130. package/lib/cli/project-scaffolder.mjs +0 -29
  131. package/lib/cli/rollback.mjs +0 -66
  132. package/lib/cli/token-optimization.mjs +0 -486
  133. package/lib/cli/utils/filesystem.mjs +0 -81
  134. package/lib/cli/utils/managed-surface.mjs +0 -280
  135. package/lib/cli/utils/prompting.mjs +0 -44
  136. package/lib/cli/utils.mjs +0 -479
  137. package/mcp.json +0 -134
  138. package/scripts/adaptive-context/fixtures.mjs +0 -183
  139. package/scripts/adaptive-context-benchmark.mjs +0 -9
  140. package/scripts/ascx-runtime-token-saver-benchmark.mjs +0 -9
  141. package/scripts/audit-cache-layer-contract.mjs +0 -263
  142. package/scripts/audit-caching-scope-hygiene.mjs +0 -268
  143. package/scripts/audit-file-size.mjs +0 -219
  144. package/scripts/audit-reflection-citations.mjs +0 -163
  145. package/scripts/audit-release-bundle.mjs +0 -170
  146. package/scripts/audit-rule-id-uniqueness.mjs +0 -313
  147. package/scripts/audit-typography-palette-anti-repeat.mjs +0 -120
  148. package/scripts/benchmark-evidence-bundle.mjs +0 -645
  149. package/scripts/benchmark-gate.mjs +0 -121
  150. package/scripts/benchmark-intelligence.mjs +0 -33
  151. package/scripts/benchmark-writer-judge-matrix.mjs +0 -379
  152. package/scripts/build-release-benchmark-bundle.mjs +0 -202
  153. package/scripts/bump-version.mjs +0 -103
  154. package/scripts/clean-local-artifacts.mjs +0 -78
  155. package/scripts/compact-natural-mode-benchmark.mjs +0 -9
  156. package/scripts/context-triggered-audit.mjs +0 -391
  157. package/scripts/detection-benchmark.mjs +0 -127
  158. package/scripts/docs-quality-drift-report.mjs +0 -358
  159. package/scripts/documentation-boundary-audit.mjs +0 -305
  160. package/scripts/explain-on-demand-audit.mjs +0 -427
  161. package/scripts/forbidden-content-check.mjs +0 -123
  162. package/scripts/frontend-usability-audit.mjs +0 -243
  163. package/scripts/generate-sbom.mjs +0 -61
  164. package/scripts/governance-weekly-report.mjs +0 -466
  165. package/scripts/llm-judge/checklist-loader.mjs +0 -45
  166. package/scripts/llm-judge/constants.mjs +0 -66
  167. package/scripts/llm-judge/diff-collection.mjs +0 -74
  168. package/scripts/llm-judge/prompting.mjs +0 -78
  169. package/scripts/llm-judge/providers.mjs +0 -111
  170. package/scripts/llm-judge/verdict.mjs +0 -134
  171. package/scripts/llm-judge.mjs +0 -200
  172. package/scripts/memory-continuity-benchmark.mjs +0 -322
  173. package/scripts/quality-trend-report.mjs +0 -289
  174. package/scripts/release-gate/audit-checks.mjs +0 -441
  175. package/scripts/release-gate/constants.mjs +0 -53
  176. package/scripts/release-gate/runtime.mjs +0 -63
  177. package/scripts/release-gate/static-checks.mjs +0 -182
  178. package/scripts/release-gate.mjs +0 -42
  179. package/scripts/rules-guardian-audit.mjs +0 -580
  180. package/scripts/single-source-lazy-loading-audit.mjs +0 -449
  181. package/scripts/sync-thin-adapters.mjs +0 -72
  182. package/scripts/token-optimization-benchmark.mjs +0 -252
  183. package/scripts/ui-design-judge/constants.mjs +0 -13
  184. package/scripts/ui-design-judge/design-execution-summary.mjs +0 -81
  185. package/scripts/ui-design-judge/git-input.mjs +0 -134
  186. package/scripts/ui-design-judge/prompting.mjs +0 -52
  187. package/scripts/ui-design-judge/providers.mjs +0 -102
  188. package/scripts/ui-design-judge/reporting.mjs +0 -183
  189. package/scripts/ui-design-judge/rubric-calibration.mjs +0 -214
  190. package/scripts/ui-design-judge/rubric-goldset.json +0 -188
  191. package/scripts/ui-design-judge.mjs +0 -319
  192. package/scripts/ui-rubric-calibration.mjs +0 -35
  193. package/scripts/validate/config.mjs +0 -519
  194. package/scripts/validate/coverage-checks.mjs +0 -446
  195. package/scripts/validate/file-structure.mjs +0 -162
  196. package/scripts/validate/markdown-content.mjs +0 -109
  197. package/scripts/validate/project-metadata.mjs +0 -166
  198. package/scripts/validate.mjs +0 -338
@@ -1,537 +0,0 @@
1
- // @file-size-exception: Multiple memory passes (normalize + redact + index + hydrate); planned for split in Phase 1.
2
- /**
3
- * Cross-agent memory continuity utilities.
4
- * Provides provider-agnostic observation normalization, privacy redaction,
5
- * lightweight indexing, and selective hydration helpers.
6
- */
7
-
8
- import fs from 'node:fs/promises';
9
- import path from 'node:path';
10
-
11
- import { pathExists } from './utils.mjs';
12
-
13
- const PRIVATE_BLOCK_PATTERN = /<private>[\s\S]*?<\/private>/gi;
14
-
15
- const INLINE_SENSITIVE_PATTERNS = [
16
- {
17
- reason: 'api-key-like-value',
18
- pattern: /\b(api[_-]?key)\b\s*[:=]\s*[^\s,;]+/gi,
19
- replacer: (_match, fieldName) => `${fieldName}=[REDACTED]`,
20
- },
21
- {
22
- reason: 'token-like-value',
23
- pattern: /\b(token)\b\s*[:=]\s*[^\s,;]+/gi,
24
- replacer: (_match, fieldName) => `${fieldName}=[REDACTED]`,
25
- },
26
- {
27
- reason: 'password-like-value',
28
- pattern: /\b(password|passwd|pwd)\b\s*[:=]\s*[^\s,;]+/gi,
29
- replacer: (_match, fieldName) => `${fieldName}=[REDACTED]`,
30
- },
31
- {
32
- reason: 'bearer-token',
33
- pattern: /\bBearer\s+[A-Za-z0-9._-]+/g,
34
- replacer: () => 'Bearer [REDACTED]',
35
- },
36
- ];
37
-
38
- export const MEMORY_SCHEMA_VERSION = '1.0.0';
39
- export const MEMORY_CONTINUITY_STATE_FILE_NAME = 'memory-continuity.json';
40
- export const ACTIVE_MEMORY_STATE_FILE_NAME = 'active-memory.json';
41
-
42
- const MEMORY_CONTINUITY_STATE_SCHEMA_VERSION = 'memory-continuity-v1';
43
- const ACTIVE_MEMORY_STATE_SCHEMA_VERSION = 'active-memory-v1';
44
-
45
- export const SUPPORTED_MEMORY_ADAPTER_IDS = Object.freeze([
46
- 'claude-code',
47
- 'gemini-cli',
48
- 'vscode-chat',
49
- ]);
50
-
51
- export const SUPPORTED_MEMORY_EVENT_TYPES = Object.freeze([
52
- 'prompt',
53
- 'tool-use',
54
- 'decision',
55
- 'summary',
56
- 'issue',
57
- 'context',
58
- ]);
59
-
60
- function toIsoTimestamp(rawValue) {
61
- if (typeof rawValue !== 'string' || rawValue.trim().length === 0) {
62
- return new Date().toISOString();
63
- }
64
-
65
- const parsedDate = new Date(rawValue);
66
- if (Number.isNaN(parsedDate.getTime())) {
67
- return new Date().toISOString();
68
- }
69
-
70
- return parsedDate.toISOString();
71
- }
72
-
73
- function toNonEmptyString(rawValue, fallbackValue = '') {
74
- if (typeof rawValue !== 'string') {
75
- return fallbackValue;
76
- }
77
-
78
- const normalizedValue = rawValue.trim();
79
- return normalizedValue.length > 0 ? normalizedValue : fallbackValue;
80
- }
81
-
82
- function normalizeTags(rawTags) {
83
- if (!Array.isArray(rawTags)) {
84
- return [];
85
- }
86
-
87
- const tagSet = new Set();
88
- for (const rawTag of rawTags) {
89
- const normalizedTag = toNonEmptyString(String(rawTag || '')).toLowerCase();
90
- if (normalizedTag) {
91
- tagSet.add(normalizedTag);
92
- }
93
- }
94
-
95
- return Array.from(tagSet);
96
- }
97
-
98
- function normalizeMemoryAdapterIds(rawAdapterIds) {
99
- if (!Array.isArray(rawAdapterIds) || rawAdapterIds.length === 0) {
100
- return [...SUPPORTED_MEMORY_ADAPTER_IDS];
101
- }
102
-
103
- const normalizedAdapterIdSet = new Set();
104
- for (const rawAdapterId of rawAdapterIds) {
105
- const normalizedAdapterId = toNonEmptyString(String(rawAdapterId || '')).toLowerCase();
106
- if (!normalizedAdapterId) {
107
- continue;
108
- }
109
-
110
- if (!SUPPORTED_MEMORY_ADAPTER_IDS.includes(normalizedAdapterId)) {
111
- continue;
112
- }
113
-
114
- normalizedAdapterIdSet.add(normalizedAdapterId);
115
- }
116
-
117
- if (normalizedAdapterIdSet.size === 0) {
118
- return [...SUPPORTED_MEMORY_ADAPTER_IDS];
119
- }
120
-
121
- return Array.from(normalizedAdapterIdSet);
122
- }
123
-
124
- export function estimateTokenUsage(rawText = '') {
125
- const normalizedText = String(rawText || '');
126
- return Math.max(1, Math.ceil(normalizedText.length / 4));
127
- }
128
-
129
- export function redactSensitiveMemoryText(rawText = '') {
130
- let normalizedText = String(rawText || '');
131
- const redactionReasons = new Set();
132
- let privateTagRedactionCount = 0;
133
- let inlineRedactionCount = 0;
134
-
135
- normalizedText = normalizedText.replace(PRIVATE_BLOCK_PATTERN, () => {
136
- privateTagRedactionCount += 1;
137
- redactionReasons.add('private-tag');
138
- return '[REDACTED_PRIVATE_BLOCK]';
139
- });
140
-
141
- for (const sensitivePattern of INLINE_SENSITIVE_PATTERNS) {
142
- normalizedText = normalizedText.replace(sensitivePattern.pattern, (...replacerArguments) => {
143
- inlineRedactionCount += 1;
144
- redactionReasons.add(sensitivePattern.reason);
145
- return sensitivePattern.replacer(...replacerArguments);
146
- });
147
- }
148
-
149
- return {
150
- redactedText: normalizedText,
151
- wasRedacted: privateTagRedactionCount > 0 || inlineRedactionCount > 0,
152
- privateTagRedactionCount,
153
- inlineRedactionCount,
154
- redactionReasons: Array.from(redactionReasons),
155
- };
156
- }
157
-
158
- export function normalizeMemoryObservation(rawObservation, options = {}) {
159
- const fallbackAdapterId = options.fallbackAdapterId || 'unknown-adapter';
160
- const observationId = toNonEmptyString(rawObservation?.id, `${fallbackAdapterId}-${Date.now()}`);
161
- const adapterId = toNonEmptyString(rawObservation?.adapterId, fallbackAdapterId);
162
-
163
- const eventTypeCandidate = toNonEmptyString(rawObservation?.eventType, 'context').toLowerCase();
164
- const eventType = SUPPORTED_MEMORY_EVENT_TYPES.includes(eventTypeCandidate)
165
- ? eventTypeCandidate
166
- : 'context';
167
-
168
- const rawDetail = toNonEmptyString(rawObservation?.detail, '');
169
- const detailRedaction = redactSensitiveMemoryText(rawDetail);
170
-
171
- const rawSummary = toNonEmptyString(rawObservation?.summary, detailRedaction.redactedText.slice(0, 220));
172
- const summaryRedaction = redactSensitiveMemoryText(rawSummary);
173
-
174
- const title = toNonEmptyString(rawObservation?.title, `${eventType} from ${adapterId}`);
175
- const tags = normalizeTags(rawObservation?.tags);
176
-
177
- return {
178
- id: observationId,
179
- projectId: toNonEmptyString(rawObservation?.projectId, 'default-project'),
180
- sessionId: toNonEmptyString(rawObservation?.sessionId, 'default-session'),
181
- adapterId,
182
- eventType,
183
- timestamp: toIsoTimestamp(rawObservation?.timestamp),
184
- title,
185
- summary: summaryRedaction.redactedText,
186
- detail: detailRedaction.redactedText,
187
- tags,
188
- privacy: {
189
- level: toNonEmptyString(rawObservation?.privacyLevel, 'internal'),
190
- redactionApplied: detailRedaction.wasRedacted || summaryRedaction.wasRedacted,
191
- redactionReasons: Array.from(new Set([
192
- ...detailRedaction.redactionReasons,
193
- ...summaryRedaction.redactionReasons,
194
- ])),
195
- privateTagRedactionCount: detailRedaction.privateTagRedactionCount + summaryRedaction.privateTagRedactionCount,
196
- inlineRedactionCount: detailRedaction.inlineRedactionCount + summaryRedaction.inlineRedactionCount,
197
- },
198
- };
199
- }
200
-
201
- export function scoreObservationRelevance(queryText, normalizedObservation) {
202
- const normalizedQuery = toNonEmptyString(queryText, '').toLowerCase();
203
- if (!normalizedQuery) {
204
- return 0;
205
- }
206
-
207
- const queryTerms = normalizedQuery
208
- .split(/\s+/)
209
- .map((queryTerm) => queryTerm.trim())
210
- .filter((queryTerm) => queryTerm.length > 2);
211
-
212
- if (queryTerms.length === 0) {
213
- return 0;
214
- }
215
-
216
- const searchableContent = [
217
- normalizedObservation.title,
218
- normalizedObservation.summary,
219
- normalizedObservation.detail,
220
- normalizedObservation.tags.join(' '),
221
- normalizedObservation.eventType,
222
- normalizedObservation.adapterId,
223
- ].join(' ').toLowerCase();
224
-
225
- let matchCount = 0;
226
- for (const queryTerm of queryTerms) {
227
- if (searchableContent.includes(queryTerm)) {
228
- matchCount += 1;
229
- }
230
- }
231
-
232
- return Number((matchCount / queryTerms.length).toFixed(4));
233
- }
234
-
235
- export function buildSessionStartIndex(normalizedObservations, options = {}) {
236
- const queryText = toNonEmptyString(options.queryText, '');
237
- const maxIndexEntries = Number.isFinite(Number(options.limit)) ? Math.max(1, Number(options.limit)) : 8;
238
-
239
- const rankedEntries = normalizedObservations
240
- .map((normalizedObservation) => {
241
- const relevanceScore = scoreObservationRelevance(queryText, normalizedObservation);
242
- const indexLine = `${normalizedObservation.id}|${normalizedObservation.adapterId}|${normalizedObservation.eventType}|${normalizedObservation.title}`;
243
- const indexTokenEstimate = estimateTokenUsage(indexLine);
244
-
245
- return {
246
- id: normalizedObservation.id,
247
- adapterId: normalizedObservation.adapterId,
248
- eventType: normalizedObservation.eventType,
249
- timestamp: normalizedObservation.timestamp,
250
- title: normalizedObservation.title,
251
- summarySnippet: normalizedObservation.summary.slice(0, 120),
252
- tags: normalizedObservation.tags,
253
- relevanceScore,
254
- indexTokenEstimate,
255
- };
256
- })
257
- .sort((leftEntry, rightEntry) => {
258
- if (rightEntry.relevanceScore !== leftEntry.relevanceScore) {
259
- return rightEntry.relevanceScore - leftEntry.relevanceScore;
260
- }
261
-
262
- return rightEntry.timestamp.localeCompare(leftEntry.timestamp);
263
- });
264
-
265
- const indexEntries = rankedEntries.slice(0, maxIndexEntries);
266
- const totalTokenEstimate = indexEntries.reduce(
267
- (tokenAccumulator, indexEntry) => tokenAccumulator + indexEntry.indexTokenEstimate,
268
- 0
269
- );
270
-
271
- return {
272
- indexEntries,
273
- totalTokenEstimate,
274
- totalCandidateCount: rankedEntries.length,
275
- };
276
- }
277
-
278
- export function hydrateIndexedObservations(indexEntries, normalizedObservations, options = {}) {
279
- const fullFetchLimit = Number.isFinite(Number(options.fullFetchLimit))
280
- ? Math.max(1, Number(options.fullFetchLimit))
281
- : 2;
282
-
283
- const observationLookup = new Map(normalizedObservations.map((normalizedObservation) => [
284
- normalizedObservation.id,
285
- normalizedObservation,
286
- ]));
287
-
288
- const selectedIds = indexEntries.slice(0, fullFetchLimit).map((indexEntry) => indexEntry.id);
289
- const hydratedObservations = selectedIds
290
- .map((selectedId) => observationLookup.get(selectedId))
291
- .filter(Boolean);
292
-
293
- const hydrationTokenEstimate = hydratedObservations.reduce(
294
- (tokenAccumulator, hydratedObservation) => tokenAccumulator + estimateTokenUsage(hydratedObservation.detail),
295
- 0
296
- );
297
-
298
- return {
299
- selectedIds,
300
- hydratedObservations,
301
- hydrationTokenEstimate,
302
- };
303
- }
304
-
305
- export function createMemoryContinuityState(options = {}) {
306
- const isEnabled = options.isEnabled !== false;
307
- const sessionStartIndexLimit = Number.isFinite(Number(options.sessionStartIndexLimit))
308
- ? Math.max(1, Number(options.sessionStartIndexLimit))
309
- : 8;
310
- const fullHydrationLimit = Number.isFinite(Number(options.fullHydrationLimit))
311
- ? Math.max(1, Number(options.fullHydrationLimit))
312
- : 2;
313
-
314
- return {
315
- schemaVersion: MEMORY_CONTINUITY_STATE_SCHEMA_VERSION,
316
- enabled: isEnabled,
317
- hydrationMode: 'progressive-disclosure',
318
- adapters: normalizeMemoryAdapterIds(options.adapterIds),
319
- retrieval: {
320
- sessionStartIndexLimit,
321
- fullHydrationLimit,
322
- },
323
- privacy: {
324
- redactPrivateTags: true,
325
- redactInlineSensitivePatterns: true,
326
- },
327
- generatedAt: new Date().toISOString(),
328
- };
329
- }
330
-
331
- export async function readMemoryContinuityState(targetDirectoryPath) {
332
- const stateFilePath = path.join(
333
- targetDirectoryPath,
334
- '.agent-context',
335
- 'state',
336
- MEMORY_CONTINUITY_STATE_FILE_NAME
337
- );
338
-
339
- if (!(await pathExists(stateFilePath))) {
340
- return null;
341
- }
342
-
343
- try {
344
- const stateContent = await fs.readFile(stateFilePath, 'utf8');
345
- const parsedState = JSON.parse(stateContent);
346
- if (typeof parsedState.enabled !== 'boolean') {
347
- return null;
348
- }
349
-
350
- parsedState.adapters = normalizeMemoryAdapterIds(parsedState.adapters);
351
- return parsedState;
352
- } catch {
353
- return null;
354
- }
355
- }
356
-
357
- export async function writeMemoryContinuityState(targetDirectoryPath, memoryContinuityState) {
358
- const stateDirectoryPath = path.join(targetDirectoryPath, '.agent-context', 'state');
359
- const stateFilePath = path.join(stateDirectoryPath, MEMORY_CONTINUITY_STATE_FILE_NAME);
360
-
361
- await fs.mkdir(stateDirectoryPath, { recursive: true });
362
- await fs.writeFile(stateFilePath, JSON.stringify(memoryContinuityState, null, 2) + '\n', 'utf8');
363
- }
364
-
365
- export function createActiveMemorySnapshot(options = {}) {
366
- return {
367
- schemaVersion: ACTIVE_MEMORY_STATE_SCHEMA_VERSION,
368
- snapshotPurpose: 'compact-cross-session-continuity',
369
- updatePolicy: {
370
- writeWhen: 'natural-task-boundary',
371
- overwriteOnlyWithCurrentRepoEvidence: true,
372
- preserveUserOwnedContent: true,
373
- },
374
- project: {
375
- name: toNonEmptyString(options.projectName, ''),
376
- currentFocus: '',
377
- durableFacts: [],
378
- },
379
- progress: {
380
- lastAchievements: [],
381
- pendingIssues: [],
382
- nextBestActions: [],
383
- validationState: [],
384
- },
385
- designContinuity: {
386
- visualLanguageContinuity: 'opt-in-only',
387
- currentConceptualAnchor: '',
388
- forbiddenCarryover: [
389
- 'prior-project-style-memory',
390
- 'old-ui-visual-dna-without-user-approval',
391
- 'generic-dashboard-defaults',
392
- ],
393
- },
394
- privacy: {
395
- storeSecrets: false,
396
- storeRawChatLogs: false,
397
- redactSensitiveTextBeforeWriting: true,
398
- },
399
- generatedAt: new Date().toISOString(),
400
- lastUpdatedAt: null,
401
- };
402
- }
403
-
404
- export function validateActiveMemorySnapshot(activeMemorySnapshot) {
405
- const validationErrors = [];
406
-
407
- if (!activeMemorySnapshot || typeof activeMemorySnapshot !== 'object') {
408
- return ['active-memory snapshot must be an object.'];
409
- }
410
-
411
- if (activeMemorySnapshot.schemaVersion !== ACTIVE_MEMORY_STATE_SCHEMA_VERSION) {
412
- validationErrors.push(`active-memory.schemaVersion must equal "${ACTIVE_MEMORY_STATE_SCHEMA_VERSION}".`);
413
- }
414
-
415
- if (activeMemorySnapshot.snapshotPurpose !== 'compact-cross-session-continuity') {
416
- validationErrors.push('active-memory.snapshotPurpose must equal "compact-cross-session-continuity".');
417
- }
418
-
419
- const serializedSnapshot = JSON.stringify(activeMemorySnapshot);
420
- if (estimateTokenUsage(serializedSnapshot) > 3000) {
421
- validationErrors.push('active-memory snapshot must stay compact enough for session-start hydration.');
422
- }
423
-
424
- const redactionProbe = redactSensitiveMemoryText(serializedSnapshot);
425
- if (redactionProbe.wasRedacted) {
426
- validationErrors.push('active-memory snapshot must not contain secret-like fields, bearer tokens, or private blocks.');
427
- }
428
-
429
- if (activeMemorySnapshot.privacy?.storeSecrets !== false) {
430
- validationErrors.push('active-memory.privacy.storeSecrets must equal false.');
431
- }
432
-
433
- if (activeMemorySnapshot.privacy?.storeRawChatLogs !== false) {
434
- validationErrors.push('active-memory.privacy.storeRawChatLogs must equal false.');
435
- }
436
-
437
- if (activeMemorySnapshot.privacy?.redactSensitiveTextBeforeWriting !== true) {
438
- validationErrors.push('active-memory.privacy.redactSensitiveTextBeforeWriting must equal true.');
439
- }
440
-
441
- for (const arrayPath of [
442
- ['project', 'durableFacts'],
443
- ['progress', 'lastAchievements'],
444
- ['progress', 'pendingIssues'],
445
- ['progress', 'nextBestActions'],
446
- ['progress', 'validationState'],
447
- ]) {
448
- const arrayValue = arrayPath.reduce((currentValue, pathSegment) => currentValue?.[pathSegment], activeMemorySnapshot);
449
- const pathLabel = `active-memory.${arrayPath.join('.')}`;
450
- if (!Array.isArray(arrayValue)) {
451
- validationErrors.push(`${pathLabel} must be an array.`);
452
- continue;
453
- }
454
-
455
- if (arrayValue.length > 12) {
456
- validationErrors.push(`${pathLabel} must stay compact and contain at most 12 entries.`);
457
- }
458
- }
459
-
460
- if (activeMemorySnapshot.designContinuity?.visualLanguageContinuity !== 'opt-in-only') {
461
- validationErrors.push('active-memory.designContinuity.visualLanguageContinuity must equal "opt-in-only".');
462
- }
463
-
464
- return validationErrors;
465
- }
466
-
467
- export async function ensureActiveMemorySnapshot(targetDirectoryPath, options = {}) {
468
- const stateDirectoryPath = path.join(targetDirectoryPath, '.agent-context', 'state');
469
- const stateFilePath = path.join(stateDirectoryPath, ACTIVE_MEMORY_STATE_FILE_NAME);
470
-
471
- if (await pathExists(stateFilePath)) {
472
- return {
473
- created: false,
474
- filePath: stateFilePath,
475
- };
476
- }
477
-
478
- await fs.mkdir(stateDirectoryPath, { recursive: true });
479
- const activeMemorySnapshot = createActiveMemorySnapshot(options);
480
- const validationErrors = validateActiveMemorySnapshot(activeMemorySnapshot);
481
- if (validationErrors.length > 0) {
482
- throw new Error(`Invalid active memory snapshot seed: ${validationErrors.join(' ')}`);
483
- }
484
-
485
- await fs.writeFile(
486
- stateFilePath,
487
- JSON.stringify(activeMemorySnapshot, null, 2) + '\n',
488
- 'utf8'
489
- );
490
-
491
- return {
492
- created: true,
493
- filePath: stateFilePath,
494
- };
495
- }
496
-
497
- export function buildMemoryContinuityGuidanceBlock(memoryContinuityState) {
498
- if (!memoryContinuityState?.enabled) {
499
- return [
500
- 'Memory continuity mode is disabled for this repository.',
501
- 'Use explicit session summaries when handing off context across tools.',
502
- ].join('\n');
503
- }
504
-
505
- const adapterGuidanceLine = memoryContinuityState.adapters?.length
506
- ? `Supported adapters: ${memoryContinuityState.adapters.join(', ')}.`
507
- : `Supported adapters: ${SUPPORTED_MEMORY_ADAPTER_IDS.join(', ')}.`;
508
-
509
- const sessionStartIndexLimit = Number.isFinite(Number(memoryContinuityState.retrieval?.sessionStartIndexLimit))
510
- ? Number(memoryContinuityState.retrieval.sessionStartIndexLimit)
511
- : 8;
512
- const fullHydrationLimit = Number.isFinite(Number(memoryContinuityState.retrieval?.fullHydrationLimit))
513
- ? Number(memoryContinuityState.retrieval.fullHydrationLimit)
514
- : 2;
515
-
516
- return [
517
- 'Project memory continuity mode is enabled.',
518
- 'Hydration mode: progressive-disclosure.',
519
- adapterGuidanceLine,
520
- '',
521
- 'Session-start retrieval policy:',
522
- '- Read `.agent-context/state/active-memory.json` first when it exists; it is the compact project-focus snapshot.',
523
- `- Load compact index first (limit: ${sessionStartIndexLimit} entries).`,
524
- `- Hydrate full detail only for highest-value entries (limit: ${fullHydrationLimit}).`,
525
- '- Always redact sensitive text before persistence (<private> blocks and inline secret-like fields).',
526
- '- Refresh `.agent-context/state/active-memory.json` directly at natural task boundaries when material project progress happened.',
527
- '- Before the final response, update `project.currentFocus`, compact `progress.lastAchievements`, `progress.pendingIssues`, `progress.nextBestActions`, `progress.validationState`, and `lastUpdatedAt` when they changed.',
528
- '- Preserve existing user-owned entries, keep each array compact (12 entries or fewer), and append only durable facts proven by current repo evidence.',
529
- '- If no durable project progress happened, leave the snapshot unchanged and state that no memory update was needed.',
530
- '- Current repo evidence, current user brief, and live research override active-memory when they conflict.',
531
- '',
532
- 'Host compatibility scope:',
533
- '- This memory layer does not replace reading bootstrap instruction files at the start of a session.',
534
- '- Works for local IDE, CLI, and cloud IDE chat hosts that implement the memory adapter contract or MCP retrieval path.',
535
- '- Generic web chat sessions without repository tools cannot auto-hydrate runtime memory and should rely on manual summary export/import.',
536
- ].join('\n');
537
- }
@@ -1,76 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- import { constants } from 'node:fs';
4
- import { pathExists } from './utils.mjs';
5
- import { entryPointFiles } from './constants.mjs';
6
-
7
- const MINIMUM_NODE_VERSION = 18;
8
- const MINIMUM_FREE_DISK_SPACE_MB = 5;
9
-
10
- export async function runPreflightChecks(targetDirectoryPath, operationMode) {
11
- const result = {
12
- passed: true,
13
- checks: [],
14
- errors: [],
15
- };
16
-
17
- // Check 1: Node Version
18
- const nodeVersionString = process.version;
19
- const majorVersion = parseInt(nodeVersionString.slice(1).split('.')[0], 10);
20
- if (majorVersion >= MINIMUM_NODE_VERSION) {
21
- result.checks.push(`Node.js version is compatible: ${nodeVersionString}`);
22
- } else {
23
- result.passed = false;
24
- result.errors.push(`Node.js version ${nodeVersionString} is unsupported. Minimum required is v${MINIMUM_NODE_VERSION}.x`);
25
- }
26
-
27
- // Check 2: Write Permissions
28
- try {
29
- await fs.access(targetDirectoryPath, constants.W_OK);
30
- result.checks.push(`Target directory is writable: ${targetDirectoryPath}`);
31
- } catch (error) {
32
- if (error.code === 'ENOENT') {
33
- // Target directory does not exist yet. Ensure its parent is writable so we can create it
34
- const parentDir = path.dirname(targetDirectoryPath);
35
- try {
36
- await fs.access(parentDir, constants.W_OK);
37
- result.checks.push(`Target parent directory is writable: ${parentDir}`);
38
- } catch {
39
- result.passed = false;
40
- result.errors.push(`Target directory does not exist and parent is read-only: ${parentDir}`);
41
- }
42
- } else {
43
- result.passed = false;
44
- result.errors.push(`Target directory is read-only: ${targetDirectoryPath}`);
45
- }
46
- }
47
-
48
- // Check 3: Disk Space
49
- try {
50
- const statfsString = typeof fs.statfs === 'function';
51
- // Use fs.statfs if available (Node 18.15+)
52
- if (statfsString) {
53
- // If directory doesn't exist, check its parent
54
- const pathToCheck = await pathExists(targetDirectoryPath) ? targetDirectoryPath : path.dirname(targetDirectoryPath);
55
- const diskStats = await fs.statfs(pathToCheck);
56
- // diskStats.bavail is free blocks available to unprivileged user
57
- // diskStats.bsize is block size
58
- const freeBytes = Number(diskStats.bavail) * Number(diskStats.bsize);
59
- const freeMb = freeBytes / (1024 * 1024);
60
-
61
- if (freeMb >= MINIMUM_FREE_DISK_SPACE_MB) {
62
- result.checks.push(`Sufficient free disk space available: ${freeMb.toFixed(2)} MB`);
63
- } else {
64
- result.passed = false;
65
- result.errors.push(`Insufficient free disk space. Required: ${MINIMUM_FREE_DISK_SPACE_MB} MB, Available: ${freeMb.toFixed(2)} MB`);
66
- }
67
- } else {
68
- result.checks.push('Skipping disk space check (fs.statfs requires Node.js v18.15+)');
69
- }
70
- } catch (error) {
71
- result.checks.push(`Skipping disk space check due to standard library limitation: ${error.message}`);
72
- }
73
-
74
-
75
- return result;
76
- }
@@ -1,69 +0,0 @@
1
- export const SUPPORTED_DOC_LANGUAGES = new Set(['en', 'id']);
2
- export const PROJECT_DOC_FILE_NAMES = [
3
- 'project-brief.md',
4
- 'architecture-decision-record.md',
5
- 'database-schema.md',
6
- 'api-contract.md',
7
- 'flow-overview.md',
8
- ];
9
- export const DOC_INDEX_FILE_NAME = 'doc-index.md';
10
- export const UI_DESIGN_CONTRACT_FILE_NAMES = ['DESIGN.md'];
11
-
12
- // Legacy project docs may still carry this version header; keep for upgrade staleness checks.
13
- export const PROJECT_DOC_TEMPLATE_VERSION = '1.2.0';
14
- export const PROJECT_DOC_SYNTHESIS_PROMPT_VERSION = '2.0.0';
15
-
16
- export const DOMAIN_CHOICES = [
17
- 'API service',
18
- 'Web application',
19
- 'Mobile app',
20
- 'CLI tool',
21
- 'Library / SDK',
22
- 'Other',
23
- ];
24
-
25
- export const DATABASE_CHOICES = [
26
- 'None (stateless service)',
27
- 'SQL (PostgreSQL, MySQL, SQLite)',
28
- 'NoSQL (MongoDB, Redis, DynamoDB)',
29
- 'Both (SQL primary + cache layer)',
30
- 'Other',
31
- ];
32
-
33
- export const AUTH_CHOICES = [
34
- 'None (public service)',
35
- 'JWT (stateless token auth)',
36
- 'OAuth 2.0 (third-party login)',
37
- 'Session-based (server-side sessions)',
38
- 'API Key (simple key auth)',
39
- 'Other',
40
- ];
41
-
42
- export const DOCKER_STRATEGY_CHOICES = [
43
- 'No Docker (run services directly)',
44
- 'Docker for development only',
45
- 'Docker for production only',
46
- 'Docker for both development and production',
47
- ];
48
-
49
- export const ARCHITECTURE_STYLE_CHOICES = [
50
- 'Monolith',
51
- 'Microservice / distributed system',
52
- ];
53
-
54
- export const DESIGN_REQUIRED_SECTIONS = [
55
- 'Design Intent and Product Personality',
56
- 'Audience and Use-Context Signals',
57
- 'Visual Direction and Distinctive Moves',
58
- 'Color Science and Semantic Roles',
59
- 'Typographic Engineering and Hierarchy',
60
- 'Spacing, Layout Rhythm, and Density Strategy',
61
- 'Token Architecture and Alias Strategy',
62
- 'Responsive Strategy and Cross-Viewport Adaptation Matrix',
63
- 'Interaction, Motion, and Feedback Rules',
64
- 'Component Language, Morphology, and Shared Patterns',
65
- 'Context Hygiene and Source Boundaries',
66
- 'Accessibility Non-Negotiables',
67
- 'Anti-Patterns to Avoid',
68
- 'Implementation Notes for Future UI Tasks',
69
- ];