@stackmemoryai/stackmemory 1.10.5 → 1.14.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.
- package/LICENSE +131 -64
- package/README.md +107 -24
- package/bin/claude-sm +16 -1
- package/bin/claude-smd +16 -1
- package/bin/codex-smd +16 -1
- package/bin/gemini-sm +16 -1
- package/bin/hermes-sm +21 -0
- package/bin/hermes-smd +21 -0
- package/bin/opencode-sm +16 -1
- package/dist/src/cli/claude-sm.js +266 -84
- package/dist/src/cli/codex-sm.js +225 -33
- package/dist/src/cli/commands/bench.js +209 -2
- package/dist/src/cli/commands/brain.js +206 -0
- package/dist/src/cli/commands/cache.js +126 -0
- package/dist/src/cli/commands/company-os.js +184 -0
- package/dist/src/cli/commands/context.js +5 -0
- package/dist/src/cli/commands/daemon.js +41 -0
- package/dist/src/cli/commands/handoff.js +40 -9
- package/dist/src/cli/commands/onboard.js +70 -3
- package/dist/src/cli/commands/operator.js +127 -0
- package/dist/src/cli/commands/optimize.js +117 -0
- package/dist/src/cli/commands/orchestrate.js +232 -5
- package/dist/src/cli/commands/orchestrator.js +315 -26
- package/dist/src/cli/commands/pack.js +322 -0
- package/dist/src/cli/commands/patterns.js +254 -0
- package/dist/src/cli/commands/portal.js +161 -0
- package/dist/src/cli/commands/scaffold.js +92 -0
- package/dist/src/cli/commands/search.js +40 -1
- package/dist/src/cli/commands/setup.js +178 -11
- package/dist/src/cli/commands/skills.js +10 -1
- package/dist/src/cli/commands/state.js +265 -0
- package/dist/src/cli/commands/sync.js +253 -0
- package/dist/src/cli/commands/tasks.js +130 -1
- package/dist/src/cli/commands/vision.js +221 -0
- package/dist/src/cli/gemini-sm.js +19 -29
- package/dist/src/cli/hermes-sm.js +224 -0
- package/dist/src/cli/index.js +105 -39
- package/dist/src/cli/opencode-sm.js +38 -21
- package/dist/src/cli/utils/determinism-watcher.js +66 -0
- package/dist/src/cli/utils/real-cli-bin.js +116 -0
- package/dist/src/core/brain/brain-store.js +187 -0
- package/dist/src/core/brain/brain-sync.js +193 -0
- package/dist/src/core/brain/index.js +78 -0
- package/dist/src/core/brain/types.js +10 -0
- package/dist/src/core/cache/content-cache.js +238 -0
- package/dist/src/{integrations/diffmem → core/cache}/index.js +5 -5
- package/dist/src/core/cache/token-estimator.js +39 -0
- package/dist/src/core/config/feature-flags.js +2 -6
- package/dist/src/core/context/frame-database.js +79 -27
- package/dist/src/core/context/recursive-context-manager.js +1 -1
- package/dist/src/core/context/rehydration.js +2 -1
- package/dist/src/core/cross-search/cross-project-search.js +269 -0
- package/dist/src/core/cross-search/index.js +10 -0
- package/dist/src/core/database/sqlite-adapter.js +14 -84
- package/dist/src/core/extensions/provider-adapter.js +5 -0
- package/dist/src/core/models/model-router.js +54 -2
- package/dist/src/core/models/provider-pricing.js +58 -4
- package/dist/src/core/monitoring/logger.js +2 -1
- package/dist/src/core/optimization/trace-optimizer.js +413 -0
- package/dist/src/core/patterns/index.js +22 -0
- package/dist/src/core/patterns/pattern-applier.js +39 -0
- package/dist/src/core/patterns/pattern-observer.js +157 -0
- package/dist/src/core/patterns/pattern-store.js +259 -0
- package/dist/src/core/patterns/types.js +19 -0
- package/dist/src/core/provenance/confidence-scorer.js +128 -0
- package/dist/src/core/provenance/index.js +40 -0
- package/dist/src/core/provenance/provenance-store.js +194 -0
- package/dist/src/core/provenance/types.js +82 -0
- package/dist/src/core/retrieval/llm-context-retrieval.js +5 -4
- package/dist/src/core/retrieval/unified-context-assembler.js +11 -66
- package/dist/src/core/session/project-handoff.js +64 -0
- package/dist/src/core/session/session-manager.js +28 -0
- package/dist/src/core/shared-state/canonical-store.js +564 -0
- package/dist/src/core/skill-packs/index.js +18 -0
- package/dist/src/core/skill-packs/parser.js +42 -0
- package/dist/src/core/skill-packs/registry.js +224 -0
- package/dist/src/core/skill-packs/types.js +79 -0
- package/dist/src/core/storage/cloud-sync-manager.js +116 -0
- package/dist/src/core/storage/cloud-sync.js +574 -0
- package/dist/src/core/storage/two-tier-storage.js +5 -1
- package/dist/src/core/tasks/master-tasks-template.js +43 -0
- package/dist/src/core/tasks/md-task-parser.js +138 -0
- package/dist/src/core/trace/trace-event-store.js +282 -0
- package/dist/src/core/vision/index.js +27 -0
- package/dist/src/core/vision/signals.js +79 -0
- package/dist/src/core/vision/types.js +22 -0
- package/dist/src/core/vision/vision-file.js +146 -0
- package/dist/src/core/vision/vision-loop.js +220 -0
- package/dist/src/core/wiki/wiki-compiler.js +103 -1
- package/dist/src/daemon/daemon-config.js +52 -0
- package/dist/src/daemon/services/desire-path-service.js +566 -0
- package/dist/src/daemon/services/github-service.js +126 -0
- package/dist/src/daemon/services/research-stream-service.js +320 -0
- package/dist/src/daemon/services/telemetry-service.js +192 -0
- package/dist/src/daemon/unified-daemon.js +58 -1
- package/dist/src/features/browser/cli-browser-agent.js +417 -0
- package/dist/src/features/browser/stagehand-workflows.js +578 -0
- package/dist/src/features/operator/adapter-factory.js +62 -0
- package/dist/src/features/operator/browser-adapter.js +109 -0
- package/dist/src/features/operator/desktop-adapter.js +125 -0
- package/dist/src/features/operator/index.js +39 -0
- package/dist/src/features/operator/llm-decision.js +137 -0
- package/dist/src/features/operator/operator-logger.js +92 -0
- package/dist/src/features/operator/overnight-runner.js +327 -0
- package/dist/src/features/operator/screen-adapter.js +91 -0
- package/dist/src/features/operator/session-manager.js +127 -0
- package/dist/src/features/operator/state-machine.js +227 -0
- package/dist/src/features/operator/task-queue.js +81 -0
- package/dist/src/features/portal/index.js +26 -0
- package/dist/src/features/portal/server.js +240 -0
- package/dist/src/features/portal/types.js +14 -0
- package/dist/src/features/portal/ui.js +195 -0
- package/dist/src/features/sweep/pty-wrapper.js +13 -5
- package/dist/src/features/tasks/task-aware-context.js +2 -1
- package/dist/src/features/tui/simple-monitor.js +0 -23
- package/dist/src/features/tui/swarm-monitor.js +8 -66
- package/dist/src/features/web/client/hooks/use-socket.js +12 -0
- package/dist/src/{core/merge/index.js → features/web/client/lib/utils.js} +8 -4
- package/dist/src/features/web/client/next-env.d.js +4 -0
- package/dist/src/features/web/client/stores/session-store.js +12 -0
- package/dist/src/features/web/server/gcp-billing.js +76 -0
- package/dist/src/features/web/server/index.js +10 -0
- package/dist/src/features/web/server/spend-calculator.js +228 -0
- package/dist/src/hooks/schemas.js +6 -1
- package/dist/src/integrations/anthropic/client.js +3 -2
- package/dist/src/integrations/claude-code/agent-bridge.js +0 -3
- package/dist/src/integrations/claude-code/subagent-client.js +307 -11
- package/dist/src/integrations/claude-code/task-coordinator.js +2 -1
- package/dist/src/integrations/github/pr-state.js +158 -0
- package/dist/src/integrations/linear/client.js +4 -1
- package/dist/src/integrations/linear/webhook-retry.js +196 -0
- package/dist/src/integrations/linear/webhook-server.js +18 -22
- package/dist/src/integrations/mcp/handlers/cloud-sync-handlers.js +101 -0
- package/dist/src/integrations/mcp/handlers/index.js +40 -84
- package/dist/src/integrations/mcp/server.js +542 -641
- package/dist/src/integrations/mcp/tool-alias-registry.js +297 -0
- package/dist/src/integrations/mcp/tool-definitions.js +152 -682
- package/dist/src/mcp/stackmemory-mcp-server.js +571 -231
- package/dist/src/orchestrators/multimodal/determinism.js +244 -0
- package/dist/src/orchestrators/multimodal/harness.js +149 -78
- package/dist/src/orchestrators/multimodal/providers.js +44 -3
- package/dist/src/skills/recursive-agent-orchestrator.js +2 -4
- package/dist/src/utils/hook-installer.js +0 -8
- package/dist/src/utils/process-cleanup.js +1 -7
- package/docs/README.md +42 -0
- package/docs/guides/README_INSTALL.md +208 -0
- package/package.json +27 -9
- package/packs/coding/python-fastapi/instructions.md +60 -0
- package/packs/coding/python-fastapi/pack.yaml +28 -0
- package/packs/coding/typescript-react/instructions.md +47 -0
- package/packs/coding/typescript-react/pack.yaml +28 -0
- package/packs/core/commands/capture.md +32 -0
- package/packs/core/commands/learn.md +73 -0
- package/packs/core/commands/next.md +36 -0
- package/packs/core/commands/restart.md +58 -0
- package/packs/core/commands/restore.md +29 -0
- package/packs/core/commands/start.md +57 -0
- package/packs/core/commands/stop.md +65 -0
- package/packs/core/commands/summary.md +40 -0
- package/packs/core/manifest.json +24 -0
- package/packs/ops/decision-recovery/instructions.md +65 -0
- package/packs/ops/decision-recovery/pack.yaml +89 -0
- package/scripts/claude-code-wrapper.sh +11 -0
- package/scripts/claude-sm-setup.sh +12 -1
- package/scripts/codex-wrapper.sh +11 -0
- package/scripts/git-hooks/branch-context-manager.sh +11 -0
- package/scripts/git-hooks/post-checkout-stackmemory.sh +11 -0
- package/scripts/git-hooks/post-commit-stackmemory.sh +11 -0
- package/scripts/git-hooks/pre-commit-stackmemory.sh +11 -0
- package/scripts/hooks/cleanup-shell.sh +12 -1
- package/scripts/hooks/task-complete.sh +12 -1
- package/scripts/install-code-execution-hooks.sh +12 -1
- package/scripts/install-sweep-hook.sh +12 -0
- package/scripts/install.sh +11 -0
- package/scripts/opencode-wrapper.sh +11 -0
- package/scripts/portal/cloud-init.yaml +69 -0
- package/scripts/portal/setup.sh +69 -0
- package/scripts/portal/stackmemory-portal.service +34 -0
- package/scripts/setup-claude-integration.sh +12 -1
- package/scripts/smoke-init-db.sh +23 -0
- package/scripts/stackmemory-daemon.sh +11 -0
- package/scripts/verify-dist.cjs +11 -4
- package/dist/src/cli/commands/ralph.js +0 -1053
- package/dist/src/cli/commands/team.js +0 -168
- package/dist/src/core/context/shared-context-layer.js +0 -620
- package/dist/src/core/context/stack-merge-resolver.js +0 -748
- package/dist/src/core/merge/conflict-detector.js +0 -430
- package/dist/src/core/merge/resolution-engine.js +0 -557
- package/dist/src/core/merge/stack-diff.js +0 -531
- package/dist/src/core/merge/unified-merge-resolver.js +0 -302
- package/dist/src/hooks/diffmem-hooks.js +0 -376
- package/dist/src/integrations/diffmem/client.js +0 -208
- package/dist/src/integrations/diffmem/config.js +0 -14
- package/dist/src/integrations/greptile/client.js +0 -101
- package/dist/src/integrations/greptile/config.js +0 -14
- package/dist/src/integrations/greptile/index.js +0 -11
- package/dist/src/integrations/mcp/handlers/cord-handlers.js +0 -397
- package/dist/src/integrations/mcp/handlers/diffmem-handlers.js +0 -455
- package/dist/src/integrations/mcp/handlers/greptile-handlers.js +0 -456
- package/dist/src/integrations/mcp/handlers/provider-handlers.js +0 -227
- package/dist/src/integrations/mcp/handlers/team-handlers.js +0 -211
- package/dist/src/integrations/ralph/bridge/ralph-stackmemory-bridge.js +0 -863
- package/dist/src/integrations/ralph/context/context-budget-manager.js +0 -308
- package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +0 -391
- package/dist/src/integrations/ralph/index.js +0 -17
- package/dist/src/integrations/ralph/learning/pattern-learner.js +0 -435
- package/dist/src/integrations/ralph/lifecycle/iteration-lifecycle.js +0 -448
- package/dist/src/integrations/ralph/loopmax.js +0 -488
- package/dist/src/integrations/ralph/monitoring/swarm-dashboard.js +0 -293
- package/dist/src/integrations/ralph/monitoring/swarm-registry.js +0 -107
- package/dist/src/integrations/ralph/orchestration/multi-loop-orchestrator.js +0 -508
- package/dist/src/integrations/ralph/patterns/compounding-engineering-pattern.js +0 -407
- package/dist/src/integrations/ralph/patterns/extended-coherence-sessions.js +0 -495
- package/dist/src/integrations/ralph/patterns/oracle-worker-pattern.js +0 -387
- package/dist/src/integrations/ralph/performance/performance-optimizer.js +0 -357
- package/dist/src/integrations/ralph/recovery/crash-recovery.js +0 -461
- package/dist/src/integrations/ralph/state/state-reconciler.js +0 -420
- package/dist/src/integrations/ralph/swarm/git-workflow-manager.js +0 -444
- package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +0 -1007
- package/dist/src/integrations/ralph/visualization/ralph-debugger.js +0 -635
- package/scripts/ralph-loop-implementation.js +0 -404
- /package/dist/src/core/{merge → cache}/types.js +0 -0
- /package/dist/src/{integrations/diffmem/types.js → core/storage/cloud-sync-types.js} +0 -0
- /package/dist/src/{integrations/greptile/types.js → core/trace/trace-event.js} +0 -0
- /package/dist/src/{integrations/ralph → features/operator}/types.js +0 -0
|
@@ -35,7 +35,18 @@ const MODEL_TOKEN_LIMITS = {
|
|
|
35
35
|
// Cerebras
|
|
36
36
|
"llama-4-scout-17b-16e-instruct": 131072,
|
|
37
37
|
// DeepInfra
|
|
38
|
-
"THUDM/glm-4-9b-chat": 128e3
|
|
38
|
+
"THUDM/glm-4-9b-chat": 128e3,
|
|
39
|
+
// Moonshot (Kimi)
|
|
40
|
+
"kimi-k2.6": 256e3,
|
|
41
|
+
"kimi-k2.5": 256e3,
|
|
42
|
+
// xAI (Grok)
|
|
43
|
+
"grok-4.1-fast": 131072,
|
|
44
|
+
"grok-4.3": 131072,
|
|
45
|
+
"grok-4": 131072,
|
|
46
|
+
// DeepSeek
|
|
47
|
+
"deepseek-v4-flash": 131072,
|
|
48
|
+
"deepseek-v4": 131072,
|
|
49
|
+
"deepseek-v4-pro": 131072
|
|
39
50
|
};
|
|
40
51
|
const DEFAULT_MODEL_TOKEN_LIMIT = 2e5;
|
|
41
52
|
function getModelTokenLimit(model) {
|
|
@@ -91,6 +102,24 @@ const DEFAULT_CONFIG = {
|
|
|
91
102
|
baseUrl: "https://openrouter.ai/api",
|
|
92
103
|
apiKeyEnv: "OPENROUTER_API_KEY"
|
|
93
104
|
},
|
|
105
|
+
moonshot: {
|
|
106
|
+
provider: "moonshot",
|
|
107
|
+
model: "kimi-k2.6",
|
|
108
|
+
baseUrl: "https://api.moonshot.ai/v1",
|
|
109
|
+
apiKeyEnv: "MOONSHOT_API_KEY"
|
|
110
|
+
},
|
|
111
|
+
xai: {
|
|
112
|
+
provider: "xai",
|
|
113
|
+
model: "grok-4.1-fast",
|
|
114
|
+
baseUrl: "https://api.x.ai/v1",
|
|
115
|
+
apiKeyEnv: "XAI_API_KEY"
|
|
116
|
+
},
|
|
117
|
+
deepseek: {
|
|
118
|
+
provider: "deepseek",
|
|
119
|
+
model: "deepseek-v4-flash",
|
|
120
|
+
baseUrl: "https://api.deepseek.com/v1",
|
|
121
|
+
apiKeyEnv: "DEEPSEEK_API_KEY"
|
|
122
|
+
},
|
|
94
123
|
"anthropic-batch": {
|
|
95
124
|
provider: "anthropic-batch",
|
|
96
125
|
model: "claude-sonnet-4-5-20250929",
|
|
@@ -235,8 +264,31 @@ const OPTIMAL_ROUTING = {
|
|
|
235
264
|
apiKeyEnv: "ANTHROPIC_API_KEY"
|
|
236
265
|
}
|
|
237
266
|
};
|
|
238
|
-
const FALLBACK_CHAIN = [
|
|
267
|
+
const FALLBACK_CHAIN = [
|
|
268
|
+
"moonshot",
|
|
269
|
+
"deepinfra",
|
|
270
|
+
"cerebras",
|
|
271
|
+
"anthropic"
|
|
272
|
+
];
|
|
239
273
|
const CHEAP_PROVIDERS = [
|
|
274
|
+
{
|
|
275
|
+
provider: "deepseek",
|
|
276
|
+
model: "deepseek-v4-flash",
|
|
277
|
+
apiKeyEnv: "DEEPSEEK_API_KEY",
|
|
278
|
+
baseUrl: "https://api.deepseek.com/v1"
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
provider: "xai",
|
|
282
|
+
model: "grok-4.1-fast",
|
|
283
|
+
apiKeyEnv: "XAI_API_KEY",
|
|
284
|
+
baseUrl: "https://api.x.ai/v1"
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
provider: "moonshot",
|
|
288
|
+
model: "kimi-k2.6",
|
|
289
|
+
apiKeyEnv: "MOONSHOT_API_KEY",
|
|
290
|
+
baseUrl: "https://api.moonshot.ai/v1"
|
|
291
|
+
},
|
|
240
292
|
{
|
|
241
293
|
provider: "openrouter",
|
|
242
294
|
model: "meta-llama/llama-4-scout",
|
|
@@ -3,7 +3,28 @@ import { dirname as __pathDirname } from 'path';
|
|
|
3
3
|
const __filename = __fileURLToPath(import.meta.url);
|
|
4
4
|
const __dirname = __pathDirname(__filename);
|
|
5
5
|
const MODEL_PRICING = {
|
|
6
|
-
// Anthropic (direct API)
|
|
6
|
+
// Anthropic (direct API) — Opus 4.x share one price; 1M context, no
|
|
7
|
+
// long-context premium. Sourced platform.claude.com 2026-05-26.
|
|
8
|
+
"anthropic/claude-opus-4-8": {
|
|
9
|
+
inputPer1M: 5,
|
|
10
|
+
outputPer1M: 25,
|
|
11
|
+
source: "platform.claude.com"
|
|
12
|
+
},
|
|
13
|
+
"anthropic/claude-opus-4-7": {
|
|
14
|
+
inputPer1M: 5,
|
|
15
|
+
outputPer1M: 25,
|
|
16
|
+
source: "platform.claude.com"
|
|
17
|
+
},
|
|
18
|
+
"anthropic/claude-opus-4-6": {
|
|
19
|
+
inputPer1M: 5,
|
|
20
|
+
outputPer1M: 25,
|
|
21
|
+
source: "platform.claude.com"
|
|
22
|
+
},
|
|
23
|
+
"anthropic/claude-sonnet-4-6": {
|
|
24
|
+
inputPer1M: 3,
|
|
25
|
+
outputPer1M: 15,
|
|
26
|
+
source: "platform.claude.com"
|
|
27
|
+
},
|
|
7
28
|
"anthropic/claude-sonnet-4-5-20250929": {
|
|
8
29
|
inputPer1M: 3,
|
|
9
30
|
outputPer1M: 15,
|
|
@@ -15,9 +36,9 @@ const MODEL_PRICING = {
|
|
|
15
36
|
source: "anthropic.com"
|
|
16
37
|
},
|
|
17
38
|
"anthropic/claude-haiku-4-5-20251001": {
|
|
18
|
-
inputPer1M:
|
|
19
|
-
outputPer1M:
|
|
20
|
-
source: "
|
|
39
|
+
inputPer1M: 1,
|
|
40
|
+
outputPer1M: 5,
|
|
41
|
+
source: "platform.claude.com"
|
|
21
42
|
},
|
|
22
43
|
// OpenAI (direct API)
|
|
23
44
|
"openai/gpt-4o": {
|
|
@@ -56,8 +77,41 @@ function formatCost(usd) {
|
|
|
56
77
|
if (usd < 0.01) return `$${usd.toFixed(6)}`;
|
|
57
78
|
return `$${usd.toFixed(4)}`;
|
|
58
79
|
}
|
|
80
|
+
const MAX_PLAN_DISCOUNT_RAMP = {
|
|
81
|
+
start: process.env.STACKMEMORY_COST_RAMP_START ?? "2026-06-06",
|
|
82
|
+
end: process.env.STACKMEMORY_COST_RAMP_END ?? "2026-09-06",
|
|
83
|
+
startMultiplier: Number(
|
|
84
|
+
process.env.STACKMEMORY_COST_RAMP_START_MULTIPLIER ?? "0.2"
|
|
85
|
+
),
|
|
86
|
+
endMultiplier: 1
|
|
87
|
+
};
|
|
88
|
+
function effectiveSpendMultiplier(date = /* @__PURE__ */ new Date(), ramp = MAX_PLAN_DISCOUNT_RAMP) {
|
|
89
|
+
const start = Date.parse(ramp.start);
|
|
90
|
+
const end = Date.parse(ramp.end);
|
|
91
|
+
const now = date.getTime();
|
|
92
|
+
if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) {
|
|
93
|
+
return ramp.endMultiplier;
|
|
94
|
+
}
|
|
95
|
+
if (now <= start) return ramp.startMultiplier;
|
|
96
|
+
if (now >= end) return ramp.endMultiplier;
|
|
97
|
+
const progress = (now - start) / (end - start);
|
|
98
|
+
return ramp.startMultiplier + progress * (ramp.endMultiplier - ramp.startMultiplier);
|
|
99
|
+
}
|
|
100
|
+
function effectiveCost(provider, model, inputTokens, outputTokens, date = /* @__PURE__ */ new Date()) {
|
|
101
|
+
const list = calculateCost(provider, model, inputTokens, outputTokens);
|
|
102
|
+
if (!list) return null;
|
|
103
|
+
const multiplier = effectiveSpendMultiplier(date);
|
|
104
|
+
return {
|
|
105
|
+
listCost: list.totalCost,
|
|
106
|
+
effectiveCost: list.totalCost * multiplier,
|
|
107
|
+
multiplier
|
|
108
|
+
};
|
|
109
|
+
}
|
|
59
110
|
export {
|
|
111
|
+
MAX_PLAN_DISCOUNT_RAMP,
|
|
60
112
|
MODEL_PRICING,
|
|
61
113
|
calculateCost,
|
|
114
|
+
effectiveCost,
|
|
115
|
+
effectiveSpendMultiplier,
|
|
62
116
|
formatCost
|
|
63
117
|
};
|
|
@@ -76,6 +76,7 @@ class Logger {
|
|
|
76
76
|
fileLoggingDisabledNotified = false;
|
|
77
77
|
constructor() {
|
|
78
78
|
const envLevel = process.env["STACKMEMORY_LOG_LEVEL"]?.toUpperCase();
|
|
79
|
+
const jsonCliMode = !envLevel && process.argv.includes("--json");
|
|
79
80
|
switch (envLevel) {
|
|
80
81
|
case "ERROR":
|
|
81
82
|
this.logLevel = 0 /* ERROR */;
|
|
@@ -87,7 +88,7 @@ class Logger {
|
|
|
87
88
|
this.logLevel = 3 /* DEBUG */;
|
|
88
89
|
break;
|
|
89
90
|
default:
|
|
90
|
-
this.logLevel = 2 /* INFO */;
|
|
91
|
+
this.logLevel = jsonCliMode ? 0 /* ERROR */ : 2 /* INFO */;
|
|
91
92
|
}
|
|
92
93
|
if (this.logLevel === 3 /* DEBUG */ || process.env["STACKMEMORY_LOG_FILE"]) {
|
|
93
94
|
this.logFile = process.env["STACKMEMORY_LOG_FILE"] || path.join(
|
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
import { fileURLToPath as __fileURLToPath } from 'url';
|
|
2
|
+
import { dirname as __pathDirname } from 'path';
|
|
3
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
4
|
+
const __dirname = __pathDirname(__filename);
|
|
5
|
+
import { existsSync, mkdirSync, writeFileSync } from "fs";
|
|
6
|
+
import { join } from "path";
|
|
7
|
+
const DEFAULT_OPTIONS = {
|
|
8
|
+
lookbackDays: 30,
|
|
9
|
+
minOccurrences: 2,
|
|
10
|
+
maxExamples: 3
|
|
11
|
+
};
|
|
12
|
+
const MUTATING_TOOLS = /* @__PURE__ */ new Set(["edit", "write", "multi_edit"]);
|
|
13
|
+
const SEARCH_TOOLS = /* @__PURE__ */ new Set(["search", "grep", "read", "glob", "find"]);
|
|
14
|
+
const VERIFICATION_TOOLS = /* @__PURE__ */ new Set([
|
|
15
|
+
"test",
|
|
16
|
+
"bash",
|
|
17
|
+
"lint",
|
|
18
|
+
"build",
|
|
19
|
+
"npm",
|
|
20
|
+
"pytest",
|
|
21
|
+
"vitest",
|
|
22
|
+
"jest"
|
|
23
|
+
]);
|
|
24
|
+
function classifyErrorText(text) {
|
|
25
|
+
const lower = text.toLowerCase();
|
|
26
|
+
if (lower.includes("lint") || lower.includes("eslint") || lower.includes("prettier")) {
|
|
27
|
+
return "lint_failure";
|
|
28
|
+
}
|
|
29
|
+
if (lower.includes("test") && (lower.includes("fail") || lower.includes("error"))) {
|
|
30
|
+
return "test_failure";
|
|
31
|
+
}
|
|
32
|
+
if (lower.includes("timeout") || lower.includes("timed out")) {
|
|
33
|
+
return "timeout";
|
|
34
|
+
}
|
|
35
|
+
if (lower.includes("rate limit") || lower.includes("429")) {
|
|
36
|
+
return "rate_limit";
|
|
37
|
+
}
|
|
38
|
+
if (lower.includes("permission") || lower.includes("eacces")) {
|
|
39
|
+
return "permission_failure";
|
|
40
|
+
}
|
|
41
|
+
if (lower.includes("build") && lower.includes("error")) {
|
|
42
|
+
return "build_failure";
|
|
43
|
+
}
|
|
44
|
+
return "unknown_failure";
|
|
45
|
+
}
|
|
46
|
+
function uniq(items) {
|
|
47
|
+
return [...new Set(items)];
|
|
48
|
+
}
|
|
49
|
+
function truncate(value, max = 120) {
|
|
50
|
+
return value.length > max ? `${value.slice(0, max - 1)}\u2026` : value;
|
|
51
|
+
}
|
|
52
|
+
function toolPattern(trace) {
|
|
53
|
+
return trace.tools.map((tool) => tool.tool).join("\u2192");
|
|
54
|
+
}
|
|
55
|
+
function hasVerification(trace) {
|
|
56
|
+
return trace.tools.some((tool) => VERIFICATION_TOOLS.has(tool.tool));
|
|
57
|
+
}
|
|
58
|
+
function hasMutation(trace) {
|
|
59
|
+
return trace.tools.some((tool) => MUTATING_TOOLS.has(tool.tool));
|
|
60
|
+
}
|
|
61
|
+
function countSearchTools(trace) {
|
|
62
|
+
return trace.tools.filter((tool) => SEARCH_TOOLS.has(tool.tool)).length;
|
|
63
|
+
}
|
|
64
|
+
function countRepeatedFailingTools(trace) {
|
|
65
|
+
const counts = /* @__PURE__ */ new Map();
|
|
66
|
+
for (const tool of trace.tools) {
|
|
67
|
+
if (!tool.error) continue;
|
|
68
|
+
counts.set(tool.tool, (counts.get(tool.tool) || 0) + 1);
|
|
69
|
+
}
|
|
70
|
+
let max = 0;
|
|
71
|
+
for (const value of counts.values()) {
|
|
72
|
+
if (value > max) max = value;
|
|
73
|
+
}
|
|
74
|
+
return max;
|
|
75
|
+
}
|
|
76
|
+
function createAccumulator(kind, label, targetAreas, actions, validations) {
|
|
77
|
+
return {
|
|
78
|
+
kind,
|
|
79
|
+
label,
|
|
80
|
+
traceIds: /* @__PURE__ */ new Set(),
|
|
81
|
+
summaries: [],
|
|
82
|
+
affectedFiles: /* @__PURE__ */ new Set(),
|
|
83
|
+
toolPatterns: /* @__PURE__ */ new Set(),
|
|
84
|
+
targetAreas: new Set(targetAreas),
|
|
85
|
+
actions,
|
|
86
|
+
validations
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function pushTraceEvidence(bucket, trace, maxExamples) {
|
|
90
|
+
bucket.traceIds.add(trace.id);
|
|
91
|
+
if (bucket.summaries.length < maxExamples) {
|
|
92
|
+
bucket.summaries.push(truncate(trace.summary));
|
|
93
|
+
}
|
|
94
|
+
for (const file of trace.metadata.filesModified) {
|
|
95
|
+
bucket.affectedFiles.add(file);
|
|
96
|
+
}
|
|
97
|
+
bucket.toolPatterns.add(toolPattern(trace));
|
|
98
|
+
}
|
|
99
|
+
function buildCluster(id, bucket) {
|
|
100
|
+
return {
|
|
101
|
+
id,
|
|
102
|
+
kind: bucket.kind,
|
|
103
|
+
label: bucket.label,
|
|
104
|
+
occurrences: bucket.traceIds.size,
|
|
105
|
+
traceIds: [...bucket.traceIds],
|
|
106
|
+
sampleSummaries: bucket.summaries,
|
|
107
|
+
affectedFiles: [...bucket.affectedFiles].sort(),
|
|
108
|
+
toolPatterns: [...bucket.toolPatterns].sort(),
|
|
109
|
+
targetAreas: [...bucket.targetAreas],
|
|
110
|
+
actions: bucket.actions,
|
|
111
|
+
validations: bucket.validations
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function recommendationForCluster(cluster) {
|
|
115
|
+
const highPriority = cluster.kind === "error_pattern" || cluster.occurrences >= 3;
|
|
116
|
+
return {
|
|
117
|
+
id: `rec-${cluster.id}`,
|
|
118
|
+
title: cluster.label,
|
|
119
|
+
priority: highPriority ? "high" : "medium",
|
|
120
|
+
confidence: Math.min(0.45 + cluster.occurrences * 0.12, 0.95),
|
|
121
|
+
summary: `${cluster.label} appeared in ${cluster.occurrences} trace${cluster.occurrences === 1 ? "" : "s"}. Focus on ${cluster.targetAreas.join(", ")} first.`,
|
|
122
|
+
targetAreas: cluster.targetAreas,
|
|
123
|
+
actions: cluster.actions,
|
|
124
|
+
validations: cluster.validations,
|
|
125
|
+
supportingClusters: [cluster.id]
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
class TraceOptimizer {
|
|
129
|
+
constructor(traceStore) {
|
|
130
|
+
this.traceStore = traceStore;
|
|
131
|
+
}
|
|
132
|
+
analyze(options = {}) {
|
|
133
|
+
const config = { ...DEFAULT_OPTIONS, ...options };
|
|
134
|
+
const cutoff = Date.now() - config.lookbackDays * 24 * 60 * 60 * 1e3;
|
|
135
|
+
const traces = this.traceStore.getAllTraces().filter((trace) => trace.metadata.startTime >= cutoff);
|
|
136
|
+
const clusters = this.buildClusters(traces, config);
|
|
137
|
+
const recommendations = clusters.map(recommendationForCluster);
|
|
138
|
+
const tracesByType = {};
|
|
139
|
+
for (const trace of traces) {
|
|
140
|
+
tracesByType[trace.type] = (tracesByType[trace.type] || 0) + 1;
|
|
141
|
+
}
|
|
142
|
+
const averageToolsPerTrace = traces.length > 0 ? traces.reduce((sum, trace) => sum + trace.tools.length, 0) / traces.length : 0;
|
|
143
|
+
const averageTraceScore = traces.length > 0 ? traces.reduce((sum, trace) => sum + trace.score, 0) / traces.length : 0;
|
|
144
|
+
return {
|
|
145
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
146
|
+
lookbackDays: config.lookbackDays,
|
|
147
|
+
totalTracesAnalyzed: traces.length,
|
|
148
|
+
tracesWithErrors: traces.filter(hasErrors).length,
|
|
149
|
+
causalTraces: traces.filter((trace) => trace.metadata.causalChain).length,
|
|
150
|
+
averageToolsPerTrace,
|
|
151
|
+
averageTraceScore,
|
|
152
|
+
tracesByType,
|
|
153
|
+
clusters,
|
|
154
|
+
recommendations
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
persistReport(projectRoot, report) {
|
|
158
|
+
const outputDir = join(projectRoot, ".stackmemory", "build");
|
|
159
|
+
if (!existsSync(outputDir)) {
|
|
160
|
+
mkdirSync(outputDir, { recursive: true });
|
|
161
|
+
}
|
|
162
|
+
const jsonPath = join(outputDir, "trace-optimizer-latest.json");
|
|
163
|
+
const markdownPath = join(outputDir, "trace-optimizer-latest.md");
|
|
164
|
+
writeFileSync(jsonPath, `${JSON.stringify(report, null, 2)}
|
|
165
|
+
`, "utf8");
|
|
166
|
+
writeFileSync(markdownPath, renderMarkdownReport(report), "utf8");
|
|
167
|
+
return { jsonPath, markdownPath };
|
|
168
|
+
}
|
|
169
|
+
buildClusters(traces, options) {
|
|
170
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
171
|
+
for (const trace of traces) {
|
|
172
|
+
const errors = extractErrors(trace);
|
|
173
|
+
for (const error of errors) {
|
|
174
|
+
const code = classifyErrorText(error);
|
|
175
|
+
const key = `error:${code}`;
|
|
176
|
+
if (!buckets.has(key)) {
|
|
177
|
+
buckets.set(
|
|
178
|
+
key,
|
|
179
|
+
createAccumulator(
|
|
180
|
+
"error_pattern",
|
|
181
|
+
labelForError(code),
|
|
182
|
+
targetAreasForError(code),
|
|
183
|
+
actionsForError(code),
|
|
184
|
+
validationsForError(code)
|
|
185
|
+
)
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
pushTraceEvidence(buckets.get(key), trace, options.maxExamples);
|
|
189
|
+
}
|
|
190
|
+
if (hasMutation(trace) && !hasVerification(trace)) {
|
|
191
|
+
const key = "verification_gap";
|
|
192
|
+
if (!buckets.has(key)) {
|
|
193
|
+
buckets.set(
|
|
194
|
+
key,
|
|
195
|
+
createAccumulator(
|
|
196
|
+
"verification_gap",
|
|
197
|
+
"Mutating traces often finish without an explicit verification step",
|
|
198
|
+
["hooks", "wrappers", "orchestrator"],
|
|
199
|
+
[
|
|
200
|
+
"Add a post-edit verification policy that requires targeted test, lint, or build execution before a task is considered complete.",
|
|
201
|
+
"Teach wrappers and agent prompts to prefer the smallest validating command after edits instead of stopping at file changes."
|
|
202
|
+
],
|
|
203
|
+
[
|
|
204
|
+
"npm run test:run",
|
|
205
|
+
"npm run lint",
|
|
206
|
+
"stackmemory bench determinism --latest --json"
|
|
207
|
+
]
|
|
208
|
+
)
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
pushTraceEvidence(buckets.get(key), trace, options.maxExamples);
|
|
212
|
+
}
|
|
213
|
+
if (countRepeatedFailingTools(trace) >= 2) {
|
|
214
|
+
const key = "retry_loop";
|
|
215
|
+
if (!buckets.has(key)) {
|
|
216
|
+
buckets.set(
|
|
217
|
+
key,
|
|
218
|
+
createAccumulator(
|
|
219
|
+
"retry_loop",
|
|
220
|
+
"Failing tools are being retried in loops instead of changing strategy",
|
|
221
|
+
["orchestrator", "hooks", "prompts"],
|
|
222
|
+
[
|
|
223
|
+
"Add retry guards that trigger diagnosis or fallback prompts after the second failing attempt of the same tool.",
|
|
224
|
+
"Capture the first failure reason and inject it into the next planning step so the harness pivots instead of repeating."
|
|
225
|
+
],
|
|
226
|
+
["npm run determinism:test", "stackmemory conductor trace-stats"]
|
|
227
|
+
)
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
pushTraceEvidence(buckets.get(key), trace, options.maxExamples);
|
|
231
|
+
}
|
|
232
|
+
if (countSearchTools(trace) >= 4 && !hasMutation(trace) && trace.tools.length >= 5) {
|
|
233
|
+
const key = "context_thrash";
|
|
234
|
+
if (!buckets.has(key)) {
|
|
235
|
+
buckets.set(
|
|
236
|
+
key,
|
|
237
|
+
createAccumulator(
|
|
238
|
+
"context_thrash",
|
|
239
|
+
"Search-heavy traces suggest context assembly or retrieval is too weak",
|
|
240
|
+
["retrieval", "hooks", "context bundling"],
|
|
241
|
+
[
|
|
242
|
+
"Promote recurring search\u2192read loops into explicit retrieval bundles or preloaded context packets.",
|
|
243
|
+
"Use trace summaries to precompute likely files, anchors, or commands for similar future tasks."
|
|
244
|
+
],
|
|
245
|
+
["python scripts/dspy/eval.py", "stackmemory retrieval stats"]
|
|
246
|
+
)
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
pushTraceEvidence(buckets.get(key), trace, options.maxExamples);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return [...buckets.entries()].map(([id, bucket]) => buildCluster(id, bucket)).filter((cluster) => cluster.occurrences >= options.minOccurrences).sort((a, b) => {
|
|
253
|
+
if (b.occurrences !== a.occurrences) {
|
|
254
|
+
return b.occurrences - a.occurrences;
|
|
255
|
+
}
|
|
256
|
+
return a.label.localeCompare(b.label);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function hasErrors(trace) {
|
|
261
|
+
return extractErrors(trace).length > 0;
|
|
262
|
+
}
|
|
263
|
+
function extractErrors(trace) {
|
|
264
|
+
const toolErrors = trace.tools.map((tool) => tool.error).filter((value) => Boolean(value));
|
|
265
|
+
return uniq([...trace.metadata.errorsEncountered, ...toolErrors]);
|
|
266
|
+
}
|
|
267
|
+
function labelForError(code) {
|
|
268
|
+
switch (code) {
|
|
269
|
+
case "lint_failure":
|
|
270
|
+
return "Lint failures recur across traces and should be gated earlier";
|
|
271
|
+
case "test_failure":
|
|
272
|
+
return "Test failures recur and need tighter edit-time validation";
|
|
273
|
+
case "timeout":
|
|
274
|
+
return "Timeouts recur and need fallback or budget-aware orchestration";
|
|
275
|
+
case "rate_limit":
|
|
276
|
+
return "Rate-limit failures recur and need backoff-aware retry policies";
|
|
277
|
+
case "permission_failure":
|
|
278
|
+
return "Permission or missing-file failures recur and need environment preflight checks";
|
|
279
|
+
case "build_failure":
|
|
280
|
+
return "Build failures recur and should be surfaced before finalization";
|
|
281
|
+
default:
|
|
282
|
+
return "Unclassified failures recur and need structured diagnosis";
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function targetAreasForError(code) {
|
|
286
|
+
switch (code) {
|
|
287
|
+
case "lint_failure":
|
|
288
|
+
case "test_failure":
|
|
289
|
+
case "build_failure":
|
|
290
|
+
return ["hooks", "wrappers", "verification"];
|
|
291
|
+
case "timeout":
|
|
292
|
+
case "rate_limit":
|
|
293
|
+
return ["orchestrator", "fallbacks", "retry policy"];
|
|
294
|
+
case "permission_failure":
|
|
295
|
+
return ["setup", "hooks", "environment checks"];
|
|
296
|
+
default:
|
|
297
|
+
return ["orchestrator", "prompts", "diagnostics"];
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function actionsForError(code) {
|
|
301
|
+
switch (code) {
|
|
302
|
+
case "lint_failure":
|
|
303
|
+
return [
|
|
304
|
+
"Insert a fast lint or formatting guard after edits when touched files match configured source globs.",
|
|
305
|
+
"Surface the exact lint failure in the next planning turn so the harness repairs before moving on."
|
|
306
|
+
];
|
|
307
|
+
case "test_failure":
|
|
308
|
+
return [
|
|
309
|
+
"Require targeted test execution after code edits in code paths that already have tests.",
|
|
310
|
+
"Teach the orchestrator to stop on the second failing test loop and switch to diagnosis mode."
|
|
311
|
+
];
|
|
312
|
+
case "timeout":
|
|
313
|
+
return [
|
|
314
|
+
"Add time-budget-aware fallbacks and cut off repeated long-running commands sooner.",
|
|
315
|
+
"Persist timeout causes so later attempts can shorten prompts, narrow file scopes, or switch models."
|
|
316
|
+
];
|
|
317
|
+
case "rate_limit":
|
|
318
|
+
return [
|
|
319
|
+
"Back off and downgrade to a cheaper model or cached context path after a rate-limit event.",
|
|
320
|
+
"Record rate-limit state in session context so retry attempts do not immediately hit the same ceiling."
|
|
321
|
+
];
|
|
322
|
+
case "permission_failure":
|
|
323
|
+
return [
|
|
324
|
+
"Run environment and path preflight checks before invoking tools that assume local binaries or files exist.",
|
|
325
|
+
"Convert common permission failures into actionable setup hints instead of opaque retries."
|
|
326
|
+
];
|
|
327
|
+
case "build_failure":
|
|
328
|
+
return [
|
|
329
|
+
"Add a build gate for changes that touch runtime entrypoints, package manifests, or bundler config.",
|
|
330
|
+
"Capture compiler diagnostics into the next repair prompt instead of relying on the model to infer them."
|
|
331
|
+
];
|
|
332
|
+
default:
|
|
333
|
+
return [
|
|
334
|
+
"Capture richer error metadata and turn repeated failures into a structured diagnosis step.",
|
|
335
|
+
"Route repeated unknown failures through a narrower repair prompt instead of repeating the same harness path."
|
|
336
|
+
];
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function validationsForError(code) {
|
|
340
|
+
switch (code) {
|
|
341
|
+
case "lint_failure":
|
|
342
|
+
return ["npm run lint", "npm run test:run"];
|
|
343
|
+
case "test_failure":
|
|
344
|
+
return ["npm run test:run", "npm run determinism:test"];
|
|
345
|
+
case "build_failure":
|
|
346
|
+
return ["npm run build", "npm run test:run"];
|
|
347
|
+
case "timeout":
|
|
348
|
+
return [
|
|
349
|
+
"stackmemory conductor trace-stats",
|
|
350
|
+
"npm run determinism:latest"
|
|
351
|
+
];
|
|
352
|
+
case "rate_limit":
|
|
353
|
+
return ["stackmemory conductor trace-stats"];
|
|
354
|
+
case "permission_failure":
|
|
355
|
+
return ["stackmemory doctor", "npm run test:smoke-db"];
|
|
356
|
+
default:
|
|
357
|
+
return ["npm run test:run"];
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
function renderMarkdownReport(report) {
|
|
361
|
+
const lines = [];
|
|
362
|
+
lines.push("# Trace Optimizer Report");
|
|
363
|
+
lines.push("");
|
|
364
|
+
lines.push(`Generated: ${report.generatedAt}`);
|
|
365
|
+
lines.push(`Lookback: ${report.lookbackDays} day(s)`);
|
|
366
|
+
lines.push("");
|
|
367
|
+
lines.push("## Summary");
|
|
368
|
+
lines.push(`- Traces analyzed: ${report.totalTracesAnalyzed}`);
|
|
369
|
+
lines.push(`- Traces with errors: ${report.tracesWithErrors}`);
|
|
370
|
+
lines.push(`- Causal traces: ${report.causalTraces}`);
|
|
371
|
+
lines.push(`- Avg tools/trace: ${report.averageToolsPerTrace.toFixed(2)}`);
|
|
372
|
+
lines.push(`- Avg trace score: ${report.averageTraceScore.toFixed(2)}`);
|
|
373
|
+
lines.push("");
|
|
374
|
+
lines.push("## Recommendations");
|
|
375
|
+
if (report.recommendations.length === 0) {
|
|
376
|
+
lines.push("- No repeated failure patterns crossed the current threshold.");
|
|
377
|
+
} else {
|
|
378
|
+
for (const recommendation of report.recommendations) {
|
|
379
|
+
lines.push(
|
|
380
|
+
`- ${recommendation.title} (${recommendation.priority}, confidence ${recommendation.confidence.toFixed(2)})`
|
|
381
|
+
);
|
|
382
|
+
lines.push(` Summary: ${recommendation.summary}`);
|
|
383
|
+
lines.push(` Targets: ${recommendation.targetAreas.join(", ")}`);
|
|
384
|
+
lines.push(` Actions: ${recommendation.actions.join(" | ")}`);
|
|
385
|
+
lines.push(` Validate: ${recommendation.validations.join(" | ")}`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
lines.push("");
|
|
389
|
+
lines.push("## Clusters");
|
|
390
|
+
if (report.clusters.length === 0) {
|
|
391
|
+
lines.push("- No clusters found.");
|
|
392
|
+
} else {
|
|
393
|
+
for (const cluster of report.clusters) {
|
|
394
|
+
lines.push(`### ${cluster.label}`);
|
|
395
|
+
lines.push(`- Occurrences: ${cluster.occurrences}`);
|
|
396
|
+
lines.push(`- Kind: ${cluster.kind}`);
|
|
397
|
+
lines.push(
|
|
398
|
+
`- Tool patterns: ${cluster.toolPatterns.join(", ") || "n/a"}`
|
|
399
|
+
);
|
|
400
|
+
lines.push(`- Files: ${cluster.affectedFiles.join(", ") || "n/a"}`);
|
|
401
|
+
lines.push(
|
|
402
|
+
`- Sample traces: ${cluster.sampleSummaries.join(" | ") || "n/a"}`
|
|
403
|
+
);
|
|
404
|
+
lines.push("");
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return `${lines.join("\n")}
|
|
408
|
+
`;
|
|
409
|
+
}
|
|
410
|
+
export {
|
|
411
|
+
TraceOptimizer,
|
|
412
|
+
renderMarkdownReport
|
|
413
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { fileURLToPath as __fileURLToPath } from 'url';
|
|
2
|
+
import { dirname as __pathDirname } from 'path';
|
|
3
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
4
|
+
const __dirname = __pathDirname(__filename);
|
|
5
|
+
import {
|
|
6
|
+
computeConfidence,
|
|
7
|
+
CONFIDENCE_DECAY_PER_WEEK,
|
|
8
|
+
CONFIDENCE_BOOST_PER_OBSERVATION,
|
|
9
|
+
CONFIDENCE_PENALTY_PER_CONTRADICTION
|
|
10
|
+
} from "./types.js";
|
|
11
|
+
import { PatternStore } from "./pattern-store.js";
|
|
12
|
+
import { PatternObserver } from "./pattern-observer.js";
|
|
13
|
+
import { PatternApplier } from "./pattern-applier.js";
|
|
14
|
+
export {
|
|
15
|
+
CONFIDENCE_BOOST_PER_OBSERVATION,
|
|
16
|
+
CONFIDENCE_DECAY_PER_WEEK,
|
|
17
|
+
CONFIDENCE_PENALTY_PER_CONTRADICTION,
|
|
18
|
+
PatternApplier,
|
|
19
|
+
PatternObserver,
|
|
20
|
+
PatternStore,
|
|
21
|
+
computeConfidence
|
|
22
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { fileURLToPath as __fileURLToPath } from 'url';
|
|
2
|
+
import { dirname as __pathDirname } from 'path';
|
|
3
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
4
|
+
const __dirname = __pathDirname(__filename);
|
|
5
|
+
class PatternApplier {
|
|
6
|
+
constructor(store) {
|
|
7
|
+
this.store = store;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Find and format patterns relevant to a task.
|
|
11
|
+
* Returns a markdown block to inject into context.
|
|
12
|
+
*/
|
|
13
|
+
apply(taskDescription, projectId) {
|
|
14
|
+
const patterns = this.store.search(taskDescription, projectId);
|
|
15
|
+
if (patterns.length === 0) return "";
|
|
16
|
+
for (const p of patterns) {
|
|
17
|
+
this.store.recordMatch(p.id);
|
|
18
|
+
}
|
|
19
|
+
const lines = ["## Learned Patterns", ""];
|
|
20
|
+
for (const p of patterns) {
|
|
21
|
+
const bar = this.confidenceBar(p.confidence);
|
|
22
|
+
lines.push(
|
|
23
|
+
`- ${bar} **${p.trigger}** \u2192 ${p.action} _(${p.domain}, ${p.observationCount} obs)_`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
return lines.join("\n");
|
|
27
|
+
}
|
|
28
|
+
/** Get patterns as structured data (for MCP tool) */
|
|
29
|
+
query(taskDescription, projectId) {
|
|
30
|
+
return this.store.search(taskDescription, projectId);
|
|
31
|
+
}
|
|
32
|
+
confidenceBar(confidence) {
|
|
33
|
+
const filled = Math.round(confidence * 5);
|
|
34
|
+
return "\u2588".repeat(filled) + "\u2591".repeat(5 - filled);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
PatternApplier
|
|
39
|
+
};
|