@foothill/agent-move 1.0.8 → 1.0.10
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 +46 -9
- package/package.json +2 -1
- package/packages/client/dist/assets/{BufferResource-Ddjob236.js → BufferResource-Dfd5uHKt.js} +1 -1
- package/packages/client/dist/assets/{CanvasRenderer-B0w6SYyW.js → CanvasRenderer-7Cv6xZVP.js} +1 -1
- package/packages/client/dist/assets/{Filter-NcMGuiK-.js → Filter-CBX7EB7j.js} +1 -1
- package/packages/client/dist/assets/{RenderTargetSystem-DgAzY5_U.js → RenderTargetSystem-ko-v73NG.js} +1 -1
- package/packages/client/dist/assets/{WebGLRenderer-DUWXDPIX.js → WebGLRenderer-vhPQEPUG.js} +1 -1
- package/packages/client/dist/assets/{WebGPURenderer-C1HbrllR.js → WebGPURenderer-Dwywvwqe.js} +1 -1
- package/packages/client/dist/assets/{browserAll-CaF1Fl0O.js → browserAll-QyCAT8_K.js} +1 -1
- package/packages/client/dist/assets/index-BPJtz4FL.js +722 -0
- package/packages/client/dist/assets/{webworkerAll-BJ6UhC7r.js → webworkerAll-hM-gNP7L.js} +1 -1
- package/packages/client/dist/index.html +1 -1
- package/packages/server/dist/config.d.ts +4 -0
- package/packages/server/dist/config.d.ts.map +1 -1
- package/packages/server/dist/config.js +5 -5
- package/packages/server/dist/config.js.map +1 -1
- package/packages/server/dist/hooks/hook-event-manager.js +0 -4
- package/packages/server/dist/hooks/hook-installer.js +0 -4
- package/packages/server/dist/index.d.ts.map +1 -1
- package/packages/server/dist/index.js +792 -856
- package/packages/server/dist/index.js.map +1 -1
- package/packages/server/dist/routes/api.js +0 -4
- package/packages/server/dist/state/activity-processor.d.ts +1 -1
- package/packages/server/dist/state/activity-processor.d.ts.map +1 -1
- package/packages/server/dist/state/activity-processor.js +1 -5
- package/packages/server/dist/state/activity-processor.js.map +1 -1
- package/packages/server/dist/state/agent-state-manager.d.ts +1 -2
- package/packages/server/dist/state/agent-state-manager.d.ts.map +1 -1
- package/packages/server/dist/state/agent-state-manager.js +87 -6
- package/packages/server/dist/state/agent-state-manager.js.map +1 -1
- package/packages/server/dist/state/anomaly-detector.js +0 -4
- package/packages/server/dist/state/identity-manager.js +0 -4
- package/packages/server/dist/state/role-resolver.d.ts +1 -2
- package/packages/server/dist/state/role-resolver.d.ts.map +1 -1
- package/packages/server/dist/state/role-resolver.js +0 -4
- package/packages/server/dist/state/role-resolver.js.map +1 -1
- package/packages/server/dist/state/task-graph-manager.d.ts +12 -0
- package/packages/server/dist/state/task-graph-manager.d.ts.map +1 -1
- package/packages/server/dist/state/task-graph-manager.js +80 -4
- package/packages/server/dist/state/task-graph-manager.js.map +1 -1
- package/packages/server/dist/state/tool-chain-tracker.js +0 -4
- package/packages/server/dist/watcher/agent-watcher.js +0 -5
- package/packages/server/dist/watcher/claude/claude-paths.d.ts +18 -0
- package/packages/server/dist/watcher/claude/claude-paths.d.ts.map +1 -0
- package/packages/server/dist/watcher/{claude-paths.js → claude/claude-paths.js} +47 -59
- package/packages/server/dist/watcher/claude/claude-paths.js.map +1 -0
- package/packages/server/dist/watcher/{file-watcher.d.ts → claude/claude-watcher.d.ts} +3 -3
- package/packages/server/dist/watcher/claude/claude-watcher.d.ts.map +1 -0
- package/packages/server/dist/watcher/{file-watcher.js → claude/claude-watcher.js} +59 -69
- package/packages/server/dist/watcher/claude/claude-watcher.js.map +1 -0
- package/packages/server/dist/watcher/claude/jsonl-parser.d.ts +6 -0
- package/packages/server/dist/watcher/claude/jsonl-parser.d.ts.map +1 -0
- package/packages/server/dist/watcher/{jsonl-parser.js → claude/jsonl-parser.js} +1 -5
- package/packages/server/dist/watcher/claude/jsonl-parser.js.map +1 -0
- package/packages/server/dist/watcher/codex/codex-parser.d.ts +30 -0
- package/packages/server/dist/watcher/codex/codex-parser.d.ts.map +1 -0
- package/packages/server/dist/watcher/codex/codex-parser.js +326 -0
- package/packages/server/dist/watcher/codex/codex-parser.js.map +1 -0
- package/packages/server/dist/watcher/codex/codex-paths.d.ts +35 -0
- package/packages/server/dist/watcher/codex/codex-paths.d.ts.map +1 -0
- package/packages/server/dist/watcher/codex/codex-paths.js +46 -0
- package/packages/server/dist/watcher/codex/codex-paths.js.map +1 -0
- package/packages/server/dist/watcher/codex/codex-watcher.d.ts +42 -0
- package/packages/server/dist/watcher/codex/codex-watcher.d.ts.map +1 -0
- package/packages/server/dist/watcher/codex/codex-watcher.js +577 -0
- package/packages/server/dist/watcher/codex/codex-watcher.js.map +1 -0
- package/packages/server/dist/watcher/git-info.js +0 -4
- package/packages/server/dist/watcher/opencode/opencode-parser.d.ts +1 -1
- package/packages/server/dist/watcher/opencode/opencode-parser.d.ts.map +1 -1
- package/packages/server/dist/watcher/opencode/opencode-parser.js +31 -6
- package/packages/server/dist/watcher/opencode/opencode-paths.d.ts +1 -1
- package/packages/server/dist/watcher/opencode/opencode-paths.d.ts.map +1 -1
- package/packages/server/dist/watcher/opencode/opencode-paths.js +1 -4
- package/packages/server/dist/watcher/opencode/opencode-paths.js.map +1 -1
- package/packages/server/dist/watcher/opencode/opencode-watcher.d.ts.map +1 -1
- package/packages/server/dist/watcher/opencode/opencode-watcher.js +50 -789
- package/packages/server/dist/watcher/opencode/opencode-watcher.js.map +1 -1
- package/packages/server/dist/watcher/path-utils.d.ts +10 -0
- package/packages/server/dist/watcher/path-utils.d.ts.map +1 -0
- package/packages/server/dist/watcher/path-utils.js +38 -0
- package/packages/server/dist/watcher/path-utils.js.map +1 -0
- package/packages/server/dist/watcher/pi/pi-parser.d.ts +19 -0
- package/packages/server/dist/watcher/pi/pi-parser.d.ts.map +1 -0
- package/packages/server/dist/watcher/pi/pi-parser.js +307 -0
- package/packages/server/dist/watcher/pi/pi-parser.js.map +1 -0
- package/packages/server/dist/watcher/pi/pi-paths.d.ts +28 -0
- package/packages/server/dist/watcher/pi/pi-paths.d.ts.map +1 -0
- package/packages/server/dist/watcher/pi/pi-paths.js +86 -0
- package/packages/server/dist/watcher/pi/pi-paths.js.map +1 -0
- package/packages/server/dist/watcher/pi/pi-watcher.d.ts +36 -0
- package/packages/server/dist/watcher/pi/pi-watcher.d.ts.map +1 -0
- package/packages/server/dist/watcher/pi/pi-watcher.js +593 -0
- package/packages/server/dist/watcher/pi/pi-watcher.js.map +1 -0
- package/packages/server/dist/watcher/session-scanner.d.ts +9 -3
- package/packages/server/dist/watcher/session-scanner.d.ts.map +1 -1
- package/packages/server/dist/watcher/session-scanner.js +11 -13
- package/packages/server/dist/watcher/session-scanner.js.map +1 -1
- package/packages/server/dist/watcher/types.d.ts +30 -0
- package/packages/server/dist/watcher/types.d.ts.map +1 -0
- package/packages/server/dist/watcher/types.js +14 -0
- package/packages/server/dist/watcher/types.js.map +1 -0
- package/packages/server/dist/ws/broadcaster.js +0 -4
- package/packages/server/dist/ws/ws-handler.js +0 -4
- package/packages/shared/dist/constants/colors.d.ts +1 -1
- package/packages/shared/dist/constants/colors.js +1 -1
- package/packages/shared/dist/constants/colors.js.map +1 -1
- package/packages/shared/dist/constants/tools.d.ts.map +1 -1
- package/packages/shared/dist/constants/tools.js +30 -1
- package/packages/shared/dist/constants/tools.js.map +1 -1
- package/packages/shared/dist/index.d.ts +1 -1
- package/packages/shared/dist/index.d.ts.map +1 -1
- package/packages/shared/dist/types/agent.d.ts +3 -0
- package/packages/shared/dist/types/agent.d.ts.map +1 -1
- package/packages/client/dist/assets/index-Dh8yWoLP.js +0 -711
- package/packages/server/dist/watcher/claude-paths.d.ts +0 -32
- package/packages/server/dist/watcher/claude-paths.d.ts.map +0 -1
- package/packages/server/dist/watcher/claude-paths.js.map +0 -1
- package/packages/server/dist/watcher/file-watcher.d.ts.map +0 -1
- package/packages/server/dist/watcher/file-watcher.js.map +0 -1
- package/packages/server/dist/watcher/jsonl-parser.d.ts +0 -21
- package/packages/server/dist/watcher/jsonl-parser.d.ts.map +0 -1
- package/packages/server/dist/watcher/jsonl-parser.js.map +0 -1
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import { createRequire } from 'module'; const require = createRequire(import.meta.url);
|
|
2
|
-
|
|
3
1
|
// dist/index.js
|
|
4
|
-
import { createRequire } from "module";
|
|
5
2
|
import { fileURLToPath } from "url";
|
|
6
|
-
import { dirname, join as
|
|
3
|
+
import { dirname as dirname2, join as join10 } from "path";
|
|
7
4
|
import Fastify from "fastify";
|
|
8
5
|
import cors from "@fastify/cors";
|
|
9
6
|
import websocket from "@fastify/websocket";
|
|
@@ -13,793 +10,32 @@ import { join } from "path";
|
|
|
13
10
|
import chokidar from "chokidar";
|
|
14
11
|
import { stat as stat2, open } from "fs/promises";
|
|
15
12
|
import { join as join4, basename } from "path";
|
|
16
|
-
import { existsSync } from "fs";
|
|
17
13
|
import { join as join2 } from "path";
|
|
14
|
+
import { existsSync } from "fs";
|
|
18
15
|
import { readdir, stat } from "fs/promises";
|
|
19
16
|
import { join as join3 } from "path";
|
|
20
17
|
import chokidar2 from "chokidar";
|
|
18
|
+
import Database from "better-sqlite3";
|
|
21
19
|
import { homedir as homedir2 } from "os";
|
|
22
20
|
import { join as join5 } from "path";
|
|
23
21
|
import { existsSync as existsSync2 } from "fs";
|
|
22
|
+
import chokidar3 from "chokidar";
|
|
23
|
+
import { stat as stat3, open as open2 } from "fs/promises";
|
|
24
|
+
import { join as join7, basename as basename2, dirname } from "path";
|
|
25
|
+
import { homedir as homedir3 } from "os";
|
|
26
|
+
import { join as join6 } from "path";
|
|
27
|
+
import { existsSync as existsSync3 } from "fs";
|
|
28
|
+
import chokidar4 from "chokidar";
|
|
29
|
+
import { stat as stat4, open as open3, readdir as readdir2 } from "fs/promises";
|
|
30
|
+
import { join as join9, basename as basename4 } from "path";
|
|
31
|
+
import { homedir as homedir4 } from "os";
|
|
32
|
+
import { join as join8, basename as basename3 } from "path";
|
|
33
|
+
import { existsSync as existsSync4 } from "fs";
|
|
24
34
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
25
35
|
import { EventEmitter } from "events";
|
|
26
36
|
import { execSync } from "child_process";
|
|
27
37
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
28
38
|
import { randomUUID } from "crypto";
|
|
29
|
-
var require2 = createRequire(import.meta.url);
|
|
30
|
-
var __create = Object.create;
|
|
31
|
-
var __defProp = Object.defineProperty;
|
|
32
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
33
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
34
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
35
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
36
|
-
var __require = /* @__PURE__ */ ((x) => typeof require2 !== "undefined" ? require2 : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
37
|
-
get: (a, b) => (typeof require2 !== "undefined" ? require2 : a)[b]
|
|
38
|
-
}) : x)(function(x) {
|
|
39
|
-
if (typeof require2 !== "undefined") return require2.apply(this, arguments);
|
|
40
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
41
|
-
});
|
|
42
|
-
var __commonJS = (cb, mod) => function __require2() {
|
|
43
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
44
|
-
};
|
|
45
|
-
var __copyProps = (to, from, except, desc) => {
|
|
46
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
47
|
-
for (let key of __getOwnPropNames(from))
|
|
48
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
49
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
50
|
-
}
|
|
51
|
-
return to;
|
|
52
|
-
};
|
|
53
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
54
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
55
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
56
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
57
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
58
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
59
|
-
mod
|
|
60
|
-
));
|
|
61
|
-
var require_util = __commonJS({
|
|
62
|
-
"../../node_modules/better-sqlite3/lib/util.js"(exports) {
|
|
63
|
-
"use strict";
|
|
64
|
-
exports.getBooleanOption = (options, key) => {
|
|
65
|
-
let value = false;
|
|
66
|
-
if (key in options && typeof (value = options[key]) !== "boolean") {
|
|
67
|
-
throw new TypeError(`Expected the "${key}" option to be a boolean`);
|
|
68
|
-
}
|
|
69
|
-
return value;
|
|
70
|
-
};
|
|
71
|
-
exports.cppdb = /* @__PURE__ */ Symbol();
|
|
72
|
-
exports.inspect = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
var require_sqlite_error = __commonJS({
|
|
76
|
-
"../../node_modules/better-sqlite3/lib/sqlite-error.js"(exports, module) {
|
|
77
|
-
"use strict";
|
|
78
|
-
var descriptor = { value: "SqliteError", writable: true, enumerable: false, configurable: true };
|
|
79
|
-
function SqliteError(message, code) {
|
|
80
|
-
if (new.target !== SqliteError) {
|
|
81
|
-
return new SqliteError(message, code);
|
|
82
|
-
}
|
|
83
|
-
if (typeof code !== "string") {
|
|
84
|
-
throw new TypeError("Expected second argument to be a string");
|
|
85
|
-
}
|
|
86
|
-
Error.call(this, message);
|
|
87
|
-
descriptor.value = "" + message;
|
|
88
|
-
Object.defineProperty(this, "message", descriptor);
|
|
89
|
-
Error.captureStackTrace(this, SqliteError);
|
|
90
|
-
this.code = code;
|
|
91
|
-
}
|
|
92
|
-
Object.setPrototypeOf(SqliteError, Error);
|
|
93
|
-
Object.setPrototypeOf(SqliteError.prototype, Error.prototype);
|
|
94
|
-
Object.defineProperty(SqliteError.prototype, "name", descriptor);
|
|
95
|
-
module.exports = SqliteError;
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
var require_file_uri_to_path = __commonJS({
|
|
99
|
-
"../../node_modules/file-uri-to-path/index.js"(exports, module) {
|
|
100
|
-
var sep = __require("path").sep || "/";
|
|
101
|
-
module.exports = fileUriToPath;
|
|
102
|
-
function fileUriToPath(uri) {
|
|
103
|
-
if ("string" != typeof uri || uri.length <= 7 || "file://" != uri.substring(0, 7)) {
|
|
104
|
-
throw new TypeError("must pass in a file:// URI to convert to a file path");
|
|
105
|
-
}
|
|
106
|
-
var rest = decodeURI(uri.substring(7));
|
|
107
|
-
var firstSlash = rest.indexOf("/");
|
|
108
|
-
var host = rest.substring(0, firstSlash);
|
|
109
|
-
var path = rest.substring(firstSlash + 1);
|
|
110
|
-
if ("localhost" == host) host = "";
|
|
111
|
-
if (host) {
|
|
112
|
-
host = sep + sep + host;
|
|
113
|
-
}
|
|
114
|
-
path = path.replace(/^(.+)\|/, "$1:");
|
|
115
|
-
if (sep == "\\") {
|
|
116
|
-
path = path.replace(/\//g, "\\");
|
|
117
|
-
}
|
|
118
|
-
if (/^.+\:/.test(path)) {
|
|
119
|
-
} else {
|
|
120
|
-
path = sep + path;
|
|
121
|
-
}
|
|
122
|
-
return host + path;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
var require_bindings = __commonJS({
|
|
127
|
-
"../../node_modules/bindings/bindings.js"(exports, module) {
|
|
128
|
-
var fs = __require("fs");
|
|
129
|
-
var path = __require("path");
|
|
130
|
-
var fileURLToPath2 = require_file_uri_to_path();
|
|
131
|
-
var join7 = path.join;
|
|
132
|
-
var dirname2 = path.dirname;
|
|
133
|
-
var exists = fs.accessSync && function(path2) {
|
|
134
|
-
try {
|
|
135
|
-
fs.accessSync(path2);
|
|
136
|
-
} catch (e) {
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
return true;
|
|
140
|
-
} || fs.existsSync || path.existsSync;
|
|
141
|
-
var defaults = {
|
|
142
|
-
arrow: process.env.NODE_BINDINGS_ARROW || " \u2192 ",
|
|
143
|
-
compiled: process.env.NODE_BINDINGS_COMPILED_DIR || "compiled",
|
|
144
|
-
platform: process.platform,
|
|
145
|
-
arch: process.arch,
|
|
146
|
-
nodePreGyp: "node-v" + process.versions.modules + "-" + process.platform + "-" + process.arch,
|
|
147
|
-
version: process.versions.node,
|
|
148
|
-
bindings: "bindings.node",
|
|
149
|
-
try: [
|
|
150
|
-
// node-gyp's linked version in the "build" dir
|
|
151
|
-
["module_root", "build", "bindings"],
|
|
152
|
-
// node-waf and gyp_addon (a.k.a node-gyp)
|
|
153
|
-
["module_root", "build", "Debug", "bindings"],
|
|
154
|
-
["module_root", "build", "Release", "bindings"],
|
|
155
|
-
// Debug files, for development (legacy behavior, remove for node v0.9)
|
|
156
|
-
["module_root", "out", "Debug", "bindings"],
|
|
157
|
-
["module_root", "Debug", "bindings"],
|
|
158
|
-
// Release files, but manually compiled (legacy behavior, remove for node v0.9)
|
|
159
|
-
["module_root", "out", "Release", "bindings"],
|
|
160
|
-
["module_root", "Release", "bindings"],
|
|
161
|
-
// Legacy from node-waf, node <= 0.4.x
|
|
162
|
-
["module_root", "build", "default", "bindings"],
|
|
163
|
-
// Production "Release" buildtype binary (meh...)
|
|
164
|
-
["module_root", "compiled", "version", "platform", "arch", "bindings"],
|
|
165
|
-
// node-qbs builds
|
|
166
|
-
["module_root", "addon-build", "release", "install-root", "bindings"],
|
|
167
|
-
["module_root", "addon-build", "debug", "install-root", "bindings"],
|
|
168
|
-
["module_root", "addon-build", "default", "install-root", "bindings"],
|
|
169
|
-
// node-pre-gyp path ./lib/binding/{node_abi}-{platform}-{arch}
|
|
170
|
-
["module_root", "lib", "binding", "nodePreGyp", "bindings"]
|
|
171
|
-
]
|
|
172
|
-
};
|
|
173
|
-
function bindings(opts) {
|
|
174
|
-
if (typeof opts == "string") {
|
|
175
|
-
opts = { bindings: opts };
|
|
176
|
-
} else if (!opts) {
|
|
177
|
-
opts = {};
|
|
178
|
-
}
|
|
179
|
-
Object.keys(defaults).map(function(i2) {
|
|
180
|
-
if (!(i2 in opts)) opts[i2] = defaults[i2];
|
|
181
|
-
});
|
|
182
|
-
if (!opts.module_root) {
|
|
183
|
-
opts.module_root = exports.getRoot(exports.getFileName());
|
|
184
|
-
}
|
|
185
|
-
if (path.extname(opts.bindings) != ".node") {
|
|
186
|
-
opts.bindings += ".node";
|
|
187
|
-
}
|
|
188
|
-
var requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
189
|
-
var tries = [], i = 0, l = opts.try.length, n, b, err;
|
|
190
|
-
for (; i < l; i++) {
|
|
191
|
-
n = join7.apply(
|
|
192
|
-
null,
|
|
193
|
-
opts.try[i].map(function(p) {
|
|
194
|
-
return opts[p] || p;
|
|
195
|
-
})
|
|
196
|
-
);
|
|
197
|
-
tries.push(n);
|
|
198
|
-
try {
|
|
199
|
-
b = opts.path ? requireFunc.resolve(n) : requireFunc(n);
|
|
200
|
-
if (!opts.path) {
|
|
201
|
-
b.path = n;
|
|
202
|
-
}
|
|
203
|
-
return b;
|
|
204
|
-
} catch (e) {
|
|
205
|
-
if (e.code !== "MODULE_NOT_FOUND" && e.code !== "QUALIFIED_PATH_RESOLUTION_FAILED" && !/not find/i.test(e.message)) {
|
|
206
|
-
throw e;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
err = new Error(
|
|
211
|
-
"Could not locate the bindings file. Tried:\n" + tries.map(function(a) {
|
|
212
|
-
return opts.arrow + a;
|
|
213
|
-
}).join("\n")
|
|
214
|
-
);
|
|
215
|
-
err.tries = tries;
|
|
216
|
-
throw err;
|
|
217
|
-
}
|
|
218
|
-
module.exports = exports = bindings;
|
|
219
|
-
exports.getFileName = function getFileName(calling_file) {
|
|
220
|
-
var origPST = Error.prepareStackTrace, origSTL = Error.stackTraceLimit, dummy = {}, fileName;
|
|
221
|
-
Error.stackTraceLimit = 10;
|
|
222
|
-
Error.prepareStackTrace = function(e, st) {
|
|
223
|
-
for (var i = 0, l = st.length; i < l; i++) {
|
|
224
|
-
fileName = st[i].getFileName();
|
|
225
|
-
if (fileName !== __filename) {
|
|
226
|
-
if (calling_file) {
|
|
227
|
-
if (fileName !== calling_file) {
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
} else {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
|
-
Error.captureStackTrace(dummy);
|
|
237
|
-
dummy.stack;
|
|
238
|
-
Error.prepareStackTrace = origPST;
|
|
239
|
-
Error.stackTraceLimit = origSTL;
|
|
240
|
-
var fileSchema = "file://";
|
|
241
|
-
if (fileName.indexOf(fileSchema) === 0) {
|
|
242
|
-
fileName = fileURLToPath2(fileName);
|
|
243
|
-
}
|
|
244
|
-
return fileName;
|
|
245
|
-
};
|
|
246
|
-
exports.getRoot = function getRoot(file) {
|
|
247
|
-
var dir = dirname2(file), prev;
|
|
248
|
-
while (true) {
|
|
249
|
-
if (dir === ".") {
|
|
250
|
-
dir = process.cwd();
|
|
251
|
-
}
|
|
252
|
-
if (exists(join7(dir, "package.json")) || exists(join7(dir, "node_modules"))) {
|
|
253
|
-
return dir;
|
|
254
|
-
}
|
|
255
|
-
if (prev === dir) {
|
|
256
|
-
throw new Error(
|
|
257
|
-
'Could not find module root given file: "' + file + '". Do you have a `package.json` file? '
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
prev = dir;
|
|
261
|
-
dir = join7(dir, "..");
|
|
262
|
-
}
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
var require_wrappers = __commonJS({
|
|
267
|
-
"../../node_modules/better-sqlite3/lib/methods/wrappers.js"(exports) {
|
|
268
|
-
"use strict";
|
|
269
|
-
var { cppdb } = require_util();
|
|
270
|
-
exports.prepare = function prepare(sql) {
|
|
271
|
-
return this[cppdb].prepare(sql, this, false);
|
|
272
|
-
};
|
|
273
|
-
exports.exec = function exec(sql) {
|
|
274
|
-
this[cppdb].exec(sql);
|
|
275
|
-
return this;
|
|
276
|
-
};
|
|
277
|
-
exports.close = function close() {
|
|
278
|
-
this[cppdb].close();
|
|
279
|
-
return this;
|
|
280
|
-
};
|
|
281
|
-
exports.loadExtension = function loadExtension(...args) {
|
|
282
|
-
this[cppdb].loadExtension(...args);
|
|
283
|
-
return this;
|
|
284
|
-
};
|
|
285
|
-
exports.defaultSafeIntegers = function defaultSafeIntegers(...args) {
|
|
286
|
-
this[cppdb].defaultSafeIntegers(...args);
|
|
287
|
-
return this;
|
|
288
|
-
};
|
|
289
|
-
exports.unsafeMode = function unsafeMode(...args) {
|
|
290
|
-
this[cppdb].unsafeMode(...args);
|
|
291
|
-
return this;
|
|
292
|
-
};
|
|
293
|
-
exports.getters = {
|
|
294
|
-
name: {
|
|
295
|
-
get: function name() {
|
|
296
|
-
return this[cppdb].name;
|
|
297
|
-
},
|
|
298
|
-
enumerable: true
|
|
299
|
-
},
|
|
300
|
-
open: {
|
|
301
|
-
get: function open2() {
|
|
302
|
-
return this[cppdb].open;
|
|
303
|
-
},
|
|
304
|
-
enumerable: true
|
|
305
|
-
},
|
|
306
|
-
inTransaction: {
|
|
307
|
-
get: function inTransaction() {
|
|
308
|
-
return this[cppdb].inTransaction;
|
|
309
|
-
},
|
|
310
|
-
enumerable: true
|
|
311
|
-
},
|
|
312
|
-
readonly: {
|
|
313
|
-
get: function readonly() {
|
|
314
|
-
return this[cppdb].readonly;
|
|
315
|
-
},
|
|
316
|
-
enumerable: true
|
|
317
|
-
},
|
|
318
|
-
memory: {
|
|
319
|
-
get: function memory() {
|
|
320
|
-
return this[cppdb].memory;
|
|
321
|
-
},
|
|
322
|
-
enumerable: true
|
|
323
|
-
}
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
});
|
|
327
|
-
var require_transaction = __commonJS({
|
|
328
|
-
"../../node_modules/better-sqlite3/lib/methods/transaction.js"(exports, module) {
|
|
329
|
-
"use strict";
|
|
330
|
-
var { cppdb } = require_util();
|
|
331
|
-
var controllers = /* @__PURE__ */ new WeakMap();
|
|
332
|
-
module.exports = function transaction(fn) {
|
|
333
|
-
if (typeof fn !== "function") throw new TypeError("Expected first argument to be a function");
|
|
334
|
-
const db = this[cppdb];
|
|
335
|
-
const controller = getController(db, this);
|
|
336
|
-
const { apply } = Function.prototype;
|
|
337
|
-
const properties = {
|
|
338
|
-
default: { value: wrapTransaction(apply, fn, db, controller.default) },
|
|
339
|
-
deferred: { value: wrapTransaction(apply, fn, db, controller.deferred) },
|
|
340
|
-
immediate: { value: wrapTransaction(apply, fn, db, controller.immediate) },
|
|
341
|
-
exclusive: { value: wrapTransaction(apply, fn, db, controller.exclusive) },
|
|
342
|
-
database: { value: this, enumerable: true }
|
|
343
|
-
};
|
|
344
|
-
Object.defineProperties(properties.default.value, properties);
|
|
345
|
-
Object.defineProperties(properties.deferred.value, properties);
|
|
346
|
-
Object.defineProperties(properties.immediate.value, properties);
|
|
347
|
-
Object.defineProperties(properties.exclusive.value, properties);
|
|
348
|
-
return properties.default.value;
|
|
349
|
-
};
|
|
350
|
-
var getController = (db, self) => {
|
|
351
|
-
let controller = controllers.get(db);
|
|
352
|
-
if (!controller) {
|
|
353
|
-
const shared = {
|
|
354
|
-
commit: db.prepare("COMMIT", self, false),
|
|
355
|
-
rollback: db.prepare("ROLLBACK", self, false),
|
|
356
|
-
savepoint: db.prepare("SAVEPOINT ` _bs3. `", self, false),
|
|
357
|
-
release: db.prepare("RELEASE ` _bs3. `", self, false),
|
|
358
|
-
rollbackTo: db.prepare("ROLLBACK TO ` _bs3. `", self, false)
|
|
359
|
-
};
|
|
360
|
-
controllers.set(db, controller = {
|
|
361
|
-
default: Object.assign({ begin: db.prepare("BEGIN", self, false) }, shared),
|
|
362
|
-
deferred: Object.assign({ begin: db.prepare("BEGIN DEFERRED", self, false) }, shared),
|
|
363
|
-
immediate: Object.assign({ begin: db.prepare("BEGIN IMMEDIATE", self, false) }, shared),
|
|
364
|
-
exclusive: Object.assign({ begin: db.prepare("BEGIN EXCLUSIVE", self, false) }, shared)
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
return controller;
|
|
368
|
-
};
|
|
369
|
-
var wrapTransaction = (apply, fn, db, { begin, commit, rollback, savepoint, release, rollbackTo }) => function sqliteTransaction() {
|
|
370
|
-
let before, after, undo;
|
|
371
|
-
if (db.inTransaction) {
|
|
372
|
-
before = savepoint;
|
|
373
|
-
after = release;
|
|
374
|
-
undo = rollbackTo;
|
|
375
|
-
} else {
|
|
376
|
-
before = begin;
|
|
377
|
-
after = commit;
|
|
378
|
-
undo = rollback;
|
|
379
|
-
}
|
|
380
|
-
before.run();
|
|
381
|
-
try {
|
|
382
|
-
const result = apply.call(fn, this, arguments);
|
|
383
|
-
if (result && typeof result.then === "function") {
|
|
384
|
-
throw new TypeError("Transaction function cannot return a promise");
|
|
385
|
-
}
|
|
386
|
-
after.run();
|
|
387
|
-
return result;
|
|
388
|
-
} catch (ex) {
|
|
389
|
-
if (db.inTransaction) {
|
|
390
|
-
undo.run();
|
|
391
|
-
if (undo !== rollback) after.run();
|
|
392
|
-
}
|
|
393
|
-
throw ex;
|
|
394
|
-
}
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
});
|
|
398
|
-
var require_pragma = __commonJS({
|
|
399
|
-
"../../node_modules/better-sqlite3/lib/methods/pragma.js"(exports, module) {
|
|
400
|
-
"use strict";
|
|
401
|
-
var { getBooleanOption, cppdb } = require_util();
|
|
402
|
-
module.exports = function pragma(source, options) {
|
|
403
|
-
if (options == null) options = {};
|
|
404
|
-
if (typeof source !== "string") throw new TypeError("Expected first argument to be a string");
|
|
405
|
-
if (typeof options !== "object") throw new TypeError("Expected second argument to be an options object");
|
|
406
|
-
const simple = getBooleanOption(options, "simple");
|
|
407
|
-
const stmt = this[cppdb].prepare(`PRAGMA ${source}`, this, true);
|
|
408
|
-
return simple ? stmt.pluck().get() : stmt.all();
|
|
409
|
-
};
|
|
410
|
-
}
|
|
411
|
-
});
|
|
412
|
-
var require_backup = __commonJS({
|
|
413
|
-
"../../node_modules/better-sqlite3/lib/methods/backup.js"(exports, module) {
|
|
414
|
-
"use strict";
|
|
415
|
-
var fs = __require("fs");
|
|
416
|
-
var path = __require("path");
|
|
417
|
-
var { promisify } = __require("util");
|
|
418
|
-
var { cppdb } = require_util();
|
|
419
|
-
var fsAccess = promisify(fs.access);
|
|
420
|
-
module.exports = async function backup(filename, options) {
|
|
421
|
-
if (options == null) options = {};
|
|
422
|
-
if (typeof filename !== "string") throw new TypeError("Expected first argument to be a string");
|
|
423
|
-
if (typeof options !== "object") throw new TypeError("Expected second argument to be an options object");
|
|
424
|
-
filename = filename.trim();
|
|
425
|
-
const attachedName = "attached" in options ? options.attached : "main";
|
|
426
|
-
const handler = "progress" in options ? options.progress : null;
|
|
427
|
-
if (!filename) throw new TypeError("Backup filename cannot be an empty string");
|
|
428
|
-
if (filename === ":memory:") throw new TypeError('Invalid backup filename ":memory:"');
|
|
429
|
-
if (typeof attachedName !== "string") throw new TypeError('Expected the "attached" option to be a string');
|
|
430
|
-
if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string');
|
|
431
|
-
if (handler != null && typeof handler !== "function") throw new TypeError('Expected the "progress" option to be a function');
|
|
432
|
-
await fsAccess(path.dirname(filename)).catch(() => {
|
|
433
|
-
throw new TypeError("Cannot save backup because the directory does not exist");
|
|
434
|
-
});
|
|
435
|
-
const isNewFile = await fsAccess(filename).then(() => false, () => true);
|
|
436
|
-
return runBackup(this[cppdb].backup(this, attachedName, filename, isNewFile), handler || null);
|
|
437
|
-
};
|
|
438
|
-
var runBackup = (backup, handler) => {
|
|
439
|
-
let rate = 0;
|
|
440
|
-
let useDefault = true;
|
|
441
|
-
return new Promise((resolve, reject) => {
|
|
442
|
-
setImmediate(function step() {
|
|
443
|
-
try {
|
|
444
|
-
const progress = backup.transfer(rate);
|
|
445
|
-
if (!progress.remainingPages) {
|
|
446
|
-
backup.close();
|
|
447
|
-
resolve(progress);
|
|
448
|
-
return;
|
|
449
|
-
}
|
|
450
|
-
if (useDefault) {
|
|
451
|
-
useDefault = false;
|
|
452
|
-
rate = 100;
|
|
453
|
-
}
|
|
454
|
-
if (handler) {
|
|
455
|
-
const ret = handler(progress);
|
|
456
|
-
if (ret !== void 0) {
|
|
457
|
-
if (typeof ret === "number" && ret === ret) rate = Math.max(0, Math.min(2147483647, Math.round(ret)));
|
|
458
|
-
else throw new TypeError("Expected progress callback to return a number or undefined");
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
setImmediate(step);
|
|
462
|
-
} catch (err) {
|
|
463
|
-
backup.close();
|
|
464
|
-
reject(err);
|
|
465
|
-
}
|
|
466
|
-
});
|
|
467
|
-
});
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
});
|
|
471
|
-
var require_serialize = __commonJS({
|
|
472
|
-
"../../node_modules/better-sqlite3/lib/methods/serialize.js"(exports, module) {
|
|
473
|
-
"use strict";
|
|
474
|
-
var { cppdb } = require_util();
|
|
475
|
-
module.exports = function serialize(options) {
|
|
476
|
-
if (options == null) options = {};
|
|
477
|
-
if (typeof options !== "object") throw new TypeError("Expected first argument to be an options object");
|
|
478
|
-
const attachedName = "attached" in options ? options.attached : "main";
|
|
479
|
-
if (typeof attachedName !== "string") throw new TypeError('Expected the "attached" option to be a string');
|
|
480
|
-
if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string');
|
|
481
|
-
return this[cppdb].serialize(attachedName);
|
|
482
|
-
};
|
|
483
|
-
}
|
|
484
|
-
});
|
|
485
|
-
var require_function = __commonJS({
|
|
486
|
-
"../../node_modules/better-sqlite3/lib/methods/function.js"(exports, module) {
|
|
487
|
-
"use strict";
|
|
488
|
-
var { getBooleanOption, cppdb } = require_util();
|
|
489
|
-
module.exports = function defineFunction(name, options, fn) {
|
|
490
|
-
if (options == null) options = {};
|
|
491
|
-
if (typeof options === "function") {
|
|
492
|
-
fn = options;
|
|
493
|
-
options = {};
|
|
494
|
-
}
|
|
495
|
-
if (typeof name !== "string") throw new TypeError("Expected first argument to be a string");
|
|
496
|
-
if (typeof fn !== "function") throw new TypeError("Expected last argument to be a function");
|
|
497
|
-
if (typeof options !== "object") throw new TypeError("Expected second argument to be an options object");
|
|
498
|
-
if (!name) throw new TypeError("User-defined function name cannot be an empty string");
|
|
499
|
-
const safeIntegers = "safeIntegers" in options ? +getBooleanOption(options, "safeIntegers") : 2;
|
|
500
|
-
const deterministic = getBooleanOption(options, "deterministic");
|
|
501
|
-
const directOnly = getBooleanOption(options, "directOnly");
|
|
502
|
-
const varargs = getBooleanOption(options, "varargs");
|
|
503
|
-
let argCount = -1;
|
|
504
|
-
if (!varargs) {
|
|
505
|
-
argCount = fn.length;
|
|
506
|
-
if (!Number.isInteger(argCount) || argCount < 0) throw new TypeError("Expected function.length to be a positive integer");
|
|
507
|
-
if (argCount > 100) throw new RangeError("User-defined functions cannot have more than 100 arguments");
|
|
508
|
-
}
|
|
509
|
-
this[cppdb].function(fn, name, argCount, safeIntegers, deterministic, directOnly);
|
|
510
|
-
return this;
|
|
511
|
-
};
|
|
512
|
-
}
|
|
513
|
-
});
|
|
514
|
-
var require_aggregate = __commonJS({
|
|
515
|
-
"../../node_modules/better-sqlite3/lib/methods/aggregate.js"(exports, module) {
|
|
516
|
-
"use strict";
|
|
517
|
-
var { getBooleanOption, cppdb } = require_util();
|
|
518
|
-
module.exports = function defineAggregate(name, options) {
|
|
519
|
-
if (typeof name !== "string") throw new TypeError("Expected first argument to be a string");
|
|
520
|
-
if (typeof options !== "object" || options === null) throw new TypeError("Expected second argument to be an options object");
|
|
521
|
-
if (!name) throw new TypeError("User-defined function name cannot be an empty string");
|
|
522
|
-
const start = "start" in options ? options.start : null;
|
|
523
|
-
const step = getFunctionOption(options, "step", true);
|
|
524
|
-
const inverse = getFunctionOption(options, "inverse", false);
|
|
525
|
-
const result = getFunctionOption(options, "result", false);
|
|
526
|
-
const safeIntegers = "safeIntegers" in options ? +getBooleanOption(options, "safeIntegers") : 2;
|
|
527
|
-
const deterministic = getBooleanOption(options, "deterministic");
|
|
528
|
-
const directOnly = getBooleanOption(options, "directOnly");
|
|
529
|
-
const varargs = getBooleanOption(options, "varargs");
|
|
530
|
-
let argCount = -1;
|
|
531
|
-
if (!varargs) {
|
|
532
|
-
argCount = Math.max(getLength(step), inverse ? getLength(inverse) : 0);
|
|
533
|
-
if (argCount > 0) argCount -= 1;
|
|
534
|
-
if (argCount > 100) throw new RangeError("User-defined functions cannot have more than 100 arguments");
|
|
535
|
-
}
|
|
536
|
-
this[cppdb].aggregate(start, step, inverse, result, name, argCount, safeIntegers, deterministic, directOnly);
|
|
537
|
-
return this;
|
|
538
|
-
};
|
|
539
|
-
var getFunctionOption = (options, key, required) => {
|
|
540
|
-
const value = key in options ? options[key] : null;
|
|
541
|
-
if (typeof value === "function") return value;
|
|
542
|
-
if (value != null) throw new TypeError(`Expected the "${key}" option to be a function`);
|
|
543
|
-
if (required) throw new TypeError(`Missing required option "${key}"`);
|
|
544
|
-
return null;
|
|
545
|
-
};
|
|
546
|
-
var getLength = ({ length }) => {
|
|
547
|
-
if (Number.isInteger(length) && length >= 0) return length;
|
|
548
|
-
throw new TypeError("Expected function.length to be a positive integer");
|
|
549
|
-
};
|
|
550
|
-
}
|
|
551
|
-
});
|
|
552
|
-
var require_table = __commonJS({
|
|
553
|
-
"../../node_modules/better-sqlite3/lib/methods/table.js"(exports, module) {
|
|
554
|
-
"use strict";
|
|
555
|
-
var { cppdb } = require_util();
|
|
556
|
-
module.exports = function defineTable(name, factory) {
|
|
557
|
-
if (typeof name !== "string") throw new TypeError("Expected first argument to be a string");
|
|
558
|
-
if (!name) throw new TypeError("Virtual table module name cannot be an empty string");
|
|
559
|
-
let eponymous = false;
|
|
560
|
-
if (typeof factory === "object" && factory !== null) {
|
|
561
|
-
eponymous = true;
|
|
562
|
-
factory = defer(parseTableDefinition(factory, "used", name));
|
|
563
|
-
} else {
|
|
564
|
-
if (typeof factory !== "function") throw new TypeError("Expected second argument to be a function or a table definition object");
|
|
565
|
-
factory = wrapFactory(factory);
|
|
566
|
-
}
|
|
567
|
-
this[cppdb].table(factory, name, eponymous);
|
|
568
|
-
return this;
|
|
569
|
-
};
|
|
570
|
-
function wrapFactory(factory) {
|
|
571
|
-
return function virtualTableFactory(moduleName, databaseName, tableName, ...args) {
|
|
572
|
-
const thisObject = {
|
|
573
|
-
module: moduleName,
|
|
574
|
-
database: databaseName,
|
|
575
|
-
table: tableName
|
|
576
|
-
};
|
|
577
|
-
const def = apply.call(factory, thisObject, args);
|
|
578
|
-
if (typeof def !== "object" || def === null) {
|
|
579
|
-
throw new TypeError(`Virtual table module "${moduleName}" did not return a table definition object`);
|
|
580
|
-
}
|
|
581
|
-
return parseTableDefinition(def, "returned", moduleName);
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
function parseTableDefinition(def, verb, moduleName) {
|
|
585
|
-
if (!hasOwnProperty.call(def, "rows")) {
|
|
586
|
-
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition without a "rows" property`);
|
|
587
|
-
}
|
|
588
|
-
if (!hasOwnProperty.call(def, "columns")) {
|
|
589
|
-
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition without a "columns" property`);
|
|
590
|
-
}
|
|
591
|
-
const rows = def.rows;
|
|
592
|
-
if (typeof rows !== "function" || Object.getPrototypeOf(rows) !== GeneratorFunctionPrototype) {
|
|
593
|
-
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "rows" property (should be a generator function)`);
|
|
594
|
-
}
|
|
595
|
-
let columns = def.columns;
|
|
596
|
-
if (!Array.isArray(columns) || !(columns = [...columns]).every((x) => typeof x === "string")) {
|
|
597
|
-
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "columns" property (should be an array of strings)`);
|
|
598
|
-
}
|
|
599
|
-
if (columns.length !== new Set(columns).size) {
|
|
600
|
-
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with duplicate column names`);
|
|
601
|
-
}
|
|
602
|
-
if (!columns.length) {
|
|
603
|
-
throw new RangeError(`Virtual table module "${moduleName}" ${verb} a table definition with zero columns`);
|
|
604
|
-
}
|
|
605
|
-
let parameters;
|
|
606
|
-
if (hasOwnProperty.call(def, "parameters")) {
|
|
607
|
-
parameters = def.parameters;
|
|
608
|
-
if (!Array.isArray(parameters) || !(parameters = [...parameters]).every((x) => typeof x === "string")) {
|
|
609
|
-
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "parameters" property (should be an array of strings)`);
|
|
610
|
-
}
|
|
611
|
-
} else {
|
|
612
|
-
parameters = inferParameters(rows);
|
|
613
|
-
}
|
|
614
|
-
if (parameters.length !== new Set(parameters).size) {
|
|
615
|
-
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with duplicate parameter names`);
|
|
616
|
-
}
|
|
617
|
-
if (parameters.length > 32) {
|
|
618
|
-
throw new RangeError(`Virtual table module "${moduleName}" ${verb} a table definition with more than the maximum number of 32 parameters`);
|
|
619
|
-
}
|
|
620
|
-
for (const parameter of parameters) {
|
|
621
|
-
if (columns.includes(parameter)) {
|
|
622
|
-
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with column "${parameter}" which was ambiguously defined as both a column and parameter`);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
let safeIntegers = 2;
|
|
626
|
-
if (hasOwnProperty.call(def, "safeIntegers")) {
|
|
627
|
-
const bool = def.safeIntegers;
|
|
628
|
-
if (typeof bool !== "boolean") {
|
|
629
|
-
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "safeIntegers" property (should be a boolean)`);
|
|
630
|
-
}
|
|
631
|
-
safeIntegers = +bool;
|
|
632
|
-
}
|
|
633
|
-
let directOnly = false;
|
|
634
|
-
if (hasOwnProperty.call(def, "directOnly")) {
|
|
635
|
-
directOnly = def.directOnly;
|
|
636
|
-
if (typeof directOnly !== "boolean") {
|
|
637
|
-
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "directOnly" property (should be a boolean)`);
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
const columnDefinitions = [
|
|
641
|
-
...parameters.map(identifier).map((str) => `${str} HIDDEN`),
|
|
642
|
-
...columns.map(identifier)
|
|
643
|
-
];
|
|
644
|
-
return [
|
|
645
|
-
`CREATE TABLE x(${columnDefinitions.join(", ")});`,
|
|
646
|
-
wrapGenerator(rows, new Map(columns.map((x, i) => [x, parameters.length + i])), moduleName),
|
|
647
|
-
parameters,
|
|
648
|
-
safeIntegers,
|
|
649
|
-
directOnly
|
|
650
|
-
];
|
|
651
|
-
}
|
|
652
|
-
function wrapGenerator(generator, columnMap, moduleName) {
|
|
653
|
-
return function* virtualTable(...args) {
|
|
654
|
-
const output = args.map((x) => Buffer.isBuffer(x) ? Buffer.from(x) : x);
|
|
655
|
-
for (let i = 0; i < columnMap.size; ++i) {
|
|
656
|
-
output.push(null);
|
|
657
|
-
}
|
|
658
|
-
for (const row of generator(...args)) {
|
|
659
|
-
if (Array.isArray(row)) {
|
|
660
|
-
extractRowArray(row, output, columnMap.size, moduleName);
|
|
661
|
-
yield output;
|
|
662
|
-
} else if (typeof row === "object" && row !== null) {
|
|
663
|
-
extractRowObject(row, output, columnMap, moduleName);
|
|
664
|
-
yield output;
|
|
665
|
-
} else {
|
|
666
|
-
throw new TypeError(`Virtual table module "${moduleName}" yielded something that isn't a valid row object`);
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
};
|
|
670
|
-
}
|
|
671
|
-
function extractRowArray(row, output, columnCount, moduleName) {
|
|
672
|
-
if (row.length !== columnCount) {
|
|
673
|
-
throw new TypeError(`Virtual table module "${moduleName}" yielded a row with an incorrect number of columns`);
|
|
674
|
-
}
|
|
675
|
-
const offset = output.length - columnCount;
|
|
676
|
-
for (let i = 0; i < columnCount; ++i) {
|
|
677
|
-
output[i + offset] = row[i];
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
function extractRowObject(row, output, columnMap, moduleName) {
|
|
681
|
-
let count = 0;
|
|
682
|
-
for (const key of Object.keys(row)) {
|
|
683
|
-
const index = columnMap.get(key);
|
|
684
|
-
if (index === void 0) {
|
|
685
|
-
throw new TypeError(`Virtual table module "${moduleName}" yielded a row with an undeclared column "${key}"`);
|
|
686
|
-
}
|
|
687
|
-
output[index] = row[key];
|
|
688
|
-
count += 1;
|
|
689
|
-
}
|
|
690
|
-
if (count !== columnMap.size) {
|
|
691
|
-
throw new TypeError(`Virtual table module "${moduleName}" yielded a row with missing columns`);
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
function inferParameters({ length }) {
|
|
695
|
-
if (!Number.isInteger(length) || length < 0) {
|
|
696
|
-
throw new TypeError("Expected function.length to be a positive integer");
|
|
697
|
-
}
|
|
698
|
-
const params = [];
|
|
699
|
-
for (let i = 0; i < length; ++i) {
|
|
700
|
-
params.push(`$${i + 1}`);
|
|
701
|
-
}
|
|
702
|
-
return params;
|
|
703
|
-
}
|
|
704
|
-
var { hasOwnProperty } = Object.prototype;
|
|
705
|
-
var { apply } = Function.prototype;
|
|
706
|
-
var GeneratorFunctionPrototype = Object.getPrototypeOf(function* () {
|
|
707
|
-
});
|
|
708
|
-
var identifier = (str) => `"${str.replace(/"/g, '""')}"`;
|
|
709
|
-
var defer = (x) => () => x;
|
|
710
|
-
}
|
|
711
|
-
});
|
|
712
|
-
var require_inspect = __commonJS({
|
|
713
|
-
"../../node_modules/better-sqlite3/lib/methods/inspect.js"(exports, module) {
|
|
714
|
-
"use strict";
|
|
715
|
-
var DatabaseInspection = function Database2() {
|
|
716
|
-
};
|
|
717
|
-
module.exports = function inspect(depth, opts) {
|
|
718
|
-
return Object.assign(new DatabaseInspection(), this);
|
|
719
|
-
};
|
|
720
|
-
}
|
|
721
|
-
});
|
|
722
|
-
var require_database = __commonJS({
|
|
723
|
-
"../../node_modules/better-sqlite3/lib/database.js"(exports, module) {
|
|
724
|
-
"use strict";
|
|
725
|
-
var fs = __require("fs");
|
|
726
|
-
var path = __require("path");
|
|
727
|
-
var util = require_util();
|
|
728
|
-
var SqliteError = require_sqlite_error();
|
|
729
|
-
var DEFAULT_ADDON;
|
|
730
|
-
function Database2(filenameGiven, options) {
|
|
731
|
-
if (new.target == null) {
|
|
732
|
-
return new Database2(filenameGiven, options);
|
|
733
|
-
}
|
|
734
|
-
let buffer;
|
|
735
|
-
if (Buffer.isBuffer(filenameGiven)) {
|
|
736
|
-
buffer = filenameGiven;
|
|
737
|
-
filenameGiven = ":memory:";
|
|
738
|
-
}
|
|
739
|
-
if (filenameGiven == null) filenameGiven = "";
|
|
740
|
-
if (options == null) options = {};
|
|
741
|
-
if (typeof filenameGiven !== "string") throw new TypeError("Expected first argument to be a string");
|
|
742
|
-
if (typeof options !== "object") throw new TypeError("Expected second argument to be an options object");
|
|
743
|
-
if ("readOnly" in options) throw new TypeError('Misspelled option "readOnly" should be "readonly"');
|
|
744
|
-
if ("memory" in options) throw new TypeError('Option "memory" was removed in v7.0.0 (use ":memory:" filename instead)');
|
|
745
|
-
const filename = filenameGiven.trim();
|
|
746
|
-
const anonymous = filename === "" || filename === ":memory:";
|
|
747
|
-
const readonly = util.getBooleanOption(options, "readonly");
|
|
748
|
-
const fileMustExist = util.getBooleanOption(options, "fileMustExist");
|
|
749
|
-
const timeout = "timeout" in options ? options.timeout : 5e3;
|
|
750
|
-
const verbose = "verbose" in options ? options.verbose : null;
|
|
751
|
-
const nativeBinding = "nativeBinding" in options ? options.nativeBinding : null;
|
|
752
|
-
if (readonly && anonymous && !buffer) throw new TypeError("In-memory/temporary databases cannot be readonly");
|
|
753
|
-
if (!Number.isInteger(timeout) || timeout < 0) throw new TypeError('Expected the "timeout" option to be a positive integer');
|
|
754
|
-
if (timeout > 2147483647) throw new RangeError('Option "timeout" cannot be greater than 2147483647');
|
|
755
|
-
if (verbose != null && typeof verbose !== "function") throw new TypeError('Expected the "verbose" option to be a function');
|
|
756
|
-
if (nativeBinding != null && typeof nativeBinding !== "string" && typeof nativeBinding !== "object") throw new TypeError('Expected the "nativeBinding" option to be a string or addon object');
|
|
757
|
-
let addon;
|
|
758
|
-
if (nativeBinding == null) {
|
|
759
|
-
addon = DEFAULT_ADDON || (DEFAULT_ADDON = require_bindings()("better_sqlite3.node"));
|
|
760
|
-
} else if (typeof nativeBinding === "string") {
|
|
761
|
-
const requireFunc = typeof __non_webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
762
|
-
addon = requireFunc(path.resolve(nativeBinding).replace(/(\.node)?$/, ".node"));
|
|
763
|
-
} else {
|
|
764
|
-
addon = nativeBinding;
|
|
765
|
-
}
|
|
766
|
-
if (!addon.isInitialized) {
|
|
767
|
-
addon.setErrorConstructor(SqliteError);
|
|
768
|
-
addon.isInitialized = true;
|
|
769
|
-
}
|
|
770
|
-
if (!anonymous && !filename.startsWith("file:") && !fs.existsSync(path.dirname(filename))) {
|
|
771
|
-
throw new TypeError("Cannot open database because the directory does not exist");
|
|
772
|
-
}
|
|
773
|
-
Object.defineProperties(this, {
|
|
774
|
-
[util.cppdb]: { value: new addon.Database(filename, filenameGiven, anonymous, readonly, fileMustExist, timeout, verbose || null, buffer || null) },
|
|
775
|
-
...wrappers.getters
|
|
776
|
-
});
|
|
777
|
-
}
|
|
778
|
-
var wrappers = require_wrappers();
|
|
779
|
-
Database2.prototype.prepare = wrappers.prepare;
|
|
780
|
-
Database2.prototype.transaction = require_transaction();
|
|
781
|
-
Database2.prototype.pragma = require_pragma();
|
|
782
|
-
Database2.prototype.backup = require_backup();
|
|
783
|
-
Database2.prototype.serialize = require_serialize();
|
|
784
|
-
Database2.prototype.function = require_function();
|
|
785
|
-
Database2.prototype.aggregate = require_aggregate();
|
|
786
|
-
Database2.prototype.table = require_table();
|
|
787
|
-
Database2.prototype.loadExtension = wrappers.loadExtension;
|
|
788
|
-
Database2.prototype.exec = wrappers.exec;
|
|
789
|
-
Database2.prototype.close = wrappers.close;
|
|
790
|
-
Database2.prototype.defaultSafeIntegers = wrappers.defaultSafeIntegers;
|
|
791
|
-
Database2.prototype.unsafeMode = wrappers.unsafeMode;
|
|
792
|
-
Database2.prototype[util.inspect] = require_inspect();
|
|
793
|
-
module.exports = Database2;
|
|
794
|
-
}
|
|
795
|
-
});
|
|
796
|
-
var require_lib = __commonJS({
|
|
797
|
-
"../../node_modules/better-sqlite3/lib/index.js"(exports, module) {
|
|
798
|
-
"use strict";
|
|
799
|
-
module.exports = require_database();
|
|
800
|
-
module.exports.SqliteError = require_sqlite_error();
|
|
801
|
-
}
|
|
802
|
-
});
|
|
803
39
|
var config = {
|
|
804
40
|
port: parseInt(process.env.AGENT_MOVE_PORT || "3333", 10),
|
|
805
41
|
claudeHome: join(homedir(), ".claude"),
|
|
@@ -811,7 +47,11 @@ var config = {
|
|
|
811
47
|
activeThresholdMs: 10 * 60 * 1e3,
|
|
812
48
|
// 10 minutes
|
|
813
49
|
/** Enable OpenCode session watching (auto-detected if storage dir exists) */
|
|
814
|
-
enableOpenCode: process.env.AGENT_MOVE_OPENCODE !== "false"
|
|
50
|
+
enableOpenCode: process.env.AGENT_MOVE_OPENCODE !== "false",
|
|
51
|
+
/** Enable pi coding agent session watching (auto-detected if sessions dir exists) */
|
|
52
|
+
enablePi: process.env.AGENT_MOVE_PI !== "false",
|
|
53
|
+
/** Enable Codex CLI session watching (auto-detected if sessions dir exists) */
|
|
54
|
+
enableCodex: process.env.AGENT_MOVE_CODEX !== "false"
|
|
815
55
|
};
|
|
816
56
|
var JsonlParser = class {
|
|
817
57
|
parseLine(line) {
|
|
@@ -904,6 +144,38 @@ var JsonlParser = class {
|
|
|
904
144
|
return null;
|
|
905
145
|
}
|
|
906
146
|
};
|
|
147
|
+
function resolveEncodedPath(root, segments) {
|
|
148
|
+
try {
|
|
149
|
+
const parts = segments.split("-").filter(Boolean);
|
|
150
|
+
let currentPath = root;
|
|
151
|
+
let lastName = "";
|
|
152
|
+
let i = 0;
|
|
153
|
+
while (i < parts.length) {
|
|
154
|
+
let found = false;
|
|
155
|
+
const maxLen = Math.min(parts.length - i, 6);
|
|
156
|
+
for (let len = 1; len <= maxLen; len++) {
|
|
157
|
+
const segment = parts.slice(i, i + len).join("-");
|
|
158
|
+
for (const prefix of ["", "."]) {
|
|
159
|
+
const testPath = join2(currentPath, prefix + segment);
|
|
160
|
+
if (existsSync(testPath)) {
|
|
161
|
+
currentPath = testPath;
|
|
162
|
+
lastName = prefix + segment;
|
|
163
|
+
i += len;
|
|
164
|
+
found = true;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (found)
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
if (!found)
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
return lastName || null;
|
|
175
|
+
} catch {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
907
179
|
var ClaudePaths = class {
|
|
908
180
|
/**
|
|
909
181
|
* Parse a JSONL session file path to extract project info.
|
|
@@ -916,6 +188,7 @@ var ClaudePaths = class {
|
|
|
916
188
|
const projectsIdx = parts.indexOf("projects");
|
|
917
189
|
if (projectsIdx === -1 || projectsIdx + 1 >= parts.length) {
|
|
918
190
|
return {
|
|
191
|
+
agentType: "claude",
|
|
919
192
|
projectPath: "unknown",
|
|
920
193
|
projectName: "Unknown",
|
|
921
194
|
isSubagent: false,
|
|
@@ -929,6 +202,7 @@ var ClaudePaths = class {
|
|
|
929
202
|
const isSubagent = depthAfterProject > 1;
|
|
930
203
|
const parentSessionId = isSubagent ? parts[projectsIdx + 2] : null;
|
|
931
204
|
return {
|
|
205
|
+
agentType: "claude",
|
|
932
206
|
projectPath: encodedProjectName,
|
|
933
207
|
projectName,
|
|
934
208
|
isSubagent,
|
|
@@ -942,80 +216,37 @@ var ClaudePaths = class {
|
|
|
942
216
|
* e.g., "C--projects-fts-temp-agent-move" → "agent-move"
|
|
943
217
|
*/
|
|
944
218
|
decodeProjectName(encoded) {
|
|
945
|
-
const
|
|
946
|
-
|
|
947
|
-
|
|
219
|
+
const driveMatch = encoded.match(/^([A-Za-z])--(.*)/);
|
|
220
|
+
const unixMatch = !driveMatch && encoded.match(/^-(.*)/);
|
|
221
|
+
if (driveMatch) {
|
|
222
|
+
const resolved = resolveEncodedPath(driveMatch[1] + ":/", driveMatch[2]);
|
|
223
|
+
if (resolved)
|
|
224
|
+
return resolved;
|
|
225
|
+
} else if (unixMatch) {
|
|
226
|
+
const resolved = resolveEncodedPath("/", unixMatch[1]);
|
|
227
|
+
if (resolved)
|
|
228
|
+
return resolved;
|
|
229
|
+
}
|
|
948
230
|
const parts = encoded.split("-").filter((p) => p.length > 0);
|
|
949
231
|
if (parts.length <= 2)
|
|
950
232
|
return parts.join("/");
|
|
951
233
|
return parts.slice(-2).join("/");
|
|
952
234
|
}
|
|
953
|
-
/**
|
|
954
|
-
* Greedily resolve the encoded path against the filesystem.
|
|
955
|
-
* Tries each dash-segment as a directory, joining multiple segments
|
|
956
|
-
* when a single one doesn't exist (to handle dashes in folder names).
|
|
957
|
-
*/
|
|
958
|
-
resolveToFolderName(encoded) {
|
|
959
|
-
try {
|
|
960
|
-
let root;
|
|
961
|
-
let rest;
|
|
962
|
-
const driveMatch = encoded.match(/^([A-Za-z])--(.*)/);
|
|
963
|
-
const unixMatch = !driveMatch && encoded.match(/^-(.*)/);
|
|
964
|
-
if (driveMatch) {
|
|
965
|
-
root = driveMatch[1] + ":/";
|
|
966
|
-
rest = driveMatch[2];
|
|
967
|
-
} else if (unixMatch) {
|
|
968
|
-
root = "/";
|
|
969
|
-
rest = unixMatch[1];
|
|
970
|
-
} else {
|
|
971
|
-
return null;
|
|
972
|
-
}
|
|
973
|
-
const parts = rest.split("-").filter(Boolean);
|
|
974
|
-
let currentPath = root;
|
|
975
|
-
let lastName = "";
|
|
976
|
-
let i = 0;
|
|
977
|
-
while (i < parts.length) {
|
|
978
|
-
let found = false;
|
|
979
|
-
const maxLen = Math.min(parts.length - i, 6);
|
|
980
|
-
for (let len = 1; len <= maxLen; len++) {
|
|
981
|
-
const segment = parts.slice(i, i + len).join("-");
|
|
982
|
-
for (const prefix of ["", "."]) {
|
|
983
|
-
const testPath = join2(currentPath, prefix + segment);
|
|
984
|
-
if (existsSync(testPath)) {
|
|
985
|
-
currentPath = testPath;
|
|
986
|
-
lastName = prefix + segment;
|
|
987
|
-
i += len;
|
|
988
|
-
found = true;
|
|
989
|
-
break;
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
if (found)
|
|
993
|
-
break;
|
|
994
|
-
}
|
|
995
|
-
if (!found)
|
|
996
|
-
break;
|
|
997
|
-
}
|
|
998
|
-
return lastName || null;
|
|
999
|
-
} catch {
|
|
1000
|
-
return null;
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
235
|
};
|
|
1004
236
|
var claudePaths = new ClaudePaths();
|
|
1005
237
|
var SessionScanner = class {
|
|
1006
|
-
|
|
1007
|
-
constructor(
|
|
1008
|
-
this.
|
|
238
|
+
rootDir;
|
|
239
|
+
constructor(rootDir) {
|
|
240
|
+
this.rootDir = rootDir;
|
|
1009
241
|
}
|
|
1010
|
-
/** Find
|
|
242
|
+
/** Find the most recently modified JSONL per project subdirectory */
|
|
1011
243
|
async scan() {
|
|
1012
244
|
const results = [];
|
|
1013
|
-
const projectsDir = join3(this.claudeHome, "projects");
|
|
1014
245
|
try {
|
|
1015
|
-
const projects = await readdir(
|
|
246
|
+
const projects = await readdir(this.rootDir);
|
|
1016
247
|
const now = Date.now();
|
|
1017
248
|
for (const project of projects) {
|
|
1018
|
-
const projectDir = join3(
|
|
249
|
+
const projectDir = join3(this.rootDir, project);
|
|
1019
250
|
try {
|
|
1020
251
|
const projectStat = await stat(projectDir);
|
|
1021
252
|
if (!projectStat.isDirectory())
|
|
@@ -1045,7 +276,6 @@ var SessionScanner = class {
|
|
|
1045
276
|
}
|
|
1046
277
|
}
|
|
1047
278
|
} catch {
|
|
1048
|
-
console.log("No projects directory found \u2014 will wait for new sessions");
|
|
1049
279
|
}
|
|
1050
280
|
return results;
|
|
1051
281
|
}
|
|
@@ -1063,7 +293,7 @@ var FileWatcher = class {
|
|
|
1063
293
|
this.stateManager = stateManager;
|
|
1064
294
|
}
|
|
1065
295
|
async start() {
|
|
1066
|
-
const scanner = new SessionScanner(this.claudeHome);
|
|
296
|
+
const scanner = new SessionScanner(join4(this.claudeHome, "projects"));
|
|
1067
297
|
const existingFiles = await scanner.scan();
|
|
1068
298
|
for (const file of existingFiles) {
|
|
1069
299
|
await this.processFile(file);
|
|
@@ -1134,7 +364,16 @@ var FileWatcher = class {
|
|
|
1134
364
|
}
|
|
1135
365
|
}
|
|
1136
366
|
};
|
|
1137
|
-
|
|
367
|
+
function createFallbackSession(agentType, name) {
|
|
368
|
+
return {
|
|
369
|
+
agentType,
|
|
370
|
+
projectPath: name,
|
|
371
|
+
projectName: name,
|
|
372
|
+
isSubagent: false,
|
|
373
|
+
projectDir: name,
|
|
374
|
+
parentSessionId: null
|
|
375
|
+
};
|
|
376
|
+
}
|
|
1138
377
|
function getOpenCodeDbPath() {
|
|
1139
378
|
const home = homedir2();
|
|
1140
379
|
const candidates = [
|
|
@@ -1153,6 +392,7 @@ function parseOpenCodeSession(row) {
|
|
|
1153
392
|
const segments = row.directory.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
1154
393
|
const projectName = segments[segments.length - 1] || "opencode";
|
|
1155
394
|
return {
|
|
395
|
+
agentType: "opencode",
|
|
1156
396
|
// Use the actual directory as projectPath so getGitBranch() gets a valid cwd.
|
|
1157
397
|
// projectDir uses the project_id hash to group agents belonging to the same project.
|
|
1158
398
|
projectPath: row.directory || row.project_id,
|
|
@@ -1212,7 +452,7 @@ function getZoneForTool(toolName) {
|
|
|
1212
452
|
return TOOL_ZONE_MAP[toolName] ?? "thinking";
|
|
1213
453
|
}
|
|
1214
454
|
var TOOL_NAME_MAP = {
|
|
1215
|
-
// OpenCode lowercase → canonical PascalCase
|
|
455
|
+
// OpenCode / pi lowercase → canonical PascalCase
|
|
1216
456
|
read: "Read",
|
|
1217
457
|
write: "Write",
|
|
1218
458
|
edit: "Edit",
|
|
@@ -1223,7 +463,36 @@ var TOOL_NAME_MAP = {
|
|
|
1223
463
|
websearch: "WebSearch",
|
|
1224
464
|
webfetch: "WebFetch",
|
|
1225
465
|
todoread: "TodoRead",
|
|
1226
|
-
todowrite: "TodoWrite"
|
|
466
|
+
todowrite: "TodoWrite",
|
|
467
|
+
// pi-specific tool names
|
|
468
|
+
"edit-diff": "Patch",
|
|
469
|
+
find: "Glob",
|
|
470
|
+
ls: "Bash",
|
|
471
|
+
truncate: "Write",
|
|
472
|
+
// Codex CLI tool names
|
|
473
|
+
shell_command: "Bash",
|
|
474
|
+
exec_command: "Bash",
|
|
475
|
+
read_file: "Read",
|
|
476
|
+
apply_patch: "Patch",
|
|
477
|
+
list_dir: "Bash",
|
|
478
|
+
grep_files: "Grep",
|
|
479
|
+
web_search: "WebSearch",
|
|
480
|
+
js_repl: "Bash",
|
|
481
|
+
js_repl_reset: "Bash",
|
|
482
|
+
spawn_agent: "Agent",
|
|
483
|
+
send_input: "Agent",
|
|
484
|
+
wait: "Agent",
|
|
485
|
+
close_agent: "Agent",
|
|
486
|
+
resume_agent: "Agent",
|
|
487
|
+
spawn_agents_on_csv: "Agent",
|
|
488
|
+
report_agent_job_result: "Agent",
|
|
489
|
+
request_user_input: "AskUserQuestion",
|
|
490
|
+
request_permissions: "AskUserQuestion",
|
|
491
|
+
update_plan: "TodoWrite",
|
|
492
|
+
view_image: "Read",
|
|
493
|
+
image_generation: "Write",
|
|
494
|
+
write_stdin: "Bash",
|
|
495
|
+
search_apps: "WebSearch"
|
|
1227
496
|
};
|
|
1228
497
|
function normalizeToolName(name) {
|
|
1229
498
|
return TOOL_NAME_MAP[name] ?? name;
|
|
@@ -1520,7 +789,7 @@ var OpenCodeWatcher = class {
|
|
|
1520
789
|
}
|
|
1521
790
|
console.log(`[opencode] Database found at ${dbPath}`);
|
|
1522
791
|
try {
|
|
1523
|
-
this.db = new
|
|
792
|
+
this.db = new Database(dbPath, { readonly: true, fileMustExist: true });
|
|
1524
793
|
this.prepareStatements();
|
|
1525
794
|
} catch (err) {
|
|
1526
795
|
console.error("[opencode] Failed to open database:", err);
|
|
@@ -1684,13 +953,597 @@ var OpenCodeWatcher = class {
|
|
|
1684
953
|
return id.startsWith("oc:") ? id : `oc:${id}`;
|
|
1685
954
|
}
|
|
1686
955
|
fallbackSession() {
|
|
1687
|
-
return
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
956
|
+
return createFallbackSession("opencode", "opencode");
|
|
957
|
+
}
|
|
958
|
+
};
|
|
959
|
+
var PiParser = class {
|
|
960
|
+
/**
|
|
961
|
+
* Parse a single JSONL line from a pi session file into a raw object.
|
|
962
|
+
* Returns the parsed JSON, or null on parse error.
|
|
963
|
+
*/
|
|
964
|
+
parseRaw(line) {
|
|
965
|
+
try {
|
|
966
|
+
return JSON.parse(line);
|
|
967
|
+
} catch {
|
|
968
|
+
return null;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Extract a ParsedActivity from a pre-parsed JSONL entry.
|
|
973
|
+
* Returns null for non-actionable entries (session header, user messages, etc.).
|
|
974
|
+
*/
|
|
975
|
+
parseEntry(entry) {
|
|
976
|
+
if (entry.type !== "message")
|
|
977
|
+
return null;
|
|
978
|
+
const msg = entry.message;
|
|
979
|
+
if (!msg || msg.role !== "assistant")
|
|
980
|
+
return null;
|
|
981
|
+
return this.parseAssistantMessage(msg);
|
|
982
|
+
}
|
|
983
|
+
/**
|
|
984
|
+
* Check if a pre-parsed entry is a session header.
|
|
985
|
+
*/
|
|
986
|
+
isSessionHeader(entry) {
|
|
987
|
+
return entry.type === "session";
|
|
988
|
+
}
|
|
989
|
+
parseAssistantMessage(msg) {
|
|
990
|
+
const content = msg.content;
|
|
991
|
+
if (!Array.isArray(content))
|
|
992
|
+
return null;
|
|
993
|
+
for (const block of content) {
|
|
994
|
+
if (block.type === "toolCall") {
|
|
995
|
+
const tool = block;
|
|
996
|
+
return {
|
|
997
|
+
type: "tool_use",
|
|
998
|
+
toolName: normalizeToolName(tool.name),
|
|
999
|
+
toolInput: normalizeToolInput(tool.arguments ?? {}),
|
|
1000
|
+
model: msg.model,
|
|
1001
|
+
inputTokens: msg.usage?.input,
|
|
1002
|
+
outputTokens: msg.usage?.output,
|
|
1003
|
+
cacheReadTokens: msg.usage?.cacheRead,
|
|
1004
|
+
cacheCreationTokens: msg.usage?.cacheWrite
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
for (const block of content) {
|
|
1009
|
+
if (block.type === "text") {
|
|
1010
|
+
const text = block.text?.trim() ?? "";
|
|
1011
|
+
if (text.length > 0 && text.length < 200) {
|
|
1012
|
+
return {
|
|
1013
|
+
type: "text",
|
|
1014
|
+
text,
|
|
1015
|
+
model: msg.model,
|
|
1016
|
+
inputTokens: msg.usage?.input,
|
|
1017
|
+
outputTokens: msg.usage?.output,
|
|
1018
|
+
cacheReadTokens: msg.usage?.cacheRead,
|
|
1019
|
+
cacheCreationTokens: msg.usage?.cacheWrite
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
for (const block of content) {
|
|
1025
|
+
if (block.type === "thinking") {
|
|
1026
|
+
const thinking = block.thinking?.trim() ?? "";
|
|
1027
|
+
return {
|
|
1028
|
+
type: "tool_use",
|
|
1029
|
+
toolName: "thinking",
|
|
1030
|
+
toolInput: thinking.length > 0 ? { thought: thinking.slice(0, 120) } : void 0,
|
|
1031
|
+
model: msg.model,
|
|
1032
|
+
inputTokens: msg.usage?.input,
|
|
1033
|
+
outputTokens: msg.usage?.output,
|
|
1034
|
+
cacheReadTokens: msg.usage?.cacheRead,
|
|
1035
|
+
cacheCreationTokens: msg.usage?.cacheWrite
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
if (msg.usage && (msg.usage.input || msg.usage.output)) {
|
|
1040
|
+
return {
|
|
1041
|
+
type: "token_usage",
|
|
1042
|
+
inputTokens: msg.usage.input,
|
|
1043
|
+
outputTokens: msg.usage.output,
|
|
1044
|
+
cacheReadTokens: msg.usage.cacheRead,
|
|
1045
|
+
cacheCreationTokens: msg.usage.cacheWrite,
|
|
1046
|
+
model: msg.model
|
|
1047
|
+
};
|
|
1048
|
+
}
|
|
1049
|
+
return null;
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
function getPiSessionsDir() {
|
|
1053
|
+
const candidate = join6(homedir3(), ".pi", "agent", "sessions");
|
|
1054
|
+
return existsSync3(candidate) ? candidate : null;
|
|
1055
|
+
}
|
|
1056
|
+
function decodePiProjectDir(encoded) {
|
|
1057
|
+
let inner = encoded;
|
|
1058
|
+
if (inner.startsWith("--") && inner.endsWith("--")) {
|
|
1059
|
+
inner = inner.slice(2, -2);
|
|
1060
|
+
}
|
|
1061
|
+
const driveMatch = inner.match(/^([A-Za-z])--(.*)/);
|
|
1062
|
+
if (driveMatch) {
|
|
1063
|
+
const resolved = resolveEncodedPath(driveMatch[1] + ":/", driveMatch[2]);
|
|
1064
|
+
if (resolved)
|
|
1065
|
+
return resolved;
|
|
1066
|
+
} else {
|
|
1067
|
+
const resolved = resolveEncodedPath("/", inner);
|
|
1068
|
+
if (resolved)
|
|
1069
|
+
return resolved;
|
|
1070
|
+
}
|
|
1071
|
+
const parts = inner.split("-").filter(Boolean);
|
|
1072
|
+
if (parts.length <= 2)
|
|
1073
|
+
return parts.join("/");
|
|
1074
|
+
return parts.slice(-2).join("-");
|
|
1075
|
+
}
|
|
1076
|
+
function parsePiSessionInfo(header, dirName) {
|
|
1077
|
+
const projectName = decodePiProjectDir(dirName);
|
|
1078
|
+
return {
|
|
1079
|
+
agentType: "pi",
|
|
1080
|
+
projectPath: header.cwd || dirName,
|
|
1081
|
+
projectName,
|
|
1082
|
+
isSubagent: !!header.parentSession,
|
|
1083
|
+
projectDir: dirName,
|
|
1084
|
+
parentSessionId: header.parentSession ? extractSessionIdFromPath(header.parentSession) : null
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
function extractSessionIdFromPath(filePath) {
|
|
1088
|
+
const match = filePath.match(/([^/\\]+)\.jsonl$/);
|
|
1089
|
+
if (!match)
|
|
1090
|
+
return null;
|
|
1091
|
+
const parts = match[1].split("_");
|
|
1092
|
+
const uuid = parts[parts.length - 1];
|
|
1093
|
+
return uuid ? `pi:${uuid}` : null;
|
|
1094
|
+
}
|
|
1095
|
+
var PiWatcher = class {
|
|
1096
|
+
stateManager;
|
|
1097
|
+
watcher = null;
|
|
1098
|
+
byteOffsets = /* @__PURE__ */ new Map();
|
|
1099
|
+
parser = new PiParser();
|
|
1100
|
+
/** Per-file lock to prevent concurrent processFile calls */
|
|
1101
|
+
fileLocks = /* @__PURE__ */ new Map();
|
|
1102
|
+
/** Cached session info per file (parsed from session header) */
|
|
1103
|
+
sessionInfoCache = /* @__PURE__ */ new Map();
|
|
1104
|
+
constructor(stateManager) {
|
|
1105
|
+
this.stateManager = stateManager;
|
|
1106
|
+
}
|
|
1107
|
+
async start() {
|
|
1108
|
+
const sessionsDir = getPiSessionsDir();
|
|
1109
|
+
if (!sessionsDir) {
|
|
1110
|
+
console.log("[pi] No sessions directory found \u2014 pi not installed or not yet used");
|
|
1111
|
+
return;
|
|
1112
|
+
}
|
|
1113
|
+
console.log(`[pi] Sessions directory found at ${sessionsDir}`);
|
|
1114
|
+
const scanner = new SessionScanner(sessionsDir);
|
|
1115
|
+
const existingFiles = await scanner.scan();
|
|
1116
|
+
for (const file of existingFiles) {
|
|
1117
|
+
await this.processFile(file);
|
|
1118
|
+
}
|
|
1119
|
+
const pattern = join7(sessionsDir, "**", "*.jsonl");
|
|
1120
|
+
this.watcher = chokidar3.watch(pattern, {
|
|
1121
|
+
persistent: true,
|
|
1122
|
+
ignoreInitial: true,
|
|
1123
|
+
awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 }
|
|
1124
|
+
});
|
|
1125
|
+
this.watcher.on("add", (filePath) => {
|
|
1126
|
+
console.log(`[pi] New session file: ${filePath}`);
|
|
1127
|
+
this.processFile(filePath);
|
|
1128
|
+
});
|
|
1129
|
+
this.watcher.on("change", (filePath) => {
|
|
1130
|
+
this.processFile(filePath);
|
|
1131
|
+
});
|
|
1132
|
+
console.log(`[pi] Watching for JSONL files in ${sessionsDir}`);
|
|
1133
|
+
}
|
|
1134
|
+
stop() {
|
|
1135
|
+
this.watcher?.close();
|
|
1136
|
+
this.byteOffsets.clear();
|
|
1137
|
+
this.fileLocks.clear();
|
|
1138
|
+
this.sessionInfoCache.clear();
|
|
1139
|
+
}
|
|
1140
|
+
processFile(filePath) {
|
|
1141
|
+
const prev = this.fileLocks.get(filePath) ?? Promise.resolve();
|
|
1142
|
+
const next = prev.then(() => this.doProcessFile(filePath)).catch(() => {
|
|
1143
|
+
}).finally(() => {
|
|
1144
|
+
if (this.fileLocks.get(filePath) === next) {
|
|
1145
|
+
this.fileLocks.delete(filePath);
|
|
1146
|
+
}
|
|
1147
|
+
});
|
|
1148
|
+
this.fileLocks.set(filePath, next);
|
|
1149
|
+
}
|
|
1150
|
+
async doProcessFile(filePath) {
|
|
1151
|
+
try {
|
|
1152
|
+
const fileStats = await stat3(filePath);
|
|
1153
|
+
const currentOffset = this.byteOffsets.get(filePath) ?? 0;
|
|
1154
|
+
if (fileStats.size <= currentOffset)
|
|
1155
|
+
return;
|
|
1156
|
+
const handle = await open2(filePath, "r");
|
|
1157
|
+
try {
|
|
1158
|
+
const buffer = Buffer.alloc(fileStats.size - currentOffset);
|
|
1159
|
+
await handle.read(buffer, 0, buffer.length, currentOffset);
|
|
1160
|
+
this.byteOffsets.set(filePath, fileStats.size);
|
|
1161
|
+
const newContent = buffer.toString("utf-8");
|
|
1162
|
+
const lines = newContent.split("\n").filter((l) => l.trim());
|
|
1163
|
+
const sessionId = this.extractSessionId(filePath);
|
|
1164
|
+
let sessionInfo = this.sessionInfoCache.get(filePath);
|
|
1165
|
+
let hadParsedActivity = false;
|
|
1166
|
+
for (const line of lines) {
|
|
1167
|
+
const raw = this.parser.parseRaw(line);
|
|
1168
|
+
if (!raw)
|
|
1169
|
+
continue;
|
|
1170
|
+
if (!sessionInfo && this.parser.isSessionHeader(raw)) {
|
|
1171
|
+
const dirName = this.getProjectDirName(filePath);
|
|
1172
|
+
sessionInfo = parsePiSessionInfo(raw, dirName);
|
|
1173
|
+
this.sessionInfoCache.set(filePath, sessionInfo);
|
|
1174
|
+
continue;
|
|
1175
|
+
}
|
|
1176
|
+
const parsed = this.parser.parseEntry(raw);
|
|
1177
|
+
if (parsed) {
|
|
1178
|
+
hadParsedActivity = true;
|
|
1179
|
+
if (!sessionInfo) {
|
|
1180
|
+
sessionInfo = this.buildFallbackSession(filePath);
|
|
1181
|
+
this.sessionInfoCache.set(filePath, sessionInfo);
|
|
1182
|
+
}
|
|
1183
|
+
this.stateManager.processMessage(sessionId, parsed, sessionInfo);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
if (!hadParsedActivity && lines.length > 0) {
|
|
1187
|
+
this.stateManager.heartbeat(sessionId);
|
|
1188
|
+
}
|
|
1189
|
+
} finally {
|
|
1190
|
+
await handle.close();
|
|
1191
|
+
}
|
|
1192
|
+
} catch (err) {
|
|
1193
|
+
if (err.code !== "ENOENT") {
|
|
1194
|
+
console.error(`[pi] Error processing ${filePath}:`, err);
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
/**
|
|
1199
|
+
* Extract a prefixed session ID from a pi session file path.
|
|
1200
|
+
* Filename format: {timestamp}_{uuid}.jsonl
|
|
1201
|
+
*/
|
|
1202
|
+
extractSessionId(filePath) {
|
|
1203
|
+
const name = basename2(filePath, ".jsonl");
|
|
1204
|
+
return `pi:${name}`;
|
|
1205
|
+
}
|
|
1206
|
+
buildFallbackSession(filePath) {
|
|
1207
|
+
const dirName = this.getProjectDirName(filePath);
|
|
1208
|
+
const name = dirName.replace(/^--|--$/g, "") || "pi";
|
|
1209
|
+
return createFallbackSession("pi", name);
|
|
1210
|
+
}
|
|
1211
|
+
/**
|
|
1212
|
+
* Get the encoded project directory name from a session file path.
|
|
1213
|
+
* Path: .../sessions/--encoded-path--/{timestamp}_{uuid}.jsonl
|
|
1214
|
+
*/
|
|
1215
|
+
getProjectDirName(filePath) {
|
|
1216
|
+
const dir = dirname(filePath).replace(/\\/g, "/");
|
|
1217
|
+
const parts = dir.split("/");
|
|
1218
|
+
return parts[parts.length - 1] || "unknown";
|
|
1219
|
+
}
|
|
1220
|
+
};
|
|
1221
|
+
var CodexParser = class {
|
|
1222
|
+
/**
|
|
1223
|
+
* Parse a single JSONL line into the envelope structure.
|
|
1224
|
+
*/
|
|
1225
|
+
parseRaw(line) {
|
|
1226
|
+
try {
|
|
1227
|
+
const obj = JSON.parse(line);
|
|
1228
|
+
if (obj && typeof obj.type === "string") {
|
|
1229
|
+
return obj;
|
|
1230
|
+
}
|
|
1231
|
+
return null;
|
|
1232
|
+
} catch {
|
|
1233
|
+
return null;
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
/**
|
|
1237
|
+
* Try to extract session_meta payload. Returns null if not a session_meta envelope.
|
|
1238
|
+
*/
|
|
1239
|
+
tryGetSessionMeta(envelope) {
|
|
1240
|
+
if (envelope.type !== "session_meta")
|
|
1241
|
+
return null;
|
|
1242
|
+
return envelope.payload;
|
|
1243
|
+
}
|
|
1244
|
+
/**
|
|
1245
|
+
* Try to extract model from a turn_context envelope. Returns null otherwise.
|
|
1246
|
+
*/
|
|
1247
|
+
tryGetModel(envelope) {
|
|
1248
|
+
if (envelope.type !== "turn_context")
|
|
1249
|
+
return null;
|
|
1250
|
+
const model = envelope.payload?.model;
|
|
1251
|
+
return model ?? null;
|
|
1252
|
+
}
|
|
1253
|
+
/**
|
|
1254
|
+
* Parse a Codex JSONL envelope into a ParsedActivity.
|
|
1255
|
+
* Model is passed in from the watcher (tracked per-file).
|
|
1256
|
+
* Returns null for non-actionable entries.
|
|
1257
|
+
*/
|
|
1258
|
+
parseEntry(envelope, model) {
|
|
1259
|
+
if (envelope.type === "response_item") {
|
|
1260
|
+
return this.parseResponseItem(envelope.payload, model);
|
|
1261
|
+
}
|
|
1262
|
+
if (envelope.type === "event_msg") {
|
|
1263
|
+
return this.parseEventMsg(envelope.payload, model);
|
|
1264
|
+
}
|
|
1265
|
+
return null;
|
|
1266
|
+
}
|
|
1267
|
+
parseResponseItem(payload, model) {
|
|
1268
|
+
const itemType = payload.type;
|
|
1269
|
+
if (itemType === "function_call") {
|
|
1270
|
+
const fc = payload;
|
|
1271
|
+
let toolInput = {};
|
|
1272
|
+
try {
|
|
1273
|
+
toolInput = JSON.parse(fc.arguments);
|
|
1274
|
+
} catch {
|
|
1275
|
+
}
|
|
1276
|
+
return {
|
|
1277
|
+
type: "tool_use",
|
|
1278
|
+
toolName: normalizeToolName(fc.name),
|
|
1279
|
+
toolInput: normalizeToolInput(toolInput),
|
|
1280
|
+
model: model ?? void 0
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
if (itemType.endsWith("_call") && itemType !== "function_call") {
|
|
1284
|
+
const nativeName = itemType.replace(/_call$/, "");
|
|
1285
|
+
const toolInput = {};
|
|
1286
|
+
const action = payload.action;
|
|
1287
|
+
if (action?.query)
|
|
1288
|
+
toolInput.query = action.query;
|
|
1289
|
+
return {
|
|
1290
|
+
type: "tool_use",
|
|
1291
|
+
toolName: normalizeToolName(nativeName),
|
|
1292
|
+
toolInput,
|
|
1293
|
+
model: model ?? void 0
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
1296
|
+
return null;
|
|
1297
|
+
}
|
|
1298
|
+
parseEventMsg(payload, model) {
|
|
1299
|
+
const eventType = payload.type;
|
|
1300
|
+
if (eventType === "token_count") {
|
|
1301
|
+
const info = payload.info;
|
|
1302
|
+
if (!info?.last_token_usage)
|
|
1303
|
+
return null;
|
|
1304
|
+
const usage = info.last_token_usage;
|
|
1305
|
+
return {
|
|
1306
|
+
type: "token_usage",
|
|
1307
|
+
inputTokens: usage.input_tokens,
|
|
1308
|
+
outputTokens: (usage.output_tokens ?? 0) + (usage.reasoning_output_tokens ?? 0),
|
|
1309
|
+
cacheReadTokens: usage.cached_input_tokens,
|
|
1310
|
+
model: model ?? void 0
|
|
1311
|
+
};
|
|
1312
|
+
}
|
|
1313
|
+
if (eventType === "agent_message") {
|
|
1314
|
+
const text = payload.message?.trim();
|
|
1315
|
+
if (text && text.length > 0 && text.length < 200) {
|
|
1316
|
+
return { type: "text", text, model: model ?? void 0 };
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
if (eventType === "agent_reasoning") {
|
|
1320
|
+
const text = payload.text?.trim();
|
|
1321
|
+
if (!text)
|
|
1322
|
+
return null;
|
|
1323
|
+
return {
|
|
1324
|
+
type: "tool_use",
|
|
1325
|
+
toolName: "thinking",
|
|
1326
|
+
toolInput: { thought: text.slice(0, 120) },
|
|
1327
|
+
model: model ?? void 0
|
|
1328
|
+
};
|
|
1329
|
+
}
|
|
1330
|
+
return null;
|
|
1331
|
+
}
|
|
1332
|
+
};
|
|
1333
|
+
function getCodexSessionsDir() {
|
|
1334
|
+
const candidate = join8(homedir4(), ".codex", "sessions");
|
|
1335
|
+
return existsSync4(candidate) ? candidate : null;
|
|
1336
|
+
}
|
|
1337
|
+
var UUID_RE = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/;
|
|
1338
|
+
function extractCodexSessionId(filePath) {
|
|
1339
|
+
const name = basename3(filePath, ".jsonl");
|
|
1340
|
+
const match = name.match(UUID_RE);
|
|
1341
|
+
if (match) {
|
|
1342
|
+
return `codex:${match[1]}`;
|
|
1343
|
+
}
|
|
1344
|
+
return `codex:${name}`;
|
|
1345
|
+
}
|
|
1346
|
+
function parseCodexSessionInfo(meta) {
|
|
1347
|
+
const cwd = meta.cwd || "codex";
|
|
1348
|
+
const parts = cwd.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
1349
|
+
const projectName = parts[parts.length - 1] || "codex";
|
|
1350
|
+
return {
|
|
1351
|
+
agentType: "codex",
|
|
1352
|
+
projectPath: cwd,
|
|
1353
|
+
projectName,
|
|
1354
|
+
isSubagent: false,
|
|
1355
|
+
projectDir: cwd,
|
|
1356
|
+
parentSessionId: null
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
function createCodexSubagentSession(parentSessionId, parentInfo) {
|
|
1360
|
+
return {
|
|
1361
|
+
agentType: "codex",
|
|
1362
|
+
projectPath: parentInfo.projectPath,
|
|
1363
|
+
projectName: parentInfo.projectName,
|
|
1364
|
+
isSubagent: true,
|
|
1365
|
+
projectDir: parentInfo.projectDir,
|
|
1366
|
+
parentSessionId
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1369
|
+
var CodexWatcher = class {
|
|
1370
|
+
stateManager;
|
|
1371
|
+
watcher = null;
|
|
1372
|
+
byteOffsets = /* @__PURE__ */ new Map();
|
|
1373
|
+
parser = new CodexParser();
|
|
1374
|
+
/** Per-file lock to prevent concurrent processFile calls */
|
|
1375
|
+
fileLocks = /* @__PURE__ */ new Map();
|
|
1376
|
+
/** Cached session info per file (parsed from session_meta) */
|
|
1377
|
+
sessionInfoCache = /* @__PURE__ */ new Map();
|
|
1378
|
+
/** Per-file model tracking (from turn_context events) */
|
|
1379
|
+
fileModels = /* @__PURE__ */ new Map();
|
|
1380
|
+
/** Deduplication of spawn_agent call IDs already processed */
|
|
1381
|
+
seenSubagentCalls = /* @__PURE__ */ new Set();
|
|
1382
|
+
/** Counter for generating unique subagent session IDs */
|
|
1383
|
+
subagentCounter = 0;
|
|
1384
|
+
constructor(stateManager) {
|
|
1385
|
+
this.stateManager = stateManager;
|
|
1386
|
+
}
|
|
1387
|
+
async start() {
|
|
1388
|
+
const sessionsDir = getCodexSessionsDir();
|
|
1389
|
+
if (!sessionsDir) {
|
|
1390
|
+
console.log("[codex] No sessions directory found \u2014 Codex CLI not installed or not yet used");
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
console.log(`[codex] Sessions directory found at ${sessionsDir}`);
|
|
1394
|
+
const existingFiles = await this.scanDeep(sessionsDir);
|
|
1395
|
+
for (const file of existingFiles) {
|
|
1396
|
+
await this.processFile(file);
|
|
1397
|
+
}
|
|
1398
|
+
const pattern = join9(sessionsDir, "**", "*.jsonl");
|
|
1399
|
+
const usePolling = process.platform === "win32";
|
|
1400
|
+
this.watcher = chokidar4.watch(pattern, {
|
|
1401
|
+
persistent: true,
|
|
1402
|
+
ignoreInitial: true,
|
|
1403
|
+
usePolling,
|
|
1404
|
+
interval: usePolling ? 500 : void 0,
|
|
1405
|
+
awaitWriteFinish: usePolling ? false : { stabilityThreshold: 200, pollInterval: 50 }
|
|
1406
|
+
});
|
|
1407
|
+
this.watcher.on("add", (filePath) => {
|
|
1408
|
+
console.log(`[codex] New session file: ${filePath}`);
|
|
1409
|
+
this.processFile(filePath);
|
|
1410
|
+
});
|
|
1411
|
+
this.watcher.on("change", (filePath) => {
|
|
1412
|
+
this.processFile(filePath);
|
|
1413
|
+
});
|
|
1414
|
+
console.log(`[codex] Watching for JSONL files in ${sessionsDir} (polling: ${usePolling})`);
|
|
1415
|
+
}
|
|
1416
|
+
stop() {
|
|
1417
|
+
this.watcher?.close();
|
|
1418
|
+
this.byteOffsets.clear();
|
|
1419
|
+
this.fileLocks.clear();
|
|
1420
|
+
this.sessionInfoCache.clear();
|
|
1421
|
+
this.fileModels.clear();
|
|
1422
|
+
this.seenSubagentCalls.clear();
|
|
1423
|
+
}
|
|
1424
|
+
/**
|
|
1425
|
+
* Recursively scan for recently-modified JSONL files under the sessions dir.
|
|
1426
|
+
* Codex nests files as sessions/YYYY/MM/DD/rollout-*.jsonl.
|
|
1427
|
+
*/
|
|
1428
|
+
async scanDeep(dir) {
|
|
1429
|
+
const results = [];
|
|
1430
|
+
const now = Date.now();
|
|
1431
|
+
const walk = async (current) => {
|
|
1432
|
+
try {
|
|
1433
|
+
const entries = await readdir2(current, { withFileTypes: true });
|
|
1434
|
+
for (const entry of entries) {
|
|
1435
|
+
const full = join9(current, entry.name);
|
|
1436
|
+
if (entry.isDirectory()) {
|
|
1437
|
+
await walk(full);
|
|
1438
|
+
} else if (entry.name.endsWith(".jsonl")) {
|
|
1439
|
+
try {
|
|
1440
|
+
const s = await stat4(full);
|
|
1441
|
+
if (now - s.mtimeMs < config.activeThresholdMs) {
|
|
1442
|
+
results.push(full);
|
|
1443
|
+
}
|
|
1444
|
+
} catch {
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
} catch {
|
|
1449
|
+
}
|
|
1693
1450
|
};
|
|
1451
|
+
await walk(dir);
|
|
1452
|
+
return results;
|
|
1453
|
+
}
|
|
1454
|
+
processFile(filePath) {
|
|
1455
|
+
const prev = this.fileLocks.get(filePath) ?? Promise.resolve();
|
|
1456
|
+
const next = prev.then(() => this.doProcessFile(filePath)).catch(() => {
|
|
1457
|
+
}).finally(() => {
|
|
1458
|
+
if (this.fileLocks.get(filePath) === next) {
|
|
1459
|
+
this.fileLocks.delete(filePath);
|
|
1460
|
+
}
|
|
1461
|
+
});
|
|
1462
|
+
this.fileLocks.set(filePath, next);
|
|
1463
|
+
}
|
|
1464
|
+
async doProcessFile(filePath) {
|
|
1465
|
+
try {
|
|
1466
|
+
const fileStats = await stat4(filePath);
|
|
1467
|
+
const currentOffset = this.byteOffsets.get(filePath) ?? 0;
|
|
1468
|
+
if (fileStats.size <= currentOffset)
|
|
1469
|
+
return;
|
|
1470
|
+
const handle = await open3(filePath, "r");
|
|
1471
|
+
try {
|
|
1472
|
+
const buffer = Buffer.alloc(fileStats.size - currentOffset);
|
|
1473
|
+
await handle.read(buffer, 0, buffer.length, currentOffset);
|
|
1474
|
+
this.byteOffsets.set(filePath, fileStats.size);
|
|
1475
|
+
const newContent = buffer.toString("utf-8");
|
|
1476
|
+
const lines = newContent.split("\n").filter((l) => l.trim());
|
|
1477
|
+
const sessionId = extractCodexSessionId(filePath);
|
|
1478
|
+
let sessionInfo = this.sessionInfoCache.get(filePath);
|
|
1479
|
+
let hadParsedActivity = false;
|
|
1480
|
+
for (const line of lines) {
|
|
1481
|
+
const envelope = this.parser.parseRaw(line);
|
|
1482
|
+
if (!envelope)
|
|
1483
|
+
continue;
|
|
1484
|
+
if (!sessionInfo) {
|
|
1485
|
+
const meta = this.parser.tryGetSessionMeta(envelope);
|
|
1486
|
+
if (meta) {
|
|
1487
|
+
sessionInfo = parseCodexSessionInfo(meta);
|
|
1488
|
+
this.sessionInfoCache.set(filePath, sessionInfo);
|
|
1489
|
+
continue;
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
const model = this.parser.tryGetModel(envelope);
|
|
1493
|
+
if (model) {
|
|
1494
|
+
this.fileModels.set(filePath, model);
|
|
1495
|
+
continue;
|
|
1496
|
+
}
|
|
1497
|
+
const currentModel = this.fileModels.get(filePath) ?? null;
|
|
1498
|
+
const parsed = this.parser.parseEntry(envelope, currentModel);
|
|
1499
|
+
if (parsed) {
|
|
1500
|
+
hadParsedActivity = true;
|
|
1501
|
+
if (!sessionInfo) {
|
|
1502
|
+
sessionInfo = this.buildFallbackSession(filePath);
|
|
1503
|
+
this.sessionInfoCache.set(filePath, sessionInfo);
|
|
1504
|
+
}
|
|
1505
|
+
if (parsed.type === "tool_use" && parsed.toolName === "Agent") {
|
|
1506
|
+
this.handleSubagentSpawn(sessionId, sessionInfo, parsed, envelope.payload);
|
|
1507
|
+
}
|
|
1508
|
+
this.stateManager.processMessage(sessionId, parsed, sessionInfo);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
if (!hadParsedActivity && lines.length > 0) {
|
|
1512
|
+
this.stateManager.heartbeat(sessionId);
|
|
1513
|
+
}
|
|
1514
|
+
} finally {
|
|
1515
|
+
await handle.close();
|
|
1516
|
+
}
|
|
1517
|
+
} catch (err) {
|
|
1518
|
+
if (err.code !== "ENOENT") {
|
|
1519
|
+
console.error(`[codex] Error processing ${filePath}:`, err);
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
/**
|
|
1524
|
+
* When a spawn_agent tool call is detected, create a synthetic subagent session
|
|
1525
|
+
* so the visualization shows the child agent.
|
|
1526
|
+
*/
|
|
1527
|
+
handleSubagentSpawn(parentSessionId, parentInfo, parsed, payload) {
|
|
1528
|
+
const callId = payload.call_id;
|
|
1529
|
+
if (!callId || this.seenSubagentCalls.has(callId))
|
|
1530
|
+
return;
|
|
1531
|
+
this.subagentCounter++;
|
|
1532
|
+
this.seenSubagentCalls.add(callId);
|
|
1533
|
+
const subSessionId = `codex:sub-${parentSessionId.replace("codex:", "")}-${this.subagentCounter}`;
|
|
1534
|
+
const subInfo = createCodexSubagentSession(parentSessionId, parentInfo);
|
|
1535
|
+
const agentName = parsed.toolInput?.agent_type || parsed.toolInput?.message?.slice(0, 30) || `agent-${this.subagentCounter}`;
|
|
1536
|
+
this.stateManager.processMessage(subSessionId, {
|
|
1537
|
+
type: "tool_use",
|
|
1538
|
+
toolName: "thinking",
|
|
1539
|
+
toolInput: { thought: `Subagent: ${agentName}` },
|
|
1540
|
+
model: parsed.model,
|
|
1541
|
+
agentName
|
|
1542
|
+
}, subInfo);
|
|
1543
|
+
}
|
|
1544
|
+
buildFallbackSession(filePath) {
|
|
1545
|
+
const name = basename4(filePath, ".jsonl");
|
|
1546
|
+
return createFallbackSession("codex", name);
|
|
1694
1547
|
}
|
|
1695
1548
|
};
|
|
1696
1549
|
var COOLDOWN_MS = 6e4;
|
|
@@ -1946,6 +1799,9 @@ var TaskGraphManager = class {
|
|
|
1946
1799
|
if (toolName === "TaskUpdate") {
|
|
1947
1800
|
return this.handleUpdate(agentId, agentName, toolInput, projectName, root);
|
|
1948
1801
|
}
|
|
1802
|
+
if (toolName === "TodoWrite" || toolName === "update_plan") {
|
|
1803
|
+
return this.handlePlanUpdate(agentId, agentName, toolInput, projectName, root);
|
|
1804
|
+
}
|
|
1949
1805
|
return false;
|
|
1950
1806
|
}
|
|
1951
1807
|
handleCreate(agentId, agentName, toolInput, projectName, root) {
|
|
@@ -2051,6 +1907,83 @@ var TaskGraphManager = class {
|
|
|
2051
1907
|
}
|
|
2052
1908
|
return changed;
|
|
2053
1909
|
}
|
|
1910
|
+
/**
|
|
1911
|
+
* Handle plan/todo updates from multiple formats:
|
|
1912
|
+
* - Codex update_plan: {plan: [{step: "...", status: "pending"|"in_progress"|"completed"}, ...]}
|
|
1913
|
+
* - Claude Code / OpenCode TodoWrite: {todos: [{id, content, status}, ...]}
|
|
1914
|
+
* Each call replaces the full plan — we sync to create/update tasks accordingly.
|
|
1915
|
+
*/
|
|
1916
|
+
handlePlanUpdate(agentId, agentName, toolInput, projectName, root) {
|
|
1917
|
+
const input = toolInput;
|
|
1918
|
+
if (!input)
|
|
1919
|
+
return false;
|
|
1920
|
+
const steps = this.extractPlanSteps(input);
|
|
1921
|
+
if (steps.length === 0)
|
|
1922
|
+
return false;
|
|
1923
|
+
let changed = false;
|
|
1924
|
+
const existingBySubject = /* @__PURE__ */ new Map();
|
|
1925
|
+
for (const [key, task] of this.tasks) {
|
|
1926
|
+
if (key.startsWith(root + "::")) {
|
|
1927
|
+
existingBySubject.set(task.subject, task);
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
for (const { subject, status } of steps) {
|
|
1931
|
+
const existing = existingBySubject.get(subject);
|
|
1932
|
+
if (existing) {
|
|
1933
|
+
if (existing.status !== status) {
|
|
1934
|
+
existing.status = status;
|
|
1935
|
+
changed = true;
|
|
1936
|
+
}
|
|
1937
|
+
} else {
|
|
1938
|
+
const count = (this.counters.get(root) ?? 0) + 1;
|
|
1939
|
+
this.counters.set(root, count);
|
|
1940
|
+
const shortId = String(count);
|
|
1941
|
+
const key = this.scopedKey(root, shortId);
|
|
1942
|
+
const node = {
|
|
1943
|
+
id: shortId,
|
|
1944
|
+
subject,
|
|
1945
|
+
status,
|
|
1946
|
+
owner: void 0,
|
|
1947
|
+
agentId,
|
|
1948
|
+
agentName,
|
|
1949
|
+
projectName,
|
|
1950
|
+
blocks: [],
|
|
1951
|
+
blockedBy: [],
|
|
1952
|
+
timestamp: Date.now(),
|
|
1953
|
+
_rootKey: key
|
|
1954
|
+
};
|
|
1955
|
+
this.tasks.set(key, node);
|
|
1956
|
+
existingBySubject.set(subject, node);
|
|
1957
|
+
changed = true;
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
return changed;
|
|
1961
|
+
}
|
|
1962
|
+
/**
|
|
1963
|
+
* Extract plan steps from various tool input formats into a common shape.
|
|
1964
|
+
*/
|
|
1965
|
+
extractPlanSteps(input) {
|
|
1966
|
+
const planSteps = input.plan;
|
|
1967
|
+
if (Array.isArray(planSteps) && planSteps.length > 0) {
|
|
1968
|
+
return planSteps.filter((s) => s.step?.trim()).map((s) => ({ subject: s.step.trim(), status: this.normalizePlanStatus(s.status) }));
|
|
1969
|
+
}
|
|
1970
|
+
const todos = input.todos;
|
|
1971
|
+
if (Array.isArray(todos) && todos.length > 0) {
|
|
1972
|
+
return todos.filter((t) => t.content?.trim()).map((t) => ({ subject: t.content.trim(), status: this.normalizePlanStatus(t.status) }));
|
|
1973
|
+
}
|
|
1974
|
+
return [];
|
|
1975
|
+
}
|
|
1976
|
+
normalizePlanStatus(status) {
|
|
1977
|
+
if (!status)
|
|
1978
|
+
return "pending";
|
|
1979
|
+
if (status === "in_progress" || status === "in-progress")
|
|
1980
|
+
return "in_progress";
|
|
1981
|
+
if (status === "completed" || status === "done")
|
|
1982
|
+
return "completed";
|
|
1983
|
+
if (status === "deleted" || status === "cancelled")
|
|
1984
|
+
return "deleted";
|
|
1985
|
+
return "pending";
|
|
1986
|
+
}
|
|
2054
1987
|
/**
|
|
2055
1988
|
* Mark a task as completed (hook-sourced — TaskCompleted event).
|
|
2056
1989
|
* Returns true if the status actually changed.
|
|
@@ -2272,7 +2205,7 @@ function processToolUseActivity(deps, agent, activity, now) {
|
|
|
2272
2205
|
anomalyDetector.setAgentName(agentId, agent.agentName ?? agent.projectName ?? agentId.slice(0, 10));
|
|
2273
2206
|
anomalyDetector.checkToolUse(agentId, toolName);
|
|
2274
2207
|
toolChainTracker.recordToolUse(agentId, toolName);
|
|
2275
|
-
if (toolName === "TaskCreate" || toolName === "TaskUpdate") {
|
|
2208
|
+
if (toolName === "TaskCreate" || toolName === "TaskUpdate" || toolName === "TodoWrite") {
|
|
2276
2209
|
const graphChanged = taskGraphManager.processToolUse(agentId, agent.agentName ?? agentId.slice(0, 10), toolName, activity.toolInput, agent.projectName, agent.rootSessionId);
|
|
2277
2210
|
if (graphChanged) {
|
|
2278
2211
|
emit("taskgraph:changed", { data: taskGraphManager.getSnapshot(), timestamp: Date.now() });
|
|
@@ -2696,6 +2629,7 @@ var AgentStateManager = class extends EventEmitter2 {
|
|
|
2696
2629
|
agent = {
|
|
2697
2630
|
id: sessionId,
|
|
2698
2631
|
sessionId,
|
|
2632
|
+
agentType: sessionInfo.agentType,
|
|
2699
2633
|
rootSessionId,
|
|
2700
2634
|
projectPath: sessionInfo.projectPath,
|
|
2701
2635
|
projectName: sessionInfo.projectName,
|
|
@@ -3459,12 +3393,12 @@ function buildResponse(decision) {
|
|
|
3459
3393
|
}
|
|
3460
3394
|
};
|
|
3461
3395
|
}
|
|
3462
|
-
var __dirname =
|
|
3396
|
+
var __dirname = dirname2(fileURLToPath(import.meta.url));
|
|
3463
3397
|
async function main() {
|
|
3464
3398
|
const app = Fastify({ logger: { level: "info" } });
|
|
3465
3399
|
await app.register(cors, { origin: true });
|
|
3466
3400
|
await app.register(websocket);
|
|
3467
|
-
const clientDist =
|
|
3401
|
+
const clientDist = join10(__dirname, "..", "..", "client", "dist");
|
|
3468
3402
|
await app.register(fastifyStatic, {
|
|
3469
3403
|
root: clientDist,
|
|
3470
3404
|
prefix: "/",
|
|
@@ -3496,7 +3430,9 @@ async function main() {
|
|
|
3496
3430
|
});
|
|
3497
3431
|
const watchers = [
|
|
3498
3432
|
new FileWatcher(config.claudeHome, stateManager),
|
|
3499
|
-
...config.enableOpenCode ? [new OpenCodeWatcher(stateManager)] : []
|
|
3433
|
+
...config.enableOpenCode ? [new OpenCodeWatcher(stateManager)] : [],
|
|
3434
|
+
...config.enablePi ? [new PiWatcher(stateManager)] : [],
|
|
3435
|
+
...config.enableCodex ? [new CodexWatcher(stateManager)] : []
|
|
3500
3436
|
];
|
|
3501
3437
|
for (const w of watchers) {
|
|
3502
3438
|
await w.start();
|