toolnet-memory 0.2.0 → 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 +443 -70
- package/bin/toolnet-memory +66 -53
- 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 +11 -5
- 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/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
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { loadConfig, ProjectManager, } from "../../core/index.js";
|
|
2
|
-
import { createStorageProvider, ProjectScopedStorageProvider, withStorageRetry, } from "../../storage/index.js";
|
|
3
|
-
import { recoverOpenCodeProject, syncOpenCodeSession, } from "./adapter.js";
|
|
4
|
-
import { installOpenCodePlugin, } from "./plugin-installer.js";
|
|
5
|
-
import { refreshStartupBriefCache, } from "../../work-continuity/brief-cache.js";
|
|
6
|
-
function valueAfter(args, flag) {
|
|
7
|
-
const index = args.indexOf(flag);
|
|
8
|
-
if (index < 0) {
|
|
9
|
-
return undefined;
|
|
10
|
-
}
|
|
11
|
-
return args[index + 1];
|
|
12
|
-
}
|
|
13
|
-
function has(args, flag) {
|
|
14
|
-
return args.includes(flag);
|
|
15
|
-
}
|
|
16
|
-
function storageFor(project) {
|
|
17
|
-
const config = loadConfig();
|
|
18
|
-
const raw = withStorageRetry(createStorageProvider({
|
|
19
|
-
provider: config.storage.provider,
|
|
20
|
-
huggingface: config.storage
|
|
21
|
-
.huggingface,
|
|
22
|
-
localRoot: config.storage
|
|
23
|
-
.localRoot,
|
|
24
|
-
}), {
|
|
25
|
-
attempts: 3,
|
|
26
|
-
});
|
|
27
|
-
return new ProjectScopedStorageProvider(raw, project.id, project.name, project.remote ??
|
|
28
|
-
project.name);
|
|
29
|
-
}
|
|
30
|
-
async function main() {
|
|
31
|
-
const [command = "help", ...args] = process.argv.slice(2);
|
|
32
|
-
if (command ===
|
|
33
|
-
"install-plugin") {
|
|
34
|
-
const target = installOpenCodePlugin({
|
|
35
|
-
binary: valueAfter(args, "--bin"),
|
|
36
|
-
});
|
|
37
|
-
console.log(`✅ OpenCode plugin installed: ${target}`);
|
|
38
|
-
console.log("OpenCode will load it automatically on next start.");
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const projectPath = valueAfter(args, "--project") ??
|
|
42
|
-
process.cwd();
|
|
43
|
-
const project = new ProjectManager()
|
|
44
|
-
.detect(projectPath);
|
|
45
|
-
const storage = storageFor(project);
|
|
46
|
-
const dbPath = valueAfter(args, "--db");
|
|
47
|
-
if (command ===
|
|
48
|
-
"sync") {
|
|
49
|
-
const nativeSessionId = args.find(value => !value.startsWith("--") &&
|
|
50
|
-
value !==
|
|
51
|
-
projectPath &&
|
|
52
|
-
value !==
|
|
53
|
-
dbPath);
|
|
54
|
-
if (!nativeSessionId) {
|
|
55
|
-
throw new Error("Usage: session:opencode-sync <session-id>");
|
|
56
|
-
}
|
|
57
|
-
const idle = has(args, "--idle");
|
|
58
|
-
const error = has(args, "--error");
|
|
59
|
-
const compacted = has(args, "--compacted");
|
|
60
|
-
const result = await syncOpenCodeSession({
|
|
61
|
-
project,
|
|
62
|
-
storage,
|
|
63
|
-
nativeSessionId,
|
|
64
|
-
dbPath,
|
|
65
|
-
idle,
|
|
66
|
-
error,
|
|
67
|
-
compacted,
|
|
68
|
-
});
|
|
69
|
-
if (idle ||
|
|
70
|
-
compacted ||
|
|
71
|
-
error) {
|
|
72
|
-
try {
|
|
73
|
-
await refreshStartupBriefCache(project, storage, 900);
|
|
74
|
-
}
|
|
75
|
-
catch {
|
|
76
|
-
// Derived cache must never break session capture.
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
console.log(JSON.stringify(result, null, 2));
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
if (command ===
|
|
83
|
-
"recover") {
|
|
84
|
-
const limitValue = valueAfter(args, "--limit");
|
|
85
|
-
const limit = limitValue
|
|
86
|
-
? Number(limitValue)
|
|
87
|
-
: 100;
|
|
88
|
-
const results = await recoverOpenCodeProject({
|
|
89
|
-
project,
|
|
90
|
-
storage,
|
|
91
|
-
dbPath,
|
|
92
|
-
limit: Number.isFinite(limit)
|
|
93
|
-
? limit
|
|
94
|
-
: 100,
|
|
95
|
-
});
|
|
96
|
-
console.log(JSON.stringify({
|
|
97
|
-
project: project.name,
|
|
98
|
-
sessions: results.length,
|
|
99
|
-
importedMessages: results.reduce((total, item) => total +
|
|
100
|
-
item
|
|
101
|
-
.importedMessages, 0),
|
|
102
|
-
importedParts: results.reduce((total, item) => total +
|
|
103
|
-
item
|
|
104
|
-
.importedParts, 0),
|
|
105
|
-
}, null, 2));
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
console.log(`OpenCode Session Adapter
|
|
109
|
-
|
|
110
|
-
Commands:
|
|
111
|
-
sync <session-id> [--project PATH] [--idle]
|
|
112
|
-
recover [--project PATH] [--limit N]
|
|
113
|
-
install-plugin [--bin PATH]
|
|
114
|
-
`);
|
|
115
|
-
}
|
|
116
|
-
main().catch(error => {
|
|
117
|
-
console.error(error instanceof Error
|
|
118
|
-
? error.message
|
|
119
|
-
: error);
|
|
120
|
-
process.exit(1);
|
|
121
|
-
});
|
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync, } from "node:fs";
|
|
2
|
-
import { homedir, } from "node:os";
|
|
3
|
-
import { join, } from "node:path";
|
|
4
|
-
const START = "<!-- TOOLNET_MEMORY_BOOTSTRAP_START -->";
|
|
5
|
-
const END = "<!-- TOOLNET_MEMORY_BOOTSTRAP_END -->";
|
|
6
|
-
function installBootstrapInstructions() {
|
|
7
|
-
const file = join(homedir(), ".config", "opencode", "AGENTS.md");
|
|
8
|
-
mkdirSync(join(homedir(), ".config", "opencode"), {
|
|
9
|
-
recursive: true,
|
|
10
|
-
});
|
|
11
|
-
const block = `${START}
|
|
12
|
-
## ToolNet Memory — Project Continuity
|
|
13
|
-
|
|
14
|
-
When the current workspace belongs to a ToolNet project, identified by a nearest ancestor containing \`.toolnet/project.json\`:
|
|
15
|
-
|
|
16
|
-
1. Before planning, editing, or running implementation commands, read that project root's \`.toolnet/context/startup.md\`.
|
|
17
|
-
2. Treat its PROJECT RULES, MISSION, CURRENT OBJECTIVE, rationale, current phase/task, Definition of Done, blockers and next actions as project continuity context.
|
|
18
|
-
3. Do not restart work already marked completed unless repository evidence proves it must be revisited.
|
|
19
|
-
4. Verify current repository state before continuing old work.
|
|
20
|
-
5. If \`.toolnet/context/startup.md\` is missing, run \`toolnet-memory context:sync --project <project-root>\`, then read it.
|
|
21
|
-
6. Never invent missing rationale. If ToolNet says a reason was not explicitly recorded, inspect the implementation or ask rather than guessing.
|
|
22
|
-
|
|
23
|
-
This applies automatically to every ToolNet-managed project.
|
|
24
|
-
${END}`;
|
|
25
|
-
let content = existsSync(file)
|
|
26
|
-
? readFileSync(file, "utf8")
|
|
27
|
-
: "";
|
|
28
|
-
const start = content.indexOf(START);
|
|
29
|
-
const end = content.indexOf(END);
|
|
30
|
-
if (start >= 0 &&
|
|
31
|
-
end >= start) {
|
|
32
|
-
content =
|
|
33
|
-
content.slice(0, start) +
|
|
34
|
-
block +
|
|
35
|
-
content.slice(end +
|
|
36
|
-
END.length);
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
content =
|
|
40
|
-
content.trimEnd();
|
|
41
|
-
if (content) {
|
|
42
|
-
content +=
|
|
43
|
-
"\n\n";
|
|
44
|
-
}
|
|
45
|
-
content +=
|
|
46
|
-
block;
|
|
47
|
-
}
|
|
48
|
-
writeFileSync(file, content.trimEnd() +
|
|
49
|
-
"\n", {
|
|
50
|
-
encoding: "utf8",
|
|
51
|
-
mode: 0o600,
|
|
52
|
-
});
|
|
53
|
-
return file;
|
|
54
|
-
}
|
|
55
|
-
export function installOpenCodePlugin(options = {}) {
|
|
56
|
-
const directory = options.directory ??
|
|
57
|
-
join(homedir(), ".config", "opencode", "plugins");
|
|
58
|
-
mkdirSync(directory, {
|
|
59
|
-
recursive: true,
|
|
60
|
-
});
|
|
61
|
-
installBootstrapInstructions();
|
|
62
|
-
const target = join(directory, "toolnet-memory.js");
|
|
63
|
-
const binary = options.binary ??
|
|
64
|
-
process.env
|
|
65
|
-
.TOOLNET_MEMORY_BIN ??
|
|
66
|
-
"toolnet-memory";
|
|
67
|
-
const content = `// Generated by ToolNet Memory.
|
|
68
|
-
// OpenCode session capture + continuity bootstrap.
|
|
69
|
-
|
|
70
|
-
function getSessionId(event) {
|
|
71
|
-
const p = event?.properties ?? {}
|
|
72
|
-
|
|
73
|
-
const candidates = [
|
|
74
|
-
p.sessionID,
|
|
75
|
-
p.sessionId,
|
|
76
|
-
p.info?.id,
|
|
77
|
-
p.session?.id,
|
|
78
|
-
]
|
|
79
|
-
|
|
80
|
-
return candidates.find(
|
|
81
|
-
value => typeof value === "string" && value.length > 0
|
|
82
|
-
) ?? null
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export const ToolNetMemoryPlugin = async ({ directory }) => {
|
|
86
|
-
const binary = ${JSON.stringify(binary)}
|
|
87
|
-
|
|
88
|
-
async function refreshContext() {
|
|
89
|
-
try {
|
|
90
|
-
const child = Bun.spawn(
|
|
91
|
-
[
|
|
92
|
-
binary,
|
|
93
|
-
"context:sync",
|
|
94
|
-
"--project",
|
|
95
|
-
directory,
|
|
96
|
-
],
|
|
97
|
-
{
|
|
98
|
-
stdin: "ignore",
|
|
99
|
-
stdout: "ignore",
|
|
100
|
-
stderr: "ignore",
|
|
101
|
-
}
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
await child.exited
|
|
105
|
-
} catch {
|
|
106
|
-
// Context sync must never break OpenCode startup.
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async function readContext() {
|
|
111
|
-
try {
|
|
112
|
-
const child = Bun.spawn(
|
|
113
|
-
[
|
|
114
|
-
binary,
|
|
115
|
-
"context:print",
|
|
116
|
-
"--project",
|
|
117
|
-
directory,
|
|
118
|
-
"--tokens",
|
|
119
|
-
"900",
|
|
120
|
-
],
|
|
121
|
-
{
|
|
122
|
-
stdin: "ignore",
|
|
123
|
-
stdout: "pipe",
|
|
124
|
-
stderr: "ignore",
|
|
125
|
-
}
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
const text =
|
|
129
|
-
await new Response(
|
|
130
|
-
child.stdout
|
|
131
|
-
).text()
|
|
132
|
-
|
|
133
|
-
await child.exited
|
|
134
|
-
|
|
135
|
-
return text.trim()
|
|
136
|
-
} catch {
|
|
137
|
-
return ""
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function sync(sessionId, flag) {
|
|
142
|
-
if (!sessionId) return
|
|
143
|
-
|
|
144
|
-
try {
|
|
145
|
-
const args = [
|
|
146
|
-
binary,
|
|
147
|
-
"session:opencode-sync",
|
|
148
|
-
sessionId,
|
|
149
|
-
"--project",
|
|
150
|
-
directory,
|
|
151
|
-
]
|
|
152
|
-
|
|
153
|
-
if (flag) {
|
|
154
|
-
args.push(flag)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const child = Bun.spawn(args, {
|
|
158
|
-
stdin: "ignore",
|
|
159
|
-
stdout: "ignore",
|
|
160
|
-
stderr: "ignore",
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
if (
|
|
164
|
-
typeof child.unref === "function"
|
|
165
|
-
) {
|
|
166
|
-
child.unref()
|
|
167
|
-
}
|
|
168
|
-
} catch {
|
|
169
|
-
// Memory capture must never break OpenCode.
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/*
|
|
174
|
-
* Pull the latest project brief from ToolNet remote storage
|
|
175
|
-
* before the new OpenCode session starts doing work.
|
|
176
|
-
*/
|
|
177
|
-
await refreshContext()
|
|
178
|
-
|
|
179
|
-
return {
|
|
180
|
-
event: async ({ event }) => {
|
|
181
|
-
const sessionId =
|
|
182
|
-
getSessionId(event)
|
|
183
|
-
|
|
184
|
-
if (!sessionId) {
|
|
185
|
-
return
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (event.type === "session.idle") {
|
|
189
|
-
sync(sessionId, "--idle")
|
|
190
|
-
return
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (event.type === "session.compacted") {
|
|
194
|
-
sync(sessionId, "--compacted")
|
|
195
|
-
return
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (event.type === "session.error") {
|
|
199
|
-
sync(sessionId, "--error")
|
|
200
|
-
}
|
|
201
|
-
},
|
|
202
|
-
|
|
203
|
-
/*
|
|
204
|
-
* Official OpenCode compaction hook.
|
|
205
|
-
* Preserve ToolNet's semantic state after context compaction.
|
|
206
|
-
*/
|
|
207
|
-
"experimental.session.compacting": async (_input, output) => {
|
|
208
|
-
const context =
|
|
209
|
-
await readContext()
|
|
210
|
-
|
|
211
|
-
if (
|
|
212
|
-
context &&
|
|
213
|
-
Array.isArray(
|
|
214
|
-
output.context
|
|
215
|
-
)
|
|
216
|
-
) {
|
|
217
|
-
output.context.push(
|
|
218
|
-
context
|
|
219
|
-
)
|
|
220
|
-
}
|
|
221
|
-
},
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
`;
|
|
225
|
-
writeFileSync(target, content, {
|
|
226
|
-
encoding: "utf8",
|
|
227
|
-
mode: 0o600,
|
|
228
|
-
});
|
|
229
|
-
return target;
|
|
230
|
-
}
|
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
import { sha256, } from "./utils.js";
|
|
2
|
-
function padSequence(value) {
|
|
3
|
-
return String(value).padStart(12, "0");
|
|
4
|
-
}
|
|
5
|
-
export class RemoteSessionStore {
|
|
6
|
-
storage;
|
|
7
|
-
maxEventsPerChunk;
|
|
8
|
-
maxChunkBytes;
|
|
9
|
-
constructor(storage, maxEventsPerChunk = 100, maxChunkBytes = 512 * 1024) {
|
|
10
|
-
this.storage = storage;
|
|
11
|
-
this.maxEventsPerChunk = maxEventsPerChunk;
|
|
12
|
-
this.maxChunkBytes = maxChunkBytes;
|
|
13
|
-
if (maxEventsPerChunk <
|
|
14
|
-
1) {
|
|
15
|
-
throw new Error("maxEventsPerChunk must be positive");
|
|
16
|
-
}
|
|
17
|
-
if (maxChunkBytes <
|
|
18
|
-
1_024) {
|
|
19
|
-
throw new Error("maxChunkBytes is too small");
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
async getJson(key) {
|
|
23
|
-
const text = await this.storage
|
|
24
|
-
.getText(key);
|
|
25
|
-
if (!text) {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
return JSON.parse(text);
|
|
29
|
-
}
|
|
30
|
-
async putJson(key, value) {
|
|
31
|
-
await this.storage.put(key, JSON.stringify(value, null, 2) + "\n", "application/json");
|
|
32
|
-
}
|
|
33
|
-
async scan(identity) {
|
|
34
|
-
const prefix = `${identity.remotePrefix}/events/`;
|
|
35
|
-
const objects = await this.storage.list(prefix);
|
|
36
|
-
const chunks = [];
|
|
37
|
-
let maxSequence = 0;
|
|
38
|
-
for (const object of objects) {
|
|
39
|
-
const match = object.key.match(/\/events\/(\d+)-(\d+)-[a-f0-9]+\.jsonl$/);
|
|
40
|
-
if (!match) {
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
const start = Number(match[1]);
|
|
44
|
-
const end = Number(match[2]);
|
|
45
|
-
if (!Number.isFinite(start) ||
|
|
46
|
-
!Number.isFinite(end)) {
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
chunks.push({
|
|
50
|
-
key: object.key,
|
|
51
|
-
start,
|
|
52
|
-
end,
|
|
53
|
-
});
|
|
54
|
-
maxSequence =
|
|
55
|
-
Math.max(maxSequence, end);
|
|
56
|
-
}
|
|
57
|
-
chunks.sort((left, right) => left.start -
|
|
58
|
-
right.start);
|
|
59
|
-
return {
|
|
60
|
-
chunks,
|
|
61
|
-
maxSequence,
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
split(events) {
|
|
65
|
-
const result = [];
|
|
66
|
-
let current = [];
|
|
67
|
-
let bytes = 0;
|
|
68
|
-
for (const event of events) {
|
|
69
|
-
const lineBytes = Buffer.byteLength(JSON.stringify(event) + "\n", "utf8");
|
|
70
|
-
if (current.length >
|
|
71
|
-
0 &&
|
|
72
|
-
(current.length >=
|
|
73
|
-
this
|
|
74
|
-
.maxEventsPerChunk ||
|
|
75
|
-
bytes +
|
|
76
|
-
lineBytes >
|
|
77
|
-
this
|
|
78
|
-
.maxChunkBytes)) {
|
|
79
|
-
result.push(current);
|
|
80
|
-
current =
|
|
81
|
-
[];
|
|
82
|
-
bytes =
|
|
83
|
-
0;
|
|
84
|
-
}
|
|
85
|
-
current.push(event);
|
|
86
|
-
bytes +=
|
|
87
|
-
lineBytes;
|
|
88
|
-
}
|
|
89
|
-
if (current.length >
|
|
90
|
-
0) {
|
|
91
|
-
result.push(current);
|
|
92
|
-
}
|
|
93
|
-
return result;
|
|
94
|
-
}
|
|
95
|
-
async loadManifest(identity) {
|
|
96
|
-
return this.getJson(`${identity.remotePrefix}/session.json`);
|
|
97
|
-
}
|
|
98
|
-
async loadCursor(identity) {
|
|
99
|
-
return this.getJson(`${identity.remotePrefix}/cursor.json`);
|
|
100
|
-
}
|
|
101
|
-
async recover(identity) {
|
|
102
|
-
const scan = await this.scan(identity);
|
|
103
|
-
return {
|
|
104
|
-
maxSequence: scan.maxSequence,
|
|
105
|
-
chunkCount: scan.chunks.length,
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
async append(identity, events, sourceCursors, options = {}) {
|
|
109
|
-
const previousManifest = await this.loadManifest(identity);
|
|
110
|
-
const before = await this.scan(identity);
|
|
111
|
-
/*
|
|
112
|
-
* Crash recovery:
|
|
113
|
-
* chunks may already exist even when cursor/session.json
|
|
114
|
-
* was not successfully updated.
|
|
115
|
-
*/
|
|
116
|
-
const pending = events.filter(event => event.sequence >
|
|
117
|
-
before.maxSequence);
|
|
118
|
-
let uploadedEvents = 0;
|
|
119
|
-
for (const chunk of this.split(pending)) {
|
|
120
|
-
const first = chunk[0];
|
|
121
|
-
const last = chunk[chunk.length -
|
|
122
|
-
1];
|
|
123
|
-
const content = chunk
|
|
124
|
-
.map(event => JSON.stringify(event))
|
|
125
|
-
.join("\n") +
|
|
126
|
-
"\n";
|
|
127
|
-
const digest = sha256(content).slice(0, 16);
|
|
128
|
-
const key = [
|
|
129
|
-
identity
|
|
130
|
-
.remotePrefix,
|
|
131
|
-
"events",
|
|
132
|
-
`${padSequence(first.sequence)}-${padSequence(last.sequence)}-${digest}.jsonl`,
|
|
133
|
-
].join("/");
|
|
134
|
-
if (!await this.storage
|
|
135
|
-
.exists(key)) {
|
|
136
|
-
await this.storage.put(key, content, "application/x-ndjson");
|
|
137
|
-
}
|
|
138
|
-
uploadedEvents +=
|
|
139
|
-
chunk.length;
|
|
140
|
-
}
|
|
141
|
-
const after = await this.scan(identity);
|
|
142
|
-
const lastInput = events[events.length -
|
|
143
|
-
1];
|
|
144
|
-
let status = previousManifest
|
|
145
|
-
?.status ??
|
|
146
|
-
"active";
|
|
147
|
-
if ((lastInput
|
|
148
|
-
?.type ===
|
|
149
|
-
"session_end" ||
|
|
150
|
-
lastInput
|
|
151
|
-
?.type ===
|
|
152
|
-
"session_idle")) {
|
|
153
|
-
status =
|
|
154
|
-
"idle";
|
|
155
|
-
}
|
|
156
|
-
else if (lastInput
|
|
157
|
-
?.type ===
|
|
158
|
-
"error") {
|
|
159
|
-
status =
|
|
160
|
-
"error";
|
|
161
|
-
}
|
|
162
|
-
else if (events.length >
|
|
163
|
-
0) {
|
|
164
|
-
status =
|
|
165
|
-
"active";
|
|
166
|
-
}
|
|
167
|
-
const now = new Date()
|
|
168
|
-
.toISOString();
|
|
169
|
-
const firstInput = events[0];
|
|
170
|
-
const manifest = {
|
|
171
|
-
version: 1,
|
|
172
|
-
projectId: identity.projectId,
|
|
173
|
-
projectName: identity
|
|
174
|
-
.projectName,
|
|
175
|
-
agent: identity.agent,
|
|
176
|
-
nativeSessionId: identity
|
|
177
|
-
.nativeSessionId,
|
|
178
|
-
sessionKey: identity.sessionKey,
|
|
179
|
-
status,
|
|
180
|
-
createdAt: previousManifest
|
|
181
|
-
?.createdAt ??
|
|
182
|
-
firstInput
|
|
183
|
-
?.timestamp ??
|
|
184
|
-
now,
|
|
185
|
-
updatedAt: lastInput
|
|
186
|
-
?.timestamp ??
|
|
187
|
-
now,
|
|
188
|
-
firstEventAt: previousManifest
|
|
189
|
-
?.firstEventAt ??
|
|
190
|
-
firstInput
|
|
191
|
-
?.timestamp,
|
|
192
|
-
lastEventAt: lastInput
|
|
193
|
-
?.timestamp ??
|
|
194
|
-
previousManifest
|
|
195
|
-
?.lastEventAt,
|
|
196
|
-
eventCount: after.maxSequence,
|
|
197
|
-
chunkCount: after.chunks.length,
|
|
198
|
-
metadata: {
|
|
199
|
-
...previousManifest
|
|
200
|
-
?.metadata,
|
|
201
|
-
...options.metadata,
|
|
202
|
-
},
|
|
203
|
-
};
|
|
204
|
-
if (options.title ??
|
|
205
|
-
previousManifest
|
|
206
|
-
?.title) {
|
|
207
|
-
manifest.title =
|
|
208
|
-
options.title ??
|
|
209
|
-
previousManifest
|
|
210
|
-
?.title;
|
|
211
|
-
}
|
|
212
|
-
const cursor = {
|
|
213
|
-
version: 1,
|
|
214
|
-
projectId: identity.projectId,
|
|
215
|
-
agent: identity.agent,
|
|
216
|
-
nativeSessionId: identity
|
|
217
|
-
.nativeSessionId,
|
|
218
|
-
lastLocalSequence: events.length >
|
|
219
|
-
0
|
|
220
|
-
? events[events.length -
|
|
221
|
-
1].sequence
|
|
222
|
-
: after
|
|
223
|
-
.maxSequence,
|
|
224
|
-
lastRemoteSequence: after.maxSequence,
|
|
225
|
-
sourceCursors,
|
|
226
|
-
updatedAt: now,
|
|
227
|
-
};
|
|
228
|
-
/*
|
|
229
|
-
* Chunk first, then cursor, then manifest.
|
|
230
|
-
* Immutable chunks are the source of truth.
|
|
231
|
-
*/
|
|
232
|
-
await this.putJson(`${identity.remotePrefix}/cursor.json`, cursor);
|
|
233
|
-
await this.putJson(`${identity.remotePrefix}/session.json`, manifest);
|
|
234
|
-
return {
|
|
235
|
-
uploadedEvents,
|
|
236
|
-
lastRemoteSequence: after.maxSequence,
|
|
237
|
-
eventCount: manifest.eventCount,
|
|
238
|
-
chunkCount: manifest.chunkCount,
|
|
239
|
-
status,
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { createHash, } from "node:crypto";
|
|
2
|
-
import { dirname, } from "node:path";
|
|
3
|
-
import { mkdirSync, readFileSync, renameSync, writeFileSync, } from "node:fs";
|
|
4
|
-
export function sha256(value) {
|
|
5
|
-
return createHash("sha256")
|
|
6
|
-
.update(value)
|
|
7
|
-
.digest("hex");
|
|
8
|
-
}
|
|
9
|
-
function normalize(value) {
|
|
10
|
-
if (Array.isArray(value)) {
|
|
11
|
-
return value.map(normalize);
|
|
12
|
-
}
|
|
13
|
-
if (value &&
|
|
14
|
-
typeof value ===
|
|
15
|
-
"object") {
|
|
16
|
-
const source = value;
|
|
17
|
-
const result = {};
|
|
18
|
-
for (const key of Object.keys(source).sort()) {
|
|
19
|
-
result[key] =
|
|
20
|
-
normalize(source[key]);
|
|
21
|
-
}
|
|
22
|
-
return result;
|
|
23
|
-
}
|
|
24
|
-
return value;
|
|
25
|
-
}
|
|
26
|
-
export function stableStringify(value) {
|
|
27
|
-
return JSON.stringify(normalize(value));
|
|
28
|
-
}
|
|
29
|
-
export function readJsonFile(filePath) {
|
|
30
|
-
try {
|
|
31
|
-
return JSON.parse(readFileSync(filePath, "utf8"));
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
export function writeJsonAtomic(filePath, value) {
|
|
38
|
-
mkdirSync(dirname(filePath), {
|
|
39
|
-
recursive: true,
|
|
40
|
-
});
|
|
41
|
-
const temporary = `${filePath}.${process.pid}.tmp`;
|
|
42
|
-
writeFileSync(temporary, JSON.stringify(value, null, 2) + "\n", {
|
|
43
|
-
encoding: "utf8",
|
|
44
|
-
mode: 0o600,
|
|
45
|
-
});
|
|
46
|
-
renameSync(temporary, filePath);
|
|
47
|
-
}
|