@yhong91/vibetime 0.1.25 → 0.1.26
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/bin/vibetime.mjs +659 -165
- package/package.json +1 -1
package/bin/vibetime.mjs
CHANGED
|
@@ -159,9 +159,9 @@ var init_fs = __esm({
|
|
|
159
159
|
|
|
160
160
|
// src/cli.ts
|
|
161
161
|
import { spawn as spawn2, spawnSync } from "node:child_process";
|
|
162
|
-
import { mkdir as mkdir5, open, rm, stat as
|
|
162
|
+
import { mkdir as mkdir5, open, rm, stat as stat13, writeFile as writeFile4 } from "node:fs/promises";
|
|
163
163
|
import os9 from "node:os";
|
|
164
|
-
import
|
|
164
|
+
import path22 from "node:path";
|
|
165
165
|
import { fileURLToPath } from "node:url";
|
|
166
166
|
|
|
167
167
|
// ../shared/src/index.ts
|
|
@@ -191,13 +191,15 @@ var TELEMETRY_EVENT_TYPES = [
|
|
|
191
191
|
"model.usage",
|
|
192
192
|
"permission.requested",
|
|
193
193
|
"permission.resolved",
|
|
194
|
+
"permission.granted",
|
|
195
|
+
"permission.denied",
|
|
194
196
|
"context.compacted",
|
|
195
197
|
"test.completed",
|
|
196
198
|
"git.changed",
|
|
197
199
|
"agent.operation"
|
|
198
200
|
];
|
|
199
201
|
var FILE_ACTIVITY_OPERATIONS = ["read", "search", "create", "write", "edit", "delete"];
|
|
200
|
-
var BACKFILL_SOURCE_IDS = ["codex", "claude-code", "claude-cowork", "copilot", "opencode", "pi", "agy", "codebuddy", "qoder", "qoder-cn", "workbuddy", "zcode"];
|
|
202
|
+
var BACKFILL_SOURCE_IDS = ["codex", "claude-code", "claude-cowork", "copilot", "opencode", "pi", "agy", "codebuddy", "qoder", "qoder-cn", "workbuddy", "zcode", "grok-build"];
|
|
201
203
|
function createWorkspaceId(input) {
|
|
202
204
|
const basis = input.repoUrl || input.repoRoot || input.projectName || "unknown";
|
|
203
205
|
return `workspace_${fnv1a(basis)}`;
|
|
@@ -1201,7 +1203,7 @@ function countTextLines(text) {
|
|
|
1201
1203
|
}
|
|
1202
1204
|
|
|
1203
1205
|
// src/lib/constants.ts
|
|
1204
|
-
var PACKAGE_VERSION = true ? "0.1.
|
|
1206
|
+
var PACKAGE_VERSION = true ? "0.1.26" : "0.1.1";
|
|
1205
1207
|
var DEFAULT_API_URL = "http://121.196.224.82:3001";
|
|
1206
1208
|
var DEFAULT_BACKFILL_BATCH_SIZE = 50;
|
|
1207
1209
|
var DEFAULT_BACKFILL_BATCH_BYTES = 800 * 1024;
|
|
@@ -4029,8 +4031,8 @@ async function codebuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
4029
4031
|
}
|
|
4030
4032
|
const filePath = path9.join(traceDir, entry);
|
|
4031
4033
|
try {
|
|
4032
|
-
const
|
|
4033
|
-
files.push({ path: filePath, modifiedAt:
|
|
4034
|
+
const stat14 = await import("node:fs/promises").then((fs) => fs.stat(filePath));
|
|
4035
|
+
files.push({ path: filePath, modifiedAt: stat14.mtime.toISOString() });
|
|
4034
4036
|
} catch {
|
|
4035
4037
|
}
|
|
4036
4038
|
}
|
|
@@ -5058,9 +5060,497 @@ function createCopilotAdapter() {
|
|
|
5058
5060
|
};
|
|
5059
5061
|
}
|
|
5060
5062
|
|
|
5063
|
+
// src/adapters/grok-build.ts
|
|
5064
|
+
import { readdir as readdir6, readFile as readFile8, stat as stat7 } from "node:fs/promises";
|
|
5065
|
+
import path13 from "node:path";
|
|
5066
|
+
init_fs();
|
|
5067
|
+
var SOURCE_ID = "grok-build";
|
|
5068
|
+
var AGENT_NAME = "grok-build";
|
|
5069
|
+
var HOOK_COMMAND = `vibetime hook --agent ${SOURCE_ID}`;
|
|
5070
|
+
function grokHome(home, env) {
|
|
5071
|
+
const override = env?.GROK_HOME;
|
|
5072
|
+
if (override && override.trim()) {
|
|
5073
|
+
return path13.resolve(override);
|
|
5074
|
+
}
|
|
5075
|
+
return path13.join(home, ".grok");
|
|
5076
|
+
}
|
|
5077
|
+
function grokHooksPath(home, env) {
|
|
5078
|
+
return path13.join(grokHome(home, env), "hooks", "vibetime.json");
|
|
5079
|
+
}
|
|
5080
|
+
function grokSessionsDir(home, env) {
|
|
5081
|
+
return path13.join(grokHome(home, env), "sessions");
|
|
5082
|
+
}
|
|
5083
|
+
async function grokBackfillFiles(sourceRoot, home, env) {
|
|
5084
|
+
const root = sourceRoot || grokSessionsDir(home, env);
|
|
5085
|
+
const files = [];
|
|
5086
|
+
async function walk(dir) {
|
|
5087
|
+
let entries;
|
|
5088
|
+
try {
|
|
5089
|
+
entries = await readdir6(dir, { withFileTypes: true });
|
|
5090
|
+
} catch {
|
|
5091
|
+
return;
|
|
5092
|
+
}
|
|
5093
|
+
for (const entry of entries) {
|
|
5094
|
+
const entryPath = path13.join(dir, entry.name);
|
|
5095
|
+
if (entry.isDirectory()) {
|
|
5096
|
+
await walk(entryPath);
|
|
5097
|
+
continue;
|
|
5098
|
+
}
|
|
5099
|
+
if (!entry.isFile() || entry.name !== "summary.json") {
|
|
5100
|
+
continue;
|
|
5101
|
+
}
|
|
5102
|
+
try {
|
|
5103
|
+
const info = await stat7(entryPath);
|
|
5104
|
+
files.push({ path: entryPath, modifiedAt: info.mtime.toISOString() });
|
|
5105
|
+
} catch {
|
|
5106
|
+
}
|
|
5107
|
+
}
|
|
5108
|
+
}
|
|
5109
|
+
await walk(root);
|
|
5110
|
+
return files.sort((a, b) => a.path.localeCompare(b.path));
|
|
5111
|
+
}
|
|
5112
|
+
async function parseGrokSessionFile(filePath, options) {
|
|
5113
|
+
const sessionDir = resolveSessionDir(filePath);
|
|
5114
|
+
if (!sessionDir) {
|
|
5115
|
+
return [];
|
|
5116
|
+
}
|
|
5117
|
+
const summaryPath = path13.join(sessionDir, "summary.json");
|
|
5118
|
+
const eventsPath = path13.join(sessionDir, "events.jsonl");
|
|
5119
|
+
const signalsPath = path13.join(sessionDir, "signals.json");
|
|
5120
|
+
const updatesPath = path13.join(sessionDir, "updates.jsonl");
|
|
5121
|
+
const summary = await readJsonIfExists(summaryPath);
|
|
5122
|
+
if (!isPlainObject(summary)) {
|
|
5123
|
+
return [];
|
|
5124
|
+
}
|
|
5125
|
+
const info = objectField(summary, "info");
|
|
5126
|
+
const sessionId = stringField(info, "id") || path13.basename(sessionDir);
|
|
5127
|
+
const cwd = stringField(info, "cwd");
|
|
5128
|
+
const project = cwd ? path13.basename(cwd) : void 0;
|
|
5129
|
+
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
5130
|
+
const model = stringField(summary, "current_model_id");
|
|
5131
|
+
const createdAt = timestampFrom(summary.created_at) || timestampFrom(summary.createdAt);
|
|
5132
|
+
const updatedAt = timestampFrom(summary.updated_at) || timestampFrom(summary.last_active_at) || timestampFrom(summary.updatedAt) || createdAt;
|
|
5133
|
+
if (!createdAt) {
|
|
5134
|
+
return [];
|
|
5135
|
+
}
|
|
5136
|
+
const sourcePathHash = `sha256:${createStableHash(summaryPath)}`;
|
|
5137
|
+
const toolInputs = await loadToolInputsFromUpdates(updatesPath);
|
|
5138
|
+
const events = [];
|
|
5139
|
+
const push = (event, lineNumber2, topType, payloadType) => {
|
|
5140
|
+
const validated = validateCanonicalEvent(event);
|
|
5141
|
+
if (!validated.valid) {
|
|
5142
|
+
return;
|
|
5143
|
+
}
|
|
5144
|
+
events.push(withBackfillRefs(event, {
|
|
5145
|
+
filePath: summaryPath,
|
|
5146
|
+
sourcePathHash,
|
|
5147
|
+
lineNumber: lineNumber2,
|
|
5148
|
+
topType: topType || "session",
|
|
5149
|
+
payloadType: payloadType || event.type,
|
|
5150
|
+
options
|
|
5151
|
+
}));
|
|
5152
|
+
};
|
|
5153
|
+
const base = (partial) => ({
|
|
5154
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
5155
|
+
source: SOURCE_ID,
|
|
5156
|
+
agent: AGENT_NAME,
|
|
5157
|
+
workspaceId,
|
|
5158
|
+
project,
|
|
5159
|
+
cwd,
|
|
5160
|
+
model,
|
|
5161
|
+
sessionId,
|
|
5162
|
+
...partial
|
|
5163
|
+
});
|
|
5164
|
+
push(base({
|
|
5165
|
+
ts: createdAt,
|
|
5166
|
+
type: "session.started",
|
|
5167
|
+
confidence: "exact",
|
|
5168
|
+
refs: stringRefs({ sourceId: `${sessionId}:started` })
|
|
5169
|
+
}), 0, "summary", "session.started");
|
|
5170
|
+
let currentTurnId;
|
|
5171
|
+
let currentTurnStartedAt;
|
|
5172
|
+
let lineNumber = 0;
|
|
5173
|
+
const pendingTools = /* @__PURE__ */ new Map();
|
|
5174
|
+
let eventsText = "";
|
|
5175
|
+
try {
|
|
5176
|
+
eventsText = await readFile8(eventsPath, "utf8");
|
|
5177
|
+
} catch {
|
|
5178
|
+
}
|
|
5179
|
+
const lines = eventsText.split("\n").filter(Boolean);
|
|
5180
|
+
for (const [index, line] of lines.entries()) {
|
|
5181
|
+
lineNumber = index + 1;
|
|
5182
|
+
const raw = parseJsonLine(line);
|
|
5183
|
+
if (!raw) {
|
|
5184
|
+
continue;
|
|
5185
|
+
}
|
|
5186
|
+
const type = stringField(raw, "type");
|
|
5187
|
+
const ts = timestampFrom(raw.ts) || timestampFrom(raw.timestamp);
|
|
5188
|
+
if (!type || !ts) {
|
|
5189
|
+
continue;
|
|
5190
|
+
}
|
|
5191
|
+
if (type === "turn_started") {
|
|
5192
|
+
const turnNumber = numberField(raw, "turn_number");
|
|
5193
|
+
currentTurnId = turnNumber !== void 0 ? `turn_${turnNumber}` : `turn_${createStableHash([sessionId, lineNumber]).slice(0, 24)}`;
|
|
5194
|
+
currentTurnStartedAt = ts;
|
|
5195
|
+
const turnModel = stringField(raw, "model_id") || model;
|
|
5196
|
+
push(base({
|
|
5197
|
+
ts,
|
|
5198
|
+
type: "turn.started",
|
|
5199
|
+
turnId: currentTurnId,
|
|
5200
|
+
model: turnModel,
|
|
5201
|
+
confidence: "exact",
|
|
5202
|
+
refs: stringRefs({ sourceId: `${sessionId}:${currentTurnId}:started` })
|
|
5203
|
+
}), lineNumber, type, "turn.started");
|
|
5204
|
+
continue;
|
|
5205
|
+
}
|
|
5206
|
+
if (type === "turn_ended") {
|
|
5207
|
+
const turnId = currentTurnId;
|
|
5208
|
+
const outcome = stringField(raw, "outcome");
|
|
5209
|
+
const success = outcome !== "error" && outcome !== "failed" && outcome !== "cancelled";
|
|
5210
|
+
const durationMs = durationMsBetween(currentTurnStartedAt, ts);
|
|
5211
|
+
push(base({
|
|
5212
|
+
ts,
|
|
5213
|
+
type: success ? "turn.completed" : "turn.failed",
|
|
5214
|
+
turnId,
|
|
5215
|
+
success,
|
|
5216
|
+
confidence: "exact",
|
|
5217
|
+
metrics: durationMs !== void 0 ? { durationMs } : void 0,
|
|
5218
|
+
refs: stringRefs({
|
|
5219
|
+
sourceId: `${sessionId}:${turnId || "turn"}:ended`,
|
|
5220
|
+
outcome
|
|
5221
|
+
})
|
|
5222
|
+
}), lineNumber, type, "turn.ended");
|
|
5223
|
+
currentTurnId = void 0;
|
|
5224
|
+
currentTurnStartedAt = void 0;
|
|
5225
|
+
continue;
|
|
5226
|
+
}
|
|
5227
|
+
if (type === "tool_started" || type === "mcp_tool_call_started") {
|
|
5228
|
+
const toolName = type === "mcp_tool_call_started" ? mcpToolName(raw) : stringField(raw, "tool_name") || "unknown";
|
|
5229
|
+
const toolId = stringField(raw, "call_id") || `${sessionId}:tool:${lineNumber}:${toolName}`;
|
|
5230
|
+
pendingTools.set(toolId, {
|
|
5231
|
+
id: toolId,
|
|
5232
|
+
name: toolName,
|
|
5233
|
+
startedAt: ts,
|
|
5234
|
+
lineNumber,
|
|
5235
|
+
turnId: currentTurnId
|
|
5236
|
+
});
|
|
5237
|
+
const knownInput = toolInputs.get(toolId);
|
|
5238
|
+
const fileActivities = fileActivitiesFromTool(
|
|
5239
|
+
toolName,
|
|
5240
|
+
knownInput?.input || {},
|
|
5241
|
+
ts,
|
|
5242
|
+
cwd
|
|
5243
|
+
);
|
|
5244
|
+
push(base({
|
|
5245
|
+
ts,
|
|
5246
|
+
type: "tool.started",
|
|
5247
|
+
turnId: currentTurnId,
|
|
5248
|
+
tool: toolName,
|
|
5249
|
+
operation: `${toolName} started`,
|
|
5250
|
+
confidence: "exact",
|
|
5251
|
+
fileActivities: fileActivities.length > 0 ? fileActivities : void 0,
|
|
5252
|
+
refs: stringRefs({ sourceId: `${toolId}:started` })
|
|
5253
|
+
}), lineNumber, type, "tool.started");
|
|
5254
|
+
if (isShellTool(toolName)) {
|
|
5255
|
+
const command = stringField(knownInput?.input || {}, "command");
|
|
5256
|
+
if (command) {
|
|
5257
|
+
push(base({
|
|
5258
|
+
ts,
|
|
5259
|
+
type: "command.started",
|
|
5260
|
+
turnId: currentTurnId,
|
|
5261
|
+
tool: toolName,
|
|
5262
|
+
operation: "command started",
|
|
5263
|
+
confidence: "derived",
|
|
5264
|
+
refs: stringRefs({
|
|
5265
|
+
sourceId: `${toolId}:command:started`,
|
|
5266
|
+
commandHash: `sha256:${createStableHash(command)}`
|
|
5267
|
+
})
|
|
5268
|
+
}), lineNumber, type, "command.started");
|
|
5269
|
+
}
|
|
5270
|
+
}
|
|
5271
|
+
continue;
|
|
5272
|
+
}
|
|
5273
|
+
if (type === "tool_completed" || type === "mcp_tool_call_completed") {
|
|
5274
|
+
const toolName = type === "mcp_tool_call_completed" ? mcpToolName(raw) : stringField(raw, "tool_name") || "unknown";
|
|
5275
|
+
const toolId = stringField(raw, "call_id") || findPendingToolId(pendingTools, toolName) || `${sessionId}:tool:${lineNumber}:${toolName}`;
|
|
5276
|
+
const pending = pendingTools.get(toolId);
|
|
5277
|
+
const durationMs = numberField(raw, "duration_ms") ?? durationMsBetween(pending?.startedAt, ts);
|
|
5278
|
+
const outcome = stringField(raw, "outcome");
|
|
5279
|
+
const success = raw.success !== false && outcome !== "error" && outcome !== "failed" && !raw.is_timeout;
|
|
5280
|
+
push(base({
|
|
5281
|
+
ts,
|
|
5282
|
+
type: success ? "tool.completed" : "tool.failed",
|
|
5283
|
+
turnId: pending?.turnId || currentTurnId,
|
|
5284
|
+
tool: pending?.name || toolName,
|
|
5285
|
+
operation: `${pending?.name || toolName} completed`,
|
|
5286
|
+
success,
|
|
5287
|
+
confidence: "exact",
|
|
5288
|
+
metrics: {
|
|
5289
|
+
toolCalls: 1,
|
|
5290
|
+
toolDurationMs: durationMs,
|
|
5291
|
+
durationMs
|
|
5292
|
+
},
|
|
5293
|
+
refs: stringRefs({ sourceId: `${toolId}:completed` })
|
|
5294
|
+
}), lineNumber, type, "tool.completed");
|
|
5295
|
+
if (isShellTool(pending?.name || toolName)) {
|
|
5296
|
+
push(base({
|
|
5297
|
+
ts,
|
|
5298
|
+
type: success ? "command.completed" : "command.failed",
|
|
5299
|
+
turnId: pending?.turnId || currentTurnId,
|
|
5300
|
+
tool: pending?.name || toolName,
|
|
5301
|
+
operation: "command completed",
|
|
5302
|
+
success,
|
|
5303
|
+
confidence: "derived",
|
|
5304
|
+
metrics: {
|
|
5305
|
+
commandCalls: 1,
|
|
5306
|
+
commandDurationMs: durationMs,
|
|
5307
|
+
durationMs
|
|
5308
|
+
},
|
|
5309
|
+
refs: stringRefs({ sourceId: `${toolId}:command:completed` })
|
|
5310
|
+
}), lineNumber, type, "command.completed");
|
|
5311
|
+
}
|
|
5312
|
+
pendingTools.delete(toolId);
|
|
5313
|
+
continue;
|
|
5314
|
+
}
|
|
5315
|
+
if (type === "permission_resolved") {
|
|
5316
|
+
const toolName = stringField(raw, "tool_name");
|
|
5317
|
+
const decision = stringField(raw, "decision") || stringField(raw, "outcome");
|
|
5318
|
+
const allowed = decision !== "deny" && decision !== "denied" && decision !== "reject";
|
|
5319
|
+
push(base({
|
|
5320
|
+
ts,
|
|
5321
|
+
type: allowed ? "permission.granted" : "permission.denied",
|
|
5322
|
+
turnId: currentTurnId,
|
|
5323
|
+
tool: toolName,
|
|
5324
|
+
success: allowed,
|
|
5325
|
+
confidence: "partial",
|
|
5326
|
+
refs: stringRefs({
|
|
5327
|
+
sourceId: `${sessionId}:permission:${lineNumber}`,
|
|
5328
|
+
decision
|
|
5329
|
+
})
|
|
5330
|
+
}), lineNumber, type, "permission");
|
|
5331
|
+
}
|
|
5332
|
+
}
|
|
5333
|
+
const signals = await readJsonIfExists(signalsPath);
|
|
5334
|
+
if (isPlainObject(signals) && updatedAt) {
|
|
5335
|
+
const metrics = metricsFromSignals(signals);
|
|
5336
|
+
if (metrics) {
|
|
5337
|
+
push(base({
|
|
5338
|
+
ts: updatedAt,
|
|
5339
|
+
type: "model.usage",
|
|
5340
|
+
model: stringField(signals, "primaryModelId") || model,
|
|
5341
|
+
confidence: "partial",
|
|
5342
|
+
metrics,
|
|
5343
|
+
refs: stringRefs({ sourceId: `${sessionId}:usage:signals` })
|
|
5344
|
+
}), lineNumber + 1, "signals", "model.usage");
|
|
5345
|
+
}
|
|
5346
|
+
}
|
|
5347
|
+
if (updatedAt) {
|
|
5348
|
+
push(base({
|
|
5349
|
+
ts: updatedAt,
|
|
5350
|
+
type: "session.ended",
|
|
5351
|
+
confidence: "derived",
|
|
5352
|
+
refs: stringRefs({ sourceId: `${sessionId}:ended` })
|
|
5353
|
+
}), lineNumber + 2, "summary", "session.ended");
|
|
5354
|
+
}
|
|
5355
|
+
return events;
|
|
5356
|
+
}
|
|
5357
|
+
function resolveSessionDir(filePath) {
|
|
5358
|
+
const base = path13.basename(filePath);
|
|
5359
|
+
if (base === "summary.json" || base === "events.jsonl" || base === "signals.json") {
|
|
5360
|
+
return path13.dirname(filePath);
|
|
5361
|
+
}
|
|
5362
|
+
if (base.match(/^[0-9a-f]{8}-[0-9a-f-]{27,}$/i)) {
|
|
5363
|
+
return filePath;
|
|
5364
|
+
}
|
|
5365
|
+
return void 0;
|
|
5366
|
+
}
|
|
5367
|
+
function mcpToolName(raw) {
|
|
5368
|
+
const server = stringField(raw, "server_name");
|
|
5369
|
+
const tool = stringField(raw, "tool_name");
|
|
5370
|
+
if (server && tool) {
|
|
5371
|
+
return `${server}__${tool}`;
|
|
5372
|
+
}
|
|
5373
|
+
return tool || server || "mcp_tool";
|
|
5374
|
+
}
|
|
5375
|
+
function findPendingToolId(pending, toolName) {
|
|
5376
|
+
for (const [id, item] of pending) {
|
|
5377
|
+
if (item.name === toolName) {
|
|
5378
|
+
return id;
|
|
5379
|
+
}
|
|
5380
|
+
}
|
|
5381
|
+
return void 0;
|
|
5382
|
+
}
|
|
5383
|
+
function isShellTool(name) {
|
|
5384
|
+
if (!name) {
|
|
5385
|
+
return false;
|
|
5386
|
+
}
|
|
5387
|
+
const lower = name.toLowerCase();
|
|
5388
|
+
return lower === "run_terminal_command" || lower === "bash" || lower === "shell" || lower.endsWith("__run_terminal_command");
|
|
5389
|
+
}
|
|
5390
|
+
function fileActivitiesFromTool(toolName, input, ts, cwd) {
|
|
5391
|
+
const lower = toolName.toLowerCase();
|
|
5392
|
+
if (isShellTool(toolName)) {
|
|
5393
|
+
const command = stringField(input, "command");
|
|
5394
|
+
if (command) {
|
|
5395
|
+
return fileActivitiesFromShellCommand(command, ts, cwd, cwd);
|
|
5396
|
+
}
|
|
5397
|
+
return [];
|
|
5398
|
+
}
|
|
5399
|
+
if (lower === "read_file" || lower.endsWith("__read_file")) {
|
|
5400
|
+
const target = stringField(input, "target_file") || stringField(input, "path");
|
|
5401
|
+
if (!target) {
|
|
5402
|
+
return [];
|
|
5403
|
+
}
|
|
5404
|
+
return [{
|
|
5405
|
+
ts,
|
|
5406
|
+
path: displayPath(target, cwd),
|
|
5407
|
+
operation: "read",
|
|
5408
|
+
confidence: "exact"
|
|
5409
|
+
}];
|
|
5410
|
+
}
|
|
5411
|
+
if (lower === "search_replace" || lower === "write" || lower.endsWith("__search_replace") || lower.endsWith("__write")) {
|
|
5412
|
+
const target = stringField(input, "file_path") || stringField(input, "target_file") || stringField(input, "path");
|
|
5413
|
+
if (!target) {
|
|
5414
|
+
return [];
|
|
5415
|
+
}
|
|
5416
|
+
return [{
|
|
5417
|
+
ts,
|
|
5418
|
+
path: displayPath(target, cwd),
|
|
5419
|
+
operation: "edit",
|
|
5420
|
+
confidence: "exact"
|
|
5421
|
+
}];
|
|
5422
|
+
}
|
|
5423
|
+
return [];
|
|
5424
|
+
}
|
|
5425
|
+
function displayPath(filePath, cwd) {
|
|
5426
|
+
if (!cwd || !path13.isAbsolute(filePath)) {
|
|
5427
|
+
return filePath;
|
|
5428
|
+
}
|
|
5429
|
+
const relative = path13.relative(cwd, filePath);
|
|
5430
|
+
return relative && !relative.startsWith("..") && !path13.isAbsolute(relative) ? relative : filePath;
|
|
5431
|
+
}
|
|
5432
|
+
async function loadToolInputsFromUpdates(updatesPath) {
|
|
5433
|
+
const map = /* @__PURE__ */ new Map();
|
|
5434
|
+
let text = "";
|
|
5435
|
+
try {
|
|
5436
|
+
text = await readFile8(updatesPath, "utf8");
|
|
5437
|
+
} catch {
|
|
5438
|
+
return map;
|
|
5439
|
+
}
|
|
5440
|
+
for (const line of text.split("\n")) {
|
|
5441
|
+
if (!line.trim()) {
|
|
5442
|
+
continue;
|
|
5443
|
+
}
|
|
5444
|
+
const raw = parseJsonLine(line);
|
|
5445
|
+
if (!raw) {
|
|
5446
|
+
continue;
|
|
5447
|
+
}
|
|
5448
|
+
const params = objectField(raw, "params");
|
|
5449
|
+
const update = objectField(params, "update");
|
|
5450
|
+
const sessionUpdate = stringField(update, "sessionUpdate");
|
|
5451
|
+
if (sessionUpdate !== "tool_call" && sessionUpdate !== "tool_call_update") {
|
|
5452
|
+
continue;
|
|
5453
|
+
}
|
|
5454
|
+
const toolCallId = stringField(update, "toolCallId");
|
|
5455
|
+
if (!toolCallId) {
|
|
5456
|
+
continue;
|
|
5457
|
+
}
|
|
5458
|
+
const meta = objectField(update, "_meta");
|
|
5459
|
+
const toolMeta = objectField(meta, "x.ai/tool");
|
|
5460
|
+
const name = stringField(toolMeta, "name") || stringField(update, "title") || "unknown";
|
|
5461
|
+
const rawInput = objectField(update, "rawInput");
|
|
5462
|
+
const nestedInput = objectField(toolMeta, "input");
|
|
5463
|
+
const input = Object.keys(rawInput).length > 0 ? rawInput : nestedInput;
|
|
5464
|
+
if (!map.has(toolCallId) || Object.keys(input).length > 0) {
|
|
5465
|
+
map.set(toolCallId, { name, input });
|
|
5466
|
+
}
|
|
5467
|
+
}
|
|
5468
|
+
return map;
|
|
5469
|
+
}
|
|
5470
|
+
function metricsFromSignals(signals) {
|
|
5471
|
+
const contextTokens = numberField(signals, "contextTokensUsed");
|
|
5472
|
+
const toolCallCount = numberField(signals, "toolCallCount");
|
|
5473
|
+
const turnCount = numberField(signals, "turnCount");
|
|
5474
|
+
const durationSec = numberField(signals, "sessionDurationSeconds");
|
|
5475
|
+
const linesAdded = numberField(signals, "agentLinesAdded");
|
|
5476
|
+
const linesRemoved = numberField(signals, "agentLinesRemoved");
|
|
5477
|
+
if (contextTokens === void 0 && toolCallCount === void 0 && turnCount === void 0 && durationSec === void 0) {
|
|
5478
|
+
return void 0;
|
|
5479
|
+
}
|
|
5480
|
+
const metrics = {};
|
|
5481
|
+
if (contextTokens !== void 0 && contextTokens > 0) {
|
|
5482
|
+
metrics.tokensTotal = contextTokens;
|
|
5483
|
+
metrics.tokensInput = contextTokens;
|
|
5484
|
+
}
|
|
5485
|
+
if (toolCallCount !== void 0) {
|
|
5486
|
+
metrics.toolCalls = toolCallCount;
|
|
5487
|
+
}
|
|
5488
|
+
if (turnCount !== void 0) {
|
|
5489
|
+
metrics.modelCalls = turnCount;
|
|
5490
|
+
}
|
|
5491
|
+
if (durationSec !== void 0) {
|
|
5492
|
+
metrics.durationMs = Math.round(durationSec * 1e3);
|
|
5493
|
+
}
|
|
5494
|
+
if (linesAdded !== void 0) {
|
|
5495
|
+
metrics.linesAdded = linesAdded;
|
|
5496
|
+
}
|
|
5497
|
+
if (linesRemoved !== void 0) {
|
|
5498
|
+
metrics.linesRemoved = linesRemoved;
|
|
5499
|
+
}
|
|
5500
|
+
return metrics;
|
|
5501
|
+
}
|
|
5502
|
+
var grokHandler = (msg) => hookHandler(SOURCE_ID, msg);
|
|
5503
|
+
function hookConfig5() {
|
|
5504
|
+
const anyTool = [{ matcher: ".*", hooks: [grokHandler("Reporting tool activity")] }];
|
|
5505
|
+
return {
|
|
5506
|
+
hooks: {
|
|
5507
|
+
SessionStart: [{ hooks: [grokHandler("Reporting session start")] }],
|
|
5508
|
+
SessionEnd: [{ hooks: [grokHandler("Reporting session end")] }],
|
|
5509
|
+
UserPromptSubmit: [{ hooks: [grokHandler("Reporting prompt activity")] }],
|
|
5510
|
+
PreToolUse: anyTool,
|
|
5511
|
+
PostToolUse: anyTool,
|
|
5512
|
+
PostToolUseFailure: anyTool,
|
|
5513
|
+
PermissionDenied: anyTool,
|
|
5514
|
+
SubagentStart: [{ hooks: [grokHandler("Reporting subagent start")] }],
|
|
5515
|
+
SubagentStop: [{ hooks: [grokHandler("Reporting subagent completion")] }],
|
|
5516
|
+
Stop: [{ hooks: [grokHandler("Reporting turn completion")] }],
|
|
5517
|
+
StopFailure: [{ hooks: [grokHandler("Reporting turn failure")] }],
|
|
5518
|
+
PostCompact: [{ hooks: [grokHandler("Reporting context compaction")] }]
|
|
5519
|
+
}
|
|
5520
|
+
};
|
|
5521
|
+
}
|
|
5522
|
+
function createGrokBuildAdapter() {
|
|
5523
|
+
return {
|
|
5524
|
+
id: SOURCE_ID,
|
|
5525
|
+
label: "Grok Build",
|
|
5526
|
+
agentName: AGENT_NAME,
|
|
5527
|
+
kind: "agent",
|
|
5528
|
+
detectPath(home, env) {
|
|
5529
|
+
return grokHome(home, env);
|
|
5530
|
+
},
|
|
5531
|
+
installedPath(home, env) {
|
|
5532
|
+
return grokHooksPath(home, env);
|
|
5533
|
+
},
|
|
5534
|
+
async isInstalled(home, env) {
|
|
5535
|
+
return isHooksJsonInstalled(grokHooksPath(home, env), HOOK_COMMAND);
|
|
5536
|
+
},
|
|
5537
|
+
installEntries(home, env) {
|
|
5538
|
+
return [{
|
|
5539
|
+
kind: "hooks-json",
|
|
5540
|
+
path: grokHooksPath(home, env),
|
|
5541
|
+
content: hookConfig5()
|
|
5542
|
+
}];
|
|
5543
|
+
},
|
|
5544
|
+
sourcePaths(home, env) {
|
|
5545
|
+
return [grokSessionsDir(home, env)];
|
|
5546
|
+
},
|
|
5547
|
+
parseSessionFile: parseGrokSessionFile
|
|
5548
|
+
};
|
|
5549
|
+
}
|
|
5550
|
+
|
|
5061
5551
|
// src/adapters/opencode.ts
|
|
5062
5552
|
import os6 from "node:os";
|
|
5063
|
-
import
|
|
5553
|
+
import path14 from "node:path";
|
|
5064
5554
|
async function parseOpenCodeSessionFile(dbPath, options) {
|
|
5065
5555
|
const { DatabaseSync } = await import("node:sqlite");
|
|
5066
5556
|
if (!dbPath.endsWith(".db")) {
|
|
@@ -5091,7 +5581,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
5091
5581
|
for (const session of sessions) {
|
|
5092
5582
|
const sessionId = session.id;
|
|
5093
5583
|
const cwd = session.directory || session.path || void 0;
|
|
5094
|
-
const project = cwd ?
|
|
5584
|
+
const project = cwd ? path14.basename(cwd) : void 0;
|
|
5095
5585
|
const sessionTs = msToIso(session.time_created);
|
|
5096
5586
|
events.push(baseOpenCodeEvent({
|
|
5097
5587
|
ts: sessionTs,
|
|
@@ -5199,7 +5689,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
5199
5689
|
const provider = currentProvider;
|
|
5200
5690
|
const pathObj = objectField(info, "path");
|
|
5201
5691
|
const assistantCwd = stringField(pathObj, "cwd") || cwd;
|
|
5202
|
-
const assistantProject = assistantCwd ?
|
|
5692
|
+
const assistantProject = assistantCwd ? path14.basename(assistantCwd) : project;
|
|
5203
5693
|
const completedTs = numberField(objectField(info, "time"), "completed");
|
|
5204
5694
|
const createdTs = timeCreated;
|
|
5205
5695
|
const tokens = opencodeUsageFromInfo(info);
|
|
@@ -5447,33 +5937,33 @@ function opencodeUsageFromInfo(info) {
|
|
|
5447
5937
|
function opencodeConfigDir(home, env) {
|
|
5448
5938
|
const override = env?.OPENCODE_CONFIG_DIR;
|
|
5449
5939
|
if (override && override.trim()) {
|
|
5450
|
-
return
|
|
5940
|
+
return path14.resolve(override);
|
|
5451
5941
|
}
|
|
5452
5942
|
const xdgConfig = env?.XDG_CONFIG_HOME;
|
|
5453
5943
|
if (xdgConfig && xdgConfig.trim()) {
|
|
5454
|
-
return
|
|
5944
|
+
return path14.join(path14.resolve(xdgConfig), "opencode");
|
|
5455
5945
|
}
|
|
5456
|
-
return
|
|
5946
|
+
return path14.join(home, ".config", "opencode");
|
|
5457
5947
|
}
|
|
5458
5948
|
function opencodeDataCandidates(home, env) {
|
|
5459
5949
|
const xdgData = env?.XDG_DATA_HOME;
|
|
5460
|
-
const primary = xdgData && xdgData.trim() ?
|
|
5461
|
-
return [primary,
|
|
5950
|
+
const primary = xdgData && xdgData.trim() ? path14.join(path14.resolve(xdgData), "opencode", "opencode.db") : path14.join(home, ".local", "share", "opencode", "opencode.db");
|
|
5951
|
+
return [primary, path14.join(home, ".opencode", "opencode.db")];
|
|
5462
5952
|
}
|
|
5463
5953
|
async function opencodeBackfillFiles(sourceRoot, home = os6.homedir(), env) {
|
|
5464
|
-
const { stat:
|
|
5954
|
+
const { stat: stat14 } = await import("node:fs/promises");
|
|
5465
5955
|
if (sourceRoot) {
|
|
5466
5956
|
if (!sourceRoot.endsWith(".db")) {
|
|
5467
5957
|
return [];
|
|
5468
5958
|
}
|
|
5469
|
-
const info = await
|
|
5959
|
+
const info = await stat14(sourceRoot).catch(() => null);
|
|
5470
5960
|
if (!info) {
|
|
5471
5961
|
return [];
|
|
5472
5962
|
}
|
|
5473
5963
|
return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
|
|
5474
5964
|
}
|
|
5475
5965
|
for (const candidatePath of opencodeDataCandidates(home, env)) {
|
|
5476
|
-
const info = await
|
|
5966
|
+
const info = await stat14(candidatePath).catch(() => null);
|
|
5477
5967
|
if (info) {
|
|
5478
5968
|
return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
|
|
5479
5969
|
}
|
|
@@ -5548,12 +6038,12 @@ function createOpenCodeAdapter() {
|
|
|
5548
6038
|
return opencodeConfigDir(home, env);
|
|
5549
6039
|
},
|
|
5550
6040
|
installedPath(home, env) {
|
|
5551
|
-
return
|
|
6041
|
+
return path14.join(opencodeConfigDir(home, env), PLUGIN_PATH);
|
|
5552
6042
|
},
|
|
5553
6043
|
async isInstalled(home, env) {
|
|
5554
6044
|
try {
|
|
5555
6045
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
5556
|
-
return await pathExists2(
|
|
6046
|
+
return await pathExists2(path14.join(opencodeConfigDir(home, env), PLUGIN_PATH)) || await pathExists2(path14.join(".opencode", PLUGIN_PATH));
|
|
5557
6047
|
} catch {
|
|
5558
6048
|
return false;
|
|
5559
6049
|
}
|
|
@@ -5561,7 +6051,7 @@ function createOpenCodeAdapter() {
|
|
|
5561
6051
|
installEntries(home, env) {
|
|
5562
6052
|
return [{
|
|
5563
6053
|
kind: "file",
|
|
5564
|
-
path:
|
|
6054
|
+
path: path14.join(opencodeConfigDir(home, env), PLUGIN_PATH),
|
|
5565
6055
|
content: opencodePluginContent()
|
|
5566
6056
|
}];
|
|
5567
6057
|
},
|
|
@@ -5573,10 +6063,10 @@ function createOpenCodeAdapter() {
|
|
|
5573
6063
|
}
|
|
5574
6064
|
|
|
5575
6065
|
// src/adapters/pi.ts
|
|
5576
|
-
import { readFile as
|
|
5577
|
-
import
|
|
6066
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
6067
|
+
import path15 from "node:path";
|
|
5578
6068
|
async function parsePiSessionFile(filePath, options) {
|
|
5579
|
-
const text = await
|
|
6069
|
+
const text = await readFile9(filePath, "utf8");
|
|
5580
6070
|
const lines = text.split("\n").filter(Boolean);
|
|
5581
6071
|
let sessionId;
|
|
5582
6072
|
let cwd;
|
|
@@ -5607,7 +6097,7 @@ async function parsePiSessionFile(filePath, options) {
|
|
|
5607
6097
|
sessionId = stringField(raw, "id") || state.sessionId;
|
|
5608
6098
|
state.sessionId = sessionId || state.sessionId;
|
|
5609
6099
|
cwd = stringField(raw, "cwd") || cwd;
|
|
5610
|
-
project = cwd ?
|
|
6100
|
+
project = cwd ? path15.basename(cwd) : project;
|
|
5611
6101
|
continue;
|
|
5612
6102
|
}
|
|
5613
6103
|
if (entryType === "model_change") {
|
|
@@ -6016,16 +6506,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
6016
6506
|
function piAgentDir(home, env) {
|
|
6017
6507
|
const override = env?.PI_CODING_AGENT_DIR;
|
|
6018
6508
|
if (override && override.trim()) {
|
|
6019
|
-
return
|
|
6509
|
+
return path15.resolve(override);
|
|
6020
6510
|
}
|
|
6021
|
-
return
|
|
6511
|
+
return path15.join(home, ".pi", "agent");
|
|
6022
6512
|
}
|
|
6023
6513
|
function piSessionDir(home, env) {
|
|
6024
6514
|
const override = env?.PI_CODING_AGENT_SESSION_DIR;
|
|
6025
6515
|
if (override && override.trim()) {
|
|
6026
|
-
return
|
|
6516
|
+
return path15.resolve(override);
|
|
6027
6517
|
}
|
|
6028
|
-
return
|
|
6518
|
+
return path15.join(piAgentDir(home, env), "sessions");
|
|
6029
6519
|
}
|
|
6030
6520
|
function createPiAdapter() {
|
|
6031
6521
|
return {
|
|
@@ -6037,12 +6527,12 @@ function createPiAdapter() {
|
|
|
6037
6527
|
return piAgentDir(home, env);
|
|
6038
6528
|
},
|
|
6039
6529
|
installedPath(home, env) {
|
|
6040
|
-
return
|
|
6530
|
+
return path15.join(piAgentDir(home, env), "extensions", "vibetime.ts");
|
|
6041
6531
|
},
|
|
6042
6532
|
async isInstalled(home, env) {
|
|
6043
6533
|
try {
|
|
6044
6534
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
6045
|
-
return await pathExists2(
|
|
6535
|
+
return await pathExists2(path15.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
|
|
6046
6536
|
} catch {
|
|
6047
6537
|
return false;
|
|
6048
6538
|
}
|
|
@@ -6050,7 +6540,7 @@ function createPiAdapter() {
|
|
|
6050
6540
|
installEntries(home, env) {
|
|
6051
6541
|
return [{
|
|
6052
6542
|
kind: "file",
|
|
6053
|
-
path:
|
|
6543
|
+
path: path15.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
|
|
6054
6544
|
content: piExtensionContent()
|
|
6055
6545
|
}];
|
|
6056
6546
|
},
|
|
@@ -6062,11 +6552,11 @@ function createPiAdapter() {
|
|
|
6062
6552
|
}
|
|
6063
6553
|
|
|
6064
6554
|
// src/adapters/qoder-cn.ts
|
|
6065
|
-
import { readdir as
|
|
6555
|
+
import { readdir as readdir7, readFile as readFile10, stat as stat8 } from "node:fs/promises";
|
|
6066
6556
|
import os7 from "node:os";
|
|
6067
|
-
import
|
|
6557
|
+
import path16 from "node:path";
|
|
6068
6558
|
function parseQoderCnPaths(filePath) {
|
|
6069
|
-
const parts = filePath.split(
|
|
6559
|
+
const parts = filePath.split(path16.sep);
|
|
6070
6560
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
6071
6561
|
let sessionId = "";
|
|
6072
6562
|
let projectName = "";
|
|
@@ -6075,20 +6565,20 @@ function parseQoderCnPaths(filePath) {
|
|
|
6075
6565
|
sessionId = parts[subagentsIdx - 1];
|
|
6076
6566
|
projectName = parts[subagentsIdx - 2];
|
|
6077
6567
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
6078
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
6568
|
+
configDir2 = parts.slice(0, projectsIdx).join(path16.sep);
|
|
6079
6569
|
} else {
|
|
6080
6570
|
const filename = parts.at(-1) || "";
|
|
6081
|
-
sessionId =
|
|
6571
|
+
sessionId = path16.basename(filename, ".jsonl");
|
|
6082
6572
|
projectName = parts.at(-2) || "";
|
|
6083
6573
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
6084
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
6574
|
+
configDir2 = parts.slice(0, projectsIdx).join(path16.sep);
|
|
6085
6575
|
}
|
|
6086
6576
|
return { configDir: configDir2, projectName, sessionId };
|
|
6087
6577
|
}
|
|
6088
6578
|
async function loadQoderCnModelNames(configDir2) {
|
|
6089
6579
|
try {
|
|
6090
|
-
const dynamicTextsPath =
|
|
6091
|
-
const content = await
|
|
6580
|
+
const dynamicTextsPath = path16.join(configDir2, ".auth", "dynamic-texts.json");
|
|
6581
|
+
const content = await readFile10(dynamicTextsPath, "utf8");
|
|
6092
6582
|
const json = JSON.parse(content);
|
|
6093
6583
|
const texts = json.texts || {};
|
|
6094
6584
|
const map = {};
|
|
@@ -6105,15 +6595,15 @@ async function loadQoderCnModelNames(configDir2) {
|
|
|
6105
6595
|
}
|
|
6106
6596
|
async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
6107
6597
|
const { configDir: configDir2, projectName, sessionId } = parseQoderCnPaths(filePath);
|
|
6108
|
-
const segmentsPath =
|
|
6598
|
+
const segmentsPath = path16.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
6109
6599
|
const modelCalls = [];
|
|
6110
6600
|
try {
|
|
6111
|
-
const files = await
|
|
6601
|
+
const files = await readdir7(segmentsPath);
|
|
6112
6602
|
for (const file of files) {
|
|
6113
6603
|
if (!file.endsWith(".jsonl")) {
|
|
6114
6604
|
continue;
|
|
6115
6605
|
}
|
|
6116
|
-
const content = await
|
|
6606
|
+
const content = await readFile10(path16.join(segmentsPath, file), "utf8");
|
|
6117
6607
|
let currentTurnIsSubagent = false;
|
|
6118
6608
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
6119
6609
|
const raw = parseJsonLine(line);
|
|
@@ -6146,7 +6636,7 @@ async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMa
|
|
|
6146
6636
|
return modelCalls.filter((call) => call.isSubagent === isSubagentSession);
|
|
6147
6637
|
}
|
|
6148
6638
|
async function parseQoderCnSessionFile(filePath, options) {
|
|
6149
|
-
const text = await
|
|
6639
|
+
const text = await readFile10(filePath, "utf8");
|
|
6150
6640
|
const lines = text.split("\n").filter(Boolean);
|
|
6151
6641
|
const { configDir: configDir2 } = parseQoderCnPaths(filePath);
|
|
6152
6642
|
const projectContext = await qoderCnProjectContextFromLines(filePath, lines, options, configDir2);
|
|
@@ -6181,7 +6671,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
6181
6671
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
6182
6672
|
state.sessionId = sessionId;
|
|
6183
6673
|
cwd = stringField(raw, "cwd") || cwd;
|
|
6184
|
-
project = projectContext.project || (cwd ?
|
|
6674
|
+
project = projectContext.project || (cwd ? path16.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
|
|
6185
6675
|
if (!ts) {
|
|
6186
6676
|
continue;
|
|
6187
6677
|
}
|
|
@@ -6610,28 +7100,28 @@ function isNoisePrompt(text) {
|
|
|
6610
7100
|
}
|
|
6611
7101
|
async function qoderCnProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
6612
7102
|
const { projectName: projectDir, sessionId } = parseQoderCnPaths(filePath);
|
|
6613
|
-
const isSubagent = filePath.includes(`${
|
|
7103
|
+
const isSubagent = filePath.includes(`${path16.sep}subagents${path16.sep}`);
|
|
6614
7104
|
const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
|
|
6615
7105
|
let cwds = [];
|
|
6616
7106
|
for (const line of lines) {
|
|
6617
7107
|
const raw = parseJsonLine(line);
|
|
6618
7108
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
6619
|
-
if (cwd &&
|
|
7109
|
+
if (cwd && path16.isAbsolute(cwd)) {
|
|
6620
7110
|
cwds.push(cwd);
|
|
6621
7111
|
}
|
|
6622
7112
|
}
|
|
6623
7113
|
if (isSubagent) {
|
|
6624
|
-
if (inherited?.cwd &&
|
|
7114
|
+
if (inherited?.cwd && path16.isAbsolute(inherited.cwd)) {
|
|
6625
7115
|
cwds = [inherited.cwd];
|
|
6626
7116
|
} else {
|
|
6627
|
-
const parentSessionPath =
|
|
7117
|
+
const parentSessionPath = path16.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
6628
7118
|
try {
|
|
6629
|
-
const parentText = await
|
|
7119
|
+
const parentText = await readFile10(parentSessionPath, "utf8");
|
|
6630
7120
|
const parentCwds = [];
|
|
6631
7121
|
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
6632
7122
|
const raw = parseJsonLine(line);
|
|
6633
7123
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
6634
|
-
if (cwd &&
|
|
7124
|
+
if (cwd && path16.isAbsolute(cwd)) {
|
|
6635
7125
|
parentCwds.push(cwd);
|
|
6636
7126
|
}
|
|
6637
7127
|
}
|
|
@@ -6643,7 +7133,7 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
6643
7133
|
}
|
|
6644
7134
|
}
|
|
6645
7135
|
const root = await gitRootFromCwds2(cwds) || qoderCnProjectRootFromCwds(projectDir, cwds);
|
|
6646
|
-
const project = inherited?.project || (cwds.length > 0 ?
|
|
7136
|
+
const project = inherited?.project || (cwds.length > 0 ? path16.basename(cwds[0]) : root ? path16.basename(root) : await qoderCnProjectFromFilePath(filePath, options));
|
|
6647
7137
|
return {
|
|
6648
7138
|
project,
|
|
6649
7139
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -6652,15 +7142,15 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
6652
7142
|
async function gitRootFromCwds2(cwds) {
|
|
6653
7143
|
const seen = /* @__PURE__ */ new Set();
|
|
6654
7144
|
for (const cwd of cwds) {
|
|
6655
|
-
let current =
|
|
7145
|
+
let current = path16.resolve(cwd);
|
|
6656
7146
|
while (!seen.has(current)) {
|
|
6657
7147
|
seen.add(current);
|
|
6658
7148
|
try {
|
|
6659
|
-
await
|
|
7149
|
+
await stat8(path16.join(current, ".git"));
|
|
6660
7150
|
return current;
|
|
6661
7151
|
} catch {
|
|
6662
7152
|
}
|
|
6663
|
-
const parent =
|
|
7153
|
+
const parent = path16.dirname(current);
|
|
6664
7154
|
if (parent === current) {
|
|
6665
7155
|
break;
|
|
6666
7156
|
}
|
|
@@ -6671,12 +7161,12 @@ async function gitRootFromCwds2(cwds) {
|
|
|
6671
7161
|
}
|
|
6672
7162
|
function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
6673
7163
|
for (const cwd of cwds) {
|
|
6674
|
-
let current =
|
|
7164
|
+
let current = path16.resolve(cwd);
|
|
6675
7165
|
while (true) {
|
|
6676
7166
|
if (encodeQoderCnProjectPath(current) === projectDir) {
|
|
6677
7167
|
return current;
|
|
6678
7168
|
}
|
|
6679
|
-
const parent =
|
|
7169
|
+
const parent = path16.dirname(current);
|
|
6680
7170
|
if (parent === current) {
|
|
6681
7171
|
break;
|
|
6682
7172
|
}
|
|
@@ -6686,14 +7176,14 @@ function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
|
6686
7176
|
return void 0;
|
|
6687
7177
|
}
|
|
6688
7178
|
function encodeQoderCnProjectPath(value) {
|
|
6689
|
-
return
|
|
7179
|
+
return path16.resolve(value).split(path16.sep).join("-").replace(/_/g, "-");
|
|
6690
7180
|
}
|
|
6691
7181
|
async function qoderCnProjectFromFilePath(filePath, options) {
|
|
6692
|
-
const projectDir =
|
|
6693
|
-
const home = options ?
|
|
7182
|
+
const projectDir = path16.basename(path16.dirname(filePath));
|
|
7183
|
+
const home = options ? path16.resolve(stringOption(options.home) || os7.homedir()) : os7.homedir();
|
|
6694
7184
|
const resolved = await resolveQoderCnProjectPath(projectDir, home);
|
|
6695
7185
|
if (resolved) {
|
|
6696
|
-
return
|
|
7186
|
+
return path16.basename(resolved);
|
|
6697
7187
|
}
|
|
6698
7188
|
const homePrefix = `${encodeQoderCnProjectPath(home)}-`;
|
|
6699
7189
|
if (projectDir.startsWith(homePrefix)) {
|
|
@@ -6713,12 +7203,12 @@ async function resolveQoderCnProjectPath(projectDir, home) {
|
|
|
6713
7203
|
while (projectDir.startsWith(`${currentEncoded}-`)) {
|
|
6714
7204
|
let matchedChild;
|
|
6715
7205
|
try {
|
|
6716
|
-
const entries = await
|
|
7206
|
+
const entries = await readdir7(current, { withFileTypes: true });
|
|
6717
7207
|
for (const entry of entries) {
|
|
6718
7208
|
if (!entry.isDirectory()) {
|
|
6719
7209
|
continue;
|
|
6720
7210
|
}
|
|
6721
|
-
const candidate =
|
|
7211
|
+
const candidate = path16.join(current, entry.name);
|
|
6722
7212
|
const encoded = encodeQoderCnProjectPath(candidate);
|
|
6723
7213
|
if (encoded === projectDir) {
|
|
6724
7214
|
return candidate;
|
|
@@ -6740,7 +7230,7 @@ async function resolveQoderCnProjectPath(projectDir, home) {
|
|
|
6740
7230
|
return void 0;
|
|
6741
7231
|
}
|
|
6742
7232
|
var qoderCnHandler = (msg) => hookHandler("qoder-cn", msg);
|
|
6743
|
-
function
|
|
7233
|
+
function hookConfig6() {
|
|
6744
7234
|
const anyTool = [{ matcher: ".*", hooks: [qoderCnHandler("Reporting tool activity")] }];
|
|
6745
7235
|
return {
|
|
6746
7236
|
hooks: {
|
|
@@ -6763,9 +7253,9 @@ function hookConfig5() {
|
|
|
6763
7253
|
function qoderCnConfigDir(home, env) {
|
|
6764
7254
|
const override = env?.QODER_CN_CONFIG_DIR;
|
|
6765
7255
|
if (override && override.trim()) {
|
|
6766
|
-
return
|
|
7256
|
+
return path16.resolve(override);
|
|
6767
7257
|
}
|
|
6768
|
-
return
|
|
7258
|
+
return path16.join(home, ".qoder-cn");
|
|
6769
7259
|
}
|
|
6770
7260
|
function createQoderCnAdapter() {
|
|
6771
7261
|
return {
|
|
@@ -6777,27 +7267,27 @@ function createQoderCnAdapter() {
|
|
|
6777
7267
|
return qoderCnConfigDir(home, env);
|
|
6778
7268
|
},
|
|
6779
7269
|
installedPath(home, env) {
|
|
6780
|
-
return
|
|
7270
|
+
return path16.join(qoderCnConfigDir(home, env), "settings.json");
|
|
6781
7271
|
},
|
|
6782
7272
|
async isInstalled(home, env) {
|
|
6783
7273
|
return isHooksJsonInstalled(
|
|
6784
|
-
|
|
7274
|
+
path16.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
6785
7275
|
"vibetime hook --agent qoder-cn"
|
|
6786
7276
|
);
|
|
6787
7277
|
},
|
|
6788
7278
|
installEntries(home, env) {
|
|
6789
7279
|
return [{
|
|
6790
7280
|
kind: "hooks-json",
|
|
6791
|
-
path:
|
|
6792
|
-
content:
|
|
7281
|
+
path: path16.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
7282
|
+
content: hookConfig6()
|
|
6793
7283
|
}];
|
|
6794
7284
|
},
|
|
6795
7285
|
sourcePaths(home, env) {
|
|
6796
7286
|
const base = qoderCnConfigDir(home, env);
|
|
6797
7287
|
return [
|
|
6798
|
-
|
|
6799
|
-
|
|
6800
|
-
|
|
7288
|
+
path16.join(base, "projects"),
|
|
7289
|
+
path16.join(base, ".qoder.json"),
|
|
7290
|
+
path16.join(home, ".qoder.json")
|
|
6801
7291
|
];
|
|
6802
7292
|
},
|
|
6803
7293
|
parseSessionFile: parseQoderCnSessionFile
|
|
@@ -6805,11 +7295,11 @@ function createQoderCnAdapter() {
|
|
|
6805
7295
|
}
|
|
6806
7296
|
|
|
6807
7297
|
// src/adapters/qoder.ts
|
|
6808
|
-
import { readdir as
|
|
7298
|
+
import { readdir as readdir8, readFile as readFile11, stat as stat9 } from "node:fs/promises";
|
|
6809
7299
|
import os8 from "node:os";
|
|
6810
|
-
import
|
|
7300
|
+
import path17 from "node:path";
|
|
6811
7301
|
function parseQoderPaths(filePath) {
|
|
6812
|
-
const parts = filePath.split(
|
|
7302
|
+
const parts = filePath.split(path17.sep);
|
|
6813
7303
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
6814
7304
|
let sessionId = "";
|
|
6815
7305
|
let projectName = "";
|
|
@@ -6818,20 +7308,20 @@ function parseQoderPaths(filePath) {
|
|
|
6818
7308
|
sessionId = parts[subagentsIdx - 1];
|
|
6819
7309
|
projectName = parts[subagentsIdx - 2];
|
|
6820
7310
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
6821
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
7311
|
+
configDir2 = parts.slice(0, projectsIdx).join(path17.sep);
|
|
6822
7312
|
} else {
|
|
6823
7313
|
const filename = parts.at(-1) || "";
|
|
6824
|
-
sessionId =
|
|
7314
|
+
sessionId = path17.basename(filename, ".jsonl");
|
|
6825
7315
|
projectName = parts.at(-2) || "";
|
|
6826
7316
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
6827
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
7317
|
+
configDir2 = parts.slice(0, projectsIdx).join(path17.sep);
|
|
6828
7318
|
}
|
|
6829
7319
|
return { configDir: configDir2, projectName, sessionId };
|
|
6830
7320
|
}
|
|
6831
7321
|
async function loadQoderModelNames(configDir2) {
|
|
6832
7322
|
try {
|
|
6833
|
-
const dynamicTextsPath =
|
|
6834
|
-
const content = await
|
|
7323
|
+
const dynamicTextsPath = path17.join(configDir2, ".auth", "dynamic-texts.json");
|
|
7324
|
+
const content = await readFile11(dynamicTextsPath, "utf8");
|
|
6835
7325
|
const json = JSON.parse(content);
|
|
6836
7326
|
const texts = json.texts || {};
|
|
6837
7327
|
const map = {};
|
|
@@ -6848,15 +7338,15 @@ async function loadQoderModelNames(configDir2) {
|
|
|
6848
7338
|
}
|
|
6849
7339
|
async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
6850
7340
|
const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
|
|
6851
|
-
const segmentsPath =
|
|
7341
|
+
const segmentsPath = path17.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
6852
7342
|
const modelCalls = [];
|
|
6853
7343
|
try {
|
|
6854
|
-
const files = await
|
|
7344
|
+
const files = await readdir8(segmentsPath);
|
|
6855
7345
|
for (const file of files) {
|
|
6856
7346
|
if (!file.endsWith(".jsonl")) {
|
|
6857
7347
|
continue;
|
|
6858
7348
|
}
|
|
6859
|
-
const content = await
|
|
7349
|
+
const content = await readFile11(path17.join(segmentsPath, file), "utf8");
|
|
6860
7350
|
let currentTurnIsSubagent = false;
|
|
6861
7351
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
6862
7352
|
const raw = parseJsonLine(line);
|
|
@@ -6889,7 +7379,7 @@ async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap)
|
|
|
6889
7379
|
return modelCalls.filter((call) => call.isSubagent === isSubagentSession);
|
|
6890
7380
|
}
|
|
6891
7381
|
async function parseQoderSessionFile(filePath, options) {
|
|
6892
|
-
const text = await
|
|
7382
|
+
const text = await readFile11(filePath, "utf8");
|
|
6893
7383
|
const lines = text.split("\n").filter(Boolean);
|
|
6894
7384
|
const { configDir: configDir2 } = parseQoderPaths(filePath);
|
|
6895
7385
|
const projectContext = await qoderProjectContextFromLines(filePath, lines, options, configDir2);
|
|
@@ -6924,7 +7414,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
6924
7414
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
6925
7415
|
state.sessionId = sessionId;
|
|
6926
7416
|
cwd = stringField(raw, "cwd") || cwd;
|
|
6927
|
-
project = projectContext.project || (cwd ?
|
|
7417
|
+
project = projectContext.project || (cwd ? path17.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
|
|
6928
7418
|
if (!ts) {
|
|
6929
7419
|
continue;
|
|
6930
7420
|
}
|
|
@@ -7319,28 +7809,28 @@ function qoderExtractText(value) {
|
|
|
7319
7809
|
}
|
|
7320
7810
|
async function qoderProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
7321
7811
|
const { projectName: projectDir, sessionId } = parseQoderPaths(filePath);
|
|
7322
|
-
const isSubagent = filePath.includes(`${
|
|
7812
|
+
const isSubagent = filePath.includes(`${path17.sep}subagents${path17.sep}`);
|
|
7323
7813
|
const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
|
|
7324
7814
|
let cwds = [];
|
|
7325
7815
|
for (const line of lines) {
|
|
7326
7816
|
const raw = parseJsonLine(line);
|
|
7327
7817
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
7328
|
-
if (cwd &&
|
|
7818
|
+
if (cwd && path17.isAbsolute(cwd)) {
|
|
7329
7819
|
cwds.push(cwd);
|
|
7330
7820
|
}
|
|
7331
7821
|
}
|
|
7332
7822
|
if (isSubagent) {
|
|
7333
|
-
if (inherited?.cwd &&
|
|
7823
|
+
if (inherited?.cwd && path17.isAbsolute(inherited.cwd)) {
|
|
7334
7824
|
cwds = [inherited.cwd];
|
|
7335
7825
|
} else {
|
|
7336
|
-
const parentSessionPath =
|
|
7826
|
+
const parentSessionPath = path17.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
7337
7827
|
try {
|
|
7338
|
-
const parentText = await
|
|
7828
|
+
const parentText = await readFile11(parentSessionPath, "utf8");
|
|
7339
7829
|
const parentCwds = [];
|
|
7340
7830
|
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
7341
7831
|
const raw = parseJsonLine(line);
|
|
7342
7832
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
7343
|
-
if (cwd &&
|
|
7833
|
+
if (cwd && path17.isAbsolute(cwd)) {
|
|
7344
7834
|
parentCwds.push(cwd);
|
|
7345
7835
|
}
|
|
7346
7836
|
}
|
|
@@ -7352,7 +7842,7 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
|
|
|
7352
7842
|
}
|
|
7353
7843
|
}
|
|
7354
7844
|
const root = await gitRootFromCwds3(cwds) || qoderProjectRootFromCwds(projectDir, cwds);
|
|
7355
|
-
const project = inherited?.project || (cwds.length > 0 ?
|
|
7845
|
+
const project = inherited?.project || (cwds.length > 0 ? path17.basename(cwds[0]) : root ? path17.basename(root) : await qoderProjectFromFilePath(filePath, options));
|
|
7356
7846
|
return {
|
|
7357
7847
|
project,
|
|
7358
7848
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -7361,15 +7851,15 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
|
|
|
7361
7851
|
async function gitRootFromCwds3(cwds) {
|
|
7362
7852
|
const seen = /* @__PURE__ */ new Set();
|
|
7363
7853
|
for (const cwd of cwds) {
|
|
7364
|
-
let current =
|
|
7854
|
+
let current = path17.resolve(cwd);
|
|
7365
7855
|
while (!seen.has(current)) {
|
|
7366
7856
|
seen.add(current);
|
|
7367
7857
|
try {
|
|
7368
|
-
await
|
|
7858
|
+
await stat9(path17.join(current, ".git"));
|
|
7369
7859
|
return current;
|
|
7370
7860
|
} catch {
|
|
7371
7861
|
}
|
|
7372
|
-
const parent =
|
|
7862
|
+
const parent = path17.dirname(current);
|
|
7373
7863
|
if (parent === current) {
|
|
7374
7864
|
break;
|
|
7375
7865
|
}
|
|
@@ -7380,12 +7870,12 @@ async function gitRootFromCwds3(cwds) {
|
|
|
7380
7870
|
}
|
|
7381
7871
|
function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
7382
7872
|
for (const cwd of cwds) {
|
|
7383
|
-
let current =
|
|
7873
|
+
let current = path17.resolve(cwd);
|
|
7384
7874
|
while (true) {
|
|
7385
7875
|
if (encodeQoderProjectPath(current) === projectDir) {
|
|
7386
7876
|
return current;
|
|
7387
7877
|
}
|
|
7388
|
-
const parent =
|
|
7878
|
+
const parent = path17.dirname(current);
|
|
7389
7879
|
if (parent === current) {
|
|
7390
7880
|
break;
|
|
7391
7881
|
}
|
|
@@ -7395,10 +7885,10 @@ function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
|
7395
7885
|
return void 0;
|
|
7396
7886
|
}
|
|
7397
7887
|
function encodeQoderProjectPath(value) {
|
|
7398
|
-
return
|
|
7888
|
+
return path17.resolve(value).split(path17.sep).join("-").replace(/_/g, "-");
|
|
7399
7889
|
}
|
|
7400
7890
|
function rawQoderProjectPath(value) {
|
|
7401
|
-
return
|
|
7891
|
+
return path17.resolve(value).split(path17.sep).join("-");
|
|
7402
7892
|
}
|
|
7403
7893
|
function qoderEncodedVariants(value) {
|
|
7404
7894
|
const raw = rawQoderProjectPath(value);
|
|
@@ -7414,11 +7904,11 @@ function qoderEncodedProjectSuffix(projectDir, home) {
|
|
|
7414
7904
|
return void 0;
|
|
7415
7905
|
}
|
|
7416
7906
|
async function qoderProjectFromFilePath(filePath, options) {
|
|
7417
|
-
const projectDir =
|
|
7418
|
-
const home = options ?
|
|
7907
|
+
const projectDir = path17.basename(path17.dirname(filePath));
|
|
7908
|
+
const home = options ? path17.resolve(stringOption(options.home) || os8.homedir()) : os8.homedir();
|
|
7419
7909
|
const resolved = await resolveQoderProjectPath(projectDir, home);
|
|
7420
7910
|
if (resolved) {
|
|
7421
|
-
return
|
|
7911
|
+
return path17.basename(resolved);
|
|
7422
7912
|
}
|
|
7423
7913
|
const suffix = qoderEncodedProjectSuffix(projectDir, home);
|
|
7424
7914
|
if (suffix) {
|
|
@@ -7439,12 +7929,12 @@ async function resolveQoderProjectPath(projectDir, home) {
|
|
|
7439
7929
|
while (currentEncodedVariants.some((prefix) => projectDir.startsWith(`${prefix}-`))) {
|
|
7440
7930
|
let matchedChild;
|
|
7441
7931
|
try {
|
|
7442
|
-
const entries = await
|
|
7932
|
+
const entries = await readdir8(current, { withFileTypes: true });
|
|
7443
7933
|
for (const entry of entries) {
|
|
7444
7934
|
if (!entry.isDirectory()) {
|
|
7445
7935
|
continue;
|
|
7446
7936
|
}
|
|
7447
|
-
const candidate =
|
|
7937
|
+
const candidate = path17.join(current, entry.name);
|
|
7448
7938
|
const candidateVariants = qoderEncodedVariants(candidate);
|
|
7449
7939
|
if (candidateVariants.includes(projectDir)) {
|
|
7450
7940
|
return candidate;
|
|
@@ -7466,7 +7956,7 @@ async function resolveQoderProjectPath(projectDir, home) {
|
|
|
7466
7956
|
return void 0;
|
|
7467
7957
|
}
|
|
7468
7958
|
var qoderHandler = (msg) => hookHandler("qoder", msg);
|
|
7469
|
-
function
|
|
7959
|
+
function hookConfig7() {
|
|
7470
7960
|
const anyTool = [{ matcher: ".*", hooks: [qoderHandler("Reporting tool activity")] }];
|
|
7471
7961
|
return {
|
|
7472
7962
|
hooks: {
|
|
@@ -7489,9 +7979,9 @@ function hookConfig6() {
|
|
|
7489
7979
|
function qoderConfigDir(home, env) {
|
|
7490
7980
|
const override = env?.QODER_CONFIG_DIR;
|
|
7491
7981
|
if (override && override.trim()) {
|
|
7492
|
-
return
|
|
7982
|
+
return path17.resolve(override);
|
|
7493
7983
|
}
|
|
7494
|
-
return
|
|
7984
|
+
return path17.join(home, ".qoder");
|
|
7495
7985
|
}
|
|
7496
7986
|
function createQoderAdapter() {
|
|
7497
7987
|
return {
|
|
@@ -7503,27 +7993,27 @@ function createQoderAdapter() {
|
|
|
7503
7993
|
return qoderConfigDir(home, env);
|
|
7504
7994
|
},
|
|
7505
7995
|
installedPath(home, env) {
|
|
7506
|
-
return
|
|
7996
|
+
return path17.join(qoderConfigDir(home, env), "settings.json");
|
|
7507
7997
|
},
|
|
7508
7998
|
async isInstalled(home, env) {
|
|
7509
7999
|
return isHooksJsonInstalled(
|
|
7510
|
-
|
|
8000
|
+
path17.join(qoderConfigDir(home, env), "settings.json"),
|
|
7511
8001
|
"vibetime hook --agent qoder"
|
|
7512
8002
|
);
|
|
7513
8003
|
},
|
|
7514
8004
|
installEntries(home, env) {
|
|
7515
8005
|
return [{
|
|
7516
8006
|
kind: "hooks-json",
|
|
7517
|
-
path:
|
|
7518
|
-
content:
|
|
8007
|
+
path: path17.join(qoderConfigDir(home, env), "settings.json"),
|
|
8008
|
+
content: hookConfig7()
|
|
7519
8009
|
}];
|
|
7520
8010
|
},
|
|
7521
8011
|
sourcePaths(home, env) {
|
|
7522
8012
|
const base = qoderConfigDir(home, env);
|
|
7523
8013
|
return [
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
8014
|
+
path17.join(base, "projects"),
|
|
8015
|
+
path17.join(base, ".qoder.json"),
|
|
8016
|
+
path17.join(home, ".qoder.json")
|
|
7527
8017
|
];
|
|
7528
8018
|
},
|
|
7529
8019
|
parseSessionFile: parseQoderSessionFile
|
|
@@ -7558,21 +8048,21 @@ function normalizeId(id) {
|
|
|
7558
8048
|
}
|
|
7559
8049
|
|
|
7560
8050
|
// src/adapters/workbuddy.ts
|
|
7561
|
-
import { readFile as
|
|
7562
|
-
import
|
|
8051
|
+
import { readFile as readFile12, readdir as readdir9, stat as stat10 } from "node:fs/promises";
|
|
8052
|
+
import path18 from "node:path";
|
|
7563
8053
|
init_fs();
|
|
7564
8054
|
function workbuddyProjectsDir(home, env) {
|
|
7565
8055
|
const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
|
|
7566
8056
|
if (override && override.trim()) {
|
|
7567
|
-
return
|
|
8057
|
+
return path18.resolve(override, override.endsWith("projects") ? "" : "projects");
|
|
7568
8058
|
}
|
|
7569
|
-
return
|
|
8059
|
+
return path18.join(home, ".workbuddy", "projects");
|
|
7570
8060
|
}
|
|
7571
8061
|
function projectFromCwd(cwd, fallback) {
|
|
7572
8062
|
if (!cwd) {
|
|
7573
8063
|
return fallback;
|
|
7574
8064
|
}
|
|
7575
|
-
return
|
|
8065
|
+
return path18.basename(cwd) || fallback;
|
|
7576
8066
|
}
|
|
7577
8067
|
function sourceHash(filePath) {
|
|
7578
8068
|
return `sha256:${createStableHash(filePath)}`;
|
|
@@ -7654,7 +8144,7 @@ function contentLength(value) {
|
|
|
7654
8144
|
return 0;
|
|
7655
8145
|
}
|
|
7656
8146
|
async function readWorkbuddyLines(filePath) {
|
|
7657
|
-
const text = await
|
|
8147
|
+
const text = await readFile12(filePath, "utf8");
|
|
7658
8148
|
return text.split(/\r?\n/).map((line, index) => {
|
|
7659
8149
|
if (!line.trim()) {
|
|
7660
8150
|
return void 0;
|
|
@@ -7674,8 +8164,8 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
7674
8164
|
}
|
|
7675
8165
|
const events = [];
|
|
7676
8166
|
const first = lines[0].record;
|
|
7677
|
-
const sessionId = stringField(first, "sessionId") ||
|
|
7678
|
-
const fallbackProject =
|
|
8167
|
+
const sessionId = stringField(first, "sessionId") || path18.basename(filePath, ".jsonl");
|
|
8168
|
+
const fallbackProject = path18.basename(path18.dirname(filePath));
|
|
7679
8169
|
const cwd = lines.map((line) => stringField(line.record, "cwd")).find(Boolean);
|
|
7680
8170
|
const project = projectFromCwd(cwd, fallbackProject);
|
|
7681
8171
|
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
@@ -7844,17 +8334,17 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
7844
8334
|
const base = sourceRoot || workbuddyProjectsDir(home, env);
|
|
7845
8335
|
const files = [];
|
|
7846
8336
|
try {
|
|
7847
|
-
const projects = await
|
|
8337
|
+
const projects = await readdir9(base, { withFileTypes: true });
|
|
7848
8338
|
for (const project of projects) {
|
|
7849
8339
|
if (!project.isDirectory()) {
|
|
7850
8340
|
continue;
|
|
7851
8341
|
}
|
|
7852
|
-
const projectDir =
|
|
7853
|
-
const entries = await
|
|
8342
|
+
const projectDir = path18.join(base, project.name);
|
|
8343
|
+
const entries = await readdir9(projectDir, { withFileTypes: true });
|
|
7854
8344
|
for (const entry of entries) {
|
|
7855
8345
|
if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
7856
|
-
const filePath =
|
|
7857
|
-
const info = await
|
|
8346
|
+
const filePath = path18.join(projectDir, entry.name);
|
|
8347
|
+
const info = await stat10(filePath);
|
|
7858
8348
|
files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
|
|
7859
8349
|
}
|
|
7860
8350
|
}
|
|
@@ -7891,26 +8381,26 @@ function createWorkbuddyAdapter() {
|
|
|
7891
8381
|
|
|
7892
8382
|
// src/adapters/zcode.ts
|
|
7893
8383
|
import { execFile } from "node:child_process";
|
|
7894
|
-
import { readFile as
|
|
7895
|
-
import
|
|
8384
|
+
import { readFile as readFile13, stat as stat11 } from "node:fs/promises";
|
|
8385
|
+
import path19 from "node:path";
|
|
7896
8386
|
import { promisify as promisify2 } from "node:util";
|
|
7897
8387
|
init_fs();
|
|
7898
8388
|
var execFileAsync = promisify2(execFile);
|
|
7899
8389
|
function zcodeCliDir(home, env) {
|
|
7900
8390
|
const override = env?.ZCODE_CLI_DIR || env?.ZCODE_HOME;
|
|
7901
8391
|
if (override && override.trim()) {
|
|
7902
|
-
return
|
|
8392
|
+
return path19.resolve(override, override.endsWith("cli") ? "" : "cli");
|
|
7903
8393
|
}
|
|
7904
|
-
return
|
|
8394
|
+
return path19.join(home, ".zcode", "cli");
|
|
7905
8395
|
}
|
|
7906
8396
|
function zcodeDbPath(home, env) {
|
|
7907
|
-
return
|
|
8397
|
+
return path19.join(zcodeCliDir(home, env), "db", "db.sqlite");
|
|
7908
8398
|
}
|
|
7909
8399
|
var providerNameCache = null;
|
|
7910
8400
|
async function loadProviderNames(configPath2) {
|
|
7911
8401
|
let fileMtime = 0;
|
|
7912
8402
|
try {
|
|
7913
|
-
const info = await
|
|
8403
|
+
const info = await stat11(configPath2);
|
|
7914
8404
|
fileMtime = info.mtimeMs;
|
|
7915
8405
|
} catch {
|
|
7916
8406
|
return /* @__PURE__ */ new Map();
|
|
@@ -7920,7 +8410,7 @@ async function loadProviderNames(configPath2) {
|
|
|
7920
8410
|
}
|
|
7921
8411
|
const map = /* @__PURE__ */ new Map();
|
|
7922
8412
|
try {
|
|
7923
|
-
const raw = await
|
|
8413
|
+
const raw = await readFile13(configPath2, "utf-8");
|
|
7924
8414
|
const config = JSON.parse(raw);
|
|
7925
8415
|
const providers = config?.provider;
|
|
7926
8416
|
if (isPlainObject(providers)) {
|
|
@@ -7938,7 +8428,7 @@ function sourceHash2(filePath) {
|
|
|
7938
8428
|
return `sha256:${createStableHash(filePath)}`;
|
|
7939
8429
|
}
|
|
7940
8430
|
function projectFromDirectory(directory) {
|
|
7941
|
-
return directory ?
|
|
8431
|
+
return directory ? path19.basename(directory) || "zcode" : "zcode";
|
|
7942
8432
|
}
|
|
7943
8433
|
function isoFromMs(value) {
|
|
7944
8434
|
return timestampFrom(typeof value === "number" ? value : Number(value));
|
|
@@ -8094,16 +8584,16 @@ async function parseZCodeDb(filePath, options) {
|
|
|
8094
8584
|
if (rows.length === 0) {
|
|
8095
8585
|
return [];
|
|
8096
8586
|
}
|
|
8097
|
-
let candidate =
|
|
8587
|
+
let candidate = path19.resolve(filePath);
|
|
8098
8588
|
let configPath2 = "";
|
|
8099
8589
|
for (let i = 0; i < 12; i++) {
|
|
8100
|
-
const probe =
|
|
8590
|
+
const probe = path19.join(candidate, ".zcode", "v2", "config.json");
|
|
8101
8591
|
try {
|
|
8102
|
-
await
|
|
8592
|
+
await stat11(probe);
|
|
8103
8593
|
configPath2 = probe;
|
|
8104
8594
|
break;
|
|
8105
8595
|
} catch {
|
|
8106
|
-
const parent =
|
|
8596
|
+
const parent = path19.dirname(candidate);
|
|
8107
8597
|
if (parent === candidate) break;
|
|
8108
8598
|
candidate = parent;
|
|
8109
8599
|
}
|
|
@@ -8319,9 +8809,9 @@ async function parseZCodeDb(filePath, options) {
|
|
|
8319
8809
|
}
|
|
8320
8810
|
async function zcodeBackfillFiles(sourceRoot, home, env) {
|
|
8321
8811
|
const candidate = sourceRoot || zcodeDbPath(home, env);
|
|
8322
|
-
const filePath = candidate.endsWith(".sqlite") ? candidate :
|
|
8812
|
+
const filePath = candidate.endsWith(".sqlite") ? candidate : path19.join(candidate, "db", "db.sqlite");
|
|
8323
8813
|
try {
|
|
8324
|
-
const info = await
|
|
8814
|
+
const info = await stat11(filePath);
|
|
8325
8815
|
return [{ path: filePath, modifiedAt: info.mtime.toISOString() }];
|
|
8326
8816
|
} catch {
|
|
8327
8817
|
return [];
|
|
@@ -8583,11 +9073,11 @@ function buildSessionRollup(rollupKey, events) {
|
|
|
8583
9073
|
bucket.activityCount += 1;
|
|
8584
9074
|
}
|
|
8585
9075
|
for (const file of event.fileActivities || []) {
|
|
8586
|
-
const
|
|
8587
|
-
const pathHash = `sha256:${createStableHash(
|
|
9076
|
+
const displayPath2 = displayBackfillPath(file.path);
|
|
9077
|
+
const pathHash = `sha256:${createStableHash(displayPath2)}`;
|
|
8588
9078
|
const fileRollup = fileRollups.get(pathHash) || {
|
|
8589
9079
|
pathHash,
|
|
8590
|
-
displayPath,
|
|
9080
|
+
displayPath: displayPath2,
|
|
8591
9081
|
reads: 0,
|
|
8592
9082
|
writes: 0,
|
|
8593
9083
|
linesAdded: 0,
|
|
@@ -8796,15 +9286,15 @@ function hookCommandFromGroup(group) {
|
|
|
8796
9286
|
import { randomUUID } from "node:crypto";
|
|
8797
9287
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
8798
9288
|
import { homedir, hostname } from "node:os";
|
|
8799
|
-
import
|
|
9289
|
+
import path20 from "node:path";
|
|
8800
9290
|
function configDir(home = homedir()) {
|
|
8801
|
-
return
|
|
9291
|
+
return path20.join(home, ".vibetime");
|
|
8802
9292
|
}
|
|
8803
9293
|
function configPath(home = homedir()) {
|
|
8804
|
-
return
|
|
9294
|
+
return path20.join(configDir(home), "config.json");
|
|
8805
9295
|
}
|
|
8806
9296
|
function machineIdPath(home = homedir()) {
|
|
8807
|
-
return
|
|
9297
|
+
return path20.join(configDir(home), "machine-id");
|
|
8808
9298
|
}
|
|
8809
9299
|
function readConfig(home = homedir()) {
|
|
8810
9300
|
const file = configPath(home);
|
|
@@ -8851,15 +9341,15 @@ function defaultMachineName() {
|
|
|
8851
9341
|
init_fs();
|
|
8852
9342
|
|
|
8853
9343
|
// src/lib/logger.ts
|
|
8854
|
-
import { appendFile, mkdir as mkdir4, rename, stat as
|
|
9344
|
+
import { appendFile, mkdir as mkdir4, rename, stat as stat12 } from "node:fs/promises";
|
|
8855
9345
|
import { homedir as homedir2 } from "node:os";
|
|
8856
|
-
import
|
|
9346
|
+
import path21 from "node:path";
|
|
8857
9347
|
var MAX_BYTES = 1 * 1024 * 1024;
|
|
8858
9348
|
function logDir(home = homedir2()) {
|
|
8859
|
-
return
|
|
9349
|
+
return path21.join(home, ".vibetime", "logs");
|
|
8860
9350
|
}
|
|
8861
9351
|
function logPath(home = homedir2(), name = "cli.log") {
|
|
8862
|
-
return
|
|
9352
|
+
return path21.join(logDir(home), name);
|
|
8863
9353
|
}
|
|
8864
9354
|
function serializeError(error) {
|
|
8865
9355
|
if (error instanceof Error) {
|
|
@@ -8869,7 +9359,7 @@ function serializeError(error) {
|
|
|
8869
9359
|
}
|
|
8870
9360
|
async function rotateIfNeeded(file) {
|
|
8871
9361
|
try {
|
|
8872
|
-
const info = await
|
|
9362
|
+
const info = await stat12(file);
|
|
8873
9363
|
if (info.size > MAX_BYTES) {
|
|
8874
9364
|
await rename(file, `${file}.1`).catch(() => {
|
|
8875
9365
|
});
|
|
@@ -9034,8 +9524,8 @@ function buildHeaders(token, machine) {
|
|
|
9034
9524
|
...machine?.platform ? { "x-machine-platform": machine.platform } : {}
|
|
9035
9525
|
};
|
|
9036
9526
|
}
|
|
9037
|
-
function joinUrl(base,
|
|
9038
|
-
return new URL(
|
|
9527
|
+
function joinUrl(base, path23) {
|
|
9528
|
+
return new URL(path23, base.endsWith("/") ? base : `${base}/`).toString();
|
|
9039
9529
|
}
|
|
9040
9530
|
async function postRollupBatch(remote, rollups, options = {}) {
|
|
9041
9531
|
const response = await remote.fetchImpl(joinUrl(remote.baseUrl, "/v3/agent/ingest"), {
|
|
@@ -9117,6 +9607,7 @@ function createRegistry() {
|
|
|
9117
9607
|
registry.register(createQoderCnAdapter());
|
|
9118
9608
|
registry.register(createWorkbuddyAdapter());
|
|
9119
9609
|
registry.register(createZCodeAdapter());
|
|
9610
|
+
registry.register(createGrokBuildAdapter());
|
|
9120
9611
|
return registry;
|
|
9121
9612
|
}
|
|
9122
9613
|
var defaultContext = {
|
|
@@ -9629,11 +10120,14 @@ async function listBackfillSourceFiles(source, options, ctx) {
|
|
|
9629
10120
|
if (source.id === "copilot") {
|
|
9630
10121
|
return copilotBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
9631
10122
|
}
|
|
10123
|
+
if (source.id === "grok-build") {
|
|
10124
|
+
return grokBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
10125
|
+
}
|
|
9632
10126
|
const roots = stringOption(options["source-root"]) ? [requiredOption(options, "source-root")] : source.paths;
|
|
9633
10127
|
const fileLists = await Promise.all(roots.map((r) => listJsonlFiles(r)));
|
|
9634
10128
|
const files = fileLists.flat().sort().slice(0, numberOption(options.limit) || void 0);
|
|
9635
10129
|
return Promise.all(files.map(async (filePath) => {
|
|
9636
|
-
const info = await
|
|
10130
|
+
const info = await stat13(filePath);
|
|
9637
10131
|
return { path: filePath, modifiedAt: info.mtime.toISOString() };
|
|
9638
10132
|
}));
|
|
9639
10133
|
}
|
|
@@ -9946,13 +10440,13 @@ function selectBackfillFilesForImport(files, watermarkTs) {
|
|
|
9946
10440
|
});
|
|
9947
10441
|
}
|
|
9948
10442
|
function backfillIncrementalStatePath(home) {
|
|
9949
|
-
return
|
|
10443
|
+
return path22.join(home, ".vibetime", "backfill-state.json");
|
|
9950
10444
|
}
|
|
9951
10445
|
function syncLocalTriggerStatePath(home) {
|
|
9952
|
-
return
|
|
10446
|
+
return path22.join(home, ".vibetime", "sync-local-trigger.json");
|
|
9953
10447
|
}
|
|
9954
10448
|
function syncLocalTriggerLockPath(home) {
|
|
9955
|
-
return
|
|
10449
|
+
return path22.join(home, ".vibetime", "sync-local-trigger.lock");
|
|
9956
10450
|
}
|
|
9957
10451
|
function backfillRemoteKey(baseUrl) {
|
|
9958
10452
|
try {
|
|
@@ -10014,7 +10508,7 @@ async function readBackfillIncrementalStateFile(home, ctx) {
|
|
|
10014
10508
|
}
|
|
10015
10509
|
async function writeBackfillIncrementalStateFile(home, file) {
|
|
10016
10510
|
const statePath = backfillIncrementalStatePath(home);
|
|
10017
|
-
await mkdir5(
|
|
10511
|
+
await mkdir5(path22.dirname(statePath), { recursive: true });
|
|
10018
10512
|
await writeFile4(statePath, `${JSON.stringify(file, null, 2)}
|
|
10019
10513
|
`, "utf8");
|
|
10020
10514
|
}
|
|
@@ -10063,7 +10557,7 @@ async function readSyncLocalTriggerState(statePath) {
|
|
|
10063
10557
|
return nextState;
|
|
10064
10558
|
}
|
|
10065
10559
|
async function writeSyncLocalTriggerState(statePath, state) {
|
|
10066
|
-
await mkdir5(
|
|
10560
|
+
await mkdir5(path22.dirname(statePath), { recursive: true });
|
|
10067
10561
|
await writeFile4(statePath, `${JSON.stringify(state, null, 2)}
|
|
10068
10562
|
`, "utf8");
|
|
10069
10563
|
}
|
|
@@ -10078,12 +10572,12 @@ async function readSyncLocalLock(lockPath) {
|
|
|
10078
10572
|
return { pid: lock.pid, startedAt: lock.startedAt };
|
|
10079
10573
|
}
|
|
10080
10574
|
async function writeSyncLocalLock(lockPath, lock) {
|
|
10081
|
-
await mkdir5(
|
|
10575
|
+
await mkdir5(path22.dirname(lockPath), { recursive: true });
|
|
10082
10576
|
await writeFile4(lockPath, `${JSON.stringify(lock, null, 2)}
|
|
10083
10577
|
`, "utf8");
|
|
10084
10578
|
}
|
|
10085
10579
|
async function acquireSyncLocalLock(lockPath, lock) {
|
|
10086
|
-
await mkdir5(
|
|
10580
|
+
await mkdir5(path22.dirname(lockPath), { recursive: true });
|
|
10087
10581
|
try {
|
|
10088
10582
|
const handle = await open(lockPath, "wx");
|
|
10089
10583
|
try {
|
|
@@ -10163,10 +10657,10 @@ function syncLocalRunnerEntryArgs(cliPath) {
|
|
|
10163
10657
|
if (cliPath.endsWith(".ts")) {
|
|
10164
10658
|
return ["--import", "tsx", cliPath];
|
|
10165
10659
|
}
|
|
10166
|
-
return [
|
|
10660
|
+
return [path22.resolve(path22.dirname(cliPath), "../bin/vibetime.mjs")];
|
|
10167
10661
|
}
|
|
10168
10662
|
function resolveHome3(options, ctx) {
|
|
10169
|
-
return
|
|
10663
|
+
return path22.resolve(stringOption(options.home) || ctx.env.HOME || os9.homedir());
|
|
10170
10664
|
}
|
|
10171
10665
|
function requestedTargets(options) {
|
|
10172
10666
|
const value = options.target || options.targets;
|