@cortexkit/opencode-magic-context 0.15.7 → 0.16.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/README.md +41 -15
- package/dist/agents/magic-context-prompt.d.ts +2 -13
- package/dist/agents/magic-context-prompt.d.ts.map +1 -1
- package/dist/cli/diagnostics.d.ts.map +1 -1
- package/dist/cli/migrate.d.ts +70 -0
- package/dist/cli/migrate.d.ts.map +1 -0
- package/dist/cli.js +666 -29
- package/dist/config/schema/magic-context.d.ts +67 -4
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
- package/dist/features/magic-context/compaction.d.ts +1 -1
- package/dist/features/magic-context/compaction.d.ts.map +1 -1
- package/dist/features/magic-context/compartment-storage.d.ts +1 -1
- package/dist/features/magic-context/compartment-storage.d.ts.map +1 -1
- package/dist/features/magic-context/compression-depth-storage.d.ts +1 -1
- package/dist/features/magic-context/compression-depth-storage.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/lease.d.ts +1 -1
- package/dist/features/magic-context/dreamer/lease.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/queue.d.ts +8 -3
- package/dist/features/magic-context/dreamer/queue.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/runner.d.ts +1 -1
- package/dist/features/magic-context/dreamer/runner.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/scheduler.d.ts +1 -1
- package/dist/features/magic-context/dreamer/scheduler.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts +1 -1
- package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/storage-dream-state.d.ts +1 -1
- package/dist/features/magic-context/dreamer/storage-dream-state.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/indexer.d.ts +1 -1
- package/dist/features/magic-context/git-commits/indexer.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/search-git-commits.d.ts +1 -1
- package/dist/features/magic-context/git-commits/search-git-commits.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts +1 -1
- package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/storage-git-commits.d.ts +1 -1
- package/dist/features/magic-context/git-commits/storage-git-commits.d.ts.map +1 -1
- package/dist/features/magic-context/key-files/identify-key-files.d.ts +1 -1
- package/dist/features/magic-context/key-files/identify-key-files.d.ts.map +1 -1
- package/dist/features/magic-context/key-files/read-stats.d.ts +1 -1
- package/dist/features/magic-context/key-files/read-stats.d.ts.map +1 -1
- package/dist/features/magic-context/key-files/storage-key-files.d.ts +1 -1
- package/dist/features/magic-context/key-files/storage-key-files.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-backfill.d.ts +1 -1
- package/dist/features/magic-context/memory/embedding-backfill.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-cache.d.ts +1 -1
- package/dist/features/magic-context/memory/embedding-cache.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding.d.ts +1 -1
- package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
- package/dist/features/magic-context/memory/normalize-hash.d.ts.map +1 -1
- package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
- package/dist/features/magic-context/memory/promotion.d.ts +1 -1
- package/dist/features/magic-context/memory/promotion.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts +1 -1
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory-fts.d.ts +1 -1
- package/dist/features/magic-context/memory/storage-memory-fts.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory.d.ts +1 -1
- package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -1
- package/dist/features/magic-context/message-index.d.ts +1 -1
- package/dist/features/magic-context/message-index.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts +1 -1
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/mock-database.d.ts +1 -1
- package/dist/features/magic-context/mock-database.d.ts.map +1 -1
- package/dist/features/magic-context/plugin-messages.d.ts +1 -1
- package/dist/features/magic-context/plugin-messages.d.ts.map +1 -1
- package/dist/features/magic-context/search.d.ts +1 -1
- package/dist/features/magic-context/search.d.ts.map +1 -1
- package/dist/features/magic-context/sidekick/agent.d.ts +2 -1
- package/dist/features/magic-context/sidekick/agent.d.ts.map +1 -1
- package/dist/features/magic-context/sidekick/core.d.ts +38 -0
- package/dist/features/magic-context/sidekick/core.d.ts.map +1 -0
- package/dist/features/magic-context/storage-db.d.ts +20 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-session.d.ts +1 -1
- package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts +1 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
- package/dist/features/magic-context/storage-notes.d.ts +1 -1
- package/dist/features/magic-context/storage-notes.d.ts.map +1 -1
- package/dist/features/magic-context/storage-ops.d.ts +1 -1
- package/dist/features/magic-context/storage-ops.d.ts.map +1 -1
- package/dist/features/magic-context/storage-source.d.ts +1 -1
- package/dist/features/magic-context/storage-source.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tags.d.ts +17 -1
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/tagger.d.ts +1 -1
- package/dist/features/magic-context/tagger.d.ts.map +1 -1
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts +1 -1
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
- package/dist/features/magic-context/user-memory/storage-user-memory.d.ts +1 -1
- package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-hint.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-runner.d.ts +1 -1
- package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts +1 -1
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-prompt.d.ts +1 -0
- package/dist/hooks/magic-context/compartment-prompt.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-compressor.d.ts +1 -1
- package/dist/hooks/magic-context/compartment-runner-compressor.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts +1 -1
- package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts +1 -0
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts +1 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-trigger.d.ts +1 -1
- package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
- package/dist/hooks/magic-context/execute-flush.d.ts +1 -1
- package/dist/hooks/magic-context/execute-flush.d.ts.map +1 -1
- package/dist/hooks/magic-context/execute-status.d.ts +1 -1
- package/dist/hooks/magic-context/execute-status.d.ts.map +1 -1
- package/dist/hooks/magic-context/historian-state-file.d.ts +29 -0
- package/dist/hooks/magic-context/historian-state-file.d.ts.map +1 -0
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/note-nudger.d.ts +1 -1
- package/dist/hooks/magic-context/note-nudger.d.ts.map +1 -1
- package/dist/hooks/magic-context/nudge-placement-store.d.ts +1 -1
- package/dist/hooks/magic-context/nudge-placement-store.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-chunk.d.ts +39 -0
- package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-db.d.ts +1 -1
- package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-raw.d.ts +1 -1
- package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
- package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -1
- package/dist/hooks/magic-context/system-prompt-hash.d.ts +6 -5
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/index.js +8284 -8166
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/messages-transform.d.ts +1 -1
- package/dist/plugin/rpc-handlers.d.ts +4 -0
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/plugin/tool-registry.d.ts.map +1 -1
- package/dist/shared/conflict-detector.d.ts.map +1 -1
- package/dist/shared/data-path.d.ts +22 -0
- package/dist/shared/data-path.d.ts.map +1 -1
- package/dist/shared/harness.d.ts +43 -0
- package/dist/shared/harness.d.ts.map +1 -0
- package/dist/shared/rpc-notifications.d.ts +4 -2
- package/dist/shared/rpc-notifications.d.ts.map +1 -1
- package/dist/shared/sqlite-helpers.d.ts +16 -0
- package/dist/shared/sqlite-helpers.d.ts.map +1 -0
- package/dist/shared/sqlite.d.ts +55 -0
- package/dist/shared/sqlite.d.ts.map +1 -0
- package/dist/shared/subagent-runner.d.ts +202 -0
- package/dist/shared/subagent-runner.d.ts.map +1 -0
- package/dist/shared/tag-transcript.d.ts +66 -0
- package/dist/shared/tag-transcript.d.ts.map +1 -0
- package/dist/shared/transcript-opencode.d.ts +71 -0
- package/dist/shared/transcript-opencode.d.ts.map +1 -0
- package/dist/shared/transcript.d.ts +212 -0
- package/dist/shared/transcript.d.ts.map +1 -0
- package/dist/shared/tui-config.d.ts.map +1 -1
- package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
- package/dist/tools/ctx-memory/types.d.ts +13 -2
- package/dist/tools/ctx-memory/types.d.ts.map +1 -1
- package/dist/tools/ctx-note/tools.d.ts +8 -2
- package/dist/tools/ctx-note/tools.d.ts.map +1 -1
- package/dist/tools/ctx-reduce/tools.d.ts +1 -1
- package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
- package/dist/tools/ctx-search/tools.d.ts.map +1 -1
- package/dist/tools/ctx-search/types.d.ts +8 -2
- package/dist/tools/ctx-search/types.d.ts.map +1 -1
- package/dist/tui/data/context-db.d.ts.map +1 -1
- package/package.json +7 -5
- package/src/shared/conflict-detector.test.ts +44 -1
- package/src/shared/conflict-detector.ts +24 -8
- package/src/shared/data-path.test.ts +53 -1
- package/src/shared/data-path.ts +28 -0
- package/src/shared/harness.ts +61 -0
- package/src/shared/rpc-notifications.ts +11 -5
- package/src/shared/sqlite-helpers.ts +27 -0
- package/src/shared/sqlite.ts +91 -0
- package/src/shared/subagent-runner.ts +206 -0
- package/src/shared/tag-transcript.ts +541 -0
- package/src/shared/transcript-opencode.ts +259 -0
- package/src/shared/transcript.ts +226 -0
- package/src/shared/tui-config.ts +34 -8
- package/src/tui/data/context-db.ts +5 -1
package/dist/cli.js
CHANGED
|
@@ -8260,8 +8260,24 @@ function matchesPackageName(entry, canonicalNames) {
|
|
|
8260
8260
|
const nameOnly = lastAt > 0 ? entry.slice(0, lastAt) : entry;
|
|
8261
8261
|
return canonicalNames.has(nameOnly);
|
|
8262
8262
|
}
|
|
8263
|
+
function extractPluginName(entry) {
|
|
8264
|
+
if (typeof entry === "string")
|
|
8265
|
+
return entry;
|
|
8266
|
+
if (Array.isArray(entry) && typeof entry[0] === "string")
|
|
8267
|
+
return entry[0];
|
|
8268
|
+
return null;
|
|
8269
|
+
}
|
|
8263
8270
|
function collectPluginEntries(directory) {
|
|
8264
8271
|
const plugins = [];
|
|
8272
|
+
const pushFrom = (entries) => {
|
|
8273
|
+
if (!entries)
|
|
8274
|
+
return;
|
|
8275
|
+
for (const entry of entries) {
|
|
8276
|
+
const name = extractPluginName(entry);
|
|
8277
|
+
if (name)
|
|
8278
|
+
plugins.push(name);
|
|
8279
|
+
}
|
|
8280
|
+
};
|
|
8265
8281
|
for (const configPath of [
|
|
8266
8282
|
join2(directory, ".opencode", "opencode.jsonc"),
|
|
8267
8283
|
join2(directory, ".opencode", "opencode.json"),
|
|
@@ -8269,17 +8285,13 @@ function collectPluginEntries(directory) {
|
|
|
8269
8285
|
join2(directory, "opencode.json")
|
|
8270
8286
|
]) {
|
|
8271
8287
|
const config = readJsoncFile(configPath);
|
|
8272
|
-
|
|
8273
|
-
plugins.push(...config.plugin);
|
|
8274
|
-
}
|
|
8288
|
+
pushFrom(config?.plugin);
|
|
8275
8289
|
}
|
|
8276
8290
|
try {
|
|
8277
8291
|
const paths = getOpenCodeConfigPaths({ binary: "opencode" });
|
|
8278
8292
|
for (const configPath of [paths.configJsonc, paths.configJson]) {
|
|
8279
8293
|
const config = readJsoncFile(configPath);
|
|
8280
|
-
|
|
8281
|
-
plugins.push(...config.plugin);
|
|
8282
|
-
}
|
|
8294
|
+
pushFrom(config?.plugin);
|
|
8283
8295
|
}
|
|
8284
8296
|
} catch {}
|
|
8285
8297
|
return plugins;
|
|
@@ -8495,6 +8507,12 @@ function fixConflicts(directory, conflicts) {
|
|
|
8495
8507
|
// src/shared/data-path.ts
|
|
8496
8508
|
import * as os from "node:os";
|
|
8497
8509
|
import * as path from "node:path";
|
|
8510
|
+
function getDataDir() {
|
|
8511
|
+
return process.env.XDG_DATA_HOME ?? path.join(os.homedir(), ".local", "share");
|
|
8512
|
+
}
|
|
8513
|
+
function getMagicContextStorageDir() {
|
|
8514
|
+
return path.join(getDataDir(), "cortexkit", "magic-context");
|
|
8515
|
+
}
|
|
8498
8516
|
function getCacheDir() {
|
|
8499
8517
|
return process.env.XDG_CACHE_HOME ?? path.join(os.homedir(), ".cache");
|
|
8500
8518
|
}
|
|
@@ -8561,6 +8579,17 @@ if (!isTestEnv) {
|
|
|
8561
8579
|
// src/shared/tui-config.ts
|
|
8562
8580
|
var PLUGIN_NAME = "@cortexkit/opencode-magic-context";
|
|
8563
8581
|
var PLUGIN_ENTRY = `${PLUGIN_NAME}@latest`;
|
|
8582
|
+
function isMagicContextEntry(entry) {
|
|
8583
|
+
if (!entry)
|
|
8584
|
+
return false;
|
|
8585
|
+
if (entry === PLUGIN_NAME)
|
|
8586
|
+
return true;
|
|
8587
|
+
if (entry.startsWith(`${PLUGIN_NAME}@`))
|
|
8588
|
+
return true;
|
|
8589
|
+
if (entry.includes("opencode-magic-context"))
|
|
8590
|
+
return true;
|
|
8591
|
+
return false;
|
|
8592
|
+
}
|
|
8564
8593
|
function resolveTuiConfigPath() {
|
|
8565
8594
|
const configDir = getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
|
|
8566
8595
|
const jsoncPath = join6(configDir, "tui.jsonc");
|
|
@@ -8580,12 +8609,12 @@ function ensureTuiPluginEntry() {
|
|
|
8580
8609
|
config = import_comment_json.parse(raw) ?? {};
|
|
8581
8610
|
}
|
|
8582
8611
|
const plugins = Array.isArray(config.plugin) ? config.plugin.filter((p) => typeof p === "string") : [];
|
|
8583
|
-
const existingIdx = plugins.findIndex(
|
|
8612
|
+
const existingIdx = plugins.findIndex(isMagicContextEntry);
|
|
8584
8613
|
if (existingIdx >= 0) {
|
|
8585
|
-
|
|
8614
|
+
const existing = plugins[existingIdx];
|
|
8615
|
+
if (existing === PLUGIN_ENTRY) {
|
|
8586
8616
|
return false;
|
|
8587
8617
|
}
|
|
8588
|
-
const existing = plugins[existingIdx];
|
|
8589
8618
|
if (existing === PLUGIN_NAME) {
|
|
8590
8619
|
plugins[existingIdx] = PLUGIN_ENTRY;
|
|
8591
8620
|
} else {
|
|
@@ -8835,7 +8864,7 @@ function getPluginCacheInfo() {
|
|
|
8835
8864
|
}
|
|
8836
8865
|
function getStorageDir() {
|
|
8837
8866
|
const dataHome = process.env.XDG_DATA_HOME || join8(homedir5(), ".local", "share");
|
|
8838
|
-
return join8(dataHome, "
|
|
8867
|
+
return join8(dataHome, "cortexkit", "magic-context");
|
|
8839
8868
|
}
|
|
8840
8869
|
function fileSize(path3) {
|
|
8841
8870
|
try {
|
|
@@ -10509,7 +10538,7 @@ async function runIssueFlow() {
|
|
|
10509
10538
|
"issue",
|
|
10510
10539
|
"create",
|
|
10511
10540
|
"-R",
|
|
10512
|
-
"cortexkit/
|
|
10541
|
+
"cortexkit/magic-context",
|
|
10513
10542
|
"--title",
|
|
10514
10543
|
title,
|
|
10515
10544
|
"--body-file",
|
|
@@ -10524,7 +10553,7 @@ async function runIssueFlow() {
|
|
|
10524
10553
|
} else if (shouldSubmit && !isGhInstalled()) {
|
|
10525
10554
|
R2.warn("gh CLI not found — falling back to browser");
|
|
10526
10555
|
}
|
|
10527
|
-
const url = `https://github.com/cortexkit/
|
|
10556
|
+
const url = `https://github.com/cortexkit/magic-context/issues/new?title=${encodeURIComponent(title)}&template=bug_report.yml`;
|
|
10528
10557
|
R2.info(`Open this URL and paste the contents of ${bundled.path} into the Diagnostics field:`);
|
|
10529
10558
|
R2.info(url);
|
|
10530
10559
|
openBrowser(url);
|
|
@@ -10965,15 +10994,614 @@ async function runDoctor(options = {}) {
|
|
|
10965
10994
|
return 0;
|
|
10966
10995
|
}
|
|
10967
10996
|
|
|
10997
|
+
// src/cli/migrate.ts
|
|
10998
|
+
import { randomBytes } from "node:crypto";
|
|
10999
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
11000
|
+
import { homedir as homedir8 } from "node:os";
|
|
11001
|
+
import { join as join11 } from "node:path";
|
|
11002
|
+
|
|
11003
|
+
// src/shared/sqlite.ts
|
|
11004
|
+
var isBun = typeof process !== "undefined" && typeof process.versions?.bun === "string";
|
|
11005
|
+
var bunSpec = "bun:" + "sqlite";
|
|
11006
|
+
var betterSpec = "better-" + "sqlite3";
|
|
11007
|
+
var sqliteModule = isBun ? await import(bunSpec) : await import(betterSpec);
|
|
11008
|
+
var DatabaseImpl = isBun ? sqliteModule.Database : sqliteModule.default;
|
|
11009
|
+
var Database = DatabaseImpl;
|
|
11010
|
+
|
|
11011
|
+
// src/cli/migrate.ts
|
|
11012
|
+
var DEFAULT_PROVIDER = "openai-codex";
|
|
11013
|
+
var DEFAULT_MODEL = "gpt-5.5";
|
|
11014
|
+
var MIGRATION_COMPACTION_SUMMARY = "Magic Context compacted prior conversation. See <session-history> block for the structured summary.";
|
|
11015
|
+
function defaultOpenCodeDbPath() {
|
|
11016
|
+
return join11(homedir8(), ".local", "share", "opencode", "opencode.db");
|
|
11017
|
+
}
|
|
11018
|
+
function defaultCortexkitDbPath() {
|
|
11019
|
+
return join11(getMagicContextStorageDir(), "context.db");
|
|
11020
|
+
}
|
|
11021
|
+
function defaultPiSessionsRoot() {
|
|
11022
|
+
return join11(homedir8(), ".pi", "agent", "sessions");
|
|
11023
|
+
}
|
|
11024
|
+
function defaultFs() {
|
|
11025
|
+
return { existsSync: existsSync8, mkdirSync: mkdirSync3, writeFileSync: writeFileSync5 };
|
|
11026
|
+
}
|
|
11027
|
+
function stmt(db, sql) {
|
|
11028
|
+
return db.prepare(sql);
|
|
11029
|
+
}
|
|
11030
|
+
function projectPathToPiDirSlug(projectPath) {
|
|
11031
|
+
return `--${projectPath.replace(/^\/+|\/+$/g, "").replaceAll("/", "-")}--`;
|
|
11032
|
+
}
|
|
11033
|
+
function formatPiFilenameTimestamp(date) {
|
|
11034
|
+
return date.toISOString().replaceAll(":", "-").replace(".", "-");
|
|
11035
|
+
}
|
|
11036
|
+
function generateUuidV7(date = new Date) {
|
|
11037
|
+
const bytes = randomBytes(16);
|
|
11038
|
+
let ms = BigInt(date.getTime());
|
|
11039
|
+
for (let i = 5;i >= 0; i--) {
|
|
11040
|
+
bytes[i] = Number(ms & 0xffn);
|
|
11041
|
+
ms >>= 8n;
|
|
11042
|
+
}
|
|
11043
|
+
bytes[6] = bytes[6] & 15 | 112;
|
|
11044
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
11045
|
+
const hex = bytes.toString("hex");
|
|
11046
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
11047
|
+
}
|
|
11048
|
+
function shortId() {
|
|
11049
|
+
return randomBytes(4).toString("hex");
|
|
11050
|
+
}
|
|
11051
|
+
function parseJsonObject(text2) {
|
|
11052
|
+
const parsed = JSON.parse(text2);
|
|
11053
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
11054
|
+
throw new Error("Expected JSON object");
|
|
11055
|
+
}
|
|
11056
|
+
return parsed;
|
|
11057
|
+
}
|
|
11058
|
+
function isoFromMs(ms, fallback) {
|
|
11059
|
+
return new Date(typeof ms === "number" && Number.isFinite(ms) ? ms : fallback.getTime()).toISOString();
|
|
11060
|
+
}
|
|
11061
|
+
function textFromUnknown(value) {
|
|
11062
|
+
if (value === undefined || value === null)
|
|
11063
|
+
return "";
|
|
11064
|
+
if (typeof value === "string")
|
|
11065
|
+
return value;
|
|
11066
|
+
return JSON.stringify(value, null, 2);
|
|
11067
|
+
}
|
|
11068
|
+
function roleFromMessage(row) {
|
|
11069
|
+
const data = parseJsonObject(row.data);
|
|
11070
|
+
return data.role === "user" || data.role === "assistant" ? data.role : undefined;
|
|
11071
|
+
}
|
|
11072
|
+
function tokensFromMessage(row) {
|
|
11073
|
+
try {
|
|
11074
|
+
const data = parseJsonObject(row.data);
|
|
11075
|
+
return data.tokens ?? {};
|
|
11076
|
+
} catch {
|
|
11077
|
+
return {};
|
|
11078
|
+
}
|
|
11079
|
+
}
|
|
11080
|
+
function extractModel(rows) {
|
|
11081
|
+
for (const row of rows) {
|
|
11082
|
+
try {
|
|
11083
|
+
const data = parseJsonObject(row.data);
|
|
11084
|
+
const provider = data.providerID ?? data.model?.providerID;
|
|
11085
|
+
const modelId = data.modelID ?? data.model?.modelID;
|
|
11086
|
+
if (provider && modelId)
|
|
11087
|
+
return { provider, modelId };
|
|
11088
|
+
} catch {}
|
|
11089
|
+
}
|
|
11090
|
+
return { provider: DEFAULT_PROVIDER, modelId: DEFAULT_MODEL };
|
|
11091
|
+
}
|
|
11092
|
+
function normalizeOpenCodeTool(part) {
|
|
11093
|
+
const callId = part.callID ?? part.call_id ?? part.toolCallId ?? part.tool_call_id ?? `migrated_${shortId()}`;
|
|
11094
|
+
const name = part.tool ?? part.tool_name ?? part.name ?? part.state?.title ?? "unknown_tool";
|
|
11095
|
+
const input = part.input ?? part.state?.input ?? {};
|
|
11096
|
+
const output = part.output ?? part.state?.output ?? part.state?.metadata?.output ?? "";
|
|
11097
|
+
return { callId, name, input, output };
|
|
11098
|
+
}
|
|
11099
|
+
function tokensToPiUsage(tokens) {
|
|
11100
|
+
const input = tokens?.input ?? 0;
|
|
11101
|
+
const output = tokens?.output ?? 0;
|
|
11102
|
+
const cacheRead = tokens?.cache?.read ?? 0;
|
|
11103
|
+
const cacheWrite = tokens?.cache?.write ?? 0;
|
|
11104
|
+
const total = tokens?.total ?? input + output + cacheRead + cacheWrite;
|
|
11105
|
+
return {
|
|
11106
|
+
input,
|
|
11107
|
+
output,
|
|
11108
|
+
cacheRead,
|
|
11109
|
+
cacheWrite,
|
|
11110
|
+
totalTokens: total,
|
|
11111
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
|
|
11112
|
+
};
|
|
11113
|
+
}
|
|
11114
|
+
function makeMessageEntry(role, text2, timestamp, parentId, usage) {
|
|
11115
|
+
const message = {
|
|
11116
|
+
role,
|
|
11117
|
+
content: [{ type: "text", text: text2 }],
|
|
11118
|
+
timestamp: Date.parse(timestamp)
|
|
11119
|
+
};
|
|
11120
|
+
if (role === "assistant") {
|
|
11121
|
+
message.usage = usage;
|
|
11122
|
+
}
|
|
11123
|
+
return {
|
|
11124
|
+
type: "message",
|
|
11125
|
+
id: shortId(),
|
|
11126
|
+
parentId,
|
|
11127
|
+
timestamp,
|
|
11128
|
+
message
|
|
11129
|
+
};
|
|
11130
|
+
}
|
|
11131
|
+
function makeThinkingEntry(text2, timestamp, parentId, usage) {
|
|
11132
|
+
return {
|
|
11133
|
+
type: "message",
|
|
11134
|
+
id: shortId(),
|
|
11135
|
+
parentId,
|
|
11136
|
+
timestamp,
|
|
11137
|
+
message: {
|
|
11138
|
+
role: "assistant",
|
|
11139
|
+
content: [{ type: "thinking", thinking: text2, thinkingSignature: null }],
|
|
11140
|
+
timestamp: Date.parse(timestamp),
|
|
11141
|
+
usage
|
|
11142
|
+
}
|
|
11143
|
+
};
|
|
11144
|
+
}
|
|
11145
|
+
function makeToolCallEntry(tool, timestamp, parentId, usage) {
|
|
11146
|
+
return {
|
|
11147
|
+
type: "message",
|
|
11148
|
+
id: shortId(),
|
|
11149
|
+
parentId,
|
|
11150
|
+
timestamp,
|
|
11151
|
+
message: {
|
|
11152
|
+
role: "assistant",
|
|
11153
|
+
content: [
|
|
11154
|
+
{
|
|
11155
|
+
type: "toolCall",
|
|
11156
|
+
id: tool.callId,
|
|
11157
|
+
name: tool.name,
|
|
11158
|
+
arguments: tool.input ?? {}
|
|
11159
|
+
}
|
|
11160
|
+
],
|
|
11161
|
+
timestamp: Date.parse(timestamp),
|
|
11162
|
+
usage
|
|
11163
|
+
}
|
|
11164
|
+
};
|
|
11165
|
+
}
|
|
11166
|
+
function makeToolResultEntry(tool, timestamp, parentId) {
|
|
11167
|
+
return {
|
|
11168
|
+
type: "message",
|
|
11169
|
+
id: shortId(),
|
|
11170
|
+
parentId,
|
|
11171
|
+
timestamp,
|
|
11172
|
+
message: {
|
|
11173
|
+
role: "toolResult",
|
|
11174
|
+
toolCallId: tool.callId,
|
|
11175
|
+
toolName: tool.name,
|
|
11176
|
+
content: [{ type: "text", text: textFromUnknown(tool.output) }],
|
|
11177
|
+
isError: false,
|
|
11178
|
+
timestamp: Date.parse(timestamp)
|
|
11179
|
+
}
|
|
11180
|
+
};
|
|
11181
|
+
}
|
|
11182
|
+
function convertPartToEntries(ctx) {
|
|
11183
|
+
const part = parseJsonObject(ctx.row.data);
|
|
11184
|
+
switch (part.type) {
|
|
11185
|
+
case "step-start":
|
|
11186
|
+
case "step-finish":
|
|
11187
|
+
case "patch":
|
|
11188
|
+
return [];
|
|
11189
|
+
case "text":
|
|
11190
|
+
return part.text ? [makeMessageEntry(ctx.role, part.text, ctx.timestamp, ctx.parentId, ctx.usage)] : [];
|
|
11191
|
+
case "reasoning":
|
|
11192
|
+
return part.text ? [makeThinkingEntry(part.text, ctx.timestamp, ctx.parentId, ctx.usage)] : [];
|
|
11193
|
+
case "tool": {
|
|
11194
|
+
const tool = normalizeOpenCodeTool(part);
|
|
11195
|
+
const call = makeToolCallEntry(tool, ctx.timestamp, ctx.parentId, ctx.usage);
|
|
11196
|
+
const result = makeToolResultEntry(tool, ctx.timestamp, call.id);
|
|
11197
|
+
return [call, result];
|
|
11198
|
+
}
|
|
11199
|
+
case "file": {
|
|
11200
|
+
const name = part.filename ?? part.name ?? "attachment";
|
|
11201
|
+
return [
|
|
11202
|
+
makeMessageEntry(ctx.role, `<file omitted: ${name}>`, ctx.timestamp, ctx.parentId, ctx.usage)
|
|
11203
|
+
];
|
|
11204
|
+
}
|
|
11205
|
+
default:
|
|
11206
|
+
return [];
|
|
11207
|
+
}
|
|
11208
|
+
}
|
|
11209
|
+
function buildPiEntries(params) {
|
|
11210
|
+
const sessionUuid = generateUuidV7(params.now);
|
|
11211
|
+
const nowIso = params.now.toISOString();
|
|
11212
|
+
const entries = [
|
|
11213
|
+
{
|
|
11214
|
+
type: "session",
|
|
11215
|
+
version: 3,
|
|
11216
|
+
id: sessionUuid,
|
|
11217
|
+
timestamp: nowIso,
|
|
11218
|
+
cwd: params.session.directory ?? params.session.path ?? process.cwd()
|
|
11219
|
+
},
|
|
11220
|
+
{
|
|
11221
|
+
type: "model_change",
|
|
11222
|
+
id: shortId(),
|
|
11223
|
+
parentId: null,
|
|
11224
|
+
timestamp: nowIso,
|
|
11225
|
+
provider: params.provider,
|
|
11226
|
+
modelId: params.modelId
|
|
11227
|
+
}
|
|
11228
|
+
];
|
|
11229
|
+
const boundary = makeMessageEntry("user", `<!-- migrated from OpenCode session ${params.session.id} at ${nowIso} -->
|
|
11230
|
+
|
|
11231
|
+
The following conversation was migrated from a different harness. Reasoning context from prior turns may be incomplete; tool calls reference tools that may not exist in this environment.`, nowIso, null, {
|
|
11232
|
+
input: 0,
|
|
11233
|
+
output: 0,
|
|
11234
|
+
cacheRead: 0,
|
|
11235
|
+
cacheWrite: 0,
|
|
11236
|
+
totalTokens: 0,
|
|
11237
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
|
|
11238
|
+
});
|
|
11239
|
+
entries.push(boundary);
|
|
11240
|
+
const partsByMessage = new Map;
|
|
11241
|
+
for (const part of params.parts) {
|
|
11242
|
+
const list = partsByMessage.get(part.message_id) ?? [];
|
|
11243
|
+
list.push(part);
|
|
11244
|
+
partsByMessage.set(part.message_id, list);
|
|
11245
|
+
}
|
|
11246
|
+
const messageIdToLastPiEntryId = new Map;
|
|
11247
|
+
const orderedSourceMessageIds = [];
|
|
11248
|
+
let parentId = boundary.id;
|
|
11249
|
+
for (const message of params.messages) {
|
|
11250
|
+
const role = roleFromMessage(message);
|
|
11251
|
+
if (!role)
|
|
11252
|
+
continue;
|
|
11253
|
+
const timestamp = isoFromMs(message.time_created, params.now);
|
|
11254
|
+
const tokens = tokensFromMessage(message);
|
|
11255
|
+
const usage = tokensToPiUsage(tokens);
|
|
11256
|
+
let lastEntryIdForMessage = null;
|
|
11257
|
+
for (const part of partsByMessage.get(message.id) ?? []) {
|
|
11258
|
+
const newEntries = convertPartToEntries({
|
|
11259
|
+
role,
|
|
11260
|
+
row: part,
|
|
11261
|
+
timestamp,
|
|
11262
|
+
parentId,
|
|
11263
|
+
usage
|
|
11264
|
+
});
|
|
11265
|
+
for (const entry of newEntries) {
|
|
11266
|
+
if (entry.parentId === undefined || entry.parentId === parentId)
|
|
11267
|
+
entry.parentId = parentId;
|
|
11268
|
+
entries.push(entry);
|
|
11269
|
+
parentId = entry.id;
|
|
11270
|
+
lastEntryIdForMessage = parentId;
|
|
11271
|
+
}
|
|
11272
|
+
}
|
|
11273
|
+
if (lastEntryIdForMessage !== null) {
|
|
11274
|
+
messageIdToLastPiEntryId.set(message.id, lastEntryIdForMessage);
|
|
11275
|
+
orderedSourceMessageIds.push(message.id);
|
|
11276
|
+
}
|
|
11277
|
+
}
|
|
11278
|
+
return {
|
|
11279
|
+
entries,
|
|
11280
|
+
piSessionId: sessionUuid,
|
|
11281
|
+
messageIdToLastPiEntryId,
|
|
11282
|
+
orderedSourceMessageIds
|
|
11283
|
+
};
|
|
11284
|
+
}
|
|
11285
|
+
function fetchRows(db, sessionId, maxMessages) {
|
|
11286
|
+
const session = stmt(db, "SELECT id, title, directory, path, time_created FROM session WHERE id = ?").get(sessionId);
|
|
11287
|
+
if (!session)
|
|
11288
|
+
throw new Error(`OpenCode session not found: ${sessionId}`);
|
|
11289
|
+
const sourceMessageCount = stmt(db, "SELECT COUNT(*) AS count FROM message WHERE session_id = ?").get(sessionId)?.count ?? 0;
|
|
11290
|
+
const limitClause = maxMessages ? "LIMIT ?" : "";
|
|
11291
|
+
const params = maxMessages ? [sessionId, maxMessages] : [sessionId];
|
|
11292
|
+
const newestFirst = stmt(db, `SELECT id, time_created, data FROM message WHERE session_id = ? ORDER BY time_created DESC, id DESC ${limitClause}`).all(...params);
|
|
11293
|
+
const messages = newestFirst.reverse();
|
|
11294
|
+
const ids = messages.map((row) => row.id);
|
|
11295
|
+
const parts = ids.length ? stmt(db, `SELECT id, message_id, time_created, data FROM part WHERE message_id IN (${ids.map(() => "?").join(",")}) ORDER BY time_created, id`).all(...ids) : [];
|
|
11296
|
+
return { session, sourceMessageCount, messages, parts };
|
|
11297
|
+
}
|
|
11298
|
+
function remapBoundaryId(openCodeMessageId, messageIdToLastPiEntryId, orderedSourceMessageIds) {
|
|
11299
|
+
const direct = messageIdToLastPiEntryId.get(openCodeMessageId);
|
|
11300
|
+
if (direct !== undefined)
|
|
11301
|
+
return { piEntryId: direct, exact: true };
|
|
11302
|
+
let nearestAtOrBefore;
|
|
11303
|
+
for (const id of orderedSourceMessageIds) {
|
|
11304
|
+
if (id <= openCodeMessageId) {
|
|
11305
|
+
nearestAtOrBefore = id;
|
|
11306
|
+
} else {
|
|
11307
|
+
break;
|
|
11308
|
+
}
|
|
11309
|
+
}
|
|
11310
|
+
if (nearestAtOrBefore === undefined)
|
|
11311
|
+
return;
|
|
11312
|
+
const piEntryId = messageIdToLastPiEntryId.get(nearestAtOrBefore);
|
|
11313
|
+
if (piEntryId === undefined)
|
|
11314
|
+
return;
|
|
11315
|
+
return { piEntryId, exact: false };
|
|
11316
|
+
}
|
|
11317
|
+
function insertCompactionMarker(entries, boundaryEntryId) {
|
|
11318
|
+
if (boundaryEntryId === undefined)
|
|
11319
|
+
return { written: false };
|
|
11320
|
+
const boundaryIndex = entries.findIndex((entry) => entry.id === boundaryEntryId);
|
|
11321
|
+
if (boundaryIndex < 0)
|
|
11322
|
+
return { written: false };
|
|
11323
|
+
const firstKept = entries[boundaryIndex + 1];
|
|
11324
|
+
if (!firstKept?.id)
|
|
11325
|
+
return { written: false };
|
|
11326
|
+
const compactedPrefixChars = entries.slice(0, boundaryIndex + 1).reduce((total, entry) => total + JSON.stringify(entry.message ?? "").length, 0);
|
|
11327
|
+
const compactionId = shortId();
|
|
11328
|
+
const marker = {
|
|
11329
|
+
type: "compaction",
|
|
11330
|
+
id: compactionId,
|
|
11331
|
+
parentId: boundaryEntryId,
|
|
11332
|
+
timestamp: String(entries[boundaryIndex].timestamp),
|
|
11333
|
+
summary: MIGRATION_COMPACTION_SUMMARY,
|
|
11334
|
+
firstKeptEntryId: firstKept.id,
|
|
11335
|
+
tokensBefore: Math.ceil(compactedPrefixChars / 4),
|
|
11336
|
+
fromHook: true
|
|
11337
|
+
};
|
|
11338
|
+
firstKept.parentId = compactionId;
|
|
11339
|
+
entries.splice(boundaryIndex + 1, 0, marker);
|
|
11340
|
+
return {
|
|
11341
|
+
written: true,
|
|
11342
|
+
boundaryEntryId,
|
|
11343
|
+
firstKeptEntryId: firstKept.id
|
|
11344
|
+
};
|
|
11345
|
+
}
|
|
11346
|
+
function copyMagicContextState(args) {
|
|
11347
|
+
const sourceCompartments = stmt(args.cortexkitDb, `SELECT sequence, start_message, end_message, start_message_id, end_message_id,
|
|
11348
|
+
title, content, created_at
|
|
11349
|
+
FROM compartments
|
|
11350
|
+
WHERE session_id = ? AND harness = 'opencode'
|
|
11351
|
+
ORDER BY sequence ASC`).all(args.sourceSessionId);
|
|
11352
|
+
const sourceFacts = stmt(args.cortexkitDb, `SELECT category, content, created_at, updated_at
|
|
11353
|
+
FROM session_facts
|
|
11354
|
+
WHERE session_id = ? AND harness = 'opencode'
|
|
11355
|
+
ORDER BY category ASC, id ASC`).all(args.sourceSessionId);
|
|
11356
|
+
let boundariesApproximated = 0;
|
|
11357
|
+
const remappedCompartments = [];
|
|
11358
|
+
for (const c of sourceCompartments) {
|
|
11359
|
+
const startRemap = remapBoundaryId(c.start_message_id, args.messageIdToLastPiEntryId, args.orderedSourceMessageIds);
|
|
11360
|
+
const endRemap = remapBoundaryId(c.end_message_id, args.messageIdToLastPiEntryId, args.orderedSourceMessageIds);
|
|
11361
|
+
if (!startRemap || !endRemap)
|
|
11362
|
+
continue;
|
|
11363
|
+
if (!startRemap.exact || !endRemap.exact)
|
|
11364
|
+
boundariesApproximated++;
|
|
11365
|
+
remappedCompartments.push({
|
|
11366
|
+
sequence: c.sequence,
|
|
11367
|
+
start_message: c.start_message,
|
|
11368
|
+
end_message: c.end_message,
|
|
11369
|
+
start_message_id: startRemap.piEntryId,
|
|
11370
|
+
end_message_id: endRemap.piEntryId,
|
|
11371
|
+
title: c.title,
|
|
11372
|
+
content: c.content
|
|
11373
|
+
});
|
|
11374
|
+
}
|
|
11375
|
+
if (args.dryRun) {
|
|
11376
|
+
return {
|
|
11377
|
+
compartmentsCopied: remappedCompartments.length,
|
|
11378
|
+
factsCopied: sourceFacts.length,
|
|
11379
|
+
boundariesApproximated,
|
|
11380
|
+
lastCompartmentEndPiEntryId: remappedCompartments.at(-1)?.end_message_id
|
|
11381
|
+
};
|
|
11382
|
+
}
|
|
11383
|
+
const insertCompartment = stmt(args.cortexkitDb, `INSERT INTO compartments (
|
|
11384
|
+
session_id, sequence, start_message, end_message,
|
|
11385
|
+
start_message_id, end_message_id, title, content,
|
|
11386
|
+
created_at, harness
|
|
11387
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'pi')`);
|
|
11388
|
+
for (const c of remappedCompartments) {
|
|
11389
|
+
insertCompartment.run(args.piSessionId, c.sequence, c.start_message, c.end_message, c.start_message_id, c.end_message_id, c.title, c.content, args.now);
|
|
11390
|
+
}
|
|
11391
|
+
const insertFact = stmt(args.cortexkitDb, `INSERT INTO session_facts (
|
|
11392
|
+
session_id, category, content, created_at, updated_at, harness
|
|
11393
|
+
) VALUES (?, ?, ?, ?, ?, 'pi')`);
|
|
11394
|
+
for (const f of sourceFacts) {
|
|
11395
|
+
insertFact.run(args.piSessionId, f.category, f.content, f.created_at, f.updated_at);
|
|
11396
|
+
}
|
|
11397
|
+
return {
|
|
11398
|
+
compartmentsCopied: remappedCompartments.length,
|
|
11399
|
+
factsCopied: sourceFacts.length,
|
|
11400
|
+
boundariesApproximated,
|
|
11401
|
+
lastCompartmentEndPiEntryId: remappedCompartments.at(-1)?.end_message_id
|
|
11402
|
+
};
|
|
11403
|
+
}
|
|
11404
|
+
function ensureValidOptions(opts) {
|
|
11405
|
+
if (!opts.from)
|
|
11406
|
+
throw new Error("Missing required flag: --from <opencode>");
|
|
11407
|
+
if (!opts.to)
|
|
11408
|
+
throw new Error("Missing required flag: --to <pi>");
|
|
11409
|
+
if (opts.from !== "opencode" || opts.to !== "pi") {
|
|
11410
|
+
if (opts.from === "pi" && opts.to === "opencode") {
|
|
11411
|
+
throw new Error("Migration pi → opencode is not yet supported (V1 supports only opencode → pi)");
|
|
11412
|
+
}
|
|
11413
|
+
throw new Error(`Unsupported migration: ${opts.from} → ${opts.to} (V1 supports only opencode → pi)`);
|
|
11414
|
+
}
|
|
11415
|
+
if (!opts.session)
|
|
11416
|
+
throw new Error("Missing required flag: --session <id>");
|
|
11417
|
+
if (opts.maxMessages !== undefined && (!Number.isInteger(opts.maxMessages) || opts.maxMessages <= 0)) {
|
|
11418
|
+
throw new Error("--max-messages must be a positive integer");
|
|
11419
|
+
}
|
|
11420
|
+
}
|
|
11421
|
+
function migrateOpenCodeSessionToPi(opts) {
|
|
11422
|
+
const fs2 = opts.fs ?? defaultFs();
|
|
11423
|
+
const now = opts.now ?? new Date;
|
|
11424
|
+
const opencodeDbPath = opts.opencodeDbPath ?? defaultOpenCodeDbPath();
|
|
11425
|
+
const piSessionsRoot = opts.piSessionsRoot ?? defaultPiSessionsRoot();
|
|
11426
|
+
const ownsDb = !opts.db;
|
|
11427
|
+
const db = opts.db ?? new Database(opencodeDbPath, { readonly: true });
|
|
11428
|
+
let cortexkitDb;
|
|
11429
|
+
let ownsCortexkitDb = false;
|
|
11430
|
+
if (opts.cortexkitDb === null) {
|
|
11431
|
+
cortexkitDb = null;
|
|
11432
|
+
} else if (opts.cortexkitDb !== undefined) {
|
|
11433
|
+
cortexkitDb = opts.cortexkitDb;
|
|
11434
|
+
} else {
|
|
11435
|
+
try {
|
|
11436
|
+
cortexkitDb = new Database(defaultCortexkitDbPath());
|
|
11437
|
+
ownsCortexkitDb = true;
|
|
11438
|
+
} catch {
|
|
11439
|
+
cortexkitDb = null;
|
|
11440
|
+
}
|
|
11441
|
+
}
|
|
11442
|
+
try {
|
|
11443
|
+
const { session, sourceMessageCount, messages, parts } = fetchRows(db, opts.sessionId, opts.maxMessages);
|
|
11444
|
+
const model = extractModel(messages);
|
|
11445
|
+
const provider = opts.provider ?? model.provider;
|
|
11446
|
+
const modelId = opts.modelId ?? model.modelId;
|
|
11447
|
+
const cwd = session.directory ?? session.path ?? process.cwd();
|
|
11448
|
+
const outputDir = join11(piSessionsRoot, projectPathToPiDirSlug(cwd));
|
|
11449
|
+
const buildResult = buildPiEntries({
|
|
11450
|
+
session,
|
|
11451
|
+
messages,
|
|
11452
|
+
parts,
|
|
11453
|
+
now,
|
|
11454
|
+
provider,
|
|
11455
|
+
modelId
|
|
11456
|
+
});
|
|
11457
|
+
let copyResult = {
|
|
11458
|
+
compartmentsCopied: 0,
|
|
11459
|
+
factsCopied: 0,
|
|
11460
|
+
boundariesApproximated: 0
|
|
11461
|
+
};
|
|
11462
|
+
if (cortexkitDb !== null) {
|
|
11463
|
+
copyResult = copyMagicContextState({
|
|
11464
|
+
cortexkitDb,
|
|
11465
|
+
sourceSessionId: session.id,
|
|
11466
|
+
piSessionId: buildResult.piSessionId,
|
|
11467
|
+
messageIdToLastPiEntryId: buildResult.messageIdToLastPiEntryId,
|
|
11468
|
+
orderedSourceMessageIds: buildResult.orderedSourceMessageIds,
|
|
11469
|
+
now: now.getTime(),
|
|
11470
|
+
dryRun: Boolean(opts.dryRun)
|
|
11471
|
+
});
|
|
11472
|
+
}
|
|
11473
|
+
const compactionMarker = insertCompactionMarker(buildResult.entries, copyResult.lastCompartmentEndPiEntryId);
|
|
11474
|
+
const outputPath = join11(outputDir, `${formatPiFilenameTimestamp(now)}_${buildResult.piSessionId}.jsonl`);
|
|
11475
|
+
const jsonl = `${buildResult.entries.map((entry) => JSON.stringify(entry)).join(`
|
|
11476
|
+
`)}
|
|
11477
|
+
`;
|
|
11478
|
+
if (!opts.dryRun) {
|
|
11479
|
+
if (!fs2.existsSync(outputDir))
|
|
11480
|
+
fs2.mkdirSync(outputDir, { recursive: true });
|
|
11481
|
+
fs2.writeFileSync(outputPath, jsonl);
|
|
11482
|
+
}
|
|
11483
|
+
return {
|
|
11484
|
+
outputPath,
|
|
11485
|
+
piSessionId: buildResult.piSessionId,
|
|
11486
|
+
messageCount: buildResult.entries.length - 2,
|
|
11487
|
+
byteCount: Buffer.byteLength(jsonl, "utf8"),
|
|
11488
|
+
sourceMessageCount,
|
|
11489
|
+
compartmentsCopied: copyResult.compartmentsCopied,
|
|
11490
|
+
factsCopied: copyResult.factsCopied,
|
|
11491
|
+
boundariesApproximated: copyResult.boundariesApproximated,
|
|
11492
|
+
compactionMarkerWritten: compactionMarker.written,
|
|
11493
|
+
compactionBoundaryEntryId: compactionMarker.boundaryEntryId,
|
|
11494
|
+
compactionFirstKeptEntryId: compactionMarker.firstKeptEntryId,
|
|
11495
|
+
dryRun: Boolean(opts.dryRun)
|
|
11496
|
+
};
|
|
11497
|
+
} finally {
|
|
11498
|
+
if (ownsDb)
|
|
11499
|
+
db.close();
|
|
11500
|
+
if (ownsCortexkitDb && cortexkitDb !== null)
|
|
11501
|
+
cortexkitDb.close();
|
|
11502
|
+
}
|
|
11503
|
+
}
|
|
11504
|
+
function parseMigrateArgs(args) {
|
|
11505
|
+
const opts = {};
|
|
11506
|
+
for (let i = 0;i < args.length; i++) {
|
|
11507
|
+
const arg = args[i];
|
|
11508
|
+
const readValue = (flag) => {
|
|
11509
|
+
const value = args[++i];
|
|
11510
|
+
if (!value || value.startsWith("--"))
|
|
11511
|
+
throw new Error(`Missing value for ${flag}`);
|
|
11512
|
+
return value;
|
|
11513
|
+
};
|
|
11514
|
+
if (arg === "--from")
|
|
11515
|
+
opts.from = readValue(arg);
|
|
11516
|
+
else if (arg === "--to")
|
|
11517
|
+
opts.to = readValue(arg);
|
|
11518
|
+
else if (arg === "--session")
|
|
11519
|
+
opts.session = readValue(arg);
|
|
11520
|
+
else if (arg === "--max-messages")
|
|
11521
|
+
opts.maxMessages = Number(readValue(arg));
|
|
11522
|
+
else if (arg === "--dry-run")
|
|
11523
|
+
opts.dryRun = true;
|
|
11524
|
+
else if (arg === "--help" || arg === "-h")
|
|
11525
|
+
throw new Error("HELP");
|
|
11526
|
+
else
|
|
11527
|
+
throw new Error(`Unknown migrate flag: ${arg}`);
|
|
11528
|
+
}
|
|
11529
|
+
return opts;
|
|
11530
|
+
}
|
|
11531
|
+
function printMigrateHelp() {
|
|
11532
|
+
console.log(`
|
|
11533
|
+
Magic Context doctor migrate
|
|
11534
|
+
─────────────────────────────
|
|
11535
|
+
|
|
11536
|
+
Copy OpenCode session message content into a new Pi JSONL session,
|
|
11537
|
+
PLUS the source session's Magic Context state (compartments + facts)
|
|
11538
|
+
into the shared cortexkit database under the new Pi session id.
|
|
11539
|
+
|
|
11540
|
+
Supported pairs (V1):
|
|
11541
|
+
--from opencode --to pi
|
|
11542
|
+
|
|
11543
|
+
Usage:
|
|
11544
|
+
bunx --bun @cortexkit/opencode-magic-context@latest doctor migrate \\
|
|
11545
|
+
--from opencode --to pi --session ses_xxx [--max-messages N] [--dry-run]
|
|
11546
|
+
|
|
11547
|
+
Fidelity:
|
|
11548
|
+
- text, reasoning text, tool calls, and tool results are preserved
|
|
11549
|
+
- assistant 'usage' fields carry real input/output/cache token counts
|
|
11550
|
+
from the source so Pi's getContextUsage() reports realistic numbers
|
|
11551
|
+
- reasoning signatures are stripped; step-start/step-finish are skipped
|
|
11552
|
+
- file bytes are replaced with <file omitted: name> markers
|
|
11553
|
+
- compartments + session_facts are copied to the new Pi session_id;
|
|
11554
|
+
compartment boundary message IDs are remapped to the corresponding
|
|
11555
|
+
Pi entry IDs (nearest-at-or-before for boundaries that don't have
|
|
11556
|
+
a direct message-level Pi entry)
|
|
11557
|
+
`);
|
|
11558
|
+
}
|
|
11559
|
+
async function runMigrateCli(args) {
|
|
11560
|
+
try {
|
|
11561
|
+
const parsed = parseMigrateArgs(args);
|
|
11562
|
+
ensureValidOptions(parsed);
|
|
11563
|
+
const result = migrateOpenCodeSessionToPi({
|
|
11564
|
+
sessionId: parsed.session,
|
|
11565
|
+
maxMessages: parsed.maxMessages,
|
|
11566
|
+
dryRun: parsed.dryRun
|
|
11567
|
+
});
|
|
11568
|
+
const action = result.dryRun ? "Would write" : "Wrote";
|
|
11569
|
+
console.log(`${action} Pi session JSONL:`);
|
|
11570
|
+
console.log(` path: ${result.outputPath}`);
|
|
11571
|
+
console.log(` pi session id: ${result.piSessionId}`);
|
|
11572
|
+
console.log(` source messages: ${result.sourceMessageCount}`);
|
|
11573
|
+
console.log(` migrated entries: ${result.messageCount}`);
|
|
11574
|
+
console.log(` bytes: ${result.byteCount}`);
|
|
11575
|
+
console.log(` compartments copied: ${result.compartmentsCopied}`);
|
|
11576
|
+
console.log(` session facts copied: ${result.factsCopied}`);
|
|
11577
|
+
console.log(` compaction marker: ${result.compactionMarkerWritten ? "yes" : "no"}${result.compactionMarkerWritten ? ` (boundary: ${result.compactionBoundaryEntryId}, first kept: ${result.compactionFirstKeptEntryId})` : ""}`);
|
|
11578
|
+
if (result.boundariesApproximated > 0) {
|
|
11579
|
+
console.log(` boundaries approximated: ${result.boundariesApproximated} (nearest-at-or-before)`);
|
|
11580
|
+
}
|
|
11581
|
+
if (!result.dryRun) {
|
|
11582
|
+
console.log("Pi may need to be restarted to pick up the new session file.");
|
|
11583
|
+
}
|
|
11584
|
+
return 0;
|
|
11585
|
+
} catch (error) {
|
|
11586
|
+
if (error instanceof Error && error.message === "HELP") {
|
|
11587
|
+
printMigrateHelp();
|
|
11588
|
+
return 0;
|
|
11589
|
+
}
|
|
11590
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
11591
|
+
console.error("Run `doctor migrate --help` for usage.");
|
|
11592
|
+
return 1;
|
|
11593
|
+
}
|
|
11594
|
+
}
|
|
11595
|
+
|
|
10968
11596
|
// src/cli/setup.ts
|
|
10969
11597
|
var import_comment_json4 = __toESM(require_src2(), 1);
|
|
10970
|
-
import { existsSync as
|
|
11598
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "node:fs";
|
|
10971
11599
|
import { dirname as dirname4 } from "node:path";
|
|
10972
11600
|
var PLUGIN_NAME4 = "@cortexkit/opencode-magic-context";
|
|
10973
11601
|
var PLUGIN_ENTRY2 = "@cortexkit/opencode-magic-context@latest";
|
|
10974
11602
|
function ensureDir(dir) {
|
|
10975
|
-
if (!
|
|
10976
|
-
|
|
11603
|
+
if (!existsSync9(dir)) {
|
|
11604
|
+
mkdirSync4(dir, { recursive: true });
|
|
10977
11605
|
}
|
|
10978
11606
|
}
|
|
10979
11607
|
function readJsonc(path3) {
|
|
@@ -10992,7 +11620,7 @@ function addPluginToOpenCodeConfig(configPath, format) {
|
|
|
10992
11620
|
plugin: [PLUGIN_ENTRY2],
|
|
10993
11621
|
compaction: { auto: false, prune: false }
|
|
10994
11622
|
};
|
|
10995
|
-
|
|
11623
|
+
writeFileSync6(configPath, `${import_comment_json4.stringify(config, null, 2)}
|
|
10996
11624
|
`);
|
|
10997
11625
|
return;
|
|
10998
11626
|
}
|
|
@@ -11011,13 +11639,13 @@ function addPluginToOpenCodeConfig(configPath, format) {
|
|
|
11011
11639
|
compaction.auto = false;
|
|
11012
11640
|
compaction.prune = false;
|
|
11013
11641
|
existing.compaction = compaction;
|
|
11014
|
-
|
|
11642
|
+
writeFileSync6(configPath, `${import_comment_json4.stringify(existing, null, 2)}
|
|
11015
11643
|
`);
|
|
11016
11644
|
}
|
|
11017
11645
|
function addPluginToTuiConfig(configPath, format) {
|
|
11018
11646
|
ensureDir(dirname4(configPath));
|
|
11019
11647
|
if (format === "none") {
|
|
11020
|
-
|
|
11648
|
+
writeFileSync6(configPath, `${import_comment_json4.stringify({ plugin: [PLUGIN_ENTRY2] }, null, 2)}
|
|
11021
11649
|
`);
|
|
11022
11650
|
return;
|
|
11023
11651
|
}
|
|
@@ -11032,13 +11660,13 @@ function addPluginToTuiConfig(configPath, format) {
|
|
|
11032
11660
|
plugins.push(PLUGIN_ENTRY2);
|
|
11033
11661
|
}
|
|
11034
11662
|
existing.plugin = plugins;
|
|
11035
|
-
|
|
11663
|
+
writeFileSync6(configPath, `${import_comment_json4.stringify(existing, null, 2)}
|
|
11036
11664
|
`);
|
|
11037
11665
|
}
|
|
11038
11666
|
function writeMagicContextConfig(configPath, options) {
|
|
11039
|
-
const config = (
|
|
11667
|
+
const config = (existsSync9(configPath) ? readJsonc(configPath) : null) ?? {};
|
|
11040
11668
|
if (!config.$schema) {
|
|
11041
|
-
config.$schema = "https://raw.githubusercontent.com/cortexkit/
|
|
11669
|
+
config.$schema = "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json";
|
|
11042
11670
|
}
|
|
11043
11671
|
if (options.historianModel) {
|
|
11044
11672
|
const historian = config.historian ?? {};
|
|
@@ -11073,7 +11701,7 @@ function writeMagicContextConfig(configPath, options) {
|
|
|
11073
11701
|
cacheTtl["anthropic/claude-opus-4-6"] = "59m";
|
|
11074
11702
|
config.cache_ttl = cacheTtl;
|
|
11075
11703
|
}
|
|
11076
|
-
|
|
11704
|
+
writeFileSync6(configPath, `${import_comment_json4.stringify(config, null, 2)}
|
|
11077
11705
|
`);
|
|
11078
11706
|
}
|
|
11079
11707
|
async function runSetup() {
|
|
@@ -11102,7 +11730,7 @@ async function runSetup() {
|
|
|
11102
11730
|
R2.warn("You can configure models manually in magic-context.jsonc later");
|
|
11103
11731
|
}
|
|
11104
11732
|
const paths = detectConfigPaths();
|
|
11105
|
-
const hadExistingSetup = paths.opencodeConfigFormat !== "none" ||
|
|
11733
|
+
const hadExistingSetup = paths.opencodeConfigFormat !== "none" || existsSync9(paths.magicContextConfig) || paths.tuiConfigFormat !== "none";
|
|
11106
11734
|
addPluginToOpenCodeConfig(paths.opencodeConfig, paths.opencodeConfigFormat);
|
|
11107
11735
|
R2.success(`Plugin added to ${paths.opencodeConfig}`);
|
|
11108
11736
|
R2.info("Disabled built-in compaction (auto=false, prune=false)");
|
|
@@ -11120,7 +11748,7 @@ async function runSetup() {
|
|
|
11120
11748
|
if (shouldRemove) {
|
|
11121
11749
|
plugins.splice(dcpIndex, 1);
|
|
11122
11750
|
ocConfig.plugin = plugins;
|
|
11123
|
-
|
|
11751
|
+
writeFileSync6(paths.opencodeConfig, `${import_comment_json4.stringify(ocConfig, null, 2)}
|
|
11124
11752
|
`);
|
|
11125
11753
|
R2.success("Removed opencode-dcp from plugin list");
|
|
11126
11754
|
} else {
|
|
@@ -11248,11 +11876,14 @@ async function runSetup() {
|
|
|
11248
11876
|
if (shouldStar) {
|
|
11249
11877
|
try {
|
|
11250
11878
|
const { execSync: execSync3 } = await import("node:child_process");
|
|
11251
|
-
execSync3("gh api --silent --method PUT /user/starred/cortexkit/
|
|
11879
|
+
execSync3("gh api --silent --method PUT /user/starred/cortexkit/magic-context", {
|
|
11880
|
+
stdio: "ignore",
|
|
11881
|
+
timeout: 1e4
|
|
11882
|
+
});
|
|
11252
11883
|
R2.success("Thanks for starring! ★");
|
|
11253
11884
|
} catch {
|
|
11254
11885
|
R2.info(`Couldn't star automatically. You can star manually:
|
|
11255
|
-
https://github.com/cortexkit/
|
|
11886
|
+
https://github.com/cortexkit/magic-context`);
|
|
11256
11887
|
}
|
|
11257
11888
|
}
|
|
11258
11889
|
Gt("Run 'opencode' to start!");
|
|
@@ -11264,9 +11895,13 @@ var command = process.argv[2];
|
|
|
11264
11895
|
if (command === "setup") {
|
|
11265
11896
|
runSetup().then((code) => process.exit(code));
|
|
11266
11897
|
} else if (command === "doctor") {
|
|
11267
|
-
|
|
11268
|
-
|
|
11269
|
-
|
|
11898
|
+
if (process.argv[3] === "migrate") {
|
|
11899
|
+
runMigrateCli(process.argv.slice(4)).then((code) => process.exit(code));
|
|
11900
|
+
} else {
|
|
11901
|
+
const force = process.argv.includes("--force");
|
|
11902
|
+
const issue = process.argv.includes("--issue");
|
|
11903
|
+
runDoctor({ force, issue }).then((code) => process.exit(code));
|
|
11904
|
+
}
|
|
11270
11905
|
} else {
|
|
11271
11906
|
console.log("");
|
|
11272
11907
|
console.log(" Magic Context CLI");
|
|
@@ -11277,11 +11912,13 @@ if (command === "setup") {
|
|
|
11277
11912
|
console.log(" doctor Check and fix configuration issues");
|
|
11278
11913
|
console.log(" doctor --force Force clear plugin cache (fixes broken dependencies)");
|
|
11279
11914
|
console.log(" doctor --issue Collect diagnostics and open a GitHub issue");
|
|
11915
|
+
console.log(" doctor migrate Migrate OpenCode session content to Pi JSONL");
|
|
11280
11916
|
console.log("");
|
|
11281
11917
|
console.log(" Usage:");
|
|
11282
11918
|
console.log(" bunx --bun @cortexkit/opencode-magic-context@latest setup");
|
|
11283
11919
|
console.log(" bunx --bun @cortexkit/opencode-magic-context@latest doctor");
|
|
11284
11920
|
console.log(" bunx --bun @cortexkit/opencode-magic-context@latest doctor --issue");
|
|
11921
|
+
console.log(" bunx --bun @cortexkit/opencode-magic-context@latest doctor migrate --from opencode --to pi --session ses_xxx --dry-run");
|
|
11285
11922
|
console.log("");
|
|
11286
11923
|
process.exit(command ? 1 : 0);
|
|
11287
11924
|
}
|