@cortexkit/pi-magic-context 0.19.0 → 0.20.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 +2 -2
- package/dist/index.js +1776 -756
- package/dist/subagent-entry.js +411 -80
- package/package.json +6 -6
package/dist/subagent-entry.js
CHANGED
|
@@ -23808,10 +23808,10 @@ var require_stringify = __commonJS((exports, module) => {
|
|
|
23808
23808
|
replacer = null;
|
|
23809
23809
|
indent = EMPTY;
|
|
23810
23810
|
};
|
|
23811
|
-
var
|
|
23811
|
+
var join7 = (one, two, gap) => one ? two ? one + two.trim() + LF + gap : one.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(one, gap)), gap) : two ? two.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(two, gap)), gap) : EMPTY;
|
|
23812
23812
|
var join_content = (inside, value, gap) => {
|
|
23813
23813
|
const comment = process_comments(value, PREFIX_BEFORE, gap + indent, true);
|
|
23814
|
-
return
|
|
23814
|
+
return join7(comment, inside, gap);
|
|
23815
23815
|
};
|
|
23816
23816
|
var stringify_string = (holder, key, value) => {
|
|
23817
23817
|
const raw = get_raw_string_literal(holder, key);
|
|
@@ -23833,13 +23833,13 @@ var require_stringify = __commonJS((exports, module) => {
|
|
|
23833
23833
|
if (i !== 0) {
|
|
23834
23834
|
inside += COMMA;
|
|
23835
23835
|
}
|
|
23836
|
-
const before =
|
|
23836
|
+
const before = join7(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
|
|
23837
23837
|
inside += before || LF + deeper_gap;
|
|
23838
23838
|
inside += stringify(i, value, deeper_gap) || STR_NULL;
|
|
23839
23839
|
inside += process_comments(value, AFTER_VALUE(i), deeper_gap);
|
|
23840
23840
|
after_comma = process_comments(value, AFTER(i), deeper_gap);
|
|
23841
23841
|
}
|
|
23842
|
-
inside +=
|
|
23842
|
+
inside += join7(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
|
|
23843
23843
|
return BRACKET_OPEN + join_content(inside, value, gap) + BRACKET_CLOSE;
|
|
23844
23844
|
};
|
|
23845
23845
|
var object_stringify = (value, gap) => {
|
|
@@ -23860,13 +23860,13 @@ var require_stringify = __commonJS((exports, module) => {
|
|
|
23860
23860
|
inside += COMMA;
|
|
23861
23861
|
}
|
|
23862
23862
|
first = false;
|
|
23863
|
-
const before =
|
|
23863
|
+
const before = join7(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
|
|
23864
23864
|
inside += before || LF + deeper_gap;
|
|
23865
23865
|
inside += quote(key) + process_comments(value, AFTER_PROP(key), deeper_gap) + COLON + process_comments(value, AFTER_COLON(key), deeper_gap) + SPACE + sv + process_comments(value, AFTER_VALUE(key), deeper_gap);
|
|
23866
23866
|
after_comma = process_comments(value, AFTER(key), deeper_gap);
|
|
23867
23867
|
};
|
|
23868
23868
|
keys.forEach(iteratee);
|
|
23869
|
-
inside +=
|
|
23869
|
+
inside += join7(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
|
|
23870
23870
|
return CURLY_BRACKET_OPEN + join_content(inside, value, gap) + CURLY_BRACKET_CLOSE;
|
|
23871
23871
|
};
|
|
23872
23872
|
function stringify(key, holder, gap) {
|
|
@@ -23959,17 +23959,9 @@ var require_src2 = __commonJS((exports, module) => {
|
|
|
23959
23959
|
});
|
|
23960
23960
|
|
|
23961
23961
|
// ../plugin/src/hooks/magic-context/read-session-db.ts
|
|
23962
|
-
|
|
23963
|
-
__export(exports_read_session_db, {
|
|
23964
|
-
withReadOnlySessionDb: () => withReadOnlySessionDb,
|
|
23965
|
-
getRawSessionMessageCountFromDb: () => getRawSessionMessageCountFromDb,
|
|
23966
|
-
getMessageTimesFromOpenCodeDb: () => getMessageTimesFromOpenCodeDb,
|
|
23967
|
-
findLastAssistantModelFromOpenCodeDb: () => findLastAssistantModelFromOpenCodeDb,
|
|
23968
|
-
closeReadOnlySessionDb: () => closeReadOnlySessionDb
|
|
23969
|
-
});
|
|
23970
|
-
import { join as join7 } from "node:path";
|
|
23962
|
+
import { join as join8 } from "node:path";
|
|
23971
23963
|
function getOpenCodeDbPath() {
|
|
23972
|
-
return
|
|
23964
|
+
return join8(getDataDir(), "opencode", "opencode.db");
|
|
23973
23965
|
}
|
|
23974
23966
|
function closeCachedReadOnlyDb() {
|
|
23975
23967
|
if (!cachedReadOnlyDb) {
|
|
@@ -23996,9 +23988,6 @@ function getReadOnlySessionDb() {
|
|
|
23996
23988
|
function withReadOnlySessionDb(fn) {
|
|
23997
23989
|
return fn(getReadOnlySessionDb());
|
|
23998
23990
|
}
|
|
23999
|
-
function closeReadOnlySessionDb() {
|
|
24000
|
-
closeCachedReadOnlyDb();
|
|
24001
|
-
}
|
|
24002
23991
|
function getRawSessionMessageCountFromDb(db, sessionId) {
|
|
24003
23992
|
const row = db.prepare(`SELECT COUNT(*) as count FROM message WHERE session_id = ?
|
|
24004
23993
|
AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
|
|
@@ -24024,34 +24013,6 @@ function getMessageTimesFromOpenCodeDb(sessionId, messageIds) {
|
|
|
24024
24013
|
}
|
|
24025
24014
|
return result;
|
|
24026
24015
|
}
|
|
24027
|
-
function findLastAssistantModelFromOpenCodeDb(sessionId) {
|
|
24028
|
-
try {
|
|
24029
|
-
return withReadOnlySessionDb((db) => {
|
|
24030
|
-
const row = db.prepare(`SELECT json_extract(data, '$.providerID') as providerID,
|
|
24031
|
-
json_extract(data, '$.modelID') as modelID,
|
|
24032
|
-
json_extract(data, '$.agent') as agent
|
|
24033
|
-
FROM message
|
|
24034
|
-
WHERE session_id = ?
|
|
24035
|
-
AND json_extract(data, '$.role') = 'assistant'
|
|
24036
|
-
AND json_extract(data, '$.providerID') IS NOT NULL
|
|
24037
|
-
AND json_extract(data, '$.modelID') IS NOT NULL
|
|
24038
|
-
ORDER BY time_created DESC
|
|
24039
|
-
LIMIT 1`).get(sessionId);
|
|
24040
|
-
if (!row || typeof row.providerID !== "string" || typeof row.modelID !== "string") {
|
|
24041
|
-
return null;
|
|
24042
|
-
}
|
|
24043
|
-
const agent = typeof row.agent === "string" && row.agent.length > 0 ? row.agent : undefined;
|
|
24044
|
-
return {
|
|
24045
|
-
providerID: row.providerID,
|
|
24046
|
-
modelID: row.modelID,
|
|
24047
|
-
...agent ? { agent } : {}
|
|
24048
|
-
};
|
|
24049
|
-
});
|
|
24050
|
-
} catch (error51) {
|
|
24051
|
-
log("[magic-context] failed to recover live model from OpenCode DB:", error51);
|
|
24052
|
-
return null;
|
|
24053
|
-
}
|
|
24054
|
-
}
|
|
24055
24016
|
var cachedReadOnlyDb = null;
|
|
24056
24017
|
var init_read_session_db = __esm(async () => {
|
|
24057
24018
|
init_data_path();
|
|
@@ -24064,8 +24025,8 @@ init_embedding();
|
|
|
24064
24025
|
|
|
24065
24026
|
// ../plugin/src/features/magic-context/storage-db.ts
|
|
24066
24027
|
init_data_path();
|
|
24067
|
-
import { copyFileSync, cpSync, existsSync as
|
|
24068
|
-
import { join as
|
|
24028
|
+
import { copyFileSync, cpSync, existsSync as existsSync4, mkdirSync as mkdirSync4 } from "node:fs";
|
|
24029
|
+
import { join as join6 } from "node:path";
|
|
24069
24030
|
|
|
24070
24031
|
// ../plugin/src/shared/error-message.ts
|
|
24071
24032
|
function getErrorMessage(error51) {
|
|
@@ -24147,6 +24108,119 @@ function safeString(value) {
|
|
|
24147
24108
|
init_logger();
|
|
24148
24109
|
await init_sqlite();
|
|
24149
24110
|
|
|
24111
|
+
// ../plugin/src/features/magic-context/key-files/project-key-files.ts
|
|
24112
|
+
init_logger();
|
|
24113
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
24114
|
+
import { existsSync as existsSync2, readFileSync, realpathSync } from "node:fs";
|
|
24115
|
+
import { join as join4, resolve, sep } from "node:path";
|
|
24116
|
+
var MISSING_CONTENT_HASH = "<missing>";
|
|
24117
|
+
var ORPHAN_GRACE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
24118
|
+
function sha256(input) {
|
|
24119
|
+
return createHash2("sha256").update(input).digest("hex");
|
|
24120
|
+
}
|
|
24121
|
+
function resolveProjectPath(directory) {
|
|
24122
|
+
if (!directory?.trim())
|
|
24123
|
+
return null;
|
|
24124
|
+
try {
|
|
24125
|
+
return realpathSync(directory);
|
|
24126
|
+
} catch {
|
|
24127
|
+
return resolve(directory);
|
|
24128
|
+
}
|
|
24129
|
+
}
|
|
24130
|
+
function rowToProjectKeyFile(row) {
|
|
24131
|
+
return {
|
|
24132
|
+
projectPath: String(row.project_path),
|
|
24133
|
+
path: String(row.path),
|
|
24134
|
+
content: String(row.content),
|
|
24135
|
+
contentHash: String(row.content_hash),
|
|
24136
|
+
localTokenEstimate: Number(row.local_token_estimate),
|
|
24137
|
+
generatedAt: Number(row.generated_at),
|
|
24138
|
+
generatedByModel: row.generated_by_model == null ? null : String(row.generated_by_model),
|
|
24139
|
+
generationConfigHash: String(row.generation_config_hash),
|
|
24140
|
+
staleReason: row.stale_reason == null ? null : String(row.stale_reason)
|
|
24141
|
+
};
|
|
24142
|
+
}
|
|
24143
|
+
function readCurrentKeyFiles(db, projectPath) {
|
|
24144
|
+
const resolvedProjectPath = resolveProjectPath(projectPath) ?? projectPath;
|
|
24145
|
+
const rows = db.prepare(`SELECT project_path, path, content, content_hash, local_token_estimate,
|
|
24146
|
+
generated_at, generated_by_model, generation_config_hash, stale_reason
|
|
24147
|
+
FROM project_key_files
|
|
24148
|
+
WHERE project_path = ?
|
|
24149
|
+
ORDER BY generated_at DESC, path ASC`).all(resolvedProjectPath);
|
|
24150
|
+
return rows.map(rowToProjectKeyFile);
|
|
24151
|
+
}
|
|
24152
|
+
function getKeyFilesVersion(db, projectPath) {
|
|
24153
|
+
const resolvedProjectPath = resolveProjectPath(projectPath) ?? projectPath;
|
|
24154
|
+
const row = db.prepare("SELECT version FROM project_key_files_version WHERE project_path = ?").get(resolvedProjectPath);
|
|
24155
|
+
return Number(row?.version ?? 0);
|
|
24156
|
+
}
|
|
24157
|
+
function bumpKeyFilesVersion(db, projectPath) {
|
|
24158
|
+
const resolvedProjectPath = resolveProjectPath(projectPath) ?? projectPath;
|
|
24159
|
+
db.prepare(`INSERT INTO project_key_files_version (project_path, version)
|
|
24160
|
+
VALUES (?, 1)
|
|
24161
|
+
ON CONFLICT(project_path) DO UPDATE SET version = version + 1`).run(resolvedProjectPath);
|
|
24162
|
+
return getKeyFilesVersion(db, resolvedProjectPath);
|
|
24163
|
+
}
|
|
24164
|
+
function resolveCommitFiles(projectPath, files) {
|
|
24165
|
+
return files.map((file2) => {
|
|
24166
|
+
try {
|
|
24167
|
+
const disk = readFileSync(join4(projectPath, file2.path));
|
|
24168
|
+
return {
|
|
24169
|
+
...file2,
|
|
24170
|
+
contentHash: sha256(disk),
|
|
24171
|
+
staleReason: null
|
|
24172
|
+
};
|
|
24173
|
+
} catch {
|
|
24174
|
+
return {
|
|
24175
|
+
...file2,
|
|
24176
|
+
contentHash: MISSING_CONTENT_HASH,
|
|
24177
|
+
staleReason: "missing"
|
|
24178
|
+
};
|
|
24179
|
+
}
|
|
24180
|
+
});
|
|
24181
|
+
}
|
|
24182
|
+
function insertResolvedKeyFiles(db, projectPath, files, generatedAt, generatedByModel, generationConfigHash) {
|
|
24183
|
+
const insert = db.prepare(`INSERT INTO project_key_files
|
|
24184
|
+
(project_path, path, content, content_hash, local_token_estimate,
|
|
24185
|
+
generated_at, generated_by_model, generation_config_hash, stale_reason)
|
|
24186
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
24187
|
+
for (const file2 of files) {
|
|
24188
|
+
insert.run(projectPath, file2.path, file2.content, file2.contentHash, file2.localTokenEstimate, generatedAt, generatedByModel, generationConfigHash, file2.staleReason);
|
|
24189
|
+
}
|
|
24190
|
+
}
|
|
24191
|
+
function deleteOrphanProjectKeyFiles(db, now = Date.now()) {
|
|
24192
|
+
const cutoff = now - ORPHAN_GRACE_MS;
|
|
24193
|
+
const rows = db.prepare(`SELECT project_path AS projectPath, MAX(generated_at) AS lastGen
|
|
24194
|
+
FROM project_key_files
|
|
24195
|
+
GROUP BY project_path
|
|
24196
|
+
HAVING lastGen < ?`).all(cutoff);
|
|
24197
|
+
let deletedProjects = 0;
|
|
24198
|
+
for (const row of rows) {
|
|
24199
|
+
if (existsSync2(row.projectPath))
|
|
24200
|
+
continue;
|
|
24201
|
+
try {
|
|
24202
|
+
db.prepare("DELETE FROM project_key_files WHERE project_path = ?").run(row.projectPath);
|
|
24203
|
+
db.prepare("DELETE FROM project_key_files_version WHERE project_path = ?").run(row.projectPath);
|
|
24204
|
+
deletedProjects++;
|
|
24205
|
+
} catch (error51) {
|
|
24206
|
+
log(`[key-files] orphan GC failed for ${row.projectPath}:`, error51);
|
|
24207
|
+
}
|
|
24208
|
+
}
|
|
24209
|
+
return deletedProjects;
|
|
24210
|
+
}
|
|
24211
|
+
function isRelativeProjectFile(projectPath, relativePath) {
|
|
24212
|
+
if (!relativePath || relativePath.startsWith("/") || relativePath.includes(".."))
|
|
24213
|
+
return false;
|
|
24214
|
+
try {
|
|
24215
|
+
const root = realpathSync(projectPath);
|
|
24216
|
+
const absPath = resolve(projectPath, relativePath);
|
|
24217
|
+
const real = realpathSync(absPath);
|
|
24218
|
+
return real.startsWith(root + sep) || real === root;
|
|
24219
|
+
} catch {
|
|
24220
|
+
return false;
|
|
24221
|
+
}
|
|
24222
|
+
}
|
|
24223
|
+
|
|
24150
24224
|
// ../plugin/src/features/magic-context/migrations.ts
|
|
24151
24225
|
init_logger();
|
|
24152
24226
|
var MIGRATIONS = [
|
|
@@ -24447,6 +24521,46 @@ var MIGRATIONS = [
|
|
|
24447
24521
|
db.exec("ALTER TABLE session_meta ADD COLUMN pending_compaction_marker_state TEXT");
|
|
24448
24522
|
}
|
|
24449
24523
|
}
|
|
24524
|
+
},
|
|
24525
|
+
{
|
|
24526
|
+
version: 14,
|
|
24527
|
+
description: "Add project-scoped key files and version counter",
|
|
24528
|
+
up: (db) => {
|
|
24529
|
+
db.exec(`
|
|
24530
|
+
CREATE TABLE IF NOT EXISTS project_key_files (
|
|
24531
|
+
project_path TEXT NOT NULL,
|
|
24532
|
+
path TEXT NOT NULL,
|
|
24533
|
+
content TEXT NOT NULL,
|
|
24534
|
+
content_hash TEXT NOT NULL,
|
|
24535
|
+
local_token_estimate INTEGER NOT NULL,
|
|
24536
|
+
generated_at INTEGER NOT NULL,
|
|
24537
|
+
generated_by_model TEXT,
|
|
24538
|
+
generation_config_hash TEXT NOT NULL,
|
|
24539
|
+
stale_reason TEXT,
|
|
24540
|
+
PRIMARY KEY (project_path, path)
|
|
24541
|
+
);
|
|
24542
|
+
|
|
24543
|
+
CREATE INDEX IF NOT EXISTS idx_project_key_files_project
|
|
24544
|
+
ON project_key_files(project_path);
|
|
24545
|
+
CREATE INDEX IF NOT EXISTS idx_project_key_files_generated_at
|
|
24546
|
+
ON project_key_files(project_path, generated_at);
|
|
24547
|
+
|
|
24548
|
+
CREATE TABLE IF NOT EXISTS project_key_files_version (
|
|
24549
|
+
project_path TEXT PRIMARY KEY,
|
|
24550
|
+
version INTEGER NOT NULL DEFAULT 0
|
|
24551
|
+
);
|
|
24552
|
+
`);
|
|
24553
|
+
}
|
|
24554
|
+
},
|
|
24555
|
+
{
|
|
24556
|
+
version: 15,
|
|
24557
|
+
description: "Add deferred_execute_state column for boundary execution drain",
|
|
24558
|
+
up: (db) => {
|
|
24559
|
+
const cols = db.prepare("PRAGMA table_info(session_meta)").all();
|
|
24560
|
+
if (!cols.some((c) => c.name === "deferred_execute_state")) {
|
|
24561
|
+
db.exec("ALTER TABLE session_meta ADD COLUMN deferred_execute_state TEXT");
|
|
24562
|
+
}
|
|
24563
|
+
}
|
|
24450
24564
|
}
|
|
24451
24565
|
];
|
|
24452
24566
|
function ensureMigrationsTable(db) {
|
|
@@ -157162,12 +157276,12 @@ function loadToolDefinitionMeasurements(db) {
|
|
|
157162
157276
|
// ../plugin/src/features/magic-context/tool-owner-backfill.ts
|
|
157163
157277
|
init_data_path();
|
|
157164
157278
|
init_logger();
|
|
157165
|
-
import { existsSync as
|
|
157166
|
-
import { join as
|
|
157279
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
157280
|
+
import { join as join5 } from "node:path";
|
|
157167
157281
|
var LEASE_DURATION_MS = 5 * 60 * 1000;
|
|
157168
157282
|
var LEASE_RENEWAL_MS = 60 * 1000;
|
|
157169
157283
|
function resolveOpencodeDbPath() {
|
|
157170
|
-
return
|
|
157284
|
+
return join5(getDataDir(), "opencode", "opencode.db");
|
|
157171
157285
|
}
|
|
157172
157286
|
function ensureBackfillStateTable(db) {
|
|
157173
157287
|
db.exec(`
|
|
@@ -157202,7 +157316,7 @@ function runToolOwnerBackfill(db) {
|
|
|
157202
157316
|
return result;
|
|
157203
157317
|
}
|
|
157204
157318
|
const opencodeDbPath = resolveOpencodeDbPath();
|
|
157205
|
-
if (!
|
|
157319
|
+
if (!existsSync3(opencodeDbPath)) {
|
|
157206
157320
|
log(`[backfill] OpenCode DB not found at ${opencodeDbPath} — marking all unbackfilled sessions as skipped. Lazy adoption (defense-in-depth) handles legacy rows at runtime.`);
|
|
157207
157321
|
markAllUnbackfilledSessionsSkipped(db);
|
|
157208
157322
|
result.sessionsSkippedNoOcDb = countSessionsByStatus(db, "skipped");
|
|
@@ -157410,21 +157524,21 @@ var persistenceByDatabase = new WeakMap;
|
|
|
157410
157524
|
var persistenceErrorByDatabase = new WeakMap;
|
|
157411
157525
|
function resolveDatabasePath() {
|
|
157412
157526
|
const dbDir = getMagicContextStorageDir();
|
|
157413
|
-
return { dbDir, dbPath:
|
|
157527
|
+
return { dbDir, dbPath: join6(dbDir, "context.db") };
|
|
157414
157528
|
}
|
|
157415
157529
|
function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
|
|
157416
|
-
if (
|
|
157530
|
+
if (existsSync4(targetDbPath))
|
|
157417
157531
|
return;
|
|
157418
157532
|
const legacyDir = getLegacyOpenCodeMagicContextStorageDir();
|
|
157419
|
-
const legacyDbPath =
|
|
157420
|
-
if (!
|
|
157533
|
+
const legacyDbPath = join6(legacyDir, "context.db");
|
|
157534
|
+
if (!existsSync4(legacyDbPath))
|
|
157421
157535
|
return;
|
|
157422
157536
|
log(`[magic-context] migrating legacy plugin storage: ${legacyDir} -> ${targetDbDir} (legacy left in place as backup)`);
|
|
157423
157537
|
mkdirSync4(targetDbDir, { recursive: true });
|
|
157424
157538
|
for (const suffix of ["", "-wal", "-shm"]) {
|
|
157425
157539
|
const src = `${legacyDbPath}${suffix}`;
|
|
157426
|
-
const dst =
|
|
157427
|
-
if (
|
|
157540
|
+
const dst = join6(targetDbDir, `context.db${suffix}`);
|
|
157541
|
+
if (existsSync4(src)) {
|
|
157428
157542
|
try {
|
|
157429
157543
|
copyFileSync(src, dst);
|
|
157430
157544
|
} catch (error51) {
|
|
@@ -157432,9 +157546,9 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
|
|
|
157432
157546
|
}
|
|
157433
157547
|
}
|
|
157434
157548
|
}
|
|
157435
|
-
const legacyModelsDir =
|
|
157436
|
-
const targetModelsDir =
|
|
157437
|
-
if (
|
|
157549
|
+
const legacyModelsDir = join6(legacyDir, "models");
|
|
157550
|
+
const targetModelsDir = join6(targetDbDir, "models");
|
|
157551
|
+
if (existsSync4(legacyModelsDir) && !existsSync4(targetModelsDir)) {
|
|
157438
157552
|
try {
|
|
157439
157553
|
cpSync(legacyModelsDir, targetModelsDir, { recursive: true });
|
|
157440
157554
|
} catch (error51) {
|
|
@@ -157582,6 +157696,26 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
157582
157696
|
);
|
|
157583
157697
|
CREATE INDEX IF NOT EXISTS idx_dream_runs_project ON dream_runs(project_path, finished_at DESC);
|
|
157584
157698
|
|
|
157699
|
+
CREATE TABLE IF NOT EXISTS project_key_files (
|
|
157700
|
+
project_path TEXT NOT NULL,
|
|
157701
|
+
path TEXT NOT NULL,
|
|
157702
|
+
content TEXT NOT NULL,
|
|
157703
|
+
content_hash TEXT NOT NULL,
|
|
157704
|
+
local_token_estimate INTEGER NOT NULL,
|
|
157705
|
+
generated_at INTEGER NOT NULL,
|
|
157706
|
+
generated_by_model TEXT,
|
|
157707
|
+
generation_config_hash TEXT NOT NULL,
|
|
157708
|
+
stale_reason TEXT,
|
|
157709
|
+
PRIMARY KEY (project_path, path)
|
|
157710
|
+
);
|
|
157711
|
+
CREATE INDEX IF NOT EXISTS idx_project_key_files_project ON project_key_files(project_path);
|
|
157712
|
+
CREATE INDEX IF NOT EXISTS idx_project_key_files_generated_at ON project_key_files(project_path, generated_at);
|
|
157713
|
+
|
|
157714
|
+
CREATE TABLE IF NOT EXISTS project_key_files_version (
|
|
157715
|
+
project_path TEXT PRIMARY KEY,
|
|
157716
|
+
version INTEGER NOT NULL DEFAULT 0
|
|
157717
|
+
);
|
|
157718
|
+
|
|
157585
157719
|
-- (smart_notes: see note above; merged into unified notes table by migration v1)
|
|
157586
157720
|
|
|
157587
157721
|
CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
|
|
@@ -157659,7 +157793,11 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
157659
157793
|
-- valid JSON blob written via setPendingCompactionMarkerState.
|
|
157660
157794
|
-- Excluded from healNullTextColumns. Readers filter IS NOT NULL AND
|
|
157661
157795
|
-- != empty-string defensively. Plan v6 section 3.
|
|
157662
|
-
pending_compaction_marker_state TEXT
|
|
157796
|
+
pending_compaction_marker_state TEXT,
|
|
157797
|
+
-- deferred_execute_state: intentionally NULLABLE without a default.
|
|
157798
|
+
-- Absence is SQL NULL; presence is a JSON blob written via
|
|
157799
|
+
-- setDeferredExecutePendingIfAbsent. Excluded from healNullTextColumns.
|
|
157800
|
+
deferred_execute_state TEXT
|
|
157663
157801
|
);
|
|
157664
157802
|
|
|
157665
157803
|
CREATE INDEX IF NOT EXISTS idx_tags_session_tag_number ON tags(session_id, tag_number);
|
|
@@ -157748,6 +157886,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
157748
157886
|
ensureColumn(db, "session_meta", "detected_context_limit", "INTEGER DEFAULT 0");
|
|
157749
157887
|
ensureColumn(db, "session_meta", "needs_emergency_recovery", "INTEGER DEFAULT 0");
|
|
157750
157888
|
ensureColumn(db, "session_meta", "pending_compaction_marker_state", "TEXT");
|
|
157889
|
+
ensureColumn(db, "session_meta", "deferred_execute_state", "TEXT");
|
|
157751
157890
|
ensureColumn(db, "tags", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
157752
157891
|
ensureColumn(db, "pending_ops", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
157753
157892
|
ensureColumn(db, "source_contents", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
@@ -157824,7 +157963,15 @@ function ensureColumn(db, table, column, definition) {
|
|
|
157824
157963
|
if (rows.some((row) => row.name === column)) {
|
|
157825
157964
|
return;
|
|
157826
157965
|
}
|
|
157827
|
-
|
|
157966
|
+
try {
|
|
157967
|
+
db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
|
|
157968
|
+
} catch (err) {
|
|
157969
|
+
const recheck = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
157970
|
+
if (recheck.some((row) => row.name === column)) {
|
|
157971
|
+
return;
|
|
157972
|
+
}
|
|
157973
|
+
throw err;
|
|
157974
|
+
}
|
|
157828
157975
|
}
|
|
157829
157976
|
function openDatabase() {
|
|
157830
157977
|
const { dbDir, dbPath } = resolveDatabasePath();
|
|
@@ -157841,6 +157988,11 @@ function openDatabase() {
|
|
|
157841
157988
|
const db = new Database(dbPath);
|
|
157842
157989
|
initializeDatabase(db);
|
|
157843
157990
|
runMigrations(db);
|
|
157991
|
+
try {
|
|
157992
|
+
deleteOrphanProjectKeyFiles(db);
|
|
157993
|
+
} catch (error51) {
|
|
157994
|
+
log(`[magic-context] key-files orphan GC failed: ${getErrorMessage(error51)}`);
|
|
157995
|
+
}
|
|
157844
157996
|
try {
|
|
157845
157997
|
runToolOwnerBackfill(db);
|
|
157846
157998
|
} catch (error51) {
|
|
@@ -157864,14 +158016,14 @@ init_logger();
|
|
|
157864
158016
|
|
|
157865
158017
|
// src/config/index.ts
|
|
157866
158018
|
init_magic_context();
|
|
157867
|
-
import { existsSync as
|
|
158019
|
+
import { existsSync as existsSync6, readFileSync as readFileSync3 } from "node:fs";
|
|
157868
158020
|
import { homedir as homedir3 } from "node:os";
|
|
157869
|
-
import { join as
|
|
158021
|
+
import { join as join7 } from "node:path";
|
|
157870
158022
|
|
|
157871
158023
|
// ../plugin/src/config/variable.ts
|
|
157872
|
-
import { existsSync as
|
|
158024
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2 } from "node:fs";
|
|
157873
158025
|
import { homedir as homedir2 } from "node:os";
|
|
157874
|
-
import { dirname as dirname3, isAbsolute, resolve } from "node:path";
|
|
158026
|
+
import { dirname as dirname3, isAbsolute, resolve as resolve2 } from "node:path";
|
|
157875
158027
|
var ENV_PATTERN = /\{env:([^}]+)\}/g;
|
|
157876
158028
|
var FILE_PATTERN = /\{file:([^}]+)\}/g;
|
|
157877
158029
|
function substituteConfigVariables(input) {
|
|
@@ -157908,17 +158060,17 @@ function substituteConfigVariables(input) {
|
|
|
157908
158060
|
}
|
|
157909
158061
|
let filePath = rawPath.trim();
|
|
157910
158062
|
if (filePath.startsWith("~/")) {
|
|
157911
|
-
filePath =
|
|
158063
|
+
filePath = resolve2(homedir2(), filePath.slice(2));
|
|
157912
158064
|
} else if (!isAbsolute(filePath)) {
|
|
157913
|
-
filePath =
|
|
158065
|
+
filePath = resolve2(configDir, filePath);
|
|
157914
158066
|
}
|
|
157915
|
-
if (!
|
|
158067
|
+
if (!existsSync5(filePath)) {
|
|
157916
158068
|
warnings.push(`File not found for ${token} (resolved to ${filePath}); using empty string`);
|
|
157917
158069
|
continue;
|
|
157918
158070
|
}
|
|
157919
158071
|
let contents;
|
|
157920
158072
|
try {
|
|
157921
|
-
contents =
|
|
158073
|
+
contents = readFileSync2(filePath, "utf-8").trim();
|
|
157922
158074
|
} catch (error51) {
|
|
157923
158075
|
const message = error51 instanceof Error ? error51.message : String(error51);
|
|
157924
158076
|
warnings.push(`Failed to read file for ${token} (${filePath}): ${message}; using empty string`);
|
|
@@ -157934,20 +158086,20 @@ function substituteConfigVariables(input) {
|
|
|
157934
158086
|
var import_comment_json = __toESM(require_src2(), 1);
|
|
157935
158087
|
var CONFIG_FILE_NAME = "magic-context";
|
|
157936
158088
|
function getProjectConfigPaths(cwd) {
|
|
157937
|
-
const basePath =
|
|
158089
|
+
const basePath = join7(cwd, ".pi", CONFIG_FILE_NAME);
|
|
157938
158090
|
return [`${basePath}.jsonc`, `${basePath}.json`];
|
|
157939
158091
|
}
|
|
157940
158092
|
function getUserConfigPaths() {
|
|
157941
158093
|
const home = process.env.HOME ?? homedir3();
|
|
157942
|
-
const basePath =
|
|
158094
|
+
const basePath = join7(home, ".pi", "agent", CONFIG_FILE_NAME);
|
|
157943
158095
|
return [`${basePath}.jsonc`, `${basePath}.json`];
|
|
157944
158096
|
}
|
|
157945
158097
|
function resolveFirstExisting(paths) {
|
|
157946
|
-
return paths.find((path4) =>
|
|
158098
|
+
return paths.find((path4) => existsSync6(path4));
|
|
157947
158099
|
}
|
|
157948
158100
|
function loadConfigFile(path4, scope) {
|
|
157949
158101
|
try {
|
|
157950
|
-
const rawText =
|
|
158102
|
+
const rawText = readFileSync3(path4, "utf-8");
|
|
157951
158103
|
const substituted = substituteConfigVariables({
|
|
157952
158104
|
text: rawText,
|
|
157953
158105
|
configPath: path4
|
|
@@ -162556,6 +162708,61 @@ __export(exports_typebox, {
|
|
|
162556
162708
|
Any: () => Any
|
|
162557
162709
|
});
|
|
162558
162710
|
// src/read-session-pi.ts
|
|
162711
|
+
function isMidTurnPi(event, _sessionId) {
|
|
162712
|
+
const messages = event?.messages;
|
|
162713
|
+
if (!Array.isArray(messages))
|
|
162714
|
+
return false;
|
|
162715
|
+
let latestAssistantIndex = -1;
|
|
162716
|
+
let latestAssistant = null;
|
|
162717
|
+
for (let i = messages.length - 1;i >= 0; i--) {
|
|
162718
|
+
const msg = messages[i];
|
|
162719
|
+
if (msg !== null && typeof msg === "object") {
|
|
162720
|
+
const record4 = msg;
|
|
162721
|
+
if (record4.role === "assistant") {
|
|
162722
|
+
latestAssistantIndex = i;
|
|
162723
|
+
latestAssistant = record4;
|
|
162724
|
+
break;
|
|
162725
|
+
}
|
|
162726
|
+
}
|
|
162727
|
+
}
|
|
162728
|
+
if (latestAssistant === null)
|
|
162729
|
+
return false;
|
|
162730
|
+
if (latestAssistant.stopReason === "toolUse")
|
|
162731
|
+
return true;
|
|
162732
|
+
const toolCallIds = getToolCallIds(latestAssistant.content);
|
|
162733
|
+
if (toolCallIds.size === 0)
|
|
162734
|
+
return false;
|
|
162735
|
+
const pairedToolResultIds = new Set;
|
|
162736
|
+
for (const msg of messages.slice(latestAssistantIndex + 1)) {
|
|
162737
|
+
if (msg === null || typeof msg !== "object")
|
|
162738
|
+
continue;
|
|
162739
|
+
const record4 = msg;
|
|
162740
|
+
if (record4.role !== "toolResult")
|
|
162741
|
+
continue;
|
|
162742
|
+
if (typeof record4.toolCallId === "string") {
|
|
162743
|
+
pairedToolResultIds.add(record4.toolCallId);
|
|
162744
|
+
}
|
|
162745
|
+
}
|
|
162746
|
+
for (const id of toolCallIds) {
|
|
162747
|
+
if (!pairedToolResultIds.has(id))
|
|
162748
|
+
return true;
|
|
162749
|
+
}
|
|
162750
|
+
return false;
|
|
162751
|
+
}
|
|
162752
|
+
function getToolCallIds(content) {
|
|
162753
|
+
const ids = new Set;
|
|
162754
|
+
if (!Array.isArray(content))
|
|
162755
|
+
return ids;
|
|
162756
|
+
for (const item of content) {
|
|
162757
|
+
if (item === null || typeof item !== "object")
|
|
162758
|
+
continue;
|
|
162759
|
+
const record4 = item;
|
|
162760
|
+
if (record4.type === "toolCall" && typeof record4.id === "string") {
|
|
162761
|
+
ids.add(record4.id);
|
|
162762
|
+
}
|
|
162763
|
+
}
|
|
162764
|
+
return ids;
|
|
162765
|
+
}
|
|
162559
162766
|
function readPiSessionMessages(ctx) {
|
|
162560
162767
|
const sm = ctx.sessionManager;
|
|
162561
162768
|
if (sm === undefined)
|
|
@@ -162577,6 +162784,7 @@ function convertEntriesToRawMessages(entries) {
|
|
|
162577
162784
|
const result = [];
|
|
162578
162785
|
let nextOrdinal = 1;
|
|
162579
162786
|
let pendingToolParts = [];
|
|
162787
|
+
let pendingFirstRealId = "";
|
|
162580
162788
|
for (const entry of entries) {
|
|
162581
162789
|
if (!isMessageEntry(entry)) {
|
|
162582
162790
|
continue;
|
|
@@ -162585,6 +162793,9 @@ function convertEntriesToRawMessages(entries) {
|
|
|
162585
162793
|
const role = msg.role;
|
|
162586
162794
|
if (role === "toolResult") {
|
|
162587
162795
|
pendingToolParts.push(...synthesizeToolResultParts(msg));
|
|
162796
|
+
if (pendingFirstRealId === "") {
|
|
162797
|
+
pendingFirstRealId = entry.id;
|
|
162798
|
+
}
|
|
162588
162799
|
continue;
|
|
162589
162800
|
}
|
|
162590
162801
|
if (role === "user") {
|
|
@@ -162593,6 +162804,7 @@ function convertEntriesToRawMessages(entries) {
|
|
|
162593
162804
|
...synthesizeUserParts(msg)
|
|
162594
162805
|
];
|
|
162595
162806
|
pendingToolParts = [];
|
|
162807
|
+
pendingFirstRealId = "";
|
|
162596
162808
|
result.push({
|
|
162597
162809
|
ordinal: nextOrdinal++,
|
|
162598
162810
|
id: entry.id,
|
|
@@ -162605,11 +162817,12 @@ function convertEntriesToRawMessages(entries) {
|
|
|
162605
162817
|
if (pendingToolParts.length > 0) {
|
|
162606
162818
|
result.push({
|
|
162607
162819
|
ordinal: nextOrdinal++,
|
|
162608
|
-
id:
|
|
162820
|
+
id: pendingFirstRealId,
|
|
162609
162821
|
role: "user",
|
|
162610
162822
|
parts: pendingToolParts
|
|
162611
162823
|
});
|
|
162612
162824
|
pendingToolParts = [];
|
|
162825
|
+
pendingFirstRealId = "";
|
|
162613
162826
|
}
|
|
162614
162827
|
result.push({
|
|
162615
162828
|
ordinal: nextOrdinal++,
|
|
@@ -162629,7 +162842,7 @@ function convertEntriesToRawMessages(entries) {
|
|
|
162629
162842
|
if (pendingToolParts.length > 0) {
|
|
162630
162843
|
result.push({
|
|
162631
162844
|
ordinal: nextOrdinal,
|
|
162632
|
-
id:
|
|
162845
|
+
id: pendingFirstRealId,
|
|
162633
162846
|
role: "user",
|
|
162634
162847
|
parts: pendingToolParts
|
|
162635
162848
|
});
|
|
@@ -163130,7 +163343,7 @@ init_normalize_hash();
|
|
|
163130
163343
|
|
|
163131
163344
|
// ../plugin/src/features/magic-context/memory/project-identity.ts
|
|
163132
163345
|
import { execSync } from "node:child_process";
|
|
163133
|
-
import { createHash as
|
|
163346
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
163134
163347
|
import path4 from "node:path";
|
|
163135
163348
|
var GIT_TIMEOUT_MS = 5000;
|
|
163136
163349
|
var resolvedCache = new Map;
|
|
@@ -163151,7 +163364,7 @@ function getRootCommitHash(directory) {
|
|
|
163151
163364
|
}
|
|
163152
163365
|
function directoryFallback(directory) {
|
|
163153
163366
|
const canonical = path4.resolve(directory);
|
|
163154
|
-
const hash2 =
|
|
163367
|
+
const hash2 = createHash3("md5").update(canonical).digest("hex").slice(0, 12);
|
|
163155
163368
|
return `dir:${hash2}`;
|
|
163156
163369
|
}
|
|
163157
163370
|
function resolveProjectIdentity(directory) {
|
|
@@ -164216,6 +164429,12 @@ function isPersistedNoteNudgeRow(row) {
|
|
|
164216
164429
|
const r = row;
|
|
164217
164430
|
return typeof r.note_nudge_trigger_pending === "number" && typeof r.note_nudge_trigger_message_id === "string" && typeof r.note_nudge_sticky_text === "string" && typeof r.note_nudge_sticky_message_id === "string";
|
|
164218
164431
|
}
|
|
164432
|
+
function isPersistedTodoSyntheticAnchorRow(row) {
|
|
164433
|
+
if (row === null || typeof row !== "object")
|
|
164434
|
+
return false;
|
|
164435
|
+
const r = row;
|
|
164436
|
+
return typeof r.todo_synthetic_call_id === "string" && typeof r.todo_synthetic_anchor_message_id === "string" && typeof r.todo_synthetic_state_json === "string";
|
|
164437
|
+
}
|
|
164219
164438
|
function isPersistedHistorianFailureRow(row) {
|
|
164220
164439
|
if (row === null || typeof row !== "object")
|
|
164221
164440
|
return false;
|
|
@@ -164292,6 +164511,29 @@ function setPersistedDeliveredNoteNudge(db, sessionId, text, messageId = "") {
|
|
|
164292
164511
|
function clearPersistedNoteNudge(db, sessionId) {
|
|
164293
164512
|
db.prepare("UPDATE session_meta SET note_nudge_trigger_pending = 0, note_nudge_trigger_message_id = '', note_nudge_sticky_text = '', note_nudge_sticky_message_id = '' WHERE session_id = ?").run(sessionId);
|
|
164294
164513
|
}
|
|
164514
|
+
function getPersistedTodoSyntheticAnchor(db, sessionId) {
|
|
164515
|
+
const result = db.prepare("SELECT todo_synthetic_call_id, todo_synthetic_anchor_message_id, todo_synthetic_state_json FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
164516
|
+
if (!isPersistedTodoSyntheticAnchorRow(result)) {
|
|
164517
|
+
return null;
|
|
164518
|
+
}
|
|
164519
|
+
if (result.todo_synthetic_call_id.length === 0 || result.todo_synthetic_anchor_message_id.length === 0) {
|
|
164520
|
+
return null;
|
|
164521
|
+
}
|
|
164522
|
+
return {
|
|
164523
|
+
callId: result.todo_synthetic_call_id,
|
|
164524
|
+
messageId: result.todo_synthetic_anchor_message_id,
|
|
164525
|
+
stateJson: result.todo_synthetic_state_json
|
|
164526
|
+
};
|
|
164527
|
+
}
|
|
164528
|
+
function setPersistedTodoSyntheticAnchor(db, sessionId, callId, messageId, stateJson) {
|
|
164529
|
+
db.transaction(() => {
|
|
164530
|
+
ensureSessionMetaRow(db, sessionId);
|
|
164531
|
+
db.prepare("UPDATE session_meta SET todo_synthetic_call_id = ?, todo_synthetic_anchor_message_id = ?, todo_synthetic_state_json = ? WHERE session_id = ?").run(callId, messageId, stateJson, sessionId);
|
|
164532
|
+
})();
|
|
164533
|
+
}
|
|
164534
|
+
function clearPersistedTodoSyntheticAnchor(db, sessionId) {
|
|
164535
|
+
db.prepare("UPDATE session_meta SET todo_synthetic_call_id = '', todo_synthetic_anchor_message_id = '', todo_synthetic_state_json = '' WHERE session_id = ?").run(sessionId);
|
|
164536
|
+
}
|
|
164295
164537
|
function getNoteLastReadAt(db, sessionId) {
|
|
164296
164538
|
try {
|
|
164297
164539
|
const result = db.prepare("SELECT note_last_read_at FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
@@ -164418,6 +164660,30 @@ function clearPendingCompactionMarkerStateIf(db, sessionId, expected) {
|
|
|
164418
164660
|
WHERE session_id = ? AND pending_compaction_marker_state = ?`).run(sessionId, expectedBlob);
|
|
164419
164661
|
return result.changes > 0;
|
|
164420
164662
|
}
|
|
164663
|
+
function peekDeferredExecutePending(db, sessionId) {
|
|
164664
|
+
const row = db.prepare("SELECT deferred_execute_state FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
164665
|
+
const raw = row?.deferred_execute_state;
|
|
164666
|
+
if (raw === null || raw === undefined || raw === "")
|
|
164667
|
+
return null;
|
|
164668
|
+
try {
|
|
164669
|
+
return JSON.parse(raw);
|
|
164670
|
+
} catch {
|
|
164671
|
+
return null;
|
|
164672
|
+
}
|
|
164673
|
+
}
|
|
164674
|
+
function setDeferredExecutePendingIfAbsent(db, sessionId, payload) {
|
|
164675
|
+
ensureSessionMetaRow(db, sessionId);
|
|
164676
|
+
const payloadBlob = stableStringify(payload);
|
|
164677
|
+
const result = db.prepare(`UPDATE session_meta SET deferred_execute_state = ?
|
|
164678
|
+
WHERE session_id = ? AND deferred_execute_state IS NULL`).run(payloadBlob, sessionId);
|
|
164679
|
+
return result.changes > 0;
|
|
164680
|
+
}
|
|
164681
|
+
function clearDeferredExecutePendingIfMatches(db, sessionId, expected) {
|
|
164682
|
+
const expectedBlob = stableStringify(expected);
|
|
164683
|
+
const result = db.prepare(`UPDATE session_meta SET deferred_execute_state = NULL
|
|
164684
|
+
WHERE session_id = ? AND deferred_execute_state = ?`).run(sessionId, expectedBlob);
|
|
164685
|
+
return result.changes > 0;
|
|
164686
|
+
}
|
|
164421
164687
|
// ../plugin/src/features/magic-context/resolve-subagent-fallback.ts
|
|
164422
164688
|
init_logger();
|
|
164423
164689
|
await init_read_session_db();
|
|
@@ -166590,6 +166856,70 @@ function createCtxSearchTool(deps) {
|
|
|
166590
166856
|
};
|
|
166591
166857
|
}
|
|
166592
166858
|
|
|
166859
|
+
// src/tools/todowrite.ts
|
|
166860
|
+
var STATUS_VALUES = [
|
|
166861
|
+
"pending",
|
|
166862
|
+
"in_progress",
|
|
166863
|
+
"completed",
|
|
166864
|
+
"cancelled"
|
|
166865
|
+
];
|
|
166866
|
+
var PRIORITY_VALUES = ["high", "medium", "low"];
|
|
166867
|
+
var TodoItem = exports_typebox.Object({
|
|
166868
|
+
content: exports_typebox.String({ description: "Brief description of the task" }),
|
|
166869
|
+
status: exports_typebox.Union(STATUS_VALUES.map((v) => exports_typebox.Literal(v))),
|
|
166870
|
+
priority: exports_typebox.Optional(exports_typebox.Union(PRIORITY_VALUES.map((v) => exports_typebox.Literal(v)))),
|
|
166871
|
+
id: exports_typebox.Optional(exports_typebox.String({ description: "Optional stable id for the todo" }))
|
|
166872
|
+
});
|
|
166873
|
+
var TodowriteParams = exports_typebox.Object({
|
|
166874
|
+
todos: exports_typebox.Array(TodoItem, {
|
|
166875
|
+
description: "Replace the current task list with this complete set of todos. Include every task you intend to track this turn — pending, in_progress, completed, or cancelled — because the list overwrites previous state."
|
|
166876
|
+
})
|
|
166877
|
+
});
|
|
166878
|
+
var TOOL_DESCRIPTION = [
|
|
166879
|
+
"Manage your task list for this session.",
|
|
166880
|
+
"",
|
|
166881
|
+
"Use this tool to plan multi-step work, track in-flight tasks, and",
|
|
166882
|
+
"mark progress as you complete steps. Pass the COMPLETE updated list",
|
|
166883
|
+
"of todos every time — this tool replaces the prior list rather than",
|
|
166884
|
+
"appending to it.",
|
|
166885
|
+
"",
|
|
166886
|
+
"Task states:",
|
|
166887
|
+
" - pending: not started yet",
|
|
166888
|
+
" - in_progress: currently working on (limit to ONE task at a time)",
|
|
166889
|
+
" - completed: finished successfully",
|
|
166890
|
+
" - cancelled: no longer needed",
|
|
166891
|
+
"",
|
|
166892
|
+
"Use this tool proactively for non-trivial work spanning 3+ steps.",
|
|
166893
|
+
"Skip it for single-shot answers or trivial 1-2 step tasks."
|
|
166894
|
+
].join(`
|
|
166895
|
+
`);
|
|
166896
|
+
function createTodowriteTool() {
|
|
166897
|
+
return {
|
|
166898
|
+
name: "todowrite",
|
|
166899
|
+
label: "Todos",
|
|
166900
|
+
description: TOOL_DESCRIPTION,
|
|
166901
|
+
parameters: TodowriteParams,
|
|
166902
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
166903
|
+
const todos = params.todos ?? [];
|
|
166904
|
+
const completed = todos.filter((t) => t.status === "completed").length;
|
|
166905
|
+
const active = todos.length - completed;
|
|
166906
|
+
return {
|
|
166907
|
+
content: [
|
|
166908
|
+
{
|
|
166909
|
+
type: "text",
|
|
166910
|
+
text: JSON.stringify(todos, null, 2)
|
|
166911
|
+
}
|
|
166912
|
+
],
|
|
166913
|
+
details: {
|
|
166914
|
+
todos,
|
|
166915
|
+
title: `${active} todos`,
|
|
166916
|
+
truncated: false
|
|
166917
|
+
}
|
|
166918
|
+
};
|
|
166919
|
+
}
|
|
166920
|
+
};
|
|
166921
|
+
}
|
|
166922
|
+
|
|
166593
166923
|
// src/tools/index.ts
|
|
166594
166924
|
function registerMagicContextTools(pi, opts) {
|
|
166595
166925
|
pi.registerTool(createCtxSearchTool({
|
|
@@ -166609,6 +166939,7 @@ function registerMagicContextTools(pi, opts) {
|
|
|
166609
166939
|
dreamerEnabled: opts.dreamerEnabled ?? false
|
|
166610
166940
|
}));
|
|
166611
166941
|
pi.registerTool(createCtxExpandTool({ db: opts.db }));
|
|
166942
|
+
pi.registerTool(createTodowriteTool());
|
|
166612
166943
|
if (opts.ctxReduceEnabled === true) {
|
|
166613
166944
|
pi.registerTool(createCtxReduceTool({
|
|
166614
166945
|
db: opts.db,
|