@ryuenn3123/agentic-senior-core 4.4.0 → 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 (196) 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 -127
  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 +42 -41
  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 -60
  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 -134
  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 -38
  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 -394
  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 -151
  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/backup.mjs +0 -210
  94. package/lib/cli/commands/context.mjs +0 -140
  95. package/lib/cli/commands/init/project-context.mjs +0 -60
  96. package/lib/cli/commands/init/runtime-environment.mjs +0 -59
  97. package/lib/cli/commands/init/setup-decisions.mjs +0 -83
  98. package/lib/cli/commands/init.mjs +0 -654
  99. package/lib/cli/commands/launch.mjs +0 -76
  100. package/lib/cli/commands/optimize.mjs +0 -284
  101. package/lib/cli/commands/rollback.mjs +0 -64
  102. package/lib/cli/commands/upgrade/token-optimization-state.mjs +0 -51
  103. package/lib/cli/commands/upgrade.mjs +0 -451
  104. package/lib/cli/compiler.mjs +0 -187
  105. package/lib/cli/constants.mjs +0 -136
  106. package/lib/cli/detector/constants.mjs +0 -135
  107. package/lib/cli/detector/design-evidence/collector.mjs +0 -256
  108. package/lib/cli/detector/design-evidence/constants.mjs +0 -39
  109. package/lib/cli/detector/design-evidence/file-traversal.mjs +0 -83
  110. package/lib/cli/detector/design-evidence/structured-attribute-evidence.mjs +0 -117
  111. package/lib/cli/detector/design-evidence/summary.mjs +0 -109
  112. package/lib/cli/detector/design-evidence/utility-helpers.mjs +0 -122
  113. package/lib/cli/detector/design-evidence.mjs +0 -25
  114. package/lib/cli/detector/stack-detection.mjs +0 -243
  115. package/lib/cli/detector/ui-signals.mjs +0 -150
  116. package/lib/cli/detector/workspace-scan.mjs +0 -177
  117. package/lib/cli/detector.mjs +0 -23
  118. package/lib/cli/init-detection-flow.mjs +0 -48
  119. package/lib/cli/init-options.mjs +0 -237
  120. package/lib/cli/init-selection.mjs +0 -29
  121. package/lib/cli/memory-continuity.mjs +0 -537
  122. package/lib/cli/preflight.mjs +0 -76
  123. package/lib/cli/project-scaffolder/constants.mjs +0 -69
  124. package/lib/cli/project-scaffolder/discovery.mjs +0 -272
  125. package/lib/cli/project-scaffolder/prompt-builders.mjs +0 -171
  126. package/lib/cli/project-scaffolder/storage.mjs +0 -144
  127. package/lib/cli/project-scaffolder/ui-scope-detection.mjs +0 -36
  128. package/lib/cli/project-scaffolder.mjs +0 -29
  129. package/lib/cli/rollback.mjs +0 -66
  130. package/lib/cli/token-optimization.mjs +0 -401
  131. package/lib/cli/utils/filesystem.mjs +0 -81
  132. package/lib/cli/utils/managed-surface.mjs +0 -280
  133. package/lib/cli/utils/prompting.mjs +0 -44
  134. package/lib/cli/utils.mjs +0 -479
  135. package/mcp.json +0 -134
  136. package/scripts/adaptive-context/fixtures.mjs +0 -183
  137. package/scripts/adaptive-context-benchmark.mjs +0 -9
  138. package/scripts/ascx-runtime-token-saver-benchmark.mjs +0 -9
  139. package/scripts/benchmark-evidence-bundle.mjs +0 -645
  140. package/scripts/benchmark-gate.mjs +0 -121
  141. package/scripts/benchmark-intelligence.mjs +0 -33
  142. package/scripts/benchmark-writer-judge-matrix.mjs +0 -379
  143. package/scripts/build-release-benchmark-bundle.mjs +0 -202
  144. package/scripts/bump-version.mjs +0 -103
  145. package/scripts/clean-local-artifacts.mjs +0 -78
  146. package/scripts/compact-natural-mode-benchmark.mjs +0 -9
  147. package/scripts/context-triggered-audit.mjs +0 -391
  148. package/scripts/detection-benchmark.mjs +0 -127
  149. package/scripts/docs-quality-drift-report.mjs +0 -358
  150. package/scripts/documentation-boundary-audit.mjs +0 -305
  151. package/scripts/explain-on-demand-audit.mjs +0 -427
  152. package/scripts/forbidden-content-check.mjs +0 -123
  153. package/scripts/frontend-usability-audit.mjs +0 -243
  154. package/scripts/generate-sbom.mjs +0 -61
  155. package/scripts/governance-weekly-report.mjs +0 -466
  156. package/scripts/llm-judge/checklist-loader.mjs +0 -45
  157. package/scripts/llm-judge/constants.mjs +0 -66
  158. package/scripts/llm-judge/diff-collection.mjs +0 -74
  159. package/scripts/llm-judge/prompting.mjs +0 -78
  160. package/scripts/llm-judge/providers.mjs +0 -111
  161. package/scripts/llm-judge/verdict.mjs +0 -134
  162. package/scripts/llm-judge.mjs +0 -200
  163. package/scripts/memory-continuity-benchmark.mjs +0 -322
  164. package/scripts/quality-trend-report.mjs +0 -289
  165. package/scripts/release-gate/audit-checks.mjs +0 -441
  166. package/scripts/release-gate/constants.mjs +0 -53
  167. package/scripts/release-gate/runtime.mjs +0 -63
  168. package/scripts/release-gate/static-checks.mjs +0 -182
  169. package/scripts/release-gate.mjs +0 -42
  170. package/scripts/rules-guardian-audit.mjs +0 -580
  171. package/scripts/single-source-lazy-loading-audit.mjs +0 -449
  172. package/scripts/sync-thin-adapters.mjs +0 -72
  173. package/scripts/token-optimization-benchmark.mjs +0 -252
  174. package/scripts/ui-design-judge/constants.mjs +0 -13
  175. package/scripts/ui-design-judge/design-execution-summary.mjs +0 -81
  176. package/scripts/ui-design-judge/git-input.mjs +0 -134
  177. package/scripts/ui-design-judge/prompting.mjs +0 -52
  178. package/scripts/ui-design-judge/providers.mjs +0 -102
  179. package/scripts/ui-design-judge/reporting.mjs +0 -183
  180. package/scripts/ui-design-judge/rubric-calibration.mjs +0 -214
  181. package/scripts/ui-design-judge/rubric-goldset.json +0 -188
  182. package/scripts/ui-design-judge.mjs +0 -319
  183. package/scripts/ui-rubric-calibration.mjs +0 -35
  184. package/scripts/validate/audits/cache-layer-contract.mjs +0 -230
  185. package/scripts/validate/audits/caching-scope-hygiene.mjs +0 -235
  186. package/scripts/validate/audits/file-size.mjs +0 -158
  187. package/scripts/validate/audits/reflection-citations.mjs +0 -130
  188. package/scripts/validate/audits/release-bundle.mjs +0 -135
  189. package/scripts/validate/audits/rule-id-uniqueness.mjs +0 -278
  190. package/scripts/validate/config.mjs +0 -501
  191. package/scripts/validate/coverage-checks.mjs +0 -446
  192. package/scripts/validate/file-structure.mjs +0 -158
  193. package/scripts/validate/markdown-content.mjs +0 -109
  194. package/scripts/validate/project-metadata.mjs +0 -166
  195. package/scripts/validate/utils.mjs +0 -52
  196. package/scripts/validate.mjs +0 -267
@@ -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
- ];