@yhong91/vibetime 0.1.15 → 0.1.17
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 +326 -231
- package/package.json +1 -1
package/bin/vibetime.mjs
CHANGED
|
@@ -159,9 +159,10 @@ var init_fs = __esm({
|
|
|
159
159
|
|
|
160
160
|
// src/cli.ts
|
|
161
161
|
import { spawn, spawnSync } from "node:child_process";
|
|
162
|
-
import {
|
|
163
|
-
import
|
|
164
|
-
import
|
|
162
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
163
|
+
import { mkdir as mkdir5, rename as rename2, rm, stat as stat11, writeFile as writeFile4 } from "node:fs/promises";
|
|
164
|
+
import os9 from "node:os";
|
|
165
|
+
import path20 from "node:path";
|
|
165
166
|
import { fileURLToPath } from "node:url";
|
|
166
167
|
|
|
167
168
|
// ../shared/src/index.ts
|
|
@@ -1195,7 +1196,7 @@ function countTextLines(text) {
|
|
|
1195
1196
|
}
|
|
1196
1197
|
|
|
1197
1198
|
// src/lib/constants.ts
|
|
1198
|
-
var PACKAGE_VERSION = true ? "0.1.
|
|
1199
|
+
var PACKAGE_VERSION = true ? "0.1.17" : "0.1.1";
|
|
1199
1200
|
var DEFAULT_API_URL = "http://121.196.224.82:3001";
|
|
1200
1201
|
var DEFAULT_BACKFILL_BATCH_SIZE = 50;
|
|
1201
1202
|
var DEFAULT_BACKFILL_BATCH_BYTES = 800 * 1024;
|
|
@@ -1683,25 +1684,40 @@ function resolveModelName(text) {
|
|
|
1683
1684
|
}
|
|
1684
1685
|
var AGY_USAGE_TIME_MATCH_TOLERANCE_MS = 5 * 60 * 1e3;
|
|
1685
1686
|
var AGY_RESPONSE_MODEL_ALIASES = {
|
|
1686
|
-
"gemini-3-flash-a": "Gemini 3.5 Flash
|
|
1687
|
-
"gemini-3-flash-b": "Gemini 3.5 Flash
|
|
1688
|
-
"claude-sonnet-4-6": "Claude Sonnet 4.6
|
|
1689
|
-
"claude-opus-4-6-thinking": "Claude Opus 4.6
|
|
1687
|
+
"gemini-3-flash-a": "Gemini 3.5 Flash",
|
|
1688
|
+
"gemini-3-flash-b": "Gemini 3.5 Flash",
|
|
1689
|
+
"claude-sonnet-4-6": "Claude Sonnet 4.6",
|
|
1690
|
+
"claude-opus-4-6-thinking": "Claude Opus 4.6"
|
|
1690
1691
|
};
|
|
1692
|
+
var AGY_TIER_PATTERN = /\s*\((Medium|High|Thinking)\)\s*$/i;
|
|
1691
1693
|
function usageMetadataFromGenerator(item) {
|
|
1692
1694
|
const usage = item.chatModel?.usage;
|
|
1693
1695
|
if (!usage) {
|
|
1694
1696
|
return null;
|
|
1695
1697
|
}
|
|
1696
1698
|
const chatModel = item.chatModel;
|
|
1697
|
-
const
|
|
1699
|
+
const rawDisplayName = typeof chatModel.modelDisplayName === "string" && !chatModel.modelDisplayName.startsWith("MODEL_PLACEHOLDER_") ? chatModel.modelDisplayName : null;
|
|
1698
1700
|
const responseModel = typeof chatModel.responseModel === "string" && !chatModel.responseModel.startsWith("MODEL_PLACEHOLDER_") ? AGY_RESPONSE_MODEL_ALIASES[chatModel.responseModel] ?? chatModel.responseModel : null;
|
|
1699
|
-
|
|
1701
|
+
let model = null;
|
|
1702
|
+
let reasoningEffort;
|
|
1703
|
+
if (rawDisplayName) {
|
|
1704
|
+
const tierMatch = rawDisplayName.match(AGY_TIER_PATTERN);
|
|
1705
|
+
if (tierMatch) {
|
|
1706
|
+
model = rawDisplayName.replace(AGY_TIER_PATTERN, "").trim();
|
|
1707
|
+
const tier = tierMatch[1].toLowerCase();
|
|
1708
|
+
reasoningEffort = tier === "thinking" ? "default" : tier;
|
|
1709
|
+
} else {
|
|
1710
|
+
model = rawDisplayName;
|
|
1711
|
+
}
|
|
1712
|
+
} else if (responseModel) {
|
|
1713
|
+
model = responseModel;
|
|
1714
|
+
}
|
|
1700
1715
|
const occurredAt = Date.parse(chatModel.chatStartMetadata?.createdAt ?? "");
|
|
1701
1716
|
return {
|
|
1702
1717
|
usage,
|
|
1703
1718
|
model,
|
|
1704
|
-
occurredAt: Number.isFinite(occurredAt) ? occurredAt : null
|
|
1719
|
+
occurredAt: Number.isFinite(occurredAt) ? occurredAt : null,
|
|
1720
|
+
reasoningEffort
|
|
1705
1721
|
};
|
|
1706
1722
|
}
|
|
1707
1723
|
async function readAgyModelSetting(filePath) {
|
|
@@ -1712,7 +1728,8 @@ async function readAgyModelSetting(filePath) {
|
|
|
1712
1728
|
stat2(settingsPath)
|
|
1713
1729
|
]);
|
|
1714
1730
|
const configured = JSON.parse(text)?.model;
|
|
1715
|
-
const
|
|
1731
|
+
const rawModel = typeof configured === "string" ? configured : null;
|
|
1732
|
+
const model = rawModel ? rawModel.replace(AGY_TIER_PATTERN, "").trim() : null;
|
|
1716
1733
|
return model ? { model, changedAt: info.mtimeMs } : null;
|
|
1717
1734
|
} catch {
|
|
1718
1735
|
return null;
|
|
@@ -1938,7 +1955,8 @@ async function parseAgySessionFile(filePath, options) {
|
|
|
1938
1955
|
tokensTotal: inputTokens + cacheRead + outputTokens,
|
|
1939
1956
|
tokensCachedInput: cacheRead || void 0,
|
|
1940
1957
|
tokensCacheReadInput: cacheRead || void 0,
|
|
1941
|
-
tokensReasoningOutput: reasoning || void 0
|
|
1958
|
+
tokensReasoningOutput: reasoning || void 0,
|
|
1959
|
+
reasoningEffort: usageMetadata.reasoningEffort
|
|
1942
1960
|
}
|
|
1943
1961
|
}), lineNumber, raw.type);
|
|
1944
1962
|
} else {
|
|
@@ -2101,7 +2119,8 @@ async function parseAgySessionFile(filePath, options) {
|
|
|
2101
2119
|
tokensTotal: inputTokens + cacheRead + outputTokens,
|
|
2102
2120
|
tokensCachedInput: cacheRead || void 0,
|
|
2103
2121
|
tokensCacheReadInput: cacheRead || void 0,
|
|
2104
|
-
tokensReasoningOutput: reasoning || void 0
|
|
2122
|
+
tokensReasoningOutput: reasoning || void 0,
|
|
2123
|
+
reasoningEffort: usageMetadata.reasoningEffort
|
|
2105
2124
|
}
|
|
2106
2125
|
}), rawEvents.length + index + 1, "trajectory_metadata");
|
|
2107
2126
|
}
|
|
@@ -3713,7 +3732,7 @@ async function codebuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
3713
3732
|
|
|
3714
3733
|
// src/adapters/codex.ts
|
|
3715
3734
|
import { readFile as readFile6 } from "node:fs/promises";
|
|
3716
|
-
import
|
|
3735
|
+
import path10 from "node:path";
|
|
3717
3736
|
|
|
3718
3737
|
// src/lib/diff.ts
|
|
3719
3738
|
function diffStats(diff) {
|
|
@@ -3758,6 +3777,61 @@ function fileActivitiesFromPatchChanges(changes, ts, cwd, displayFilePath3) {
|
|
|
3758
3777
|
});
|
|
3759
3778
|
}
|
|
3760
3779
|
|
|
3780
|
+
// src/lib/session-context.ts
|
|
3781
|
+
init_fs();
|
|
3782
|
+
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
3783
|
+
import os4 from "node:os";
|
|
3784
|
+
import path9 from "node:path";
|
|
3785
|
+
var SESSION_CONTEXT_VERSION = 1;
|
|
3786
|
+
function sessionContextDir(home) {
|
|
3787
|
+
return path9.join(home, ".vibetime", "session-context");
|
|
3788
|
+
}
|
|
3789
|
+
function sessionContextPath(home, sessionId) {
|
|
3790
|
+
return path9.join(sessionContextDir(home), `${encodeURIComponent(sessionId)}.json`);
|
|
3791
|
+
}
|
|
3792
|
+
function resolveHome2(options) {
|
|
3793
|
+
return options ? path9.resolve(stringOption(options.home) || os4.homedir()) : os4.homedir();
|
|
3794
|
+
}
|
|
3795
|
+
async function readPersistedSessionContext(home, sessionId) {
|
|
3796
|
+
const raw = await readJsonIfExists(sessionContextPath(home, sessionId));
|
|
3797
|
+
if (!isPlainObject(raw)) {
|
|
3798
|
+
return void 0;
|
|
3799
|
+
}
|
|
3800
|
+
if (raw.version !== SESSION_CONTEXT_VERSION || raw.sessionId !== sessionId) {
|
|
3801
|
+
return void 0;
|
|
3802
|
+
}
|
|
3803
|
+
if (typeof raw.updatedAt !== "string") {
|
|
3804
|
+
return void 0;
|
|
3805
|
+
}
|
|
3806
|
+
const cwd = typeof raw.cwd === "string" && raw.cwd.length > 0 ? raw.cwd : void 0;
|
|
3807
|
+
const project = typeof raw.project === "string" && raw.project.length > 0 ? raw.project : void 0;
|
|
3808
|
+
return { version: SESSION_CONTEXT_VERSION, sessionId, cwd, project, updatedAt: raw.updatedAt };
|
|
3809
|
+
}
|
|
3810
|
+
async function readPersistedSessionContextFromOptions(options, sessionId) {
|
|
3811
|
+
return readPersistedSessionContext(resolveHome2(options), sessionId);
|
|
3812
|
+
}
|
|
3813
|
+
async function persistHookSessionContext(home, payload) {
|
|
3814
|
+
if (!isPlainObject(payload)) {
|
|
3815
|
+
return;
|
|
3816
|
+
}
|
|
3817
|
+
const sessionId = typeof payload.session_id === "string" ? payload.session_id.trim() : typeof payload.sessionId === "string" ? payload.sessionId.trim() : "";
|
|
3818
|
+
const cwd = typeof payload.cwd === "string" ? payload.cwd.trim() : "";
|
|
3819
|
+
if (!sessionId || !cwd || !path9.isAbsolute(cwd)) {
|
|
3820
|
+
return;
|
|
3821
|
+
}
|
|
3822
|
+
const project = path9.basename(cwd) || void 0;
|
|
3823
|
+
const context = {
|
|
3824
|
+
version: SESSION_CONTEXT_VERSION,
|
|
3825
|
+
sessionId,
|
|
3826
|
+
cwd,
|
|
3827
|
+
project,
|
|
3828
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3829
|
+
};
|
|
3830
|
+
await mkdir3(sessionContextDir(home), { recursive: true });
|
|
3831
|
+
await writeFile3(sessionContextPath(home, sessionId), `${JSON.stringify(context, null, 2)}
|
|
3832
|
+
`, "utf8");
|
|
3833
|
+
}
|
|
3834
|
+
|
|
3761
3835
|
// src/adapters/codex.ts
|
|
3762
3836
|
async function parseCodexSessionFile(filePath, options) {
|
|
3763
3837
|
const text = await readFile6(filePath, "utf8");
|
|
@@ -3792,9 +3866,11 @@ async function parseCodexSessionFile(filePath, options) {
|
|
|
3792
3866
|
continue;
|
|
3793
3867
|
}
|
|
3794
3868
|
sessionMetaLocked = true;
|
|
3869
|
+
const forkedFromId = stringField(payload, "forked_from_id");
|
|
3870
|
+
const inherited = forkedFromId ? await readPersistedSessionContextFromOptions(options, forkedFromId) : void 0;
|
|
3795
3871
|
sessionId = stringField(payload, "id") || sessionId;
|
|
3796
|
-
cwd = stringField(payload, "cwd") || cwd;
|
|
3797
|
-
project = cwd ?
|
|
3872
|
+
cwd = inherited?.cwd || stringField(payload, "cwd") || cwd;
|
|
3873
|
+
project = inherited?.project || (cwd ? path10.basename(cwd) : project);
|
|
3798
3874
|
model = stringField(payload, "model_provider") || model;
|
|
3799
3875
|
events.push(withBackfillRefs({
|
|
3800
3876
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
@@ -3815,7 +3891,7 @@ async function parseCodexSessionFile(filePath, options) {
|
|
|
3815
3891
|
if (topType === "turn_context") {
|
|
3816
3892
|
currentTurnId = stringField(payload, "turn_id") || currentTurnId;
|
|
3817
3893
|
cwd = stringField(payload, "cwd") || cwd;
|
|
3818
|
-
project = cwd ?
|
|
3894
|
+
project = cwd ? path10.basename(cwd) : project;
|
|
3819
3895
|
model = stringField(payload, "model") || model;
|
|
3820
3896
|
const effort = stringField(payload, "effort") || stringField(objectField(objectField(payload, "collaboration_mode"), "settings"), "reasoning_effort");
|
|
3821
3897
|
if (effort) {
|
|
@@ -4262,11 +4338,11 @@ function functionCallArguments(payload) {
|
|
|
4262
4338
|
}
|
|
4263
4339
|
}
|
|
4264
4340
|
function displayFilePath2(filePath, cwd) {
|
|
4265
|
-
if (!cwd || !
|
|
4341
|
+
if (!cwd || !path10.isAbsolute(filePath)) {
|
|
4266
4342
|
return filePath;
|
|
4267
4343
|
}
|
|
4268
|
-
const relative =
|
|
4269
|
-
return relative && !relative.startsWith("..") && !
|
|
4344
|
+
const relative = path10.relative(cwd, filePath);
|
|
4345
|
+
return relative && !relative.startsWith("..") && !path10.isAbsolute(relative) ? relative : filePath;
|
|
4270
4346
|
}
|
|
4271
4347
|
var codexHandler = (msg) => hookHandler("codex", msg);
|
|
4272
4348
|
function hookConfig4() {
|
|
@@ -4285,9 +4361,9 @@ function hookConfig4() {
|
|
|
4285
4361
|
function codexHome(home, env) {
|
|
4286
4362
|
const override = env?.CODEX_HOME;
|
|
4287
4363
|
if (override && override.trim()) {
|
|
4288
|
-
return
|
|
4364
|
+
return path10.resolve(override);
|
|
4289
4365
|
}
|
|
4290
|
-
return
|
|
4366
|
+
return path10.join(home, ".codex");
|
|
4291
4367
|
}
|
|
4292
4368
|
function createCodexAdapter() {
|
|
4293
4369
|
return {
|
|
@@ -4299,26 +4375,26 @@ function createCodexAdapter() {
|
|
|
4299
4375
|
return codexHome(home, env);
|
|
4300
4376
|
},
|
|
4301
4377
|
installedPath(home, env) {
|
|
4302
|
-
return
|
|
4378
|
+
return path10.join(codexHome(home, env), "hooks.json");
|
|
4303
4379
|
},
|
|
4304
4380
|
async isInstalled(home, env) {
|
|
4305
4381
|
return isHooksJsonInstalled(
|
|
4306
|
-
|
|
4382
|
+
path10.join(codexHome(home, env), "hooks.json"),
|
|
4307
4383
|
"vibetime hook --agent codex"
|
|
4308
4384
|
);
|
|
4309
4385
|
},
|
|
4310
4386
|
installEntries(home, env) {
|
|
4311
4387
|
return [{
|
|
4312
4388
|
kind: "hooks-json",
|
|
4313
|
-
path:
|
|
4389
|
+
path: path10.join(codexHome(home, env), "hooks.json"),
|
|
4314
4390
|
content: hookConfig4()
|
|
4315
4391
|
}];
|
|
4316
4392
|
},
|
|
4317
4393
|
sourcePaths(home, env) {
|
|
4318
4394
|
const base = codexHome(home, env);
|
|
4319
4395
|
return [
|
|
4320
|
-
|
|
4321
|
-
|
|
4396
|
+
path10.join(base, "sessions"),
|
|
4397
|
+
path10.join(base, "history.jsonl")
|
|
4322
4398
|
];
|
|
4323
4399
|
},
|
|
4324
4400
|
parseSessionFile: parseCodexSessionFile
|
|
@@ -4327,8 +4403,8 @@ function createCodexAdapter() {
|
|
|
4327
4403
|
|
|
4328
4404
|
// src/adapters/copilot.ts
|
|
4329
4405
|
import { readdir as readdir5, readFile as readFile7, stat as stat5 } from "node:fs/promises";
|
|
4330
|
-
import
|
|
4331
|
-
import
|
|
4406
|
+
import os5 from "node:os";
|
|
4407
|
+
import path11 from "node:path";
|
|
4332
4408
|
async function parseCopilotSessionFile(filePath, options) {
|
|
4333
4409
|
const text = await readFile7(filePath, "utf8");
|
|
4334
4410
|
const lines = text.split("\n").filter(Boolean);
|
|
@@ -4364,7 +4440,7 @@ async function parseCopilotSessionFile(filePath, options) {
|
|
|
4364
4440
|
}
|
|
4365
4441
|
const context = objectField(data, "context");
|
|
4366
4442
|
cwd = stringField(context, "cwd") || stringField(context, "gitRoot") || cwd;
|
|
4367
|
-
project = stringField(context, "repository") || (cwd ?
|
|
4443
|
+
project = stringField(context, "repository") || (cwd ? path11.basename(cwd) : void 0);
|
|
4368
4444
|
sessionStartedAt = ts;
|
|
4369
4445
|
events.push(baseCopilotEvent({
|
|
4370
4446
|
ts,
|
|
@@ -4595,8 +4671,8 @@ function baseCopilotEvent(event) {
|
|
|
4595
4671
|
...event
|
|
4596
4672
|
};
|
|
4597
4673
|
}
|
|
4598
|
-
async function copilotBackfillFiles(sourceRoot, home =
|
|
4599
|
-
const sessionDir = sourceRoot ||
|
|
4674
|
+
async function copilotBackfillFiles(sourceRoot, home = os5.homedir(), _env) {
|
|
4675
|
+
const sessionDir = sourceRoot || path11.join(home, ".copilot", "session-state");
|
|
4600
4676
|
const results = [];
|
|
4601
4677
|
let entries;
|
|
4602
4678
|
try {
|
|
@@ -4608,7 +4684,7 @@ async function copilotBackfillFiles(sourceRoot, home = os4.homedir(), _env) {
|
|
|
4608
4684
|
if (entry.startsWith("pending-session")) {
|
|
4609
4685
|
continue;
|
|
4610
4686
|
}
|
|
4611
|
-
const eventsPath =
|
|
4687
|
+
const eventsPath = path11.join(sessionDir, entry, "events.jsonl");
|
|
4612
4688
|
const info = await stat5(eventsPath).catch(() => null);
|
|
4613
4689
|
if (info) {
|
|
4614
4690
|
results.push({ path: eventsPath, modifiedAt: info.mtime.toISOString() });
|
|
@@ -4626,9 +4702,9 @@ function copilotPluginContent() {
|
|
|
4626
4702
|
function copilotHome(home, env) {
|
|
4627
4703
|
const override = env?.COPILOT_HOME;
|
|
4628
4704
|
if (override && override.trim()) {
|
|
4629
|
-
return
|
|
4705
|
+
return path11.resolve(override);
|
|
4630
4706
|
}
|
|
4631
|
-
return
|
|
4707
|
+
return path11.join(home, ".copilot");
|
|
4632
4708
|
}
|
|
4633
4709
|
function createCopilotAdapter() {
|
|
4634
4710
|
return {
|
|
@@ -4640,12 +4716,12 @@ function createCopilotAdapter() {
|
|
|
4640
4716
|
return copilotHome(home, env);
|
|
4641
4717
|
},
|
|
4642
4718
|
installedPath(home, env) {
|
|
4643
|
-
return
|
|
4719
|
+
return path11.join(copilotHome(home, env), ".vibetime");
|
|
4644
4720
|
},
|
|
4645
4721
|
async isInstalled(home, env) {
|
|
4646
4722
|
try {
|
|
4647
4723
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
4648
|
-
return await pathExists2(
|
|
4724
|
+
return await pathExists2(path11.join(copilotHome(home, env), ".vibetime"));
|
|
4649
4725
|
} catch {
|
|
4650
4726
|
return false;
|
|
4651
4727
|
}
|
|
@@ -4653,20 +4729,20 @@ function createCopilotAdapter() {
|
|
|
4653
4729
|
installEntries(home, env) {
|
|
4654
4730
|
return [{
|
|
4655
4731
|
kind: "file",
|
|
4656
|
-
path:
|
|
4732
|
+
path: path11.join(copilotHome(home, env), ".vibetime"),
|
|
4657
4733
|
content: copilotPluginContent()
|
|
4658
4734
|
}];
|
|
4659
4735
|
},
|
|
4660
4736
|
sourcePaths(home, env) {
|
|
4661
|
-
return [
|
|
4737
|
+
return [path11.join(copilotHome(home, env), "session-state")];
|
|
4662
4738
|
},
|
|
4663
4739
|
parseSessionFile: parseCopilotSessionFile
|
|
4664
4740
|
};
|
|
4665
4741
|
}
|
|
4666
4742
|
|
|
4667
4743
|
// src/adapters/opencode.ts
|
|
4668
|
-
import
|
|
4669
|
-
import
|
|
4744
|
+
import os6 from "node:os";
|
|
4745
|
+
import path12 from "node:path";
|
|
4670
4746
|
async function parseOpenCodeSessionFile(dbPath, options) {
|
|
4671
4747
|
const { DatabaseSync } = await import("node:sqlite");
|
|
4672
4748
|
if (!dbPath.endsWith(".db")) {
|
|
@@ -4697,7 +4773,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
4697
4773
|
for (const session of sessions) {
|
|
4698
4774
|
const sessionId = session.id;
|
|
4699
4775
|
const cwd = session.directory || session.path || void 0;
|
|
4700
|
-
const project = cwd ?
|
|
4776
|
+
const project = cwd ? path12.basename(cwd) : void 0;
|
|
4701
4777
|
const sessionTs = msToIso(session.time_created);
|
|
4702
4778
|
events.push(baseOpenCodeEvent({
|
|
4703
4779
|
ts: sessionTs,
|
|
@@ -4805,7 +4881,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
4805
4881
|
const provider = currentProvider;
|
|
4806
4882
|
const pathObj = objectField(info, "path");
|
|
4807
4883
|
const assistantCwd = stringField(pathObj, "cwd") || cwd;
|
|
4808
|
-
const assistantProject = assistantCwd ?
|
|
4884
|
+
const assistantProject = assistantCwd ? path12.basename(assistantCwd) : project;
|
|
4809
4885
|
const completedTs = numberField(objectField(info, "time"), "completed");
|
|
4810
4886
|
const createdTs = timeCreated;
|
|
4811
4887
|
const tokens = opencodeUsageFromInfo(info);
|
|
@@ -5051,20 +5127,20 @@ function opencodeUsageFromInfo(info) {
|
|
|
5051
5127
|
function opencodeConfigDir(home, env) {
|
|
5052
5128
|
const override = env?.OPENCODE_CONFIG_DIR;
|
|
5053
5129
|
if (override && override.trim()) {
|
|
5054
|
-
return
|
|
5130
|
+
return path12.resolve(override);
|
|
5055
5131
|
}
|
|
5056
5132
|
const xdgConfig = env?.XDG_CONFIG_HOME;
|
|
5057
5133
|
if (xdgConfig && xdgConfig.trim()) {
|
|
5058
|
-
return
|
|
5134
|
+
return path12.join(path12.resolve(xdgConfig), "opencode");
|
|
5059
5135
|
}
|
|
5060
|
-
return
|
|
5136
|
+
return path12.join(home, ".config", "opencode");
|
|
5061
5137
|
}
|
|
5062
5138
|
function opencodeDataCandidates(home, env) {
|
|
5063
5139
|
const xdgData = env?.XDG_DATA_HOME;
|
|
5064
|
-
const primary = xdgData && xdgData.trim() ?
|
|
5065
|
-
return [primary,
|
|
5140
|
+
const primary = xdgData && xdgData.trim() ? path12.join(path12.resolve(xdgData), "opencode", "opencode.db") : path12.join(home, ".local", "share", "opencode", "opencode.db");
|
|
5141
|
+
return [primary, path12.join(home, ".opencode", "opencode.db")];
|
|
5066
5142
|
}
|
|
5067
|
-
async function opencodeBackfillFiles(sourceRoot, home =
|
|
5143
|
+
async function opencodeBackfillFiles(sourceRoot, home = os6.homedir(), env) {
|
|
5068
5144
|
const { stat: stat12 } = await import("node:fs/promises");
|
|
5069
5145
|
if (sourceRoot) {
|
|
5070
5146
|
if (!sourceRoot.endsWith(".db")) {
|
|
@@ -5090,8 +5166,9 @@ function opencodePluginContent() {
|
|
|
5090
5166
|
|
|
5091
5167
|
export const AgentTime = async ({ $, directory }) => {
|
|
5092
5168
|
const report = async (payload) => {
|
|
5169
|
+
const json = JSON.stringify(payload)
|
|
5093
5170
|
try {
|
|
5094
|
-
await $\`vibetime hook --agent opencode
|
|
5171
|
+
await $\`echo \${json} | vibetime hook --agent opencode\`
|
|
5095
5172
|
} catch {}
|
|
5096
5173
|
}
|
|
5097
5174
|
|
|
@@ -5100,11 +5177,12 @@ export const AgentTime = async ({ $, directory }) => {
|
|
|
5100
5177
|
const type = event?.type
|
|
5101
5178
|
const props = event?.properties || {}
|
|
5102
5179
|
|
|
5103
|
-
if (type === "session.
|
|
5180
|
+
if (type === "session.updated") {
|
|
5181
|
+
const info = props.info || {}
|
|
5104
5182
|
await report({
|
|
5105
5183
|
hook_event_name: "SessionStart",
|
|
5106
|
-
session_id:
|
|
5107
|
-
cwd: directory
|
|
5184
|
+
session_id: props.sessionID || info.id || event?.id,
|
|
5185
|
+
cwd: info.directory || directory
|
|
5108
5186
|
})
|
|
5109
5187
|
return
|
|
5110
5188
|
}
|
|
@@ -5112,25 +5190,24 @@ export const AgentTime = async ({ $, directory }) => {
|
|
|
5112
5190
|
if (type === "session.idle") {
|
|
5113
5191
|
await report({
|
|
5114
5192
|
hook_event_name: "SessionEnd",
|
|
5115
|
-
session_id:
|
|
5193
|
+
session_id: props.sessionID || event?.id,
|
|
5116
5194
|
cwd: directory
|
|
5117
5195
|
})
|
|
5118
5196
|
return
|
|
5119
5197
|
}
|
|
5120
5198
|
|
|
5121
|
-
if (type === "
|
|
5122
|
-
const
|
|
5123
|
-
|
|
5124
|
-
const
|
|
5125
|
-
|
|
5126
|
-
const filePath = toolInput?.file_path || toolInput?.filePath
|
|
5199
|
+
if (type === "message.part.updated") {
|
|
5200
|
+
const part = props.part || {}
|
|
5201
|
+
if (part.type !== "tool") return
|
|
5202
|
+
const state = part.state || {}
|
|
5203
|
+
if (state.status !== "completed") return
|
|
5127
5204
|
|
|
5128
5205
|
await report({
|
|
5129
5206
|
hook_event_name: "PostToolUse",
|
|
5130
|
-
tool_name:
|
|
5131
|
-
tool_use_id:
|
|
5207
|
+
tool_name: part.tool || "unknown",
|
|
5208
|
+
tool_use_id: part.callID || part.id,
|
|
5132
5209
|
cwd: directory,
|
|
5133
|
-
tool_input: {
|
|
5210
|
+
tool_input: {}
|
|
5134
5211
|
})
|
|
5135
5212
|
}
|
|
5136
5213
|
}
|
|
@@ -5151,12 +5228,12 @@ function createOpenCodeAdapter() {
|
|
|
5151
5228
|
return opencodeConfigDir(home, env);
|
|
5152
5229
|
},
|
|
5153
5230
|
installedPath(home, env) {
|
|
5154
|
-
return
|
|
5231
|
+
return path12.join(opencodeConfigDir(home, env), PLUGIN_PATH);
|
|
5155
5232
|
},
|
|
5156
5233
|
async isInstalled(home, env) {
|
|
5157
5234
|
try {
|
|
5158
5235
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
5159
|
-
return await pathExists2(
|
|
5236
|
+
return await pathExists2(path12.join(opencodeConfigDir(home, env), PLUGIN_PATH)) || await pathExists2(path12.join(".opencode", PLUGIN_PATH));
|
|
5160
5237
|
} catch {
|
|
5161
5238
|
return false;
|
|
5162
5239
|
}
|
|
@@ -5164,7 +5241,7 @@ function createOpenCodeAdapter() {
|
|
|
5164
5241
|
installEntries(home, env) {
|
|
5165
5242
|
return [{
|
|
5166
5243
|
kind: "file",
|
|
5167
|
-
path:
|
|
5244
|
+
path: path12.join(opencodeConfigDir(home, env), PLUGIN_PATH),
|
|
5168
5245
|
content: opencodePluginContent()
|
|
5169
5246
|
}];
|
|
5170
5247
|
},
|
|
@@ -5177,7 +5254,7 @@ function createOpenCodeAdapter() {
|
|
|
5177
5254
|
|
|
5178
5255
|
// src/adapters/pi.ts
|
|
5179
5256
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
5180
|
-
import
|
|
5257
|
+
import path13 from "node:path";
|
|
5181
5258
|
async function parsePiSessionFile(filePath, options) {
|
|
5182
5259
|
const text = await readFile8(filePath, "utf8");
|
|
5183
5260
|
const lines = text.split("\n").filter(Boolean);
|
|
@@ -5210,7 +5287,7 @@ async function parsePiSessionFile(filePath, options) {
|
|
|
5210
5287
|
sessionId = stringField(raw, "id") || state.sessionId;
|
|
5211
5288
|
state.sessionId = sessionId || state.sessionId;
|
|
5212
5289
|
cwd = stringField(raw, "cwd") || cwd;
|
|
5213
|
-
project = cwd ?
|
|
5290
|
+
project = cwd ? path13.basename(cwd) : project;
|
|
5214
5291
|
continue;
|
|
5215
5292
|
}
|
|
5216
5293
|
if (entryType === "model_change") {
|
|
@@ -5619,16 +5696,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
5619
5696
|
function piAgentDir(home, env) {
|
|
5620
5697
|
const override = env?.PI_CODING_AGENT_DIR;
|
|
5621
5698
|
if (override && override.trim()) {
|
|
5622
|
-
return
|
|
5699
|
+
return path13.resolve(override);
|
|
5623
5700
|
}
|
|
5624
|
-
return
|
|
5701
|
+
return path13.join(home, ".pi", "agent");
|
|
5625
5702
|
}
|
|
5626
5703
|
function piSessionDir(home, env) {
|
|
5627
5704
|
const override = env?.PI_CODING_AGENT_SESSION_DIR;
|
|
5628
5705
|
if (override && override.trim()) {
|
|
5629
|
-
return
|
|
5706
|
+
return path13.resolve(override);
|
|
5630
5707
|
}
|
|
5631
|
-
return
|
|
5708
|
+
return path13.join(piAgentDir(home, env), "sessions");
|
|
5632
5709
|
}
|
|
5633
5710
|
function createPiAdapter() {
|
|
5634
5711
|
return {
|
|
@@ -5640,12 +5717,12 @@ function createPiAdapter() {
|
|
|
5640
5717
|
return piAgentDir(home, env);
|
|
5641
5718
|
},
|
|
5642
5719
|
installedPath(home, env) {
|
|
5643
|
-
return
|
|
5720
|
+
return path13.join(piAgentDir(home, env), "extensions", "vibetime.ts");
|
|
5644
5721
|
},
|
|
5645
5722
|
async isInstalled(home, env) {
|
|
5646
5723
|
try {
|
|
5647
5724
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
5648
|
-
return await pathExists2(
|
|
5725
|
+
return await pathExists2(path13.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
|
|
5649
5726
|
} catch {
|
|
5650
5727
|
return false;
|
|
5651
5728
|
}
|
|
@@ -5653,7 +5730,7 @@ function createPiAdapter() {
|
|
|
5653
5730
|
installEntries(home, env) {
|
|
5654
5731
|
return [{
|
|
5655
5732
|
kind: "file",
|
|
5656
|
-
path:
|
|
5733
|
+
path: path13.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
|
|
5657
5734
|
content: piExtensionContent()
|
|
5658
5735
|
}];
|
|
5659
5736
|
},
|
|
@@ -5666,10 +5743,10 @@ function createPiAdapter() {
|
|
|
5666
5743
|
|
|
5667
5744
|
// src/adapters/qoder-cn.ts
|
|
5668
5745
|
import { readdir as readdir6, readFile as readFile9, stat as stat6 } from "node:fs/promises";
|
|
5669
|
-
import
|
|
5670
|
-
import
|
|
5746
|
+
import os7 from "node:os";
|
|
5747
|
+
import path14 from "node:path";
|
|
5671
5748
|
function parseQoderCnPaths(filePath) {
|
|
5672
|
-
const parts = filePath.split(
|
|
5749
|
+
const parts = filePath.split(path14.sep);
|
|
5673
5750
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
5674
5751
|
let sessionId = "";
|
|
5675
5752
|
let projectName = "";
|
|
@@ -5678,19 +5755,19 @@ function parseQoderCnPaths(filePath) {
|
|
|
5678
5755
|
sessionId = parts[subagentsIdx - 1];
|
|
5679
5756
|
projectName = parts[subagentsIdx - 2];
|
|
5680
5757
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
5681
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
5758
|
+
configDir2 = parts.slice(0, projectsIdx).join(path14.sep);
|
|
5682
5759
|
} else {
|
|
5683
5760
|
const filename = parts.at(-1) || "";
|
|
5684
|
-
sessionId =
|
|
5761
|
+
sessionId = path14.basename(filename, ".jsonl");
|
|
5685
5762
|
projectName = parts.at(-2) || "";
|
|
5686
5763
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
5687
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
5764
|
+
configDir2 = parts.slice(0, projectsIdx).join(path14.sep);
|
|
5688
5765
|
}
|
|
5689
5766
|
return { configDir: configDir2, projectName, sessionId };
|
|
5690
5767
|
}
|
|
5691
5768
|
async function loadQoderCnModelNames(configDir2) {
|
|
5692
5769
|
try {
|
|
5693
|
-
const dynamicTextsPath =
|
|
5770
|
+
const dynamicTextsPath = path14.join(configDir2, ".auth", "dynamic-texts.json");
|
|
5694
5771
|
const content = await readFile9(dynamicTextsPath, "utf8");
|
|
5695
5772
|
const json = JSON.parse(content);
|
|
5696
5773
|
const texts = json.texts || {};
|
|
@@ -5708,7 +5785,7 @@ async function loadQoderCnModelNames(configDir2) {
|
|
|
5708
5785
|
}
|
|
5709
5786
|
async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
5710
5787
|
const { configDir: configDir2, projectName, sessionId } = parseQoderCnPaths(filePath);
|
|
5711
|
-
const segmentsPath =
|
|
5788
|
+
const segmentsPath = path14.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
5712
5789
|
const modelCalls = [];
|
|
5713
5790
|
try {
|
|
5714
5791
|
const files = await readdir6(segmentsPath);
|
|
@@ -5716,7 +5793,7 @@ async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMa
|
|
|
5716
5793
|
if (!file.endsWith(".jsonl")) {
|
|
5717
5794
|
continue;
|
|
5718
5795
|
}
|
|
5719
|
-
const content = await readFile9(
|
|
5796
|
+
const content = await readFile9(path14.join(segmentsPath, file), "utf8");
|
|
5720
5797
|
let currentTurnIsSubagent = false;
|
|
5721
5798
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
5722
5799
|
const raw = parseJsonLine(line);
|
|
@@ -5784,7 +5861,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
5784
5861
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
5785
5862
|
state.sessionId = sessionId;
|
|
5786
5863
|
cwd = stringField(raw, "cwd") || cwd;
|
|
5787
|
-
project = projectContext.project || (cwd ?
|
|
5864
|
+
project = projectContext.project || (cwd ? path14.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
|
|
5788
5865
|
if (!ts) {
|
|
5789
5866
|
continue;
|
|
5790
5867
|
}
|
|
@@ -6213,35 +6290,40 @@ function isNoisePrompt(text) {
|
|
|
6213
6290
|
}
|
|
6214
6291
|
async function qoderCnProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
6215
6292
|
const { projectName: projectDir, sessionId } = parseQoderCnPaths(filePath);
|
|
6216
|
-
const isSubagent = filePath.includes(`${
|
|
6293
|
+
const isSubagent = filePath.includes(`${path14.sep}subagents${path14.sep}`);
|
|
6294
|
+
const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
|
|
6217
6295
|
let cwds = [];
|
|
6218
6296
|
for (const line of lines) {
|
|
6219
6297
|
const raw = parseJsonLine(line);
|
|
6220
6298
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
6221
|
-
if (cwd &&
|
|
6299
|
+
if (cwd && path14.isAbsolute(cwd)) {
|
|
6222
6300
|
cwds.push(cwd);
|
|
6223
6301
|
}
|
|
6224
6302
|
}
|
|
6225
6303
|
if (isSubagent) {
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
const
|
|
6230
|
-
|
|
6231
|
-
const
|
|
6232
|
-
const
|
|
6233
|
-
|
|
6234
|
-
|
|
6304
|
+
if (inherited?.cwd && path14.isAbsolute(inherited.cwd)) {
|
|
6305
|
+
cwds = [inherited.cwd];
|
|
6306
|
+
} else {
|
|
6307
|
+
const parentSessionPath = path14.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
6308
|
+
try {
|
|
6309
|
+
const parentText = await readFile9(parentSessionPath, "utf8");
|
|
6310
|
+
const parentCwds = [];
|
|
6311
|
+
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
6312
|
+
const raw = parseJsonLine(line);
|
|
6313
|
+
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
6314
|
+
if (cwd && path14.isAbsolute(cwd)) {
|
|
6315
|
+
parentCwds.push(cwd);
|
|
6316
|
+
}
|
|
6235
6317
|
}
|
|
6318
|
+
if (parentCwds.length > 0) {
|
|
6319
|
+
cwds = parentCwds;
|
|
6320
|
+
}
|
|
6321
|
+
} catch {
|
|
6236
6322
|
}
|
|
6237
|
-
if (parentCwds.length > 0) {
|
|
6238
|
-
cwds = parentCwds;
|
|
6239
|
-
}
|
|
6240
|
-
} catch {
|
|
6241
6323
|
}
|
|
6242
6324
|
}
|
|
6243
6325
|
const root = await gitRootFromCwds2(cwds) || qoderCnProjectRootFromCwds(projectDir, cwds);
|
|
6244
|
-
const project = cwds.length > 0 ?
|
|
6326
|
+
const project = inherited?.project || (cwds.length > 0 ? path14.basename(cwds[0]) : root ? path14.basename(root) : await qoderCnProjectFromFilePath(filePath, options));
|
|
6245
6327
|
return {
|
|
6246
6328
|
project,
|
|
6247
6329
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -6250,15 +6332,15 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
6250
6332
|
async function gitRootFromCwds2(cwds) {
|
|
6251
6333
|
const seen = /* @__PURE__ */ new Set();
|
|
6252
6334
|
for (const cwd of cwds) {
|
|
6253
|
-
let current =
|
|
6335
|
+
let current = path14.resolve(cwd);
|
|
6254
6336
|
while (!seen.has(current)) {
|
|
6255
6337
|
seen.add(current);
|
|
6256
6338
|
try {
|
|
6257
|
-
await stat6(
|
|
6339
|
+
await stat6(path14.join(current, ".git"));
|
|
6258
6340
|
return current;
|
|
6259
6341
|
} catch {
|
|
6260
6342
|
}
|
|
6261
|
-
const parent =
|
|
6343
|
+
const parent = path14.dirname(current);
|
|
6262
6344
|
if (parent === current) {
|
|
6263
6345
|
break;
|
|
6264
6346
|
}
|
|
@@ -6269,12 +6351,12 @@ async function gitRootFromCwds2(cwds) {
|
|
|
6269
6351
|
}
|
|
6270
6352
|
function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
6271
6353
|
for (const cwd of cwds) {
|
|
6272
|
-
let current =
|
|
6354
|
+
let current = path14.resolve(cwd);
|
|
6273
6355
|
while (true) {
|
|
6274
6356
|
if (encodeQoderCnProjectPath(current) === projectDir) {
|
|
6275
6357
|
return current;
|
|
6276
6358
|
}
|
|
6277
|
-
const parent =
|
|
6359
|
+
const parent = path14.dirname(current);
|
|
6278
6360
|
if (parent === current) {
|
|
6279
6361
|
break;
|
|
6280
6362
|
}
|
|
@@ -6284,14 +6366,14 @@ function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
|
6284
6366
|
return void 0;
|
|
6285
6367
|
}
|
|
6286
6368
|
function encodeQoderCnProjectPath(value) {
|
|
6287
|
-
return
|
|
6369
|
+
return path14.resolve(value).split(path14.sep).join("-").replace(/_/g, "-");
|
|
6288
6370
|
}
|
|
6289
6371
|
async function qoderCnProjectFromFilePath(filePath, options) {
|
|
6290
|
-
const projectDir =
|
|
6291
|
-
const home = options ?
|
|
6372
|
+
const projectDir = path14.basename(path14.dirname(filePath));
|
|
6373
|
+
const home = options ? path14.resolve(stringOption(options.home) || os7.homedir()) : os7.homedir();
|
|
6292
6374
|
const resolved = await resolveQoderCnProjectPath(projectDir, home);
|
|
6293
6375
|
if (resolved) {
|
|
6294
|
-
return
|
|
6376
|
+
return path14.basename(resolved);
|
|
6295
6377
|
}
|
|
6296
6378
|
const homePrefix = `${encodeQoderCnProjectPath(home)}-`;
|
|
6297
6379
|
if (projectDir.startsWith(homePrefix)) {
|
|
@@ -6316,7 +6398,7 @@ async function resolveQoderCnProjectPath(projectDir, home) {
|
|
|
6316
6398
|
if (!entry.isDirectory()) {
|
|
6317
6399
|
continue;
|
|
6318
6400
|
}
|
|
6319
|
-
const candidate =
|
|
6401
|
+
const candidate = path14.join(current, entry.name);
|
|
6320
6402
|
const encoded = encodeQoderCnProjectPath(candidate);
|
|
6321
6403
|
if (encoded === projectDir) {
|
|
6322
6404
|
return candidate;
|
|
@@ -6361,9 +6443,9 @@ function hookConfig5() {
|
|
|
6361
6443
|
function qoderCnConfigDir(home, env) {
|
|
6362
6444
|
const override = env?.QODER_CN_CONFIG_DIR;
|
|
6363
6445
|
if (override && override.trim()) {
|
|
6364
|
-
return
|
|
6446
|
+
return path14.resolve(override);
|
|
6365
6447
|
}
|
|
6366
|
-
return
|
|
6448
|
+
return path14.join(home, ".qoder-cn");
|
|
6367
6449
|
}
|
|
6368
6450
|
function createQoderCnAdapter() {
|
|
6369
6451
|
return {
|
|
@@ -6375,27 +6457,27 @@ function createQoderCnAdapter() {
|
|
|
6375
6457
|
return qoderCnConfigDir(home, env);
|
|
6376
6458
|
},
|
|
6377
6459
|
installedPath(home, env) {
|
|
6378
|
-
return
|
|
6460
|
+
return path14.join(qoderCnConfigDir(home, env), "settings.json");
|
|
6379
6461
|
},
|
|
6380
6462
|
async isInstalled(home, env) {
|
|
6381
6463
|
return isHooksJsonInstalled(
|
|
6382
|
-
|
|
6464
|
+
path14.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
6383
6465
|
"vibetime hook --agent qoder-cn"
|
|
6384
6466
|
);
|
|
6385
6467
|
},
|
|
6386
6468
|
installEntries(home, env) {
|
|
6387
6469
|
return [{
|
|
6388
6470
|
kind: "hooks-json",
|
|
6389
|
-
path:
|
|
6471
|
+
path: path14.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
6390
6472
|
content: hookConfig5()
|
|
6391
6473
|
}];
|
|
6392
6474
|
},
|
|
6393
6475
|
sourcePaths(home, env) {
|
|
6394
6476
|
const base = qoderCnConfigDir(home, env);
|
|
6395
6477
|
return [
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
6478
|
+
path14.join(base, "projects"),
|
|
6479
|
+
path14.join(base, ".qoder.json"),
|
|
6480
|
+
path14.join(home, ".qoder.json")
|
|
6399
6481
|
];
|
|
6400
6482
|
},
|
|
6401
6483
|
parseSessionFile: parseQoderCnSessionFile
|
|
@@ -6404,10 +6486,10 @@ function createQoderCnAdapter() {
|
|
|
6404
6486
|
|
|
6405
6487
|
// src/adapters/qoder.ts
|
|
6406
6488
|
import { readdir as readdir7, readFile as readFile10, stat as stat7 } from "node:fs/promises";
|
|
6407
|
-
import
|
|
6408
|
-
import
|
|
6489
|
+
import os8 from "node:os";
|
|
6490
|
+
import path15 from "node:path";
|
|
6409
6491
|
function parseQoderPaths(filePath) {
|
|
6410
|
-
const parts = filePath.split(
|
|
6492
|
+
const parts = filePath.split(path15.sep);
|
|
6411
6493
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
6412
6494
|
let sessionId = "";
|
|
6413
6495
|
let projectName = "";
|
|
@@ -6416,19 +6498,19 @@ function parseQoderPaths(filePath) {
|
|
|
6416
6498
|
sessionId = parts[subagentsIdx - 1];
|
|
6417
6499
|
projectName = parts[subagentsIdx - 2];
|
|
6418
6500
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
6419
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
6501
|
+
configDir2 = parts.slice(0, projectsIdx).join(path15.sep);
|
|
6420
6502
|
} else {
|
|
6421
6503
|
const filename = parts.at(-1) || "";
|
|
6422
|
-
sessionId =
|
|
6504
|
+
sessionId = path15.basename(filename, ".jsonl");
|
|
6423
6505
|
projectName = parts.at(-2) || "";
|
|
6424
6506
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
6425
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
6507
|
+
configDir2 = parts.slice(0, projectsIdx).join(path15.sep);
|
|
6426
6508
|
}
|
|
6427
6509
|
return { configDir: configDir2, projectName, sessionId };
|
|
6428
6510
|
}
|
|
6429
6511
|
async function loadQoderModelNames(configDir2) {
|
|
6430
6512
|
try {
|
|
6431
|
-
const dynamicTextsPath =
|
|
6513
|
+
const dynamicTextsPath = path15.join(configDir2, ".auth", "dynamic-texts.json");
|
|
6432
6514
|
const content = await readFile10(dynamicTextsPath, "utf8");
|
|
6433
6515
|
const json = JSON.parse(content);
|
|
6434
6516
|
const texts = json.texts || {};
|
|
@@ -6446,7 +6528,7 @@ async function loadQoderModelNames(configDir2) {
|
|
|
6446
6528
|
}
|
|
6447
6529
|
async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
6448
6530
|
const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
|
|
6449
|
-
const segmentsPath =
|
|
6531
|
+
const segmentsPath = path15.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
6450
6532
|
const modelCalls = [];
|
|
6451
6533
|
try {
|
|
6452
6534
|
const files = await readdir7(segmentsPath);
|
|
@@ -6454,7 +6536,7 @@ async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap)
|
|
|
6454
6536
|
if (!file.endsWith(".jsonl")) {
|
|
6455
6537
|
continue;
|
|
6456
6538
|
}
|
|
6457
|
-
const content = await readFile10(
|
|
6539
|
+
const content = await readFile10(path15.join(segmentsPath, file), "utf8");
|
|
6458
6540
|
let currentTurnIsSubagent = false;
|
|
6459
6541
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
6460
6542
|
const raw = parseJsonLine(line);
|
|
@@ -6522,7 +6604,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
6522
6604
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
6523
6605
|
state.sessionId = sessionId;
|
|
6524
6606
|
cwd = stringField(raw, "cwd") || cwd;
|
|
6525
|
-
project = projectContext.project || (cwd ?
|
|
6607
|
+
project = projectContext.project || (cwd ? path15.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
|
|
6526
6608
|
if (!ts) {
|
|
6527
6609
|
continue;
|
|
6528
6610
|
}
|
|
@@ -6917,35 +6999,40 @@ function qoderExtractText(value) {
|
|
|
6917
6999
|
}
|
|
6918
7000
|
async function qoderProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
6919
7001
|
const { projectName: projectDir, sessionId } = parseQoderPaths(filePath);
|
|
6920
|
-
const isSubagent = filePath.includes(`${
|
|
7002
|
+
const isSubagent = filePath.includes(`${path15.sep}subagents${path15.sep}`);
|
|
7003
|
+
const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
|
|
6921
7004
|
let cwds = [];
|
|
6922
7005
|
for (const line of lines) {
|
|
6923
7006
|
const raw = parseJsonLine(line);
|
|
6924
7007
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
6925
|
-
if (cwd &&
|
|
7008
|
+
if (cwd && path15.isAbsolute(cwd)) {
|
|
6926
7009
|
cwds.push(cwd);
|
|
6927
7010
|
}
|
|
6928
7011
|
}
|
|
6929
7012
|
if (isSubagent) {
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
const
|
|
6934
|
-
|
|
6935
|
-
const
|
|
6936
|
-
const
|
|
6937
|
-
|
|
6938
|
-
|
|
7013
|
+
if (inherited?.cwd && path15.isAbsolute(inherited.cwd)) {
|
|
7014
|
+
cwds = [inherited.cwd];
|
|
7015
|
+
} else {
|
|
7016
|
+
const parentSessionPath = path15.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
7017
|
+
try {
|
|
7018
|
+
const parentText = await readFile10(parentSessionPath, "utf8");
|
|
7019
|
+
const parentCwds = [];
|
|
7020
|
+
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
7021
|
+
const raw = parseJsonLine(line);
|
|
7022
|
+
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
7023
|
+
if (cwd && path15.isAbsolute(cwd)) {
|
|
7024
|
+
parentCwds.push(cwd);
|
|
7025
|
+
}
|
|
6939
7026
|
}
|
|
7027
|
+
if (parentCwds.length > 0) {
|
|
7028
|
+
cwds = parentCwds;
|
|
7029
|
+
}
|
|
7030
|
+
} catch {
|
|
6940
7031
|
}
|
|
6941
|
-
if (parentCwds.length > 0) {
|
|
6942
|
-
cwds = parentCwds;
|
|
6943
|
-
}
|
|
6944
|
-
} catch {
|
|
6945
7032
|
}
|
|
6946
7033
|
}
|
|
6947
7034
|
const root = await gitRootFromCwds3(cwds) || qoderProjectRootFromCwds(projectDir, cwds);
|
|
6948
|
-
const project = cwds.length > 0 ?
|
|
7035
|
+
const project = inherited?.project || (cwds.length > 0 ? path15.basename(cwds[0]) : root ? path15.basename(root) : await qoderProjectFromFilePath(filePath, options));
|
|
6949
7036
|
return {
|
|
6950
7037
|
project,
|
|
6951
7038
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -6954,15 +7041,15 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
|
|
|
6954
7041
|
async function gitRootFromCwds3(cwds) {
|
|
6955
7042
|
const seen = /* @__PURE__ */ new Set();
|
|
6956
7043
|
for (const cwd of cwds) {
|
|
6957
|
-
let current =
|
|
7044
|
+
let current = path15.resolve(cwd);
|
|
6958
7045
|
while (!seen.has(current)) {
|
|
6959
7046
|
seen.add(current);
|
|
6960
7047
|
try {
|
|
6961
|
-
await stat7(
|
|
7048
|
+
await stat7(path15.join(current, ".git"));
|
|
6962
7049
|
return current;
|
|
6963
7050
|
} catch {
|
|
6964
7051
|
}
|
|
6965
|
-
const parent =
|
|
7052
|
+
const parent = path15.dirname(current);
|
|
6966
7053
|
if (parent === current) {
|
|
6967
7054
|
break;
|
|
6968
7055
|
}
|
|
@@ -6973,12 +7060,12 @@ async function gitRootFromCwds3(cwds) {
|
|
|
6973
7060
|
}
|
|
6974
7061
|
function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
6975
7062
|
for (const cwd of cwds) {
|
|
6976
|
-
let current =
|
|
7063
|
+
let current = path15.resolve(cwd);
|
|
6977
7064
|
while (true) {
|
|
6978
7065
|
if (encodeQoderProjectPath(current) === projectDir) {
|
|
6979
7066
|
return current;
|
|
6980
7067
|
}
|
|
6981
|
-
const parent =
|
|
7068
|
+
const parent = path15.dirname(current);
|
|
6982
7069
|
if (parent === current) {
|
|
6983
7070
|
break;
|
|
6984
7071
|
}
|
|
@@ -6988,10 +7075,10 @@ function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
|
6988
7075
|
return void 0;
|
|
6989
7076
|
}
|
|
6990
7077
|
function encodeQoderProjectPath(value) {
|
|
6991
|
-
return
|
|
7078
|
+
return path15.resolve(value).split(path15.sep).join("-").replace(/_/g, "-");
|
|
6992
7079
|
}
|
|
6993
7080
|
function rawQoderProjectPath(value) {
|
|
6994
|
-
return
|
|
7081
|
+
return path15.resolve(value).split(path15.sep).join("-");
|
|
6995
7082
|
}
|
|
6996
7083
|
function qoderEncodedVariants(value) {
|
|
6997
7084
|
const raw = rawQoderProjectPath(value);
|
|
@@ -7007,11 +7094,11 @@ function qoderEncodedProjectSuffix(projectDir, home) {
|
|
|
7007
7094
|
return void 0;
|
|
7008
7095
|
}
|
|
7009
7096
|
async function qoderProjectFromFilePath(filePath, options) {
|
|
7010
|
-
const projectDir =
|
|
7011
|
-
const home = options ?
|
|
7097
|
+
const projectDir = path15.basename(path15.dirname(filePath));
|
|
7098
|
+
const home = options ? path15.resolve(stringOption(options.home) || os8.homedir()) : os8.homedir();
|
|
7012
7099
|
const resolved = await resolveQoderProjectPath(projectDir, home);
|
|
7013
7100
|
if (resolved) {
|
|
7014
|
-
return
|
|
7101
|
+
return path15.basename(resolved);
|
|
7015
7102
|
}
|
|
7016
7103
|
const suffix = qoderEncodedProjectSuffix(projectDir, home);
|
|
7017
7104
|
if (suffix) {
|
|
@@ -7037,7 +7124,7 @@ async function resolveQoderProjectPath(projectDir, home) {
|
|
|
7037
7124
|
if (!entry.isDirectory()) {
|
|
7038
7125
|
continue;
|
|
7039
7126
|
}
|
|
7040
|
-
const candidate =
|
|
7127
|
+
const candidate = path15.join(current, entry.name);
|
|
7041
7128
|
const candidateVariants = qoderEncodedVariants(candidate);
|
|
7042
7129
|
if (candidateVariants.includes(projectDir)) {
|
|
7043
7130
|
return candidate;
|
|
@@ -7082,9 +7169,9 @@ function hookConfig6() {
|
|
|
7082
7169
|
function qoderConfigDir(home, env) {
|
|
7083
7170
|
const override = env?.QODER_CONFIG_DIR;
|
|
7084
7171
|
if (override && override.trim()) {
|
|
7085
|
-
return
|
|
7172
|
+
return path15.resolve(override);
|
|
7086
7173
|
}
|
|
7087
|
-
return
|
|
7174
|
+
return path15.join(home, ".qoder");
|
|
7088
7175
|
}
|
|
7089
7176
|
function createQoderAdapter() {
|
|
7090
7177
|
return {
|
|
@@ -7096,27 +7183,27 @@ function createQoderAdapter() {
|
|
|
7096
7183
|
return qoderConfigDir(home, env);
|
|
7097
7184
|
},
|
|
7098
7185
|
installedPath(home, env) {
|
|
7099
|
-
return
|
|
7186
|
+
return path15.join(qoderConfigDir(home, env), "settings.json");
|
|
7100
7187
|
},
|
|
7101
7188
|
async isInstalled(home, env) {
|
|
7102
7189
|
return isHooksJsonInstalled(
|
|
7103
|
-
|
|
7190
|
+
path15.join(qoderConfigDir(home, env), "settings.json"),
|
|
7104
7191
|
"vibetime hook --agent qoder"
|
|
7105
7192
|
);
|
|
7106
7193
|
},
|
|
7107
7194
|
installEntries(home, env) {
|
|
7108
7195
|
return [{
|
|
7109
7196
|
kind: "hooks-json",
|
|
7110
|
-
path:
|
|
7197
|
+
path: path15.join(qoderConfigDir(home, env), "settings.json"),
|
|
7111
7198
|
content: hookConfig6()
|
|
7112
7199
|
}];
|
|
7113
7200
|
},
|
|
7114
7201
|
sourcePaths(home, env) {
|
|
7115
7202
|
const base = qoderConfigDir(home, env);
|
|
7116
7203
|
return [
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7204
|
+
path15.join(base, "projects"),
|
|
7205
|
+
path15.join(base, ".qoder.json"),
|
|
7206
|
+
path15.join(home, ".qoder.json")
|
|
7120
7207
|
];
|
|
7121
7208
|
},
|
|
7122
7209
|
parseSessionFile: parseQoderSessionFile
|
|
@@ -7152,20 +7239,20 @@ function normalizeId(id) {
|
|
|
7152
7239
|
|
|
7153
7240
|
// src/adapters/workbuddy.ts
|
|
7154
7241
|
import { readFile as readFile11, readdir as readdir8, stat as stat8 } from "node:fs/promises";
|
|
7155
|
-
import
|
|
7242
|
+
import path16 from "node:path";
|
|
7156
7243
|
init_fs();
|
|
7157
7244
|
function workbuddyProjectsDir(home, env) {
|
|
7158
7245
|
const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
|
|
7159
7246
|
if (override && override.trim()) {
|
|
7160
|
-
return
|
|
7247
|
+
return path16.resolve(override, override.endsWith("projects") ? "" : "projects");
|
|
7161
7248
|
}
|
|
7162
|
-
return
|
|
7249
|
+
return path16.join(home, ".workbuddy", "projects");
|
|
7163
7250
|
}
|
|
7164
7251
|
function projectFromCwd(cwd, fallback) {
|
|
7165
7252
|
if (!cwd) {
|
|
7166
7253
|
return fallback;
|
|
7167
7254
|
}
|
|
7168
|
-
return
|
|
7255
|
+
return path16.basename(cwd) || fallback;
|
|
7169
7256
|
}
|
|
7170
7257
|
function sourceHash(filePath) {
|
|
7171
7258
|
return `sha256:${createStableHash(filePath)}`;
|
|
@@ -7267,8 +7354,8 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
7267
7354
|
}
|
|
7268
7355
|
const events = [];
|
|
7269
7356
|
const first = lines[0].record;
|
|
7270
|
-
const sessionId = stringField(first, "sessionId") ||
|
|
7271
|
-
const fallbackProject =
|
|
7357
|
+
const sessionId = stringField(first, "sessionId") || path16.basename(filePath, ".jsonl");
|
|
7358
|
+
const fallbackProject = path16.basename(path16.dirname(filePath));
|
|
7272
7359
|
const cwd = lines.map((line) => stringField(line.record, "cwd")).find(Boolean);
|
|
7273
7360
|
const project = projectFromCwd(cwd, fallbackProject);
|
|
7274
7361
|
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
@@ -7442,11 +7529,11 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
7442
7529
|
if (!project.isDirectory()) {
|
|
7443
7530
|
continue;
|
|
7444
7531
|
}
|
|
7445
|
-
const projectDir =
|
|
7532
|
+
const projectDir = path16.join(base, project.name);
|
|
7446
7533
|
const entries = await readdir8(projectDir, { withFileTypes: true });
|
|
7447
7534
|
for (const entry of entries) {
|
|
7448
7535
|
if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
7449
|
-
const filePath =
|
|
7536
|
+
const filePath = path16.join(projectDir, entry.name);
|
|
7450
7537
|
const info = await stat8(filePath);
|
|
7451
7538
|
files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
|
|
7452
7539
|
}
|
|
@@ -7485,19 +7572,19 @@ function createWorkbuddyAdapter() {
|
|
|
7485
7572
|
// src/adapters/zcode.ts
|
|
7486
7573
|
import { execFile } from "node:child_process";
|
|
7487
7574
|
import { readFile as readFile12, stat as stat9 } from "node:fs/promises";
|
|
7488
|
-
import
|
|
7575
|
+
import path17 from "node:path";
|
|
7489
7576
|
import { promisify as promisify2 } from "node:util";
|
|
7490
7577
|
init_fs();
|
|
7491
7578
|
var execFileAsync = promisify2(execFile);
|
|
7492
7579
|
function zcodeCliDir(home, env) {
|
|
7493
7580
|
const override = env?.ZCODE_CLI_DIR || env?.ZCODE_HOME;
|
|
7494
7581
|
if (override && override.trim()) {
|
|
7495
|
-
return
|
|
7582
|
+
return path17.resolve(override, override.endsWith("cli") ? "" : "cli");
|
|
7496
7583
|
}
|
|
7497
|
-
return
|
|
7584
|
+
return path17.join(home, ".zcode", "cli");
|
|
7498
7585
|
}
|
|
7499
7586
|
function zcodeDbPath(home, env) {
|
|
7500
|
-
return
|
|
7587
|
+
return path17.join(zcodeCliDir(home, env), "db", "db.sqlite");
|
|
7501
7588
|
}
|
|
7502
7589
|
var providerNameCache = null;
|
|
7503
7590
|
async function loadProviderNames(configPath2) {
|
|
@@ -7531,7 +7618,7 @@ function sourceHash2(filePath) {
|
|
|
7531
7618
|
return `sha256:${createStableHash(filePath)}`;
|
|
7532
7619
|
}
|
|
7533
7620
|
function projectFromDirectory(directory) {
|
|
7534
|
-
return directory ?
|
|
7621
|
+
return directory ? path17.basename(directory) || "zcode" : "zcode";
|
|
7535
7622
|
}
|
|
7536
7623
|
function isoFromMs(value) {
|
|
7537
7624
|
return timestampFrom(typeof value === "number" ? value : Number(value));
|
|
@@ -7687,16 +7774,16 @@ async function parseZCodeDb(filePath, options) {
|
|
|
7687
7774
|
if (rows.length === 0) {
|
|
7688
7775
|
return [];
|
|
7689
7776
|
}
|
|
7690
|
-
let candidate =
|
|
7777
|
+
let candidate = path17.resolve(filePath);
|
|
7691
7778
|
let configPath2 = "";
|
|
7692
7779
|
for (let i = 0; i < 12; i++) {
|
|
7693
|
-
const probe =
|
|
7780
|
+
const probe = path17.join(candidate, ".zcode", "v2", "config.json");
|
|
7694
7781
|
try {
|
|
7695
7782
|
await stat9(probe);
|
|
7696
7783
|
configPath2 = probe;
|
|
7697
7784
|
break;
|
|
7698
7785
|
} catch {
|
|
7699
|
-
const parent =
|
|
7786
|
+
const parent = path17.dirname(candidate);
|
|
7700
7787
|
if (parent === candidate) break;
|
|
7701
7788
|
candidate = parent;
|
|
7702
7789
|
}
|
|
@@ -7912,7 +7999,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
7912
7999
|
}
|
|
7913
8000
|
async function zcodeBackfillFiles(sourceRoot, home, env) {
|
|
7914
8001
|
const candidate = sourceRoot || zcodeDbPath(home, env);
|
|
7915
|
-
const filePath = candidate.endsWith(".sqlite") ? candidate :
|
|
8002
|
+
const filePath = candidate.endsWith(".sqlite") ? candidate : path17.join(candidate, "db", "db.sqlite");
|
|
7916
8003
|
try {
|
|
7917
8004
|
const info = await stat9(filePath);
|
|
7918
8005
|
return [{ path: filePath, modifiedAt: info.mtime.toISOString() }];
|
|
@@ -8286,7 +8373,7 @@ async function installEntry(entry, options) {
|
|
|
8286
8373
|
});
|
|
8287
8374
|
}
|
|
8288
8375
|
async function mergeHooksJson(filePath, content, { dryRun, force, onWrite }) {
|
|
8289
|
-
const { mkdir:
|
|
8376
|
+
const { mkdir: mkdir6, writeFile: writeFile5 } = await import("node:fs/promises");
|
|
8290
8377
|
const pathMod = await import("node:path");
|
|
8291
8378
|
if (dryRun) {
|
|
8292
8379
|
onWrite(`Would merge ${filePath}`);
|
|
@@ -8307,8 +8394,8 @@ async function mergeHooksJson(filePath, content, { dryRun, force, onWrite }) {
|
|
|
8307
8394
|
onWrite(`Already installed ${filePath}`);
|
|
8308
8395
|
return;
|
|
8309
8396
|
}
|
|
8310
|
-
await
|
|
8311
|
-
await
|
|
8397
|
+
await mkdir6(pathMod.dirname(filePath), { recursive: true });
|
|
8398
|
+
await writeFile5(filePath, nextText, "utf8");
|
|
8312
8399
|
onWrite(`Installed ${filePath}`);
|
|
8313
8400
|
}
|
|
8314
8401
|
function mergeAgyHooksJson(existing, addition) {
|
|
@@ -8386,15 +8473,15 @@ function hookCommandFromGroup(group) {
|
|
|
8386
8473
|
import { randomUUID } from "node:crypto";
|
|
8387
8474
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
8388
8475
|
import { homedir, hostname } from "node:os";
|
|
8389
|
-
import
|
|
8476
|
+
import path18 from "node:path";
|
|
8390
8477
|
function configDir(home = homedir()) {
|
|
8391
|
-
return
|
|
8478
|
+
return path18.join(home, ".vibetime");
|
|
8392
8479
|
}
|
|
8393
8480
|
function configPath(home = homedir()) {
|
|
8394
|
-
return
|
|
8481
|
+
return path18.join(configDir(home), "config.json");
|
|
8395
8482
|
}
|
|
8396
8483
|
function machineIdPath(home = homedir()) {
|
|
8397
|
-
return
|
|
8484
|
+
return path18.join(configDir(home), "machine-id");
|
|
8398
8485
|
}
|
|
8399
8486
|
function readConfig(home = homedir()) {
|
|
8400
8487
|
const file = configPath(home);
|
|
@@ -8441,15 +8528,15 @@ function defaultMachineName() {
|
|
|
8441
8528
|
init_fs();
|
|
8442
8529
|
|
|
8443
8530
|
// src/lib/logger.ts
|
|
8444
|
-
import { appendFile, mkdir as
|
|
8531
|
+
import { appendFile, mkdir as mkdir4, rename, stat as stat10 } from "node:fs/promises";
|
|
8445
8532
|
import { homedir as homedir2 } from "node:os";
|
|
8446
|
-
import
|
|
8533
|
+
import path19 from "node:path";
|
|
8447
8534
|
var MAX_BYTES = 1 * 1024 * 1024;
|
|
8448
8535
|
function logDir(home = homedir2()) {
|
|
8449
|
-
return
|
|
8536
|
+
return path19.join(home, ".vibetime", "logs");
|
|
8450
8537
|
}
|
|
8451
8538
|
function logPath(home = homedir2(), name = "cli.log") {
|
|
8452
|
-
return
|
|
8539
|
+
return path19.join(logDir(home), name);
|
|
8453
8540
|
}
|
|
8454
8541
|
function serializeError(error) {
|
|
8455
8542
|
if (error instanceof Error) {
|
|
@@ -8470,7 +8557,7 @@ async function rotateIfNeeded(file) {
|
|
|
8470
8557
|
async function writeLog(entry, home = homedir2(), fileName = "cli.log") {
|
|
8471
8558
|
try {
|
|
8472
8559
|
const dir = logDir(home);
|
|
8473
|
-
await
|
|
8560
|
+
await mkdir4(dir, { recursive: true });
|
|
8474
8561
|
const file = logPath(home, fileName);
|
|
8475
8562
|
await rotateIfNeeded(file);
|
|
8476
8563
|
const record = {
|
|
@@ -8624,8 +8711,8 @@ function buildHeaders(token, machine) {
|
|
|
8624
8711
|
...machine?.platform ? { "x-machine-platform": machine.platform } : {}
|
|
8625
8712
|
};
|
|
8626
8713
|
}
|
|
8627
|
-
function joinUrl(base,
|
|
8628
|
-
return new URL(
|
|
8714
|
+
function joinUrl(base, path21) {
|
|
8715
|
+
return new URL(path21, base.endsWith("/") ? base : `${base}/`).toString();
|
|
8629
8716
|
}
|
|
8630
8717
|
async function postRollupBatch(remote, rollups, options = {}) {
|
|
8631
8718
|
const response = await remote.fetchImpl(joinUrl(remote.baseUrl, "/v3/agent/ingest"), {
|
|
@@ -8797,7 +8884,7 @@ function normalizeOptions(options) {
|
|
|
8797
8884
|
return normalized;
|
|
8798
8885
|
}
|
|
8799
8886
|
async function detectCommand(options, ctx, registry) {
|
|
8800
|
-
const home =
|
|
8887
|
+
const home = resolveHome3(options, ctx);
|
|
8801
8888
|
const env = ctx.env;
|
|
8802
8889
|
const adapters = registry.all();
|
|
8803
8890
|
const targets = await Promise.all(adapters.map(async (adapter) => {
|
|
@@ -8826,7 +8913,7 @@ async function detectCommand(options, ctx, registry) {
|
|
|
8826
8913
|
}
|
|
8827
8914
|
}
|
|
8828
8915
|
async function installCommand(options, ctx, registry) {
|
|
8829
|
-
const home =
|
|
8916
|
+
const home = resolveHome3(options, ctx);
|
|
8830
8917
|
const env = ctx.env;
|
|
8831
8918
|
const dryRun = Boolean(options["dry-run"]);
|
|
8832
8919
|
const force = Boolean(options.force);
|
|
@@ -8924,7 +9011,7 @@ Upgraded ${current} \u2192 ${latest}
|
|
|
8924
9011
|
return 0;
|
|
8925
9012
|
}
|
|
8926
9013
|
async function hookCommand(options, ctx) {
|
|
8927
|
-
const home =
|
|
9014
|
+
const home = resolveHome3(options, ctx);
|
|
8928
9015
|
try {
|
|
8929
9016
|
const agent = requiredOption(options, "agent");
|
|
8930
9017
|
const payload = await readHookPayload(ctx.stdin);
|
|
@@ -8937,6 +9024,7 @@ async function hookCommand(options, ctx) {
|
|
|
8937
9024
|
`);
|
|
8938
9025
|
return 0;
|
|
8939
9026
|
}
|
|
9027
|
+
await persistHookSessionContext(home, payload);
|
|
8940
9028
|
return await syncLocalTriggerCommand({
|
|
8941
9029
|
...options,
|
|
8942
9030
|
agent,
|
|
@@ -8950,7 +9038,7 @@ async function hookCommand(options, ctx) {
|
|
|
8950
9038
|
}
|
|
8951
9039
|
}
|
|
8952
9040
|
async function syncLocalTriggerCommand(options, ctx, _registry) {
|
|
8953
|
-
const home =
|
|
9041
|
+
const home = resolveHome3(options, ctx);
|
|
8954
9042
|
const statePath = syncLocalTriggerStatePath(home);
|
|
8955
9043
|
const lockPath = syncLocalTriggerLockPath(home);
|
|
8956
9044
|
const minIntervalSeconds = Math.max(0, Math.floor(numberOption(options["min-interval"]) ?? DEFAULT_HOOK_SYNC_MIN_INTERVAL_SECONDS));
|
|
@@ -8993,7 +9081,7 @@ async function syncLocalTriggerCommand(options, ctx, _registry) {
|
|
|
8993
9081
|
return 0;
|
|
8994
9082
|
}
|
|
8995
9083
|
async function syncLocalRunnerCommand(options, ctx, _registry) {
|
|
8996
|
-
const home =
|
|
9084
|
+
const home = resolveHome3(options, ctx);
|
|
8997
9085
|
const lockPath = stringOption(options["lock-file"]) || syncLocalTriggerLockPath(home);
|
|
8998
9086
|
const statePath = stringOption(options["state-file"]) || syncLocalTriggerStatePath(home);
|
|
8999
9087
|
const state = await readSyncLocalTriggerState(statePath);
|
|
@@ -9053,7 +9141,7 @@ async function backfillCommand(options, ctx, registry) {
|
|
|
9053
9141
|
return importBackfillPlan(plan, options, ctx, reg);
|
|
9054
9142
|
}
|
|
9055
9143
|
async function createBackfillPlanFromOptions(options, ctx, action, registry) {
|
|
9056
|
-
const home =
|
|
9144
|
+
const home = resolveHome3(options, ctx);
|
|
9057
9145
|
const env = ctx.env;
|
|
9058
9146
|
const source = normalizeBackfillSource(stringOption(options.source) || "all");
|
|
9059
9147
|
const sourceDefs = source === "all" ? registry.all().map((a) => ({ id: a.id, label: a.label, paths: a.sourcePaths(home, env) })) : (() => {
|
|
@@ -9122,7 +9210,7 @@ async function createBackfillPlanFromOptions(options, ctx, action, registry) {
|
|
|
9122
9210
|
}
|
|
9123
9211
|
async function createBackfillEventsFromDefs(sourceDefs, options, registry, ctx, overrideFiles) {
|
|
9124
9212
|
const events = [];
|
|
9125
|
-
const home =
|
|
9213
|
+
const home = resolveHome3(options, ctx);
|
|
9126
9214
|
for (const item of sourceDefs) {
|
|
9127
9215
|
const parser = registry.getParser(item.id);
|
|
9128
9216
|
if (!parser) {
|
|
@@ -9172,25 +9260,25 @@ async function createBackfillCandidates(source, options) {
|
|
|
9172
9260
|
}
|
|
9173
9261
|
async function listBackfillSourceFiles(source, options, ctx) {
|
|
9174
9262
|
if (source.id === "opencode") {
|
|
9175
|
-
return opencodeBackfillFiles(stringOption(options["source-root"]),
|
|
9263
|
+
return opencodeBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
9176
9264
|
}
|
|
9177
9265
|
if (source.id === "agy") {
|
|
9178
|
-
return agyBackfillFiles(stringOption(options["source-root"]),
|
|
9266
|
+
return agyBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
9179
9267
|
}
|
|
9180
9268
|
if (source.id === "claude-cowork") {
|
|
9181
|
-
return claudeCoworkBackfillFiles(stringOption(options["source-root"]),
|
|
9269
|
+
return claudeCoworkBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
9182
9270
|
}
|
|
9183
9271
|
if (source.id === "codebuddy") {
|
|
9184
|
-
return codebuddyBackfillFiles(stringOption(options["source-root"]),
|
|
9272
|
+
return codebuddyBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
9185
9273
|
}
|
|
9186
9274
|
if (source.id === "workbuddy") {
|
|
9187
|
-
return workbuddyBackfillFiles(stringOption(options["source-root"]),
|
|
9275
|
+
return workbuddyBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
9188
9276
|
}
|
|
9189
9277
|
if (source.id === "zcode") {
|
|
9190
|
-
return zcodeBackfillFiles(stringOption(options["source-root"]),
|
|
9278
|
+
return zcodeBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
9191
9279
|
}
|
|
9192
9280
|
if (source.id === "copilot") {
|
|
9193
|
-
return copilotBackfillFiles(stringOption(options["source-root"]),
|
|
9281
|
+
return copilotBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
9194
9282
|
}
|
|
9195
9283
|
const roots = stringOption(options["source-root"]) ? [requiredOption(options, "source-root")] : source.paths;
|
|
9196
9284
|
const fileLists = await Promise.all(roots.map((r) => listJsonlFiles(r)));
|
|
@@ -9273,7 +9361,7 @@ function writeBackfillPlan(plan, options, ctx) {
|
|
|
9273
9361
|
async function importBackfillPlan(plan, options, ctx, registry) {
|
|
9274
9362
|
const source = normalizeBackfillSource(stringOption(options.source) || "all");
|
|
9275
9363
|
const supportedSources = new Set(BACKFILL_SOURCE_IDS);
|
|
9276
|
-
const home =
|
|
9364
|
+
const home = resolveHome3(options, ctx);
|
|
9277
9365
|
if (source !== "all" && !supportedSources.has(source)) {
|
|
9278
9366
|
write(ctx.stderr, `Unsupported backfill source: ${source}
|
|
9279
9367
|
`);
|
|
@@ -9342,7 +9430,7 @@ async function purgeForcedSources(sourceDefs, home, remoteKey, options, ctx) {
|
|
|
9342
9430
|
async function collectCanonicalEvents(sourceDefs, registry, incrementalState, options, ctx) {
|
|
9343
9431
|
const selectedFilesBySource = /* @__PURE__ */ new Map();
|
|
9344
9432
|
const canonicalEvents = [];
|
|
9345
|
-
const home =
|
|
9433
|
+
const home = resolveHome3(options, ctx);
|
|
9346
9434
|
for (const item of sourceDefs) {
|
|
9347
9435
|
const parser = registry.getParser(item.id);
|
|
9348
9436
|
if (!parser) {
|
|
@@ -9446,7 +9534,7 @@ async function sendSessionRollupBatch(rollups, options, ctx) {
|
|
|
9446
9534
|
if (!remote) {
|
|
9447
9535
|
throw new Error("No fetch available for HTTP upload");
|
|
9448
9536
|
}
|
|
9449
|
-
const home =
|
|
9537
|
+
const home = resolveHome3(options, ctx);
|
|
9450
9538
|
const cfg = readConfig(home);
|
|
9451
9539
|
const machine = {
|
|
9452
9540
|
id: ensureLocalMachineId(home),
|
|
@@ -9465,7 +9553,7 @@ async function deleteSessionRollupsBySourceAPI(source, options, ctx) {
|
|
|
9465
9553
|
if (!remote) {
|
|
9466
9554
|
throw new Error("No fetch available for HTTP delete");
|
|
9467
9555
|
}
|
|
9468
|
-
const home =
|
|
9556
|
+
const home = resolveHome3(options, ctx);
|
|
9469
9557
|
return deleteRollupsBySource(remote, source, {
|
|
9470
9558
|
id: ensureLocalMachineId(home),
|
|
9471
9559
|
hostname: defaultMachineName(),
|
|
@@ -9509,13 +9597,13 @@ function selectBackfillFilesForImport(files, watermarkTs) {
|
|
|
9509
9597
|
});
|
|
9510
9598
|
}
|
|
9511
9599
|
function backfillIncrementalStatePath(home) {
|
|
9512
|
-
return
|
|
9600
|
+
return path20.join(home, ".vibetime", "backfill-state.json");
|
|
9513
9601
|
}
|
|
9514
9602
|
function syncLocalTriggerStatePath(home) {
|
|
9515
|
-
return
|
|
9603
|
+
return path20.join(home, ".vibetime", "sync-local-trigger.json");
|
|
9516
9604
|
}
|
|
9517
9605
|
function syncLocalTriggerLockPath(home) {
|
|
9518
|
-
return
|
|
9606
|
+
return path20.join(home, ".vibetime", "sync-local-trigger.lock");
|
|
9519
9607
|
}
|
|
9520
9608
|
function backfillRemoteKey(baseUrl) {
|
|
9521
9609
|
try {
|
|
@@ -9577,8 +9665,8 @@ async function readBackfillIncrementalStateFile(home, ctx) {
|
|
|
9577
9665
|
}
|
|
9578
9666
|
async function writeBackfillIncrementalStateFile(home, file) {
|
|
9579
9667
|
const statePath = backfillIncrementalStatePath(home);
|
|
9580
|
-
await
|
|
9581
|
-
await
|
|
9668
|
+
await mkdir5(path20.dirname(statePath), { recursive: true });
|
|
9669
|
+
await writeFile4(statePath, `${JSON.stringify(file, null, 2)}
|
|
9582
9670
|
`, "utf8");
|
|
9583
9671
|
}
|
|
9584
9672
|
async function readBackfillIncrementalState(home, remoteKey, ctx) {
|
|
@@ -9626,9 +9714,9 @@ async function readSyncLocalTriggerState(statePath) {
|
|
|
9626
9714
|
return nextState;
|
|
9627
9715
|
}
|
|
9628
9716
|
async function writeSyncLocalTriggerState(statePath, state) {
|
|
9629
|
-
await
|
|
9630
|
-
const tmpPath = `${statePath}.tmp`;
|
|
9631
|
-
await
|
|
9717
|
+
await mkdir5(path20.dirname(statePath), { recursive: true });
|
|
9718
|
+
const tmpPath = `${statePath}.${process.pid}.${randomUUID2()}.tmp`;
|
|
9719
|
+
await writeFile4(tmpPath, `${JSON.stringify(state, null, 2)}
|
|
9632
9720
|
`, "utf8");
|
|
9633
9721
|
await rename2(tmpPath, statePath);
|
|
9634
9722
|
}
|
|
@@ -9643,8 +9731,8 @@ async function readSyncLocalLock(lockPath) {
|
|
|
9643
9731
|
return { pid: lock.pid, startedAt: lock.startedAt };
|
|
9644
9732
|
}
|
|
9645
9733
|
async function writeSyncLocalLock(lockPath, lock) {
|
|
9646
|
-
await
|
|
9647
|
-
await
|
|
9734
|
+
await mkdir5(path20.dirname(lockPath), { recursive: true });
|
|
9735
|
+
await writeFile4(lockPath, `${JSON.stringify(lock, null, 2)}
|
|
9648
9736
|
`, "utf8");
|
|
9649
9737
|
}
|
|
9650
9738
|
async function clearSyncLocalLock(lockPath) {
|
|
@@ -9682,12 +9770,19 @@ function spawnSyncLocalRunner(input) {
|
|
|
9682
9770
|
const child = input.ctx.spawn(process.execPath, args, {
|
|
9683
9771
|
detached: true,
|
|
9684
9772
|
stdio: "ignore",
|
|
9685
|
-
cwd:
|
|
9686
|
-
env:
|
|
9773
|
+
cwd: resolveSpawnCwd(input.home),
|
|
9774
|
+
env: input.ctx.env
|
|
9687
9775
|
});
|
|
9688
9776
|
child.unref();
|
|
9689
9777
|
return child;
|
|
9690
9778
|
}
|
|
9779
|
+
function resolveSpawnCwd(home) {
|
|
9780
|
+
try {
|
|
9781
|
+
return process.cwd();
|
|
9782
|
+
} catch {
|
|
9783
|
+
return home;
|
|
9784
|
+
}
|
|
9785
|
+
}
|
|
9691
9786
|
function syncLocalRunnerArgs(input) {
|
|
9692
9787
|
const args = syncLocalRunnerEntryArgs(fileURLToPath(import.meta.url));
|
|
9693
9788
|
args.push("sync-local-runner", "--home", input.home, "--lock-file", input.lockPath, "--state-file", input.statePath);
|
|
@@ -9703,10 +9798,10 @@ function syncLocalRunnerEntryArgs(cliPath) {
|
|
|
9703
9798
|
if (cliPath.endsWith(".ts")) {
|
|
9704
9799
|
return ["--import", "tsx", cliPath];
|
|
9705
9800
|
}
|
|
9706
|
-
return [
|
|
9801
|
+
return [path20.resolve(path20.dirname(cliPath), "../bin/vibetime.mjs")];
|
|
9707
9802
|
}
|
|
9708
|
-
function
|
|
9709
|
-
return
|
|
9803
|
+
function resolveHome3(options, ctx) {
|
|
9804
|
+
return path20.resolve(stringOption(options.home) || ctx.env.HOME || os9.homedir());
|
|
9710
9805
|
}
|
|
9711
9806
|
function requestedTargets(options) {
|
|
9712
9807
|
const value = options.target || options.targets;
|
|
@@ -9769,7 +9864,7 @@ function maskToken(token) {
|
|
|
9769
9864
|
}
|
|
9770
9865
|
async function tokenCommand(action, value, options, ctx) {
|
|
9771
9866
|
const verb = action || "show";
|
|
9772
|
-
const home =
|
|
9867
|
+
const home = resolveHome3(options, ctx);
|
|
9773
9868
|
if (verb === "set") {
|
|
9774
9869
|
if (!value || value.trim().length === 0) {
|
|
9775
9870
|
write(ctx.stderr, "Usage: vibetime token set <token> [--remote <url>]\n");
|
|
@@ -9841,7 +9936,7 @@ async function machineCommand(action, options, ctx) {
|
|
|
9841
9936
|
return 0;
|
|
9842
9937
|
}
|
|
9843
9938
|
if (verb === "rename") {
|
|
9844
|
-
const home =
|
|
9939
|
+
const home = resolveHome3(options, ctx);
|
|
9845
9940
|
const id = stringOption(options.id) || ensureLocalMachineId(home);
|
|
9846
9941
|
const name = stringOption(options.name);
|
|
9847
9942
|
if (!name) {
|