toolnet-memory 0.2.1 → 0.2.2
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/README.md +55 -28
- package/bin/toolnet-memory +55 -55
- package/bundle/agy.js +88 -0
- package/bundle/codex.js +92 -0
- package/bundle/context-runtime.js +56 -0
- package/bundle/context.js +62 -0
- package/bundle/doctor.js +3 -0
- package/bundle/full-index.js +8 -0
- package/bundle/learner.js +8 -0
- package/bundle/mcp.js +7 -0
- package/bundle/opencode.js +314 -0
- package/bundle/project-manual.js +54 -0
- package/bundle/setup.js +31 -0
- package/bundle/snapshot.js +4 -0
- package/bundle/work-continuity.js +12 -0
- package/package.json +9 -6
- package/dist/packages/cli/commands.js +0 -1
- package/dist/packages/cli/index.js +0 -1
- package/dist/packages/sdk/client.js +0 -78
- package/dist/packages/sdk/index.js +0 -1
- package/dist/packages/sdk/types.js +0 -1
- package/dist/src/api/index.js +0 -1
- package/dist/src/api/routes/health.js +0 -1
- package/dist/src/api/routes/index.js +0 -1
- package/dist/src/api/routes/memory.js +0 -1
- package/dist/src/api/routes/projects.js +0 -1
- package/dist/src/api/routes/search.js +0 -1
- package/dist/src/api/server.js +0 -1
- package/dist/src/capture/activity-capture.js +0 -21
- package/dist/src/capture/command-capture.js +0 -12
- package/dist/src/capture/error-capture.js +0 -14
- package/dist/src/capture/event-deduplicator.js +0 -28
- package/dist/src/capture/event-queue.js +0 -20
- package/dist/src/capture/file-capture.js +0 -23
- package/dist/src/capture/index.js +0 -8
- package/dist/src/capture/session-capture.js +0 -18
- package/dist/src/capture/tool-capture.js +0 -13
- package/dist/src/code-intelligence/analysis/analysis-engine.js +0 -26
- package/dist/src/code-intelligence/analysis/dead-code-analyzer.js +0 -127
- package/dist/src/code-intelligence/analysis/dependency-analyzer.js +0 -66
- package/dist/src/code-intelligence/analysis/index.js +0 -4
- package/dist/src/code-intelligence/analysis/types.js +0 -1
- package/dist/src/code-intelligence/architecture/architecture-engine.js +0 -48
- package/dist/src/code-intelligence/architecture/clusters.js +0 -322
- package/dist/src/code-intelligence/architecture/entry-points.js +0 -150
- package/dist/src/code-intelligence/architecture/hotspots.js +0 -136
- package/dist/src/code-intelligence/architecture/index.js +0 -6
- package/dist/src/code-intelligence/architecture/layers.js +0 -197
- package/dist/src/code-intelligence/architecture/types.js +0 -1
- package/dist/src/code-intelligence/chunks/index.js +0 -2
- package/dist/src/code-intelligence/chunks/smart-chunker.js +0 -125
- package/dist/src/code-intelligence/chunks/types.js +0 -1
- package/dist/src/code-intelligence/git/git-diff.js +0 -109
- package/dist/src/code-intelligence/git/index.js +0 -1
- package/dist/src/code-intelligence/graph/architecture.js +0 -26
- package/dist/src/code-intelligence/graph/graph-builder.js +0 -213
- package/dist/src/code-intelligence/graph/graph-store.js +0 -57
- package/dist/src/code-intelligence/graph/index.js +0 -1
- package/dist/src/code-intelligence/graph/relationships.js +0 -1
- package/dist/src/code-intelligence/graph/trace.js +0 -65
- package/dist/src/code-intelligence/impact/blast-radius.js +0 -160
- package/dist/src/code-intelligence/impact/change-mapper.js +0 -69
- package/dist/src/code-intelligence/impact/edit-tool-detector.js +0 -92
- package/dist/src/code-intelligence/impact/impact-analyzer.js +0 -60
- package/dist/src/code-intelligence/impact/impact-guard.js +0 -33
- package/dist/src/code-intelligence/impact/index.js +0 -5
- package/dist/src/code-intelligence/incremental/file-hash.js +0 -8
- package/dist/src/code-intelligence/incremental/incremental-indexer.js +0 -106
- package/dist/src/code-intelligence/incremental/manifest-builder.js +0 -19
- package/dist/src/code-intelligence/incremental/manifest.js +0 -31
- package/dist/src/code-intelligence/index.js +0 -23
- package/dist/src/code-intelligence/indexer/file-watcher.js +0 -1
- package/dist/src/code-intelligence/indexer/incremental-indexer.js +0 -1
- package/dist/src/code-intelligence/indexer/index.js +0 -1
- package/dist/src/code-intelligence/indexer/repository-indexer.js +0 -31
- package/dist/src/code-intelligence/indexer/repository-scanner.js +0 -50
- package/dist/src/code-intelligence/parsers/index.js +0 -1
- package/dist/src/code-intelligence/parsers/tree-sitter/index.js +0 -1
- package/dist/src/code-intelligence/parsers/tree-sitter/languages.js +0 -1
- package/dist/src/code-intelligence/parsers/tree-sitter/parser.js +0 -1
- package/dist/src/code-intelligence/parsers/typescript-parser.js +0 -190
- package/dist/src/code-intelligence/query/graph-query-engine.js +0 -275
- package/dist/src/code-intelligence/query/index.js +0 -2
- package/dist/src/code-intelligence/query/types.js +0 -1
- package/dist/src/code-intelligence/resolution/index.js +0 -2
- package/dist/src/code-intelligence/resolution/types.js +0 -1
- package/dist/src/code-intelligence/resolution/typescript-resolver.js +0 -316
- package/dist/src/code-intelligence/rich/index.js +0 -1
- package/dist/src/code-intelligence/rich/rich-graph-enricher.js +0 -463
- package/dist/src/code-intelligence/semantic/index.js +0 -2
- package/dist/src/code-intelligence/semantic/semantic-code-engine.js +0 -213
- package/dist/src/code-intelligence/semantic/source-priority.js +0 -22
- package/dist/src/code-intelligence/symbols/index.js +0 -1
- package/dist/src/code-intelligence/symbols/reference-resolver.js +0 -21
- package/dist/src/code-intelligence/symbols/symbol-extractor.js +0 -1
- package/dist/src/code-intelligence/test-analysis.js +0 -72
- package/dist/src/code-intelligence/test-architecture.js +0 -67
- package/dist/src/code-intelligence/test-impact.js +0 -47
- package/dist/src/code-intelligence/test-incremental.js +0 -24
- package/dist/src/code-intelligence/test-index.js +0 -39
- package/dist/src/code-intelligence/test-resolution.js +0 -54
- package/dist/src/code-intelligence/test-rich-graph.js +0 -48
- package/dist/src/code-intelligence/test-semantic.js +0 -57
- package/dist/src/code-intelligence/test-visualization.js +0 -36
- package/dist/src/code-intelligence/types.js +0 -1
- package/dist/src/code-intelligence/visualization/index.js +0 -2
- package/dist/src/code-intelligence/visualization/types.js +0 -1
- package/dist/src/code-intelligence/visualization/visualization-builder.js +0 -104
- package/dist/src/core/config.js +0 -66
- package/dist/src/core/global-env.js +0 -70
- package/dist/src/core/importance.js +0 -30
- package/dist/src/core/index.js +0 -5
- package/dist/src/core/memory-engine.js +0 -183
- package/dist/src/core/project-manager.js +0 -243
- package/dist/src/core/types.js +0 -1
- package/dist/src/embeddings/batch-embedder.js +0 -1
- package/dist/src/embeddings/cache.js +0 -1
- package/dist/src/embeddings/embedder.js +0 -51
- package/dist/src/embeddings/index.js +0 -4
- package/dist/src/embeddings/local.js +0 -37
- package/dist/src/embeddings/provider.js +0 -1
- package/dist/src/embeddings/remote.js +0 -76
- package/dist/src/embeddings/test-connection.js +0 -16
- package/dist/src/hooks/after-edit.js +0 -3
- package/dist/src/hooks/after-tool.js +0 -3
- package/dist/src/hooks/auto-context.js +0 -68
- package/dist/src/hooks/auto-impact-guard.js +0 -94
- package/dist/src/hooks/auto-retrieval.js +0 -27
- package/dist/src/hooks/before-agent.js +0 -18
- package/dist/src/hooks/before-compact.js +0 -3
- package/dist/src/hooks/before-edit.js +0 -20
- package/dist/src/hooks/index.js +0 -11
- package/dist/src/hooks/runtime.js +0 -110
- package/dist/src/hooks/session-end.js +0 -3
- package/dist/src/hooks/session-start.js +0 -3
- package/dist/src/index.js +0 -22
- package/dist/src/mcp/bootstrap.js +0 -68
- package/dist/src/mcp/context.js +0 -1
- package/dist/src/mcp/index.js +0 -3
- package/dist/src/mcp/server.js +0 -45
- package/dist/src/mcp/tools/analyze-impact.js +0 -41
- package/dist/src/mcp/tools/dead-code.js +0 -55
- package/dist/src/mcp/tools/find-callers.js +0 -24
- package/dist/src/mcp/tools/find-dependencies.js +0 -57
- package/dist/src/mcp/tools/find-symbol.js +0 -7
- package/dist/src/mcp/tools/get-architecture.js +0 -11
- package/dist/src/mcp/tools/graph-dependents.js +0 -24
- package/dist/src/mcp/tools/graph-neighborhood.js +0 -58
- package/dist/src/mcp/tools/graph-path.js +0 -43
- package/dist/src/mcp/tools/graph-query-utils.js +0 -32
- package/dist/src/mcp/tools/impact-guard.js +0 -34
- package/dist/src/mcp/tools/index-repository.js +0 -1
- package/dist/src/mcp/tools/index.js +0 -20
- package/dist/src/mcp/tools/memory-decisions.js +0 -1
- package/dist/src/mcp/tools/memory-forget.js +0 -14
- package/dist/src/mcp/tools/memory-recent.js +0 -1
- package/dist/src/mcp/tools/memory-remember.js +0 -33
- package/dist/src/mcp/tools/memory-rules.js +0 -1
- package/dist/src/mcp/tools/memory-search.js +0 -18
- package/dist/src/mcp/tools/memory-todos.js +0 -1
- package/dist/src/mcp/tools/project-context.js +0 -25
- package/dist/src/mcp/tools/search-code.js +0 -21
- package/dist/src/mcp/tools/semantic-code-search.js +0 -33
- package/dist/src/mcp/tools/snapshot-create.js +0 -13
- package/dist/src/mcp/tools/snapshot-list.js +0 -7
- package/dist/src/mcp/tools/snapshot-restore.js +0 -13
- package/dist/src/mcp/tools/trace-calls.js +0 -37
- package/dist/src/memory/activity.js +0 -5
- package/dist/src/memory/conflict-detector.js +0 -105
- package/dist/src/memory/consolidator.js +0 -104
- package/dist/src/memory/decay.js +0 -59
- package/dist/src/memory/decisions.js +0 -3
- package/dist/src/memory/deduplicate.js +0 -25
- package/dist/src/memory/index.js +0 -11
- package/dist/src/memory/maintenance.js +0 -16
- package/dist/src/memory/remember.js +0 -3
- package/dist/src/memory/rules.js +0 -3
- package/dist/src/memory/search.js +0 -3
- package/dist/src/memory/summaries.js +0 -1
- package/dist/src/memory/todos.js +0 -3
- package/dist/src/processor/decision-extractor.js +0 -13
- package/dist/src/processor/importance-scorer.js +0 -22
- package/dist/src/processor/index.js +0 -7
- package/dist/src/processor/memory-extractor.js +0 -59
- package/dist/src/processor/memory-processor.js +0 -105
- package/dist/src/processor/rule-extractor.js +0 -13
- package/dist/src/processor/summarizer.js +0 -71
- package/dist/src/processor/todo-extractor.js +0 -12
- package/dist/src/production/config-check.js +0 -34
- package/dist/src/production/doctor.js +0 -58
- package/dist/src/production/full-index.js +0 -114
- package/dist/src/production/health.js +0 -58
- package/dist/src/production/index-pipeline.js +0 -151
- package/dist/src/production/index.js +0 -4
- package/dist/src/production/project-lock.js +0 -95
- package/dist/src/production/project-status.js +0 -16
- package/dist/src/production/recovery.js +0 -15
- package/dist/src/production/setup.js +0 -219
- package/dist/src/production/snapshot-cli.js +0 -58
- package/dist/src/project-manual/cli.js +0 -77
- package/dist/src/project-manual/index.js +0 -2
- package/dist/src/project-manual/manager.js +0 -147
- package/dist/src/project-manual/types.js +0 -1
- package/dist/src/retrieval/bm25/index.js +0 -1
- package/dist/src/retrieval/bm25/search.js +0 -1
- package/dist/src/retrieval/bm25.js +0 -30
- package/dist/src/retrieval/context-budget.js +0 -1
- package/dist/src/retrieval/context-builder.js +0 -22
- package/dist/src/retrieval/graph/index.js +0 -1
- package/dist/src/retrieval/graph/search.js +0 -1
- package/dist/src/retrieval/hybrid/hybrid-search.js +0 -1
- package/dist/src/retrieval/hybrid/index.js +0 -1
- package/dist/src/retrieval/hybrid-search.js +0 -68
- package/dist/src/retrieval/importance.js +0 -16
- package/dist/src/retrieval/index.js +0 -12
- package/dist/src/retrieval/query-analyzer.js +0 -32
- package/dist/src/retrieval/query-classifier.js +0 -1
- package/dist/src/retrieval/query-expansion.js +0 -1
- package/dist/src/retrieval/recency.js +0 -12
- package/dist/src/retrieval/reranker/index.js +0 -1
- package/dist/src/retrieval/reranker/reranker.js +0 -1
- package/dist/src/retrieval/retrieval-engine.js +0 -17
- package/dist/src/retrieval/tokenizer.js +0 -9
- package/dist/src/retrieval/type-priority.js +0 -10
- package/dist/src/retrieval/types.js +0 -1
- package/dist/src/retrieval/vector/index.js +0 -4
- package/dist/src/retrieval/vector/metadata-filter.js +0 -1
- package/dist/src/retrieval/vector/persistence.js +0 -67
- package/dist/src/retrieval/vector/search.js +0 -12
- package/dist/src/retrieval/vector/test-persistence.js +0 -36
- package/dist/src/retrieval/vector/upsert.js +0 -40
- package/dist/src/retrieval/vector/vector-store.js +0 -89
- package/dist/src/retrieval/vector-hybrid-engine.js +0 -91
- package/dist/src/runtime/bootstrap.js +0 -28
- package/dist/src/runtime/graceful.js +0 -17
- package/dist/src/runtime/index.js +0 -3
- package/dist/src/runtime/toolnet-memory-runtime.js +0 -156
- package/dist/src/security/encryption.js +0 -1
- package/dist/src/security/file-filter.js +0 -30
- package/dist/src/security/index.js +0 -3
- package/dist/src/security/sanitizer.js +0 -49
- package/dist/src/security/secret-scanner.js +0 -56
- package/dist/src/session/agy/adapter.js +0 -159
- package/dist/src/session/agy/cli.js +0 -87
- package/dist/src/session/agy/hook-installer.js +0 -62
- package/dist/src/session/agy/hook.js +0 -167
- package/dist/src/session/agy/index.js +0 -5
- package/dist/src/session/agy/project-resolver.js +0 -27
- package/dist/src/session/agy/recovery.js +0 -112
- package/dist/src/session/agy/transcript.js +0 -191
- package/dist/src/session/codex/adapter.js +0 -138
- package/dist/src/session/codex/cli.js +0 -236
- package/dist/src/session/codex/context-hook-installer.js +0 -70
- package/dist/src/session/codex/context-hook.js +0 -69
- package/dist/src/session/codex/discovery.js +0 -138
- package/dist/src/session/codex/index.js +0 -6
- package/dist/src/session/codex/notify-installer.js +0 -135
- package/dist/src/session/codex/project-resolver.js +0 -25
- package/dist/src/session/codex/recovery.js +0 -27
- package/dist/src/session/codex/rollout.js +0 -186
- package/dist/src/session/core.js +0 -239
- package/dist/src/session/identity.js +0 -57
- package/dist/src/session/index.js +0 -9
- package/dist/src/session/learner/cli.js +0 -62
- package/dist/src/session/learner/extractor.js +0 -461
- package/dist/src/session/learner/index.js +0 -4
- package/dist/src/session/learner/journal.js +0 -159
- package/dist/src/session/learner/learner.js +0 -124
- package/dist/src/session/learner/types.js +0 -1
- package/dist/src/session/opencode/adapter.js +0 -553
- package/dist/src/session/opencode/cli.js +0 -121
- package/dist/src/session/opencode/index.js +0 -2
- package/dist/src/session/opencode/plugin-installer.js +0 -230
- package/dist/src/session/store.js +0 -242
- package/dist/src/session/types.js +0 -1
- package/dist/src/session/utils.js +0 -47
- package/dist/src/session/wal.js +0 -303
- package/dist/src/snapshot/index.js +0 -2
- package/dist/src/snapshot/manager.js +0 -130
- package/dist/src/snapshot/test-snapshot.js +0 -28
- package/dist/src/snapshot/types.js +0 -1
- package/dist/src/storage/architecture-store.js +0 -37
- package/dist/src/storage/cleanup-health.js +0 -20
- package/dist/src/storage/code-analysis-store.js +0 -35
- package/dist/src/storage/code-chunk-store.js +0 -25
- package/dist/src/storage/code-graph-store.js +0 -24
- package/dist/src/storage/code-manifest-store.js +0 -24
- package/dist/src/storage/code-vector-store.js +0 -25
- package/dist/src/storage/github/client.js +0 -1
- package/dist/src/storage/github/index.js +0 -1
- package/dist/src/storage/google-drive/client.js +0 -1
- package/dist/src/storage/google-drive/index.js +0 -1
- package/dist/src/storage/huggingface/client.js +0 -116
- package/dist/src/storage/huggingface/index.js +0 -1
- package/dist/src/storage/index.js +0 -16
- package/dist/src/storage/list-bucket-raw.js +0 -14
- package/dist/src/storage/list-bucket-tree.js +0 -38
- package/dist/src/storage/local/client.js +0 -99
- package/dist/src/storage/local/index.js +0 -1
- package/dist/src/storage/memory-store.js +0 -30
- package/dist/src/storage/project/cleanup-layout-v1.js +0 -72
- package/dist/src/storage/project/folder.js +0 -15
- package/dist/src/storage/project/index.js +0 -3
- package/dist/src/storage/project/layout.js +0 -74
- package/dist/src/storage/project/migrate-layout-v2.js +0 -101
- package/dist/src/storage/project/migrate.js +0 -73
- package/dist/src/storage/project/scoped-provider.js +0 -165
- package/dist/src/storage/provider.js +0 -26
- package/dist/src/storage/retrying-provider.js +0 -23
- package/dist/src/storage/test-connection.js +0 -32
- package/dist/src/storage/type-resolution-store.js +0 -26
- package/dist/src/storage/types.js +0 -1
- package/dist/src/storage/vector-store.js +0 -30
- package/dist/src/storage/visualization-store.js +0 -25
- package/dist/src/sync/compressor.js +0 -1
- package/dist/src/sync/conflict-resolver.js +0 -1
- package/dist/src/sync/downloader.js +0 -1
- package/dist/src/sync/index.js +0 -1
- package/dist/src/sync/sync-engine.js +0 -1
- package/dist/src/sync/upload-queue.js +0 -1
- package/dist/src/utils/retry.js +0 -29
- package/dist/src/visualization/server.js +0 -270
- package/dist/src/work-continuity/brief-cache.js +0 -107
- package/dist/src/work-continuity/brief.js +0 -349
- package/dist/src/work-continuity/cli.js +0 -96
- package/dist/src/work-continuity/context-cli.js +0 -106
- package/dist/src/work-continuity/context-runtime-cli.js +0 -88
- package/dist/src/work-continuity/extractor.js +0 -339
- package/dist/src/work-continuity/handoff.js +0 -185
- package/dist/src/work-continuity/index.js +0 -14
- package/dist/src/work-continuity/injection.js +0 -84
- package/dist/src/work-continuity/journal.js +0 -49
- package/dist/src/work-continuity/learner.js +0 -127
- package/dist/src/work-continuity/reducer.js +0 -316
- package/dist/src/work-continuity/semantic-extractor.js +0 -360
- package/dist/src/work-continuity/semantic-journal.js +0 -55
- package/dist/src/work-continuity/semantic-learner.js +0 -125
- package/dist/src/work-continuity/semantic-reducer.js +0 -268
- package/dist/src/work-continuity/semantic-types.js +0 -1
- package/dist/src/work-continuity/types.js +0 -1
- package/dist/visualization/public/index.html +0 -2896
- package/dist/visualization/public/vendor/3d-force-graph.min.js +0 -5
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import{existsSync as ne,readFileSync as ie}from"node:fs";import{homedir as ae}from"node:os";import{join as ce}from"node:path";function pe(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
|
|
2
|
+
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function de(){let r=process.env.TOOLNET_GLOBAL_ENV??ce(ae(),".config","toolnet-memory",".env");if(!ne(r))return;let e=ie(r,"utf8");for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let s=o.indexOf("=");if(s<=0)continue;let i=o.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=pe(o.slice(s+1)))}}de();function j(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function y(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function z(){return{memory:{autoCapture:j(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:j(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:j(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:j(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:y(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:y(process.env.MEMORY_RERANK_TOP,10),finalContext:y(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:y(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:y(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as ue}from"node:crypto";import{existsSync as V,mkdirSync as me,readFileSync as le,renameSync as ge,writeFileSync as fe}from"node:fs";import{basename as ye,dirname as k,join as R,parse as W,resolve as v}from"node:path";var K=".toolnet",he="project.json";function Se(r){return ue("sha256").update(r).digest("hex").slice(0,16)}function T(r){return R(r,K,he)}function je(r){return V(T(r))}function ke(r){let e=v(r),t=W(e).root;for(;;){if(je(e))return e;if(e===t)break;let o=k(e);if(o===e)break;e=o}return null}function ve(r){let e=v(r),t=W(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>V(R(e,i))))return e;if(e===t)break;let s=k(e);if(s===e)break;e=s}return v(r)}function xe(r){let e;try{e=JSON.parse(le(r,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${r}: ${s instanceof Error?s.message:String(s)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let o=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:k(k(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:o,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:o,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function D(r,e){let t=R(r,K);me(t,{recursive:!0});let o=T(r),s=`${o}.tmp-${process.pid}`;fe(s,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),ge(s,o)}function L(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var x=class{detect(e=process.cwd()){let t=v(e),o=ke(t);if(o){let d=T(o),p=xe(d);return p.rootPath!==o&&(p.rootPath=o,p.updatedAt=new Date().toISOString(),D(o,p)),L(p,o)}let s=ve(t),i=new Date().toISOString(),a=ye(s),c={version:1,id:Se(s),name:a,remote:a,rootPath:s,createdAt:i,updatedAt:i,graphVersion:0,memoryVersion:0};return D(s,c),L(c,s)}};import{homedir as De}from"node:os";import{join as Le}from"node:path";import{DeleteObjectCommand as we,GetObjectCommand as be,HeadObjectCommand as Pe,ListObjectsV2Command as Ae,PutObjectCommand as Re,S3Client as Te}from"@aws-sdk/client-s3";import{getSignedUrl as Me}from"@aws-sdk/s3-request-presigner";var w=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Te({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Re({Bucket:this.bucket,Key:e,Body:s,ContentType:o}))}async get(e){let t=await Me(this.client,new be({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`HF download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Pe({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new we({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let s=await this.client.send(new Ae({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of s.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=s.IsTruncated?s.NextContinuationToken:void 0}while(o);return t}};import{access as J,mkdir as Ie,readFile as Oe,readdir as Ee,rm as Ce,stat as B,writeFile as _e}from"node:fs/promises";import{dirname as Ne,join as $e,relative as F,resolve as ze}from"node:path";var h=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return ze(this.root,t)}async put(e,t){let o=this.path(e);await Ie(Ne(o),{recursive:!0}),await _e(o,t)}async get(e){try{return await Oe(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await J(this.path(e)),!0}catch{return!1}}async delete(e){await Ce(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await J(t)}catch{return o}let s=async a=>{let c=await Ee(a,{withFileTypes:!0});for(let d of c){let p=$e(a,d.name);if(d.isDirectory()){await s(p);continue}let f=await B(p);o.push({key:F(this.root,p),size:f.size,updatedAt:f.mtime.toISOString()})}},i=await B(t);return i.isDirectory()?await s(t):o.push({key:F(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),o}};function H(r){let e=r.localRoot??Le(De(),".toolnet-memory","storage");if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new w({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new h(e))}return new h(e)}function Ve(r){return new Promise(e=>setTimeout(e,r))}async function G(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,s=e.maxDelayMs??2e3,i;for(let a=1;a<=t;a++)try{return await r()}catch(c){if(i=c,a>=t)break;let d=Math.min(s,o*2**(a-1)),p=Math.floor(Math.random()*Math.max(1,d*.2));await Ve(d+p)}throw i}var We=new Set(["put","get","getText","delete","list"]);function U(r,e={}){return new Proxy(r,{get(t,o){let s=Reflect.get(t,o,t);return typeof s!="function"?s:We.has(o)?(...i)=>G(()=>Promise.resolve(s.apply(t,i)),e):s.bind(t)}})}function Y(r){let e=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function Z(r){let e=r.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(o)return`${o[1]}memory/records/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),o)return`${o[1]}memory/vectors/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),o)return`${o[1]}code/graph/${o[2]}`;let s=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:e))}var b=class{constructor(e,t,o,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=Y(s??o),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),o=t,s=await this.provider.getText(e);if(s){let a;try{a=JSON.parse(s)}catch(c){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${c instanceof Error?c.message:String(c)}`)}if(typeof a.id=="string"&&a.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${a.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof a.createdAt=="string"&&(o=a.createdAt)}let i={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:t};await this.provider.put(e,JSON.stringify(i,null,2)+`
|
|
4
|
+
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=Z(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,o){return await this.ensureRegistered(),this.provider.put(this.key(e),t,o)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{join as q}from"node:path";import{mkdirSync as Ge}from"node:fs";import{createHash as Ke}from"node:crypto";import{dirname as Je}from"node:path";import{mkdirSync as Be,readFileSync as Lr,renameSync as Fe,writeFileSync as He}from"node:fs";function X(r){return Ke("sha256").update(r).digest("hex")}function Q(r,e){Be(Je(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;He(t,JSON.stringify(e,null,2)+`
|
|
5
|
+
`,{encoding:"utf8",mode:384}),Fe(t,r)}function Ue(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function g(r,e=20){let t=[],o=new Set;for(let s of r.slice().reverse()){let i=Ue(s);if(!(!i||o.has(i))&&(o.add(i),t.push(s),t.length>=e))break}return t.reverse()}function Ye(r){return r.kind==="phase"?/^Phase\s+\d+$/iu.test(r.text):r.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(r.text):!1}function ee(r,e){let t=e.status??r?.status??"pending",o=t;r&&(r.status==="completed"&&t!=="completed"?o="completed":t==="pending"&&(r.status==="in_progress"||r.status==="blocked")&&(o=r.status));let s=r&&Ye(e)?r.title:e.text;return{id:r?.id??X(e.key).slice(0,24),title:s,status:o,order:e.order??r?.order,confidence:Math.max(e.confidence,r?.confidence??0),updatedAt:e.occurredAt,updatedBy:{agent:e.agent,nativeSessionId:e.nativeSessionId,eventId:e.eventId}}}async function Ze(r,e){let t=`projects/${r.id}/work/observations/`,o=await e.list(t),s=[];for(let i of o.filter(a=>a.key.endsWith(".json")).sort((a,c)=>a.key.localeCompare(c.key))){let a=await e.getText(i.key);if(a)try{let c=JSON.parse(a);c.version===1&&Array.isArray(c.observations)&&s.push(c)}catch{}}return s}async function te(r,e){let o=(await Ze(r,e)).flatMap(n=>n.observations).sort((n,l)=>{let N=n.occurredAt.localeCompare(l.occurredAt);if(N!==0)return N;let $=n.sequence-l.sequence;return $!==0?$:n.id.localeCompare(l.id)}),s=new Map,i=new Map,a,c,d,p=[],f=[],I=[],O=[],E=[],C=[];for(let n of o)switch(n.kind){case"goal":a=n.text;break;case"plan":c=n.text;break;case"phase":s.set(n.key,ee(s.get(n.key),n));break;case"task":i.set(n.key,ee(i.get(n.key),n));break;case"decision":p.push(n.text);break;case"blocker":f.push(n.text);break;case"warning":I.push(n.text);break;case"next_action":O.push(n.text);break;case"file":E.push(n.text);break;case"test":C.push(n.text);break;case"session":d={agent:n.agent,nativeSessionId:n.nativeSessionId,sessionKey:n.sessionKey,updatedAt:n.occurredAt};break}let m=Array.from(s.values()).sort((n,l)=>(n.order??Number.MAX_SAFE_INTEGER)-(l.order??Number.MAX_SAFE_INTEGER)),u=Array.from(i.values()).sort((n,l)=>(n.order??Number.MAX_SAFE_INTEGER)-(l.order??Number.MAX_SAFE_INTEGER)),P=m.find(n=>n.status==="in_progress")??m.find(n=>n.status==="blocked")??m.find(n=>n.status==="pending"),S=u.find(n=>n.status==="in_progress")??u.find(n=>n.status==="blocked")??u.find(n=>n.status==="pending"),oe=g([...O,...S?[S.title]:[],...!S&&P?[P.title]:[],...u.filter(n=>n.status==="pending").slice(0,5).map(n=>n.title)],8),se=g([...f,...m.filter(n=>n.status==="blocked").map(n=>n.title),...u.filter(n=>n.status==="blocked").map(n=>n.title)],20),A={version:1,projectId:r.id,projectName:r.name,goal:a,plan:c,phases:m,tasks:u,decisions:g(p,20),blockers:se,warnings:g(I,20),nextActions:oe,filesTouched:g(E,30),tests:g(C,20),currentPhase:P,currentTask:S,progress:{phasesTotal:m.length,phasesCompleted:m.filter(n=>n.status==="completed").length,tasksTotal:u.length,tasksCompleted:u.filter(n=>n.status==="completed").length,blocked:m.filter(n=>n.status==="blocked").length+u.filter(n=>n.status==="blocked").length},lastSession:d,updatedAt:o.length?o[o.length-1].occurredAt:new Date().toISOString()},_=q(r.rootPath,".toolnet","work");return Ge(_,{recursive:!0}),Q(q(_,"current.json"),A),await e.put(`projects/${r.id}/work/current.json`,JSON.stringify(A,null,2)+`
|
|
6
|
+
`,"application/json"),A}async function M(r,e){let t=await e.getText(`projects/${r.id}/work/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}function Xe(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function Qe(r){let e=z(),t=U(H({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new b(t,r.id,r.name,r.remote??r.name)}function re(r){console.log(),console.log(`Project: ${r.projectName}`),r.goal&&console.log(`Goal: ${r.goal}`),r.currentPhase&&console.log(`Current phase: ${r.currentPhase.title} [${r.currentPhase.status}]`),r.currentTask&&console.log(`Current task: ${r.currentTask.title} [${r.currentTask.status}]`),console.log(`Phases: ${r.progress.phasesCompleted}/${r.progress.phasesTotal}`),console.log(`Tasks: ${r.progress.tasksCompleted}/${r.progress.tasksTotal}`),r.nextActions.length&&(console.log(),console.log("Next actions:"),r.nextActions.forEach((e,t)=>console.log(`${t+1}. ${e}`))),r.blockers.length&&(console.log(),console.log("Blockers:"),r.blockers.forEach(e=>console.log(`- ${e}`))),r.lastSession&&(console.log(),console.log(`Last session: ${r.lastSession.agent} / ${r.lastSession.nativeSessionId}`))}async function qe(){let[r="help",...e]=process.argv.slice(2),t=new x().detect(Xe(e,"--project")??process.cwd()),o=Qe(t);if(r==="reconcile"){let s=await te(t,o);re(s);return}if(r==="status"){let s=await M(t,o);if(!s){console.log("No active work state yet.");return}re(s);return}if(r==="json"){let s=await M(t,o);console.log(JSON.stringify(s,null,2));return}console.log(`Work Continuity
|
|
7
|
+
|
|
8
|
+
Commands:
|
|
9
|
+
status [--project PATH]
|
|
10
|
+
json [--project PATH]
|
|
11
|
+
reconcile [--project PATH]
|
|
12
|
+
`)}qe().catch(r=>{console.error(r instanceof Error?r.message:r),process.exit(1)});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolnet-memory",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "tsx src/index.ts",
|
|
@@ -41,7 +41,9 @@
|
|
|
41
41
|
"work-continuity:test": "vitest run tests/work-continuity/work-continuity.test.ts",
|
|
42
42
|
"work-handoff:test": "vitest run tests/work-continuity/handoff-brief.test.ts",
|
|
43
43
|
"semantic-work:test": "vitest run tests/work-continuity/semantic-context.test.ts",
|
|
44
|
-
"context-injection:test": "vitest run tests/work-continuity/context-injection.test.ts"
|
|
44
|
+
"context-injection:test": "vitest run tests/work-continuity/context-injection.test.ts",
|
|
45
|
+
"build:bundle": "npm run build && node scripts/build-bundle.mjs",
|
|
46
|
+
"build:release": "npm run build:prod && node scripts/build-bundle.mjs"
|
|
45
47
|
},
|
|
46
48
|
"dependencies": {
|
|
47
49
|
"@aws-sdk/client-s3": "^3.1102.0",
|
|
@@ -52,17 +54,18 @@
|
|
|
52
54
|
},
|
|
53
55
|
"devDependencies": {
|
|
54
56
|
"@types/node": "^24.0.0",
|
|
57
|
+
"3d-force-graph": "^1.80.0",
|
|
58
|
+
"esbuild": "^0.28.1",
|
|
55
59
|
"tsx": "^4.20.0",
|
|
56
60
|
"typescript": "^5.9.0",
|
|
57
|
-
"vitest": "^3.2.0"
|
|
58
|
-
"3d-force-graph": "^1.80.0"
|
|
61
|
+
"vitest": "^3.2.0"
|
|
59
62
|
},
|
|
60
63
|
"bin": {
|
|
61
64
|
"toolnet-memory": "bin/toolnet-memory"
|
|
62
65
|
},
|
|
63
66
|
"files": [
|
|
64
|
-
"
|
|
65
|
-
"bin",
|
|
67
|
+
"bundle",
|
|
68
|
+
"bin/toolnet-memory",
|
|
66
69
|
"README.md",
|
|
67
70
|
".env.example"
|
|
68
71
|
],
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
export class ToolNetMemoryClient {
|
|
2
|
-
runtime;
|
|
3
|
-
autoRetrieval;
|
|
4
|
-
autoImpactGuard;
|
|
5
|
-
constructor(runtime, autoRetrieval, autoImpactGuard) {
|
|
6
|
-
this.runtime = runtime;
|
|
7
|
-
this.autoRetrieval = autoRetrieval;
|
|
8
|
-
this.autoImpactGuard = autoImpactGuard;
|
|
9
|
-
}
|
|
10
|
-
sessionStart() {
|
|
11
|
-
return this.runtime
|
|
12
|
-
.sessionStart();
|
|
13
|
-
}
|
|
14
|
-
sessionEnd() {
|
|
15
|
-
return this.runtime
|
|
16
|
-
.sessionEnd();
|
|
17
|
-
}
|
|
18
|
-
prompt(content) {
|
|
19
|
-
return this.runtime
|
|
20
|
-
.userPrompt(content);
|
|
21
|
-
}
|
|
22
|
-
preparePrompt(content) {
|
|
23
|
-
if (!this.autoRetrieval) {
|
|
24
|
-
return Promise.resolve({
|
|
25
|
-
originalPrompt: content,
|
|
26
|
-
context: "",
|
|
27
|
-
augmentedPrompt: content,
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
return this.autoRetrieval
|
|
31
|
-
.prepare(content);
|
|
32
|
-
}
|
|
33
|
-
/*
|
|
34
|
-
* Đây là hook ToolNet Agent cần gọi
|
|
35
|
-
* TRƯỚC tool executor.
|
|
36
|
-
*/
|
|
37
|
-
async beforeTool(tool, input) {
|
|
38
|
-
const impact = this.autoImpactGuard
|
|
39
|
-
? await this.autoImpactGuard
|
|
40
|
-
.beforeTool(tool, input)
|
|
41
|
-
: null;
|
|
42
|
-
await this.runtime
|
|
43
|
-
.beforeTool(tool, input);
|
|
44
|
-
return impact;
|
|
45
|
-
}
|
|
46
|
-
afterTool(tool, output) {
|
|
47
|
-
return this.runtime
|
|
48
|
-
.afterTool(tool, output);
|
|
49
|
-
}
|
|
50
|
-
fileRead(filePath) {
|
|
51
|
-
return this.runtime
|
|
52
|
-
.fileRead(filePath);
|
|
53
|
-
}
|
|
54
|
-
fileWrite(filePath) {
|
|
55
|
-
return this.runtime
|
|
56
|
-
.fileWrite(filePath);
|
|
57
|
-
}
|
|
58
|
-
command(command, exitCode) {
|
|
59
|
-
return this.runtime
|
|
60
|
-
.command(command, exitCode);
|
|
61
|
-
}
|
|
62
|
-
error(error) {
|
|
63
|
-
return this.runtime
|
|
64
|
-
.error(error);
|
|
65
|
-
}
|
|
66
|
-
decision(content) {
|
|
67
|
-
return this.runtime
|
|
68
|
-
.decision(content);
|
|
69
|
-
}
|
|
70
|
-
todo(content) {
|
|
71
|
-
return this.runtime
|
|
72
|
-
.todo(content);
|
|
73
|
-
}
|
|
74
|
-
flush() {
|
|
75
|
-
return this.runtime
|
|
76
|
-
.flush();
|
|
77
|
-
}
|
|
78
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./client.js";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/src/api/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/src/api/server.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { randomUUID, } from "node:crypto";
|
|
2
|
-
import { Sanitizer } from "../security/sanitizer.js";
|
|
3
|
-
export class ActivityCapture {
|
|
4
|
-
queue;
|
|
5
|
-
sanitizer = new Sanitizer();
|
|
6
|
-
constructor(queue) {
|
|
7
|
-
this.queue = queue;
|
|
8
|
-
}
|
|
9
|
-
capture(projectId, type, data = {}) {
|
|
10
|
-
const event = {
|
|
11
|
-
id: randomUUID(),
|
|
12
|
-
projectId,
|
|
13
|
-
type,
|
|
14
|
-
timestamp: new Date().toISOString(),
|
|
15
|
-
data: this.sanitizer
|
|
16
|
-
.sanitizeValue(data),
|
|
17
|
-
};
|
|
18
|
-
this.queue.push(event);
|
|
19
|
-
return event;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export class ErrorCapture {
|
|
2
|
-
capture;
|
|
3
|
-
constructor(capture) {
|
|
4
|
-
this.capture = capture;
|
|
5
|
-
}
|
|
6
|
-
record(projectId, error) {
|
|
7
|
-
const message = error instanceof Error
|
|
8
|
-
? error.message
|
|
9
|
-
: String(error);
|
|
10
|
-
return this.capture.capture(projectId, "error", {
|
|
11
|
-
message,
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
export class EventDeduplicator {
|
|
3
|
-
seen = new Set();
|
|
4
|
-
fingerprint(event) {
|
|
5
|
-
return createHash("sha256")
|
|
6
|
-
.update(JSON.stringify({
|
|
7
|
-
projectId: event.projectId,
|
|
8
|
-
type: event.type,
|
|
9
|
-
data: event.data,
|
|
10
|
-
}))
|
|
11
|
-
.digest("hex");
|
|
12
|
-
}
|
|
13
|
-
filter(events) {
|
|
14
|
-
const result = [];
|
|
15
|
-
for (const event of events) {
|
|
16
|
-
const hash = this.fingerprint(event);
|
|
17
|
-
if (this.seen.has(hash)) {
|
|
18
|
-
continue;
|
|
19
|
-
}
|
|
20
|
-
this.seen.add(hash);
|
|
21
|
-
result.push(event);
|
|
22
|
-
}
|
|
23
|
-
return result;
|
|
24
|
-
}
|
|
25
|
-
clear() {
|
|
26
|
-
this.seen.clear();
|
|
27
|
-
}
|
|
28
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export class EventQueue {
|
|
2
|
-
events = [];
|
|
3
|
-
push(event) {
|
|
4
|
-
this.events.push(event);
|
|
5
|
-
}
|
|
6
|
-
drain() {
|
|
7
|
-
const items = [...this.events];
|
|
8
|
-
this.events.length = 0;
|
|
9
|
-
return items;
|
|
10
|
-
}
|
|
11
|
-
list() {
|
|
12
|
-
return [...this.events];
|
|
13
|
-
}
|
|
14
|
-
size() {
|
|
15
|
-
return this.events.length;
|
|
16
|
-
}
|
|
17
|
-
shouldFlush(maxEvents) {
|
|
18
|
-
return this.events.length >= maxEvents;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { isSensitiveFile, } from "../security/file-filter.js";
|
|
2
|
-
export class FileCapture {
|
|
3
|
-
capture;
|
|
4
|
-
constructor(capture) {
|
|
5
|
-
this.capture = capture;
|
|
6
|
-
}
|
|
7
|
-
read(projectId, filePath) {
|
|
8
|
-
if (isSensitiveFile(filePath)) {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
return this.capture.capture(projectId, "file_read", {
|
|
12
|
-
filePath,
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
write(projectId, filePath) {
|
|
16
|
-
if (isSensitiveFile(filePath)) {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
return this.capture.capture(projectId, "file_write", {
|
|
20
|
-
filePath,
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export * from "./event-queue.js";
|
|
2
|
-
export * from "./event-deduplicator.js";
|
|
3
|
-
export * from "./activity-capture.js";
|
|
4
|
-
export * from "./session-capture.js";
|
|
5
|
-
export * from "./tool-capture.js";
|
|
6
|
-
export * from "./file-capture.js";
|
|
7
|
-
export * from "./command-capture.js";
|
|
8
|
-
export * from "./error-capture.js";
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { randomUUID, } from "node:crypto";
|
|
2
|
-
export class SessionCapture {
|
|
3
|
-
capture;
|
|
4
|
-
sessionId = randomUUID();
|
|
5
|
-
constructor(capture) {
|
|
6
|
-
this.capture = capture;
|
|
7
|
-
}
|
|
8
|
-
start(projectId) {
|
|
9
|
-
return this.capture.capture(projectId, "session_start", {
|
|
10
|
-
sessionId: this.sessionId,
|
|
11
|
-
});
|
|
12
|
-
}
|
|
13
|
-
end(projectId) {
|
|
14
|
-
return this.capture.capture(projectId, "session_end", {
|
|
15
|
-
sessionId: this.sessionId,
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { DeadCodeAnalyzer, } from "./dead-code-analyzer.js";
|
|
2
|
-
import { DependencyAnalyzer, } from "./dependency-analyzer.js";
|
|
3
|
-
export class CodeAnalysisEngine {
|
|
4
|
-
graph;
|
|
5
|
-
constructor(graph) {
|
|
6
|
-
this.graph = graph;
|
|
7
|
-
}
|
|
8
|
-
analyze(projectId) {
|
|
9
|
-
const deadCode = new DeadCodeAnalyzer(this.graph).analyze(projectId);
|
|
10
|
-
const dependencies = new DependencyAnalyzer(this.graph).analyze(projectId);
|
|
11
|
-
return {
|
|
12
|
-
version: 1,
|
|
13
|
-
projectId,
|
|
14
|
-
updatedAt: new Date()
|
|
15
|
-
.toISOString(),
|
|
16
|
-
summary: {
|
|
17
|
-
deadCodeCandidates: deadCode.length,
|
|
18
|
-
highConfidenceDeadCode: deadCode.filter((item) => item.confidence ===
|
|
19
|
-
"high").length,
|
|
20
|
-
files: dependencies.length,
|
|
21
|
-
},
|
|
22
|
-
deadCode,
|
|
23
|
-
dependencies,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
}
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { EntryPointDetector, } from "../architecture/entry-points.js";
|
|
2
|
-
const USAGE_EDGES = new Set([
|
|
3
|
-
"CALLS",
|
|
4
|
-
"CALL_REFERENCE",
|
|
5
|
-
"IMPORTS",
|
|
6
|
-
"USES_TYPE",
|
|
7
|
-
"WRITES",
|
|
8
|
-
"INHERITS",
|
|
9
|
-
"IMPLEMENTS",
|
|
10
|
-
"ROUTE",
|
|
11
|
-
"TESTS",
|
|
12
|
-
]);
|
|
13
|
-
function normalize(value) {
|
|
14
|
-
return value
|
|
15
|
-
.replaceAll("\\", "/")
|
|
16
|
-
.toLowerCase();
|
|
17
|
-
}
|
|
18
|
-
function isTestFile(filePath) {
|
|
19
|
-
const path = normalize(filePath);
|
|
20
|
-
return (path.startsWith("tests/") ||
|
|
21
|
-
path.includes("/tests/") ||
|
|
22
|
-
path.includes("__tests__") ||
|
|
23
|
-
/\.(test|spec)\.[^.]+$/
|
|
24
|
-
.test(path));
|
|
25
|
-
}
|
|
26
|
-
function looksPublicApi(symbol) {
|
|
27
|
-
const path = normalize(symbol.filePath);
|
|
28
|
-
return (path.startsWith("bin/") ||
|
|
29
|
-
/(^|\/)index\.[^.]+$/
|
|
30
|
-
.test(path) ||
|
|
31
|
-
/(^|\/)(main|server|cli)\.[^.]+$/
|
|
32
|
-
.test(path));
|
|
33
|
-
}
|
|
34
|
-
export class DeadCodeAnalyzer {
|
|
35
|
-
graph;
|
|
36
|
-
constructor(graph) {
|
|
37
|
-
this.graph = graph;
|
|
38
|
-
}
|
|
39
|
-
analyze(projectId) {
|
|
40
|
-
const symbols = this.graph.allSymbols(projectId);
|
|
41
|
-
const edges = this.graph.allEdges(projectId);
|
|
42
|
-
const entrySymbols = new Set(new EntryPointDetector(this.graph)
|
|
43
|
-
.detect(projectId)
|
|
44
|
-
.map((entry) => entry.symbolId));
|
|
45
|
-
const candidates = [];
|
|
46
|
-
for (const symbol of symbols) {
|
|
47
|
-
if (![
|
|
48
|
-
"function",
|
|
49
|
-
"method",
|
|
50
|
-
"class",
|
|
51
|
-
"interface",
|
|
52
|
-
"property",
|
|
53
|
-
].includes(symbol.type)) {
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
if (isTestFile(symbol.filePath) ||
|
|
57
|
-
entrySymbols.has(symbol.id) ||
|
|
58
|
-
looksPublicApi(symbol)) {
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
const incoming = edges.filter((edge) => edge.to ===
|
|
62
|
-
symbol.id &&
|
|
63
|
-
USAGE_EDGES.has(edge.type));
|
|
64
|
-
if (incoming.length >
|
|
65
|
-
0) {
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
const outgoing = edges.filter((edge) => edge.from ===
|
|
69
|
-
symbol.id &&
|
|
70
|
-
USAGE_EDGES.has(edge.type));
|
|
71
|
-
const reasons = [
|
|
72
|
-
"no incoming usage edge",
|
|
73
|
-
];
|
|
74
|
-
let score = 50;
|
|
75
|
-
if (symbol.type ===
|
|
76
|
-
"function" ||
|
|
77
|
-
symbol.type ===
|
|
78
|
-
"method") {
|
|
79
|
-
score +=
|
|
80
|
-
20;
|
|
81
|
-
reasons.push("callable symbol");
|
|
82
|
-
}
|
|
83
|
-
if (symbol.type ===
|
|
84
|
-
"property") {
|
|
85
|
-
score -=
|
|
86
|
-
15;
|
|
87
|
-
}
|
|
88
|
-
if (outgoing.length ===
|
|
89
|
-
0) {
|
|
90
|
-
score +=
|
|
91
|
-
10;
|
|
92
|
-
reasons.push("no outgoing dependency");
|
|
93
|
-
}
|
|
94
|
-
const path = normalize(symbol.filePath);
|
|
95
|
-
if (path.includes("/internal/")) {
|
|
96
|
-
score +=
|
|
97
|
-
10;
|
|
98
|
-
reasons.push("internal implementation");
|
|
99
|
-
}
|
|
100
|
-
if (symbol.name
|
|
101
|
-
.startsWith("_")) {
|
|
102
|
-
score +=
|
|
103
|
-
5;
|
|
104
|
-
}
|
|
105
|
-
const confidence = score >= 75
|
|
106
|
-
? "high"
|
|
107
|
-
: score >= 55
|
|
108
|
-
? "medium"
|
|
109
|
-
: "low";
|
|
110
|
-
candidates.push({
|
|
111
|
-
symbolId: symbol.id,
|
|
112
|
-
name: symbol.name,
|
|
113
|
-
qualifiedName: symbol.qualifiedName,
|
|
114
|
-
type: symbol.type,
|
|
115
|
-
filePath: symbol.filePath,
|
|
116
|
-
startLine: symbol.startLine,
|
|
117
|
-
confidence,
|
|
118
|
-
score,
|
|
119
|
-
reasons,
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
return candidates.sort((a, b) => b.score -
|
|
123
|
-
a.score ||
|
|
124
|
-
a.filePath.localeCompare(b.filePath) ||
|
|
125
|
-
a.name.localeCompare(b.name));
|
|
126
|
-
}
|
|
127
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
const EDGE_TYPES = new Set([
|
|
2
|
-
"CALLS",
|
|
3
|
-
"CALL_REFERENCE",
|
|
4
|
-
"IMPORTS",
|
|
5
|
-
"USES_TYPE",
|
|
6
|
-
"WRITES",
|
|
7
|
-
"INHERITS",
|
|
8
|
-
"IMPLEMENTS",
|
|
9
|
-
"ROUTE",
|
|
10
|
-
]);
|
|
11
|
-
export class DependencyAnalyzer {
|
|
12
|
-
graph;
|
|
13
|
-
constructor(graph) {
|
|
14
|
-
this.graph = graph;
|
|
15
|
-
}
|
|
16
|
-
analyze(projectId) {
|
|
17
|
-
const symbols = this.graph.allSymbols(projectId);
|
|
18
|
-
const edges = this.graph
|
|
19
|
-
.allEdges(projectId)
|
|
20
|
-
.filter((edge) => EDGE_TYPES.has(edge.type));
|
|
21
|
-
const symbolById = new Map(symbols.map((symbol) => [
|
|
22
|
-
symbol.id,
|
|
23
|
-
symbol,
|
|
24
|
-
]));
|
|
25
|
-
const files = [
|
|
26
|
-
...new Set(symbols.map((symbol) => symbol.filePath)),
|
|
27
|
-
].sort();
|
|
28
|
-
return files.map((filePath) => {
|
|
29
|
-
const dependencies = new Set();
|
|
30
|
-
const dependents = new Set();
|
|
31
|
-
let outgoingEdges = 0;
|
|
32
|
-
let incomingEdges = 0;
|
|
33
|
-
for (const edge of edges) {
|
|
34
|
-
const from = symbolById.get(edge.from);
|
|
35
|
-
const to = symbolById.get(edge.to);
|
|
36
|
-
if (!from ||
|
|
37
|
-
!to ||
|
|
38
|
-
from.filePath ===
|
|
39
|
-
to.filePath) {
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
if (from.filePath ===
|
|
43
|
-
filePath) {
|
|
44
|
-
dependencies.add(to.filePath);
|
|
45
|
-
outgoingEdges++;
|
|
46
|
-
}
|
|
47
|
-
if (to.filePath ===
|
|
48
|
-
filePath) {
|
|
49
|
-
dependents.add(from.filePath);
|
|
50
|
-
incomingEdges++;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return {
|
|
54
|
-
filePath,
|
|
55
|
-
dependencies: [
|
|
56
|
-
...dependencies,
|
|
57
|
-
].sort(),
|
|
58
|
-
dependents: [
|
|
59
|
-
...dependents,
|
|
60
|
-
].sort(),
|
|
61
|
-
outgoingEdges,
|
|
62
|
-
incomingEdges,
|
|
63
|
-
};
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { ClusterDetector, } from "./clusters.js";
|
|
2
|
-
import { EntryPointDetector, } from "./entry-points.js";
|
|
3
|
-
import { HotspotAnalyzer, } from "./hotspots.js";
|
|
4
|
-
import { LayerDetector, } from "./layers.js";
|
|
5
|
-
export class ArchitectureEngine {
|
|
6
|
-
graph;
|
|
7
|
-
entryPoints;
|
|
8
|
-
hotspots;
|
|
9
|
-
layers;
|
|
10
|
-
clusters;
|
|
11
|
-
constructor(graph) {
|
|
12
|
-
this.graph = graph;
|
|
13
|
-
this.entryPoints =
|
|
14
|
-
new EntryPointDetector(graph);
|
|
15
|
-
this.hotspots =
|
|
16
|
-
new HotspotAnalyzer(graph);
|
|
17
|
-
this.layers =
|
|
18
|
-
new LayerDetector(graph);
|
|
19
|
-
this.clusters =
|
|
20
|
-
new ClusterDetector(graph);
|
|
21
|
-
}
|
|
22
|
-
analyze(projectId) {
|
|
23
|
-
const entryPoints = this.entryPoints.detect(projectId);
|
|
24
|
-
const hotspots = this.hotspots.analyze(projectId);
|
|
25
|
-
const layers = this.layers.detect(projectId);
|
|
26
|
-
const clusters = this.clusters.detect(projectId);
|
|
27
|
-
const files = new Set(this.graph
|
|
28
|
-
.allSymbols(projectId)
|
|
29
|
-
.map((symbol) => symbol.filePath));
|
|
30
|
-
return {
|
|
31
|
-
version: 1,
|
|
32
|
-
projectId,
|
|
33
|
-
updatedAt: new Date()
|
|
34
|
-
.toISOString(),
|
|
35
|
-
summary: {
|
|
36
|
-
files: files.size,
|
|
37
|
-
entryPoints: entryPoints.length,
|
|
38
|
-
hotspots: hotspots.length,
|
|
39
|
-
layers: layers.length,
|
|
40
|
-
clusters: clusters.length,
|
|
41
|
-
},
|
|
42
|
-
entryPoints,
|
|
43
|
-
hotspots,
|
|
44
|
-
layers,
|
|
45
|
-
clusters,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
}
|