@ryuenn3123/agentic-senior-core 4.4.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/.agents/plugins/agentic-senior-core/plugin.json +3 -0
  2. package/.agents/plugins/agentic-senior-core/rules/agentic-senior-core.md +131 -0
  3. package/.agents/plugins/agentic-senior-core/skills/asc/SKILL.md +16 -0
  4. package/.agents/plugins/agentic-senior-core/skills/asc-audit/SKILL.md +28 -0
  5. package/.agents/plugins/agentic-senior-core/skills/asc-refactor/SKILL.md +35 -0
  6. package/.agents/plugins/agentic-senior-core/skills/asc-review/SKILL.md +54 -0
  7. package/.agents/rules/agentic-senior-core.md +131 -0
  8. package/.claude-plugin/marketplace.json +17 -0
  9. package/.claude-plugin/plugin.json +17 -0
  10. package/.clinerules/agentic-senior-core.md +94 -0
  11. package/.codex-plugin/plugin.json +24 -0
  12. package/.cursor/rules/agentic-senior-core.mdc +99 -0
  13. package/.devin-plugin/plugin.json +13 -0
  14. package/.github/copilot-instructions.md +94 -0
  15. package/.github/plugin/marketplace.json +20 -0
  16. package/.github/plugin/plugin.json +16 -0
  17. package/.kiro/steering/agentic-senior-core.md +94 -0
  18. package/.openclaw/skills/asc/SKILL.md +23 -0
  19. package/.openclaw/skills/asc-audit/SKILL.md +28 -0
  20. package/.openclaw/skills/asc-review/SKILL.md +54 -0
  21. package/.opencode/plugins/agentic-senior-core.mjs +31 -0
  22. package/.windsurf/rules/agentic-senior-core.md +94 -0
  23. package/AGENTS.md +126 -127
  24. package/CONTRIBUTING.md +93 -63
  25. package/README.md +190 -110
  26. package/__init__.py +61 -0
  27. package/bin/agentic-senior-core.js +42 -41
  28. package/commands/asc-audit.md +1 -0
  29. package/commands/asc-audit.toml +2 -0
  30. package/commands/asc-help.md +9 -0
  31. package/commands/asc-help.toml +2 -0
  32. package/commands/asc-refactor.md +1 -0
  33. package/commands/asc-refactor.toml +2 -0
  34. package/commands/asc-review.md +1 -0
  35. package/commands/asc-review.toml +2 -0
  36. package/gemini-extension.json +10 -0
  37. package/hooks/copilot-hooks.json +21 -0
  38. package/hooks/hooks.json +31 -0
  39. package/hooks/session-start.js +36 -0
  40. package/hooks/subagent-start.js +38 -0
  41. package/lib/cli/commands/adapter.mjs +109 -0
  42. package/lib/cli/commands/clean.mjs +63 -0
  43. package/lib/cli/commands/status.mjs +94 -0
  44. package/package.json +43 -60
  45. package/plugin.yaml +16 -0
  46. package/scripts/uninstall.js +38 -0
  47. package/skills/asc/SKILL.md +16 -0
  48. package/skills/asc-audit/SKILL.md +28 -0
  49. package/skills/asc-refactor/SKILL.md +35 -0
  50. package/skills/asc-review/SKILL.md +54 -0
  51. package/.agent-context/policies/llm-judge-threshold.json +0 -29
  52. package/.agent-context/prompts/bootstrap-design.md +0 -63
  53. package/.agent-context/prompts/compact-natural-mode.md +0 -100
  54. package/.agent-context/prompts/init-project.md +0 -60
  55. package/.agent-context/prompts/refactor.md +0 -38
  56. package/.agent-context/prompts/review-code.md +0 -31
  57. package/.agent-context/review-checklists/architecture-review.md +0 -57
  58. package/.agent-context/review-checklists/pr-checklist.md +0 -134
  59. package/.agent-context/rules/api-docs.md +0 -24
  60. package/.agent-context/rules/api-versioning.md +0 -16
  61. package/.agent-context/rules/architecture.md +0 -38
  62. package/.agent-context/rules/background-jobs.md +0 -17
  63. package/.agent-context/rules/config-and-flags.md +0 -16
  64. package/.agent-context/rules/database-design.md +0 -18
  65. package/.agent-context/rules/docker-runtime.md +0 -17
  66. package/.agent-context/rules/error-handling.md +0 -16
  67. package/.agent-context/rules/event-driven.md +0 -16
  68. package/.agent-context/rules/frontend-architecture.md +0 -54
  69. package/.agent-context/rules/microservices.md +0 -16
  70. package/.agent-context/rules/migrations.md +0 -16
  71. package/.agent-context/rules/observability.md +0 -16
  72. package/.agent-context/rules/performance.md +0 -16
  73. package/.agent-context/rules/realtime.md +0 -16
  74. package/.agent-context/rules/resilience.md +0 -18
  75. package/.agent-context/rules/security.md +0 -18
  76. package/.agent-context/rules/testing.md +0 -16
  77. package/.agent-context/state/README.md +0 -25
  78. package/.agent-context/state/architecture-map.md +0 -40
  79. package/.agent-context/state/benchmark-comparison-schema.json +0 -181
  80. package/.agent-context/state/benchmark-reproducibility.json +0 -87
  81. package/.agent-context/state/benchmark-thresholds.json +0 -10
  82. package/.agent-context/state/benchmark-writer-judge-config.json +0 -58
  83. package/.agent-context/state/dependency-map.md +0 -41
  84. package/.agent-context/state/memory-adapter-contract.json +0 -52
  85. package/.agent-context/state/memory-schema-v1.json +0 -88
  86. package/GEMINI.md +0 -1
  87. package/benchmarks/README.md +0 -60
  88. package/benchmarks/compact-natural-mode/fixtures.mjs +0 -359
  89. package/benchmarks/compact-natural-mode/scorer.mjs +0 -331
  90. package/benchmarks/runtime-token-saver/fixtures.mjs +0 -836
  91. package/lib/cli/adaptive-context/catalog.mjs +0 -394
  92. package/lib/cli/adaptive-context/file-signals.mjs +0 -100
  93. package/lib/cli/adaptive-context/implications.mjs +0 -44
  94. package/lib/cli/adaptive-context.mjs +0 -151
  95. package/lib/cli/audits/typography-palette-anti-repeat/color-utils.mjs +0 -156
  96. package/lib/cli/audits/typography-palette-anti-repeat/file-scanner.mjs +0 -103
  97. package/lib/cli/audits/typography-palette-anti-repeat/typography-utils.mjs +0 -70
  98. package/lib/cli/backup.mjs +0 -210
  99. package/lib/cli/commands/context.mjs +0 -140
  100. package/lib/cli/commands/init/project-context.mjs +0 -60
  101. package/lib/cli/commands/init/runtime-environment.mjs +0 -59
  102. package/lib/cli/commands/init/setup-decisions.mjs +0 -83
  103. package/lib/cli/commands/init.mjs +0 -654
  104. package/lib/cli/commands/launch.mjs +0 -76
  105. package/lib/cli/commands/optimize.mjs +0 -284
  106. package/lib/cli/commands/rollback.mjs +0 -64
  107. package/lib/cli/commands/upgrade/token-optimization-state.mjs +0 -51
  108. package/lib/cli/commands/upgrade.mjs +0 -451
  109. package/lib/cli/compiler.mjs +0 -187
  110. package/lib/cli/constants.mjs +0 -136
  111. package/lib/cli/detector/constants.mjs +0 -135
  112. package/lib/cli/detector/design-evidence/collector.mjs +0 -256
  113. package/lib/cli/detector/design-evidence/constants.mjs +0 -39
  114. package/lib/cli/detector/design-evidence/file-traversal.mjs +0 -83
  115. package/lib/cli/detector/design-evidence/structured-attribute-evidence.mjs +0 -117
  116. package/lib/cli/detector/design-evidence/summary.mjs +0 -109
  117. package/lib/cli/detector/design-evidence/utility-helpers.mjs +0 -122
  118. package/lib/cli/detector/design-evidence.mjs +0 -25
  119. package/lib/cli/detector/stack-detection.mjs +0 -243
  120. package/lib/cli/detector/ui-signals.mjs +0 -150
  121. package/lib/cli/detector/workspace-scan.mjs +0 -177
  122. package/lib/cli/detector.mjs +0 -23
  123. package/lib/cli/init-detection-flow.mjs +0 -48
  124. package/lib/cli/init-options.mjs +0 -237
  125. package/lib/cli/init-selection.mjs +0 -29
  126. package/lib/cli/memory-continuity.mjs +0 -537
  127. package/lib/cli/preflight.mjs +0 -76
  128. package/lib/cli/project-scaffolder/constants.mjs +0 -69
  129. package/lib/cli/project-scaffolder/discovery.mjs +0 -272
  130. package/lib/cli/project-scaffolder/prompt-builders.mjs +0 -171
  131. package/lib/cli/project-scaffolder/storage.mjs +0 -144
  132. package/lib/cli/project-scaffolder/ui-scope-detection.mjs +0 -36
  133. package/lib/cli/project-scaffolder.mjs +0 -29
  134. package/lib/cli/rollback.mjs +0 -66
  135. package/lib/cli/token-optimization.mjs +0 -401
  136. package/lib/cli/utils/filesystem.mjs +0 -81
  137. package/lib/cli/utils/managed-surface.mjs +0 -280
  138. package/lib/cli/utils/prompting.mjs +0 -44
  139. package/lib/cli/utils.mjs +0 -479
  140. package/mcp.json +0 -134
  141. package/scripts/adaptive-context/fixtures.mjs +0 -183
  142. package/scripts/adaptive-context-benchmark.mjs +0 -9
  143. package/scripts/ascx-runtime-token-saver-benchmark.mjs +0 -9
  144. package/scripts/benchmark-evidence-bundle.mjs +0 -645
  145. package/scripts/benchmark-gate.mjs +0 -121
  146. package/scripts/benchmark-intelligence.mjs +0 -33
  147. package/scripts/benchmark-writer-judge-matrix.mjs +0 -379
  148. package/scripts/build-release-benchmark-bundle.mjs +0 -202
  149. package/scripts/bump-version.mjs +0 -103
  150. package/scripts/clean-local-artifacts.mjs +0 -78
  151. package/scripts/compact-natural-mode-benchmark.mjs +0 -9
  152. package/scripts/context-triggered-audit.mjs +0 -391
  153. package/scripts/detection-benchmark.mjs +0 -127
  154. package/scripts/docs-quality-drift-report.mjs +0 -358
  155. package/scripts/documentation-boundary-audit.mjs +0 -305
  156. package/scripts/explain-on-demand-audit.mjs +0 -427
  157. package/scripts/forbidden-content-check.mjs +0 -123
  158. package/scripts/frontend-usability-audit.mjs +0 -243
  159. package/scripts/generate-sbom.mjs +0 -61
  160. package/scripts/governance-weekly-report.mjs +0 -466
  161. package/scripts/llm-judge/checklist-loader.mjs +0 -45
  162. package/scripts/llm-judge/constants.mjs +0 -66
  163. package/scripts/llm-judge/diff-collection.mjs +0 -74
  164. package/scripts/llm-judge/prompting.mjs +0 -78
  165. package/scripts/llm-judge/providers.mjs +0 -111
  166. package/scripts/llm-judge/verdict.mjs +0 -134
  167. package/scripts/llm-judge.mjs +0 -200
  168. package/scripts/memory-continuity-benchmark.mjs +0 -322
  169. package/scripts/quality-trend-report.mjs +0 -289
  170. package/scripts/release-gate/audit-checks.mjs +0 -441
  171. package/scripts/release-gate/constants.mjs +0 -53
  172. package/scripts/release-gate/runtime.mjs +0 -63
  173. package/scripts/release-gate/static-checks.mjs +0 -182
  174. package/scripts/release-gate.mjs +0 -42
  175. package/scripts/rules-guardian-audit.mjs +0 -580
  176. package/scripts/single-source-lazy-loading-audit.mjs +0 -449
  177. package/scripts/sync-thin-adapters.mjs +0 -72
  178. package/scripts/token-optimization-benchmark.mjs +0 -252
  179. package/scripts/ui-design-judge/constants.mjs +0 -13
  180. package/scripts/ui-design-judge/design-execution-summary.mjs +0 -81
  181. package/scripts/ui-design-judge/git-input.mjs +0 -134
  182. package/scripts/ui-design-judge/prompting.mjs +0 -52
  183. package/scripts/ui-design-judge/providers.mjs +0 -102
  184. package/scripts/ui-design-judge/reporting.mjs +0 -183
  185. package/scripts/ui-design-judge/rubric-calibration.mjs +0 -214
  186. package/scripts/ui-design-judge/rubric-goldset.json +0 -188
  187. package/scripts/ui-design-judge.mjs +0 -319
  188. package/scripts/ui-rubric-calibration.mjs +0 -35
  189. package/scripts/validate/audits/cache-layer-contract.mjs +0 -230
  190. package/scripts/validate/audits/caching-scope-hygiene.mjs +0 -235
  191. package/scripts/validate/audits/file-size.mjs +0 -158
  192. package/scripts/validate/audits/reflection-citations.mjs +0 -130
  193. package/scripts/validate/audits/release-bundle.mjs +0 -135
  194. package/scripts/validate/audits/rule-id-uniqueness.mjs +0 -278
  195. package/scripts/validate/config.mjs +0 -501
  196. package/scripts/validate/coverage-checks.mjs +0 -446
  197. package/scripts/validate/file-structure.mjs +0 -158
  198. package/scripts/validate/markdown-content.mjs +0 -109
  199. package/scripts/validate/project-metadata.mjs +0 -166
  200. package/scripts/validate/utils.mjs +0 -52
  201. 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
- ];