@staff0rd/assist 0.955.2 → 0.956.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { Command } from "commander";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "@staff0rd/assist",
|
|
9
|
-
version: "0.
|
|
9
|
+
version: "0.956.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -605,16 +605,87 @@ function mergeRawConfigs(globalRaw, projectRaw) {
|
|
|
605
605
|
return merged;
|
|
606
606
|
}
|
|
607
607
|
|
|
608
|
+
// src/shared/readRepoConfigCache.ts
|
|
609
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
|
|
610
|
+
import { join as join6 } from "path";
|
|
611
|
+
|
|
612
|
+
// src/shared/loadJson.ts
|
|
613
|
+
import {
|
|
614
|
+
existsSync as existsSync3,
|
|
615
|
+
mkdirSync as mkdirSync2,
|
|
616
|
+
readFileSync as readFileSync3,
|
|
617
|
+
renameSync,
|
|
618
|
+
rmSync as rmSync2,
|
|
619
|
+
writeFileSync
|
|
620
|
+
} from "fs";
|
|
621
|
+
import { homedir as homedir3 } from "os";
|
|
622
|
+
import { join as join5 } from "path";
|
|
623
|
+
function getStoreDir() {
|
|
624
|
+
return process.env.ASSIST_STORE_DIR || join5(homedir3(), ".assist");
|
|
625
|
+
}
|
|
626
|
+
function getStorePath(filename) {
|
|
627
|
+
return join5(getStoreDir(), filename);
|
|
628
|
+
}
|
|
629
|
+
function loadJson(filename) {
|
|
630
|
+
const path108 = getStorePath(filename);
|
|
631
|
+
if (existsSync3(path108)) {
|
|
632
|
+
try {
|
|
633
|
+
return JSON.parse(readFileSync3(path108, "utf8"));
|
|
634
|
+
} catch {
|
|
635
|
+
return {};
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
return {};
|
|
639
|
+
}
|
|
640
|
+
function saveJson(filename, data) {
|
|
641
|
+
const dir = getStoreDir();
|
|
642
|
+
if (!existsSync3(dir)) {
|
|
643
|
+
mkdirSync2(dir, { recursive: true });
|
|
644
|
+
}
|
|
645
|
+
const path108 = getStorePath(filename);
|
|
646
|
+
const tmp = `${path108}.${process.pid}.tmp`;
|
|
647
|
+
try {
|
|
648
|
+
writeFileSync(tmp, JSON.stringify(data, null, 2));
|
|
649
|
+
renameSync(tmp, path108);
|
|
650
|
+
} catch (error) {
|
|
651
|
+
rmSync2(tmp, { force: true });
|
|
652
|
+
throw error;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// src/shared/readRepoConfigCache.ts
|
|
657
|
+
function repoConfigCachePath() {
|
|
658
|
+
return join6(getStoreDir(), "repo-config-cache.json");
|
|
659
|
+
}
|
|
660
|
+
function readConfigCacheFile() {
|
|
661
|
+
const path108 = repoConfigCachePath();
|
|
662
|
+
if (!existsSync4(path108)) return {};
|
|
663
|
+
try {
|
|
664
|
+
const parsed = JSON.parse(readFileSync4(path108, "utf8"));
|
|
665
|
+
return parsed ?? {};
|
|
666
|
+
} catch {
|
|
667
|
+
return {};
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
function readRepoConfigCache() {
|
|
671
|
+
return readConfigCacheFile().repos ?? {};
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// src/shared/readUserConfigCache.ts
|
|
675
|
+
function readUserConfigCache() {
|
|
676
|
+
return readConfigCacheFile().user ?? {};
|
|
677
|
+
}
|
|
678
|
+
|
|
608
679
|
// src/shared/resolveRepoLayer.ts
|
|
609
680
|
import chalk2 from "chalk";
|
|
610
681
|
|
|
611
682
|
// src/shared/findRepoRoot.ts
|
|
612
|
-
import { existsSync as
|
|
683
|
+
import { existsSync as existsSync5 } from "fs";
|
|
613
684
|
import path from "path";
|
|
614
685
|
function findRepoRoot(dir) {
|
|
615
686
|
let current = dir;
|
|
616
687
|
while (current !== path.dirname(current)) {
|
|
617
|
-
if (
|
|
688
|
+
if (existsSync5(path.join(current, ".git"))) {
|
|
618
689
|
return current;
|
|
619
690
|
}
|
|
620
691
|
current = path.dirname(current);
|
|
@@ -703,69 +774,6 @@ function getCachedOrigin(cwd) {
|
|
|
703
774
|
return origin;
|
|
704
775
|
}
|
|
705
776
|
|
|
706
|
-
// src/shared/readRepoConfigCache.ts
|
|
707
|
-
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
708
|
-
import { join as join6 } from "path";
|
|
709
|
-
|
|
710
|
-
// src/shared/loadJson.ts
|
|
711
|
-
import {
|
|
712
|
-
existsSync as existsSync4,
|
|
713
|
-
mkdirSync as mkdirSync2,
|
|
714
|
-
readFileSync as readFileSync3,
|
|
715
|
-
renameSync,
|
|
716
|
-
rmSync as rmSync2,
|
|
717
|
-
writeFileSync
|
|
718
|
-
} from "fs";
|
|
719
|
-
import { homedir as homedir3 } from "os";
|
|
720
|
-
import { join as join5 } from "path";
|
|
721
|
-
function getStoreDir() {
|
|
722
|
-
return process.env.ASSIST_STORE_DIR || join5(homedir3(), ".assist");
|
|
723
|
-
}
|
|
724
|
-
function getStorePath(filename) {
|
|
725
|
-
return join5(getStoreDir(), filename);
|
|
726
|
-
}
|
|
727
|
-
function loadJson(filename) {
|
|
728
|
-
const path108 = getStorePath(filename);
|
|
729
|
-
if (existsSync4(path108)) {
|
|
730
|
-
try {
|
|
731
|
-
return JSON.parse(readFileSync3(path108, "utf8"));
|
|
732
|
-
} catch {
|
|
733
|
-
return {};
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
return {};
|
|
737
|
-
}
|
|
738
|
-
function saveJson(filename, data) {
|
|
739
|
-
const dir = getStoreDir();
|
|
740
|
-
if (!existsSync4(dir)) {
|
|
741
|
-
mkdirSync2(dir, { recursive: true });
|
|
742
|
-
}
|
|
743
|
-
const path108 = getStorePath(filename);
|
|
744
|
-
const tmp = `${path108}.${process.pid}.tmp`;
|
|
745
|
-
try {
|
|
746
|
-
writeFileSync(tmp, JSON.stringify(data, null, 2));
|
|
747
|
-
renameSync(tmp, path108);
|
|
748
|
-
} catch (error) {
|
|
749
|
-
rmSync2(tmp, { force: true });
|
|
750
|
-
throw error;
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
// src/shared/readRepoConfigCache.ts
|
|
755
|
-
function repoConfigCachePath() {
|
|
756
|
-
return join6(getStoreDir(), "repo-config-cache.json");
|
|
757
|
-
}
|
|
758
|
-
function readRepoConfigCache() {
|
|
759
|
-
const path108 = repoConfigCachePath();
|
|
760
|
-
if (!existsSync5(path108)) return {};
|
|
761
|
-
try {
|
|
762
|
-
const parsed = JSON.parse(readFileSync4(path108, "utf8"));
|
|
763
|
-
return parsed?.repos ?? {};
|
|
764
|
-
} catch {
|
|
765
|
-
return {};
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
|
|
769
777
|
// src/commands/backlog/originDisplayName.ts
|
|
770
778
|
function originDisplayName(origin) {
|
|
771
779
|
if (origin.startsWith("local:")) {
|
|
@@ -1444,7 +1452,7 @@ function loadConfigFrom(cwd, globalConfigPath = getGlobalConfigPath()) {
|
|
|
1444
1452
|
const globalRaw = loadRawYaml(globalConfigPath);
|
|
1445
1453
|
const projectRaw = loadRawYaml(projectConfigPathFrom(cwd));
|
|
1446
1454
|
const globalWithRepo = mergeRawConfigs(
|
|
1447
|
-
globalRaw,
|
|
1455
|
+
mergeRawConfigs(readUserConfigCache(), globalRaw),
|
|
1448
1456
|
resolveRepoLayer(globalRaw, cwd).override
|
|
1449
1457
|
);
|
|
1450
1458
|
const merged = stripLegacyConfigKeys(
|
|
@@ -1995,7 +2003,7 @@ function expandTilde(value) {
|
|
|
1995
2003
|
import { asc, eq } from "drizzle-orm";
|
|
1996
2004
|
|
|
1997
2005
|
// src/shared/db/schema.ts
|
|
1998
|
-
import { integer as integer13, pgTable as
|
|
2006
|
+
import { integer as integer13, pgTable as pgTable16, text as text15 } from "drizzle-orm/pg-core";
|
|
1999
2007
|
|
|
2000
2008
|
// src/shared/db/backups.ts
|
|
2001
2009
|
import { bigint, integer, pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|
@@ -2251,12 +2259,20 @@ var usagePeaks = pgTable14(
|
|
|
2251
2259
|
(t) => [primaryKey10({ columns: [t.window, t.resetsAt, t.segment] })]
|
|
2252
2260
|
);
|
|
2253
2261
|
|
|
2262
|
+
// src/shared/db/userConfig.ts
|
|
2263
|
+
import { jsonb as jsonb2, pgTable as pgTable15, smallint, timestamp as timestamp7 } from "drizzle-orm/pg-core";
|
|
2264
|
+
var userConfig = pgTable15("user_config", {
|
|
2265
|
+
id: smallint().primaryKey().default(1),
|
|
2266
|
+
config: jsonb2().$type().notNull(),
|
|
2267
|
+
updatedAt: timestamp7("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
2268
|
+
});
|
|
2269
|
+
|
|
2254
2270
|
// src/shared/db/schema.ts
|
|
2255
|
-
var metadata =
|
|
2271
|
+
var metadata = pgTable16("metadata", {
|
|
2256
2272
|
key: text15().primaryKey(),
|
|
2257
2273
|
value: text15().notNull()
|
|
2258
2274
|
});
|
|
2259
|
-
var feeds =
|
|
2275
|
+
var feeds = pgTable16("feeds", {
|
|
2260
2276
|
id: integer13().generatedByDefaultAsIdentity().primaryKey(),
|
|
2261
2277
|
url: text15().notNull().unique()
|
|
2262
2278
|
});
|
|
@@ -2276,7 +2292,8 @@ var schema = {
|
|
|
2276
2292
|
phaseCycleContext,
|
|
2277
2293
|
phaseSessions,
|
|
2278
2294
|
repoConfigs,
|
|
2279
|
-
inboxMessages
|
|
2295
|
+
inboxMessages,
|
|
2296
|
+
userConfig
|
|
2280
2297
|
};
|
|
2281
2298
|
|
|
2282
2299
|
// src/shared/db/planPhaseCounts.ts
|
|
@@ -3366,6 +3383,20 @@ var migration0009InboxMessages = {
|
|
|
3366
3383
|
sql: sql12
|
|
3367
3384
|
};
|
|
3368
3385
|
|
|
3386
|
+
// src/shared/db/migrations/migration0010UserConfig.ts
|
|
3387
|
+
var sql13 = `
|
|
3388
|
+
CREATE TABLE IF NOT EXISTS user_config (
|
|
3389
|
+
id SMALLINT PRIMARY KEY DEFAULT 1 CHECK (id = 1),
|
|
3390
|
+
config JSONB NOT NULL,
|
|
3391
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
3392
|
+
);
|
|
3393
|
+
`;
|
|
3394
|
+
var migration0010UserConfig = {
|
|
3395
|
+
id: 10,
|
|
3396
|
+
name: "user-config",
|
|
3397
|
+
sql: sql13
|
|
3398
|
+
};
|
|
3399
|
+
|
|
3369
3400
|
// src/shared/db/migrations.ts
|
|
3370
3401
|
var migrations = [
|
|
3371
3402
|
migration0001Baseline,
|
|
@@ -3376,7 +3407,8 @@ var migrations = [
|
|
|
3376
3407
|
migration0006BackfillPhaseSessions,
|
|
3377
3408
|
migration0007GithubIssue,
|
|
3378
3409
|
migration0008RepoConfigs,
|
|
3379
|
-
migration0009InboxMessages
|
|
3410
|
+
migration0009InboxMessages,
|
|
3411
|
+
migration0010UserConfig
|
|
3380
3412
|
];
|
|
3381
3413
|
var latestMigrationId = migrations.reduce(
|
|
3382
3414
|
(max, m) => Math.max(max, m.id),
|
|
@@ -3459,8 +3491,8 @@ async function assertMigrationsInSync(exec3) {
|
|
|
3459
3491
|
// src/shared/db/migrations/MigrationExecutor.ts
|
|
3460
3492
|
function pgExecutor(queryable) {
|
|
3461
3493
|
return {
|
|
3462
|
-
exec: (
|
|
3463
|
-
query: async (
|
|
3494
|
+
exec: (sql30) => queryable.query(sql30),
|
|
3495
|
+
query: async (sql30, params) => (await queryable.query(sql30, params)).rows
|
|
3464
3496
|
};
|
|
3465
3497
|
}
|
|
3466
3498
|
|
|
@@ -3614,13 +3646,13 @@ async function loadItem(orm, id) {
|
|
|
3614
3646
|
}
|
|
3615
3647
|
|
|
3616
3648
|
// src/commands/backlog/saveAllItems.ts
|
|
3617
|
-
import { eq as eq8, sql as
|
|
3649
|
+
import { eq as eq8, sql as sql14 } from "drizzle-orm";
|
|
3618
3650
|
|
|
3619
3651
|
// src/commands/backlog/deleteItemRelations.ts
|
|
3620
3652
|
import { eq as eq7 } from "drizzle-orm";
|
|
3621
3653
|
|
|
3622
3654
|
// src/commands/backlog/searchItemIds.ts
|
|
3623
|
-
import { and as and3, asc as asc5, eq as eq9, ilike, or, sql as
|
|
3655
|
+
import { and as and3, asc as asc5, eq as eq9, ilike, or, sql as sql15 } from "drizzle-orm";
|
|
3624
3656
|
async function searchItemIds(orm, query, origin) {
|
|
3625
3657
|
const pattern2 = `%${query}%`;
|
|
3626
3658
|
const numberPattern = `%${query.replace(/^#/, "")}%`;
|
|
@@ -3634,7 +3666,7 @@ async function searchItemIds(orm, query, origin) {
|
|
|
3634
3666
|
ilike(items.jiraKey, pattern2),
|
|
3635
3667
|
ilike(comments.text, pattern2),
|
|
3636
3668
|
ilike(planPhases.name, pattern2),
|
|
3637
|
-
ilike(
|
|
3669
|
+
ilike(sql15`${items.id}::text`, numberPattern)
|
|
3638
3670
|
)
|
|
3639
3671
|
)
|
|
3640
3672
|
).orderBy(asc5(items.id));
|
|
@@ -4052,7 +4084,7 @@ import * as fs4 from "fs";
|
|
|
4052
4084
|
function extractSessionMeta(lines2) {
|
|
4053
4085
|
let sessionId = "";
|
|
4054
4086
|
let cwd = "";
|
|
4055
|
-
let
|
|
4087
|
+
let timestamp8 = "";
|
|
4056
4088
|
let name = "";
|
|
4057
4089
|
let commandName = "";
|
|
4058
4090
|
let commandArgs = "";
|
|
@@ -4060,14 +4092,14 @@ function extractSessionMeta(lines2) {
|
|
|
4060
4092
|
const entry = safeParse(line);
|
|
4061
4093
|
if (!entry) continue;
|
|
4062
4094
|
sessionId ||= strField(entry, "sessionId");
|
|
4063
|
-
|
|
4095
|
+
timestamp8 ||= strField(entry, "timestamp");
|
|
4064
4096
|
cwd ||= strField(entry, "cwd");
|
|
4065
4097
|
if (entry.type === "user" && !entry.isMeta) {
|
|
4066
4098
|
({ name, commandName, commandArgs } = parseFirstUserEntry(entry));
|
|
4067
4099
|
break;
|
|
4068
4100
|
}
|
|
4069
4101
|
}
|
|
4070
|
-
return { sessionId, cwd, timestamp:
|
|
4102
|
+
return { sessionId, cwd, timestamp: timestamp8, name, commandName, commandArgs };
|
|
4071
4103
|
}
|
|
4072
4104
|
function parseFirstUserEntry(entry) {
|
|
4073
4105
|
const raw = messageText(entry);
|
|
@@ -4120,13 +4152,13 @@ async function parseSessionFile(filePath, origin = "wsl") {
|
|
|
4120
4152
|
handle = await fs4.promises.open(filePath, "r");
|
|
4121
4153
|
const meta = extractSessionMeta(await readHeadLines(handle));
|
|
4122
4154
|
if (!meta.sessionId) return null;
|
|
4123
|
-
const
|
|
4155
|
+
const timestamp8 = meta.timestamp || (await fs4.promises.stat(filePath)).mtime.toISOString();
|
|
4124
4156
|
return {
|
|
4125
4157
|
sessionId: meta.sessionId,
|
|
4126
4158
|
name: meta.name || `Session ${meta.sessionId.slice(0, 8)}`,
|
|
4127
4159
|
project: deriveProject(meta.cwd, filePath, origin),
|
|
4128
4160
|
cwd: meta.cwd,
|
|
4129
|
-
timestamp:
|
|
4161
|
+
timestamp: timestamp8,
|
|
4130
4162
|
origin,
|
|
4131
4163
|
...deriveHistoryFields(meta.commandName, meta.commandArgs, meta.name)
|
|
4132
4164
|
};
|
|
@@ -5917,6 +5949,7 @@ function readRawConfigLayers(cwd, globalConfigPath = getGlobalConfigPath()) {
|
|
|
5917
5949
|
return {
|
|
5918
5950
|
project: loadRawYaml(projectConfigPathFrom(cwd)),
|
|
5919
5951
|
global,
|
|
5952
|
+
user: readUserConfigCache(),
|
|
5920
5953
|
repoOverride: repo.override,
|
|
5921
5954
|
...repo.key === void 0 ? {} : { repoKey: repo.key },
|
|
5922
5955
|
...repo.source === void 0 ? {} : { repoSource: repo.source }
|
|
@@ -6022,7 +6055,8 @@ function getNestedValue(obj, path108) {
|
|
|
6022
6055
|
var LAYERS = [
|
|
6023
6056
|
["project", "project"],
|
|
6024
6057
|
["repo", "repoOverride"],
|
|
6025
|
-
["global", "global"]
|
|
6058
|
+
["global", "global"],
|
|
6059
|
+
["user", "user"]
|
|
6026
6060
|
];
|
|
6027
6061
|
function configEntryLayers(key, layers, node) {
|
|
6028
6062
|
const entryLayers = {};
|
|
@@ -6831,6 +6865,7 @@ function resolveConfigSources(key, layers) {
|
|
|
6831
6865
|
if (getNestedValue(layers.repoOverride, key) !== void 0)
|
|
6832
6866
|
sources.push("repo");
|
|
6833
6867
|
if (getNestedValue(layers.global, key) !== void 0) sources.push("global");
|
|
6868
|
+
if (getNestedValue(layers.user, key) !== void 0) sources.push("user");
|
|
6834
6869
|
return sources;
|
|
6835
6870
|
}
|
|
6836
6871
|
|
|
@@ -7533,11 +7568,11 @@ async function deleteItemComment(res, itemId2, commentId) {
|
|
|
7533
7568
|
}
|
|
7534
7569
|
|
|
7535
7570
|
// src/commands/backlog/appendComment.ts
|
|
7536
|
-
import { sql as
|
|
7571
|
+
import { sql as sql16 } from "drizzle-orm";
|
|
7537
7572
|
async function appendComment(orm, itemId2, text18, opts = {}) {
|
|
7538
7573
|
await orm.insert(comments).values({
|
|
7539
7574
|
itemId: itemId2,
|
|
7540
|
-
idx:
|
|
7575
|
+
idx: sql16`(SELECT COALESCE(MAX(${comments.idx}) + 1, 0) FROM ${comments} WHERE ${comments.itemId} = ${itemId2})`,
|
|
7541
7576
|
text: text18,
|
|
7542
7577
|
phase: opts.phase ?? null,
|
|
7543
7578
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -8030,11 +8065,11 @@ async function historySearch(req, res) {
|
|
|
8030
8065
|
}
|
|
8031
8066
|
|
|
8032
8067
|
// src/shared/db/listInboxMessages.ts
|
|
8033
|
-
import { desc as desc2, isNull as isNull2, sql as
|
|
8068
|
+
import { desc as desc2, isNull as isNull2, sql as sql17 } from "drizzle-orm";
|
|
8034
8069
|
function listInboxMessages(orm) {
|
|
8035
8070
|
return orm.select().from(inboxMessages).where(isNull2(inboxMessages.dismissedAt)).orderBy(
|
|
8036
8071
|
desc2(
|
|
8037
|
-
|
|
8072
|
+
sql17`coalesce(${inboxMessages.receivedAt}, ${inboxMessages.flaggedAt})`
|
|
8038
8073
|
)
|
|
8039
8074
|
);
|
|
8040
8075
|
}
|
|
@@ -9180,12 +9215,12 @@ async function countUsagePeaks(db, window) {
|
|
|
9180
9215
|
import { and as and7, desc as desc3, eq as eq18, getTableColumns } from "drizzle-orm";
|
|
9181
9216
|
|
|
9182
9217
|
// src/shared/db/avgContextPerCycle.ts
|
|
9183
|
-
import { count as count2, sql as
|
|
9218
|
+
import { count as count2, sql as sql18 } from "drizzle-orm";
|
|
9184
9219
|
function avgContextPerCycle(db) {
|
|
9185
9220
|
return db.select({
|
|
9186
9221
|
window: phaseCycleContext.window,
|
|
9187
9222
|
resetsAt: phaseCycleContext.resetsAt,
|
|
9188
|
-
avgContextPct:
|
|
9223
|
+
avgContextPct: sql18`cast(avg(${phaseCycleContext.peakContextPct}) as double precision)`.as(
|
|
9189
9224
|
"avg_context_pct"
|
|
9190
9225
|
),
|
|
9191
9226
|
phaseCount: count2().as("phase_count")
|
|
@@ -9274,9 +9309,9 @@ function listUsageHistory(req, res) {
|
|
|
9274
9309
|
}
|
|
9275
9310
|
|
|
9276
9311
|
// src/shared/db/countItemUsageByOrigin.ts
|
|
9277
|
-
import { asc as asc8, desc as desc4, eq as eq19, sql as
|
|
9312
|
+
import { asc as asc8, desc as desc4, eq as eq19, sql as sql19 } from "drizzle-orm";
|
|
9278
9313
|
async function countItemUsageByOrigin(db) {
|
|
9279
|
-
const count10 =
|
|
9314
|
+
const count10 = sql19`count(distinct ${phaseUsage.itemId})::int`;
|
|
9280
9315
|
const rows = await db.select({ origin: items.origin, count: count10 }).from(items).innerJoin(phaseUsage, eq19(phaseUsage.itemId, items.id)).groupBy(items.origin).orderBy(desc4(count10), asc8(items.origin));
|
|
9281
9316
|
return rows.map((row3) => ({ origin: row3.origin, count: Number(row3.count) }));
|
|
9282
9317
|
}
|
|
@@ -9318,22 +9353,22 @@ function parseItemUsageSort(field, direction) {
|
|
|
9318
9353
|
}
|
|
9319
9354
|
|
|
9320
9355
|
// src/shared/db/itemUsageStats.ts
|
|
9321
|
-
import { eq as eq21, sql as
|
|
9356
|
+
import { eq as eq21, sql as sql20 } from "drizzle-orm";
|
|
9322
9357
|
function median(value) {
|
|
9323
|
-
return
|
|
9358
|
+
return sql20`coalesce(percentile_cont(0.5) within group (order by (${value})::double precision), 0)`;
|
|
9324
9359
|
}
|
|
9325
9360
|
async function itemUsageStats(db, options2) {
|
|
9326
9361
|
const totals = phaseUsageTotals(db);
|
|
9327
9362
|
const planned = planPhaseCounts(db);
|
|
9328
9363
|
const [row3] = await db.select({
|
|
9329
|
-
itemCount:
|
|
9330
|
-
doneCount:
|
|
9331
|
-
repoCount:
|
|
9364
|
+
itemCount: sql20`count(*)::int`,
|
|
9365
|
+
doneCount: sql20`count(*) filter (where ${items.status} = 'done')::int`,
|
|
9366
|
+
repoCount: sql20`count(distinct ${items.origin})::int`,
|
|
9332
9367
|
medianPhases: median(
|
|
9333
|
-
|
|
9368
|
+
sql20`coalesce(${planned.count}, ${totals.recordedPhases})`
|
|
9334
9369
|
),
|
|
9335
9370
|
medianActiveMs: median(totals.activeMs),
|
|
9336
|
-
medianTokens: median(
|
|
9371
|
+
medianTokens: median(sql20`${totals.tokensUp} + ${totals.tokensDown}`)
|
|
9337
9372
|
}).from(items).innerJoin(totals, eq21(totals.itemId, items.id)).leftJoin(planned, eq21(planned.itemId, items.id)).where(itemUsageWhere(options2));
|
|
9338
9373
|
return {
|
|
9339
9374
|
itemCount: Number(row3?.itemCount ?? 0),
|
|
@@ -9349,27 +9384,27 @@ async function itemUsageStats(db, options2) {
|
|
|
9349
9384
|
import { eq as eq22 } from "drizzle-orm";
|
|
9350
9385
|
|
|
9351
9386
|
// src/shared/db/itemUsageOrderBy.ts
|
|
9352
|
-
import { desc as desc5, sql as
|
|
9387
|
+
import { desc as desc5, sql as sql21 } from "drizzle-orm";
|
|
9353
9388
|
function itemUsageOrderBy(joins, sort = defaultItemUsageSort) {
|
|
9354
9389
|
const { totals, planned, lastPhase } = joins;
|
|
9355
9390
|
const sortable = {
|
|
9356
|
-
phases:
|
|
9357
|
-
active:
|
|
9358
|
-
tokens:
|
|
9359
|
-
peakContext:
|
|
9360
|
-
lastPhase:
|
|
9391
|
+
phases: sql21`coalesce(${planned.count}, ${totals.recordedPhases})`,
|
|
9392
|
+
active: sql21`${totals.activeMs}`,
|
|
9393
|
+
tokens: sql21`${totals.tokensUp} + ${totals.tokensDown}`,
|
|
9394
|
+
peakContext: sql21`${totals.peakContextPct}`,
|
|
9395
|
+
lastPhase: sql21`${lastPhase.at}`
|
|
9361
9396
|
};
|
|
9362
|
-
const order = sort.direction === "asc" ?
|
|
9363
|
-
return [
|
|
9397
|
+
const order = sort.direction === "asc" ? sql21`asc` : sql21`desc`;
|
|
9398
|
+
return [sql21`${sortable[sort.field]} ${order} nulls last`, desc5(items.id)];
|
|
9364
9399
|
}
|
|
9365
9400
|
|
|
9366
9401
|
// src/shared/db/lastPhaseActivity.ts
|
|
9367
|
-
import { sql as
|
|
9402
|
+
import { sql as sql22 } from "drizzle-orm";
|
|
9368
9403
|
function lastPhaseActivity(db) {
|
|
9369
9404
|
return db.select({
|
|
9370
9405
|
itemId: phaseSessions.itemId,
|
|
9371
|
-
at:
|
|
9372
|
-
atIso:
|
|
9406
|
+
at: sql22`max(${phaseSessions.createdAt})`.as("last_phase_at"),
|
|
9407
|
+
atIso: sql22`to_char(max(${phaseSessions.createdAt}) at time zone 'utc', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')`.as(
|
|
9373
9408
|
"last_phase_at_iso"
|
|
9374
9409
|
)
|
|
9375
9410
|
}).from(phaseSessions).groupBy(phaseSessions.itemId).as("last_phase_activity");
|
|
@@ -11206,15 +11241,22 @@ async function saveRepoConfig(orm, repoKey, config) {
|
|
|
11206
11241
|
});
|
|
11207
11242
|
}
|
|
11208
11243
|
|
|
11244
|
+
// src/shared/db/readUserConfig.ts
|
|
11245
|
+
async function readUserConfig(orm) {
|
|
11246
|
+
const [row3] = await orm.select().from(userConfig);
|
|
11247
|
+
return row3?.config ?? {};
|
|
11248
|
+
}
|
|
11249
|
+
|
|
11209
11250
|
// src/shared/writeRepoConfigCache.ts
|
|
11210
11251
|
import { mkdirSync as mkdirSync6, renameSync as renameSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
11211
11252
|
import { dirname as dirname12 } from "path";
|
|
11212
|
-
function writeRepoConfigCache(repos2) {
|
|
11253
|
+
function writeRepoConfigCache(repos2, user = {}) {
|
|
11213
11254
|
const path108 = repoConfigCachePath();
|
|
11214
11255
|
mkdirSync6(dirname12(path108), { recursive: true });
|
|
11215
11256
|
const cache7 = {
|
|
11216
11257
|
refreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11217
|
-
repos: repos2
|
|
11258
|
+
repos: repos2,
|
|
11259
|
+
user
|
|
11218
11260
|
};
|
|
11219
11261
|
const tmp = `${path108}.${process.pid}.tmp`;
|
|
11220
11262
|
writeFileSync5(tmp, JSON.stringify(cache7, null, 2));
|
|
@@ -11223,8 +11265,9 @@ function writeRepoConfigCache(repos2) {
|
|
|
11223
11265
|
|
|
11224
11266
|
// src/shared/refreshRepoConfigCache.ts
|
|
11225
11267
|
async function refreshRepoConfigCache(orm) {
|
|
11226
|
-
const
|
|
11227
|
-
|
|
11268
|
+
const db = orm ?? await getDb();
|
|
11269
|
+
const repos2 = await listRepoConfigs(db);
|
|
11270
|
+
writeRepoConfigCache(repos2, await readUserConfig(db));
|
|
11228
11271
|
return Object.keys(repos2).length;
|
|
11229
11272
|
}
|
|
11230
11273
|
|
|
@@ -11247,12 +11290,66 @@ async function applySharedRepoConfigSet(key, coerced, repoName, cwd = process.cw
|
|
|
11247
11290
|
return { ok: true, target: "repo", label };
|
|
11248
11291
|
}
|
|
11249
11292
|
|
|
11293
|
+
// src/shared/db/updateUserConfig.ts
|
|
11294
|
+
import { eq as eq24 } from "drizzle-orm";
|
|
11295
|
+
async function updateUserConfig(orm, update3) {
|
|
11296
|
+
return orm.transaction(async (tx) => {
|
|
11297
|
+
const [row3] = await tx.select().from(userConfig).where(eq24(userConfig.id, 1)).for("update");
|
|
11298
|
+
const outcome = update3(row3?.config ?? {});
|
|
11299
|
+
if (!outcome.ok) return outcome;
|
|
11300
|
+
if (Object.keys(outcome.config).length === 0) {
|
|
11301
|
+
await tx.delete(userConfig).where(eq24(userConfig.id, 1));
|
|
11302
|
+
return outcome;
|
|
11303
|
+
}
|
|
11304
|
+
await tx.insert(userConfig).values({ id: 1, config: outcome.config }).onConflictDoUpdate({
|
|
11305
|
+
target: userConfig.id,
|
|
11306
|
+
set: { config: outcome.config, updatedAt: /* @__PURE__ */ new Date() }
|
|
11307
|
+
});
|
|
11308
|
+
return outcome;
|
|
11309
|
+
});
|
|
11310
|
+
}
|
|
11311
|
+
|
|
11312
|
+
// src/commands/config/userDbKeyError.ts
|
|
11313
|
+
var DB_EXCLUDED_ROOTS = ["repos", "database"];
|
|
11314
|
+
function isNodeOnlyKey(key) {
|
|
11315
|
+
const root2 = key.split(".")[0];
|
|
11316
|
+
return isGlobalOnlyConfigKey(key) || DB_EXCLUDED_ROOTS.includes(root2);
|
|
11317
|
+
}
|
|
11318
|
+
function userDbKeyError(key, verb) {
|
|
11319
|
+
if (!isNodeOnlyKey(key)) return void 0;
|
|
11320
|
+
return {
|
|
11321
|
+
ok: false,
|
|
11322
|
+
errors: [
|
|
11323
|
+
`"${key}" can't be stored in user (db); it stays in user (node). ${verb} it in ~/.assist.yml with -g`
|
|
11324
|
+
]
|
|
11325
|
+
};
|
|
11326
|
+
}
|
|
11327
|
+
|
|
11328
|
+
// src/commands/config/applyUserConfigSet.ts
|
|
11329
|
+
async function applyUserConfigSet(key, coerced) {
|
|
11330
|
+
const nodeOnly = userDbKeyError(key, "Set");
|
|
11331
|
+
if (nodeOnly) return nodeOnly;
|
|
11332
|
+
const orm = await getDb();
|
|
11333
|
+
const outcome = await updateUserConfig(orm, (current) => {
|
|
11334
|
+
const config = setNestedValue(current, key, coerced);
|
|
11335
|
+
const validation = validateConfig(config, key);
|
|
11336
|
+
return validation.ok ? { ok: true, config, result: void 0 } : validation;
|
|
11337
|
+
});
|
|
11338
|
+
if (!outcome.ok) return outcome;
|
|
11339
|
+
await refreshRepoConfigCache(orm);
|
|
11340
|
+
return { ok: true, target: "user" };
|
|
11341
|
+
}
|
|
11342
|
+
|
|
11250
11343
|
// src/commands/sessions/web/applyScopedConfigSet.ts
|
|
11251
11344
|
async function applyScopedConfigSet(key, value, cwd, scope, globalConfigPath) {
|
|
11252
11345
|
if (scope === "repo") {
|
|
11253
11346
|
const result2 = await applySharedRepoConfigSet(key, value, void 0, cwd);
|
|
11254
11347
|
return result2.ok ? { ok: true, payload: { target: result2.target, repoKey: result2.label } } : result2;
|
|
11255
11348
|
}
|
|
11349
|
+
if (scope === "user") {
|
|
11350
|
+
const result2 = await applyUserConfigSet(key, value);
|
|
11351
|
+
return result2.ok ? { ok: true, payload: { target: result2.target } } : result2;
|
|
11352
|
+
}
|
|
11256
11353
|
const result = applyConfigSet(
|
|
11257
11354
|
key,
|
|
11258
11355
|
value,
|
|
@@ -11265,7 +11362,7 @@ async function applyScopedConfigSet(key, value, cwd, scope, globalConfigPath) {
|
|
|
11265
11362
|
|
|
11266
11363
|
// src/commands/config/ConfigWriteScope.ts
|
|
11267
11364
|
function isConfigWriteScope(value) {
|
|
11268
|
-
return value === "project" || value === "global" || value === "repo";
|
|
11365
|
+
return value === "project" || value === "global" || value === "repo" || value === "user";
|
|
11269
11366
|
}
|
|
11270
11367
|
|
|
11271
11368
|
// src/commands/sessions/web/parseConfigWriteRequest.ts
|
|
@@ -11452,6 +11549,22 @@ async function applySharedRepoConfigUnset(key, repoName, cwd = process.cwd()) {
|
|
|
11452
11549
|
return { ok: true, target: "repo", label, removed: unset.removed };
|
|
11453
11550
|
}
|
|
11454
11551
|
|
|
11552
|
+
// src/commands/config/applyUserConfigUnset.ts
|
|
11553
|
+
async function applyUserConfigUnset(key) {
|
|
11554
|
+
const nodeOnly = userDbKeyError(key, "Unset");
|
|
11555
|
+
if (nodeOnly) return nodeOnly;
|
|
11556
|
+
const orm = await getDb();
|
|
11557
|
+
const outcome = await updateUserConfig(orm, (current) => {
|
|
11558
|
+
const { config, removed } = unsetNestedValue(current, key);
|
|
11559
|
+
if (!removed) return { ok: true, config: current, result: false };
|
|
11560
|
+
const validation = validateConfig(config, key);
|
|
11561
|
+
return validation.ok ? { ok: true, config, result: true } : validation;
|
|
11562
|
+
});
|
|
11563
|
+
if (!outcome.ok) return outcome;
|
|
11564
|
+
if (outcome.result) await refreshRepoConfigCache(orm);
|
|
11565
|
+
return { ok: true, target: "user", removed: outcome.result };
|
|
11566
|
+
}
|
|
11567
|
+
|
|
11455
11568
|
// src/commands/sessions/web/applyScopedConfigUnset.ts
|
|
11456
11569
|
async function applyScopedConfigUnset(key, cwd, scope, globalConfigPath) {
|
|
11457
11570
|
if (scope === "repo") {
|
|
@@ -11465,6 +11578,13 @@ async function applyScopedConfigUnset(key, cwd, scope, globalConfigPath) {
|
|
|
11465
11578
|
}
|
|
11466
11579
|
} : result2;
|
|
11467
11580
|
}
|
|
11581
|
+
if (scope === "user") {
|
|
11582
|
+
const result2 = await applyUserConfigUnset(key);
|
|
11583
|
+
return result2.ok ? {
|
|
11584
|
+
ok: true,
|
|
11585
|
+
payload: { target: result2.target, removed: result2.removed }
|
|
11586
|
+
} : result2;
|
|
11587
|
+
}
|
|
11468
11588
|
const result = applyConfigUnset(
|
|
11469
11589
|
key,
|
|
11470
11590
|
scope === "global",
|
|
@@ -14963,8 +15083,8 @@ async function buildDump(tables, copyOut) {
|
|
|
14963
15083
|
// src/commands/backlog/dump/copyTableOut.ts
|
|
14964
15084
|
import { to as copyTo } from "pg-copy-streams";
|
|
14965
15085
|
async function copyTableOut(client, table) {
|
|
14966
|
-
const
|
|
14967
|
-
const stream = client.query(copyTo(
|
|
15086
|
+
const sql30 = `COPY ${table.name} (${table.columns.join(", ")}) TO STDOUT`;
|
|
15087
|
+
const stream = client.query(copyTo(sql30));
|
|
14968
15088
|
const chunks = [];
|
|
14969
15089
|
for await (const chunk of stream) {
|
|
14970
15090
|
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
@@ -15076,8 +15196,8 @@ async function backup({ out }) {
|
|
|
15076
15196
|
const dir = expandTilde(out ?? loadConfig().backup.dir);
|
|
15077
15197
|
await mkdir3(dir, { recursive: true });
|
|
15078
15198
|
const start2 = Date.now();
|
|
15079
|
-
const
|
|
15080
|
-
const filePath = resolve15(join42(dir, `backup-${
|
|
15199
|
+
const timestamp8 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
15200
|
+
const filePath = resolve15(join42(dir, `backup-${timestamp8}.dump`));
|
|
15081
15201
|
await exportBacklog(filePath);
|
|
15082
15202
|
const { size } = await stat4(filePath);
|
|
15083
15203
|
const durationMs = Date.now() - start2;
|
|
@@ -15428,11 +15548,11 @@ function registerActivityCommands(cmd) {
|
|
|
15428
15548
|
|
|
15429
15549
|
// src/commands/backlog/associateGithub.ts
|
|
15430
15550
|
import chalk43 from "chalk";
|
|
15431
|
-
import { eq as
|
|
15551
|
+
import { eq as eq26 } from "drizzle-orm";
|
|
15432
15552
|
|
|
15433
15553
|
// src/commands/backlog/beginAssociation.ts
|
|
15434
15554
|
import chalk42 from "chalk";
|
|
15435
|
-
import { eq as
|
|
15555
|
+
import { eq as eq25 } from "drizzle-orm";
|
|
15436
15556
|
async function beginAssociation(id, options2, clearPatch, label) {
|
|
15437
15557
|
const found = await findOneItem(id);
|
|
15438
15558
|
if (!found) {
|
|
@@ -15442,7 +15562,7 @@ async function beginAssociation(id, options2, clearPatch, label) {
|
|
|
15442
15562
|
const { orm } = found;
|
|
15443
15563
|
const itemId2 = found.item.id;
|
|
15444
15564
|
if (options2.clear) {
|
|
15445
|
-
await orm.update(items).set(clearPatch).where(
|
|
15565
|
+
await orm.update(items).set(clearPatch).where(eq25(items.id, itemId2));
|
|
15446
15566
|
console.log(
|
|
15447
15567
|
chalk42.green(
|
|
15448
15568
|
`Cleared ${label} association on item ${formatItemId(itemId2)}.`
|
|
@@ -15510,7 +15630,7 @@ async function associateGithub(id, issue, options2) {
|
|
|
15510
15630
|
return;
|
|
15511
15631
|
}
|
|
15512
15632
|
const title = fetchGithubIssueTitle(normalized);
|
|
15513
|
-
await orm.update(items).set({ githubIssue: normalized, jiraKey: null }).where(
|
|
15633
|
+
await orm.update(items).set({ githubIssue: normalized, jiraKey: null }).where(eq26(items.id, itemId2));
|
|
15514
15634
|
console.log(
|
|
15515
15635
|
chalk43.green(`Associated ${normalized} with item ${formatItemId(itemId2)}.`),
|
|
15516
15636
|
title ? chalk43.dim(`(${title})`) : ""
|
|
@@ -15524,7 +15644,7 @@ function registerAssociateGithubCommand(cmd) {
|
|
|
15524
15644
|
|
|
15525
15645
|
// src/commands/backlog/associateJira.ts
|
|
15526
15646
|
import chalk45 from "chalk";
|
|
15527
|
-
import { eq as
|
|
15647
|
+
import { eq as eq27 } from "drizzle-orm";
|
|
15528
15648
|
|
|
15529
15649
|
// src/commands/jira/fetchIssue.ts
|
|
15530
15650
|
import { execSync as execSync17 } from "child_process";
|
|
@@ -15589,7 +15709,7 @@ async function associateJira(id, key, options2) {
|
|
|
15589
15709
|
const parsed = fetchIssue(normalized, "summary");
|
|
15590
15710
|
const fields = parsed?.fields;
|
|
15591
15711
|
const summary = fields?.summary;
|
|
15592
|
-
await orm.update(items).set({ jiraKey: normalized, githubIssue: null }).where(
|
|
15712
|
+
await orm.update(items).set({ jiraKey: normalized, githubIssue: null }).where(eq27(items.id, itemId2));
|
|
15593
15713
|
console.log(
|
|
15594
15714
|
chalk45.green(`Associated ${normalized} with item ${formatItemId(itemId2)}.`),
|
|
15595
15715
|
summary ? chalk45.dim(`(${summary})`) : ""
|
|
@@ -15871,8 +15991,8 @@ async function confirmReplace(client, tables, incoming, fromStdin) {
|
|
|
15871
15991
|
import { finished } from "stream/promises";
|
|
15872
15992
|
import { from as copyFrom } from "pg-copy-streams";
|
|
15873
15993
|
async function copyTableIn(client, table, data) {
|
|
15874
|
-
const
|
|
15875
|
-
const stream = client.query(copyFrom(
|
|
15994
|
+
const sql30 = `COPY ${table.name} (${table.columns.join(", ")}) FROM STDIN`;
|
|
15995
|
+
const stream = client.query(copyFrom(sql30));
|
|
15876
15996
|
stream.end(data);
|
|
15877
15997
|
await finished(stream);
|
|
15878
15998
|
}
|
|
@@ -15974,15 +16094,15 @@ function isClaudeCode() {
|
|
|
15974
16094
|
}
|
|
15975
16095
|
|
|
15976
16096
|
// src/commands/backlog/insertPhaseAt.ts
|
|
15977
|
-
import { eq as
|
|
16097
|
+
import { eq as eq29 } from "drizzle-orm";
|
|
15978
16098
|
|
|
15979
16099
|
// src/commands/backlog/shiftPhasesUp.ts
|
|
15980
|
-
import { and as and9, desc as desc6, eq as
|
|
16100
|
+
import { and as and9, desc as desc6, eq as eq28, gte } from "drizzle-orm";
|
|
15981
16101
|
async function shiftPhasesUp(db, itemId2, fromIdx) {
|
|
15982
|
-
const toShift = await db.select({ idx: planPhases.idx }).from(planPhases).where(and9(
|
|
16102
|
+
const toShift = await db.select({ idx: planPhases.idx }).from(planPhases).where(and9(eq28(planPhases.itemId, itemId2), gte(planPhases.idx, fromIdx))).orderBy(desc6(planPhases.idx));
|
|
15983
16103
|
for (const p of toShift) {
|
|
15984
|
-
await db.update(planTasks).set({ phaseIdx: p.idx + 1 }).where(and9(
|
|
15985
|
-
await db.update(planPhases).set({ idx: p.idx + 1 }).where(and9(
|
|
16104
|
+
await db.update(planTasks).set({ phaseIdx: p.idx + 1 }).where(and9(eq28(planTasks.itemId, itemId2), eq28(planTasks.phaseIdx, p.idx)));
|
|
16105
|
+
await db.update(planPhases).set({ idx: p.idx + 1 }).where(and9(eq28(planPhases.itemId, itemId2), eq28(planPhases.idx, p.idx)));
|
|
15986
16106
|
}
|
|
15987
16107
|
}
|
|
15988
16108
|
|
|
@@ -15995,7 +16115,7 @@ async function insertPhaseAt(orm, itemId2, phaseIdx, name, tasks, manualChecks,
|
|
|
15995
16115
|
await tx.insert(planTasks).values(tasks.map((task, i) => ({ itemId: itemId2, phaseIdx, idx: i, task })));
|
|
15996
16116
|
}
|
|
15997
16117
|
if (currentPhase !== void 0 && currentPhase - 1 >= phaseIdx) {
|
|
15998
|
-
await tx.update(items).set({ currentPhase: phaseIdx + 1 }).where(
|
|
16118
|
+
await tx.update(items).set({ currentPhase: phaseIdx + 1 }).where(eq29(items.id, itemId2));
|
|
15999
16119
|
}
|
|
16000
16120
|
});
|
|
16001
16121
|
}
|
|
@@ -16152,9 +16272,9 @@ import chalk56 from "chalk";
|
|
|
16152
16272
|
|
|
16153
16273
|
// src/commands/backlog/resolveInsertPosition.ts
|
|
16154
16274
|
import chalk55 from "chalk";
|
|
16155
|
-
import { count as count3, eq as
|
|
16275
|
+
import { count as count3, eq as eq30 } from "drizzle-orm";
|
|
16156
16276
|
async function resolveInsertPosition(orm, itemId2, position) {
|
|
16157
|
-
const [row3] = await orm.select({ cnt: count3() }).from(planPhases).where(
|
|
16277
|
+
const [row3] = await orm.select({ cnt: count3() }).from(planPhases).where(eq30(planPhases.itemId, itemId2));
|
|
16158
16278
|
const phaseCount = row3?.cnt ?? 0;
|
|
16159
16279
|
if (position === void 0) return phaseCount;
|
|
16160
16280
|
const pos = Number.parseInt(position, 10);
|
|
@@ -16574,9 +16694,9 @@ function hasCycle(adjacency, fromId, toId) {
|
|
|
16574
16694
|
}
|
|
16575
16695
|
|
|
16576
16696
|
// src/commands/backlog/loadDependencyGraph.ts
|
|
16577
|
-
import { eq as
|
|
16697
|
+
import { eq as eq31 } from "drizzle-orm";
|
|
16578
16698
|
async function loadDependencyGraph(orm) {
|
|
16579
|
-
const rows = await orm.select({ itemId: links.itemId, targetId: links.targetId }).from(links).where(
|
|
16699
|
+
const rows = await orm.select({ itemId: links.itemId, targetId: links.targetId }).from(links).where(eq31(links.type, "depends-on"));
|
|
16580
16700
|
const graph = /* @__PURE__ */ new Map();
|
|
16581
16701
|
for (const { itemId: itemId2, targetId } of rows) {
|
|
16582
16702
|
const bucket = graph.get(itemId2);
|
|
@@ -16643,7 +16763,7 @@ async function link(fromId, toId, opts) {
|
|
|
16643
16763
|
|
|
16644
16764
|
// src/commands/backlog/unlink.ts
|
|
16645
16765
|
import chalk64 from "chalk";
|
|
16646
|
-
import { and as and10, eq as
|
|
16766
|
+
import { and as and10, eq as eq32 } from "drizzle-orm";
|
|
16647
16767
|
async function unlink(fromId, toId) {
|
|
16648
16768
|
const fromNum = parseItemId(fromId);
|
|
16649
16769
|
const toNum = parseItemId(toId);
|
|
@@ -16667,7 +16787,7 @@ async function unlink(fromId, toId) {
|
|
|
16667
16787
|
);
|
|
16668
16788
|
return;
|
|
16669
16789
|
}
|
|
16670
|
-
await orm.delete(links).where(and10(
|
|
16790
|
+
await orm.delete(links).where(and10(eq32(links.itemId, fromNum), eq32(links.targetId, toNum)));
|
|
16671
16791
|
console.log(
|
|
16672
16792
|
chalk64.green(
|
|
16673
16793
|
`Removed link from ${formatItemId(fromNum)} to ${formatItemId(toNum)}.`
|
|
@@ -16687,7 +16807,7 @@ function registerLinkCommands(cmd) {
|
|
|
16687
16807
|
|
|
16688
16808
|
// src/commands/backlog/moveRepo.ts
|
|
16689
16809
|
import chalk66 from "chalk";
|
|
16690
|
-
import { eq as
|
|
16810
|
+
import { eq as eq34 } from "drizzle-orm";
|
|
16691
16811
|
|
|
16692
16812
|
// src/commands/backlog/move-repo/confirmMove.ts
|
|
16693
16813
|
import chalk65 from "chalk";
|
|
@@ -16702,9 +16822,9 @@ async function confirmMove(cnt, oldOrigin, newOrigin) {
|
|
|
16702
16822
|
}
|
|
16703
16823
|
|
|
16704
16824
|
// src/commands/backlog/move-repo/countByOrigin.ts
|
|
16705
|
-
import { count as count4, eq as
|
|
16825
|
+
import { count as count4, eq as eq33 } from "drizzle-orm";
|
|
16706
16826
|
async function countByOrigin(orm, origin) {
|
|
16707
|
-
const [{ cnt }] = await orm.select({ cnt: count4() }).from(items).where(
|
|
16827
|
+
const [{ cnt }] = await orm.select({ cnt: count4() }).from(items).where(eq33(items.origin, origin));
|
|
16708
16828
|
return cnt;
|
|
16709
16829
|
}
|
|
16710
16830
|
|
|
@@ -16747,7 +16867,7 @@ async function moveRepo(oldOriginRaw, newOriginRaw, options2 = {}) {
|
|
|
16747
16867
|
console.log(chalk66.yellow("Move cancelled; no changes made."));
|
|
16748
16868
|
return;
|
|
16749
16869
|
}
|
|
16750
|
-
await orm.update(items).set({ origin: newOrigin }).where(
|
|
16870
|
+
await orm.update(items).set({ origin: newOrigin }).where(eq34(items.origin, oldOrigin));
|
|
16751
16871
|
console.log(
|
|
16752
16872
|
chalk66.green(
|
|
16753
16873
|
`Moved ${pluralItems(cnt)} from "${oldOrigin}" to "${newOrigin}".`
|
|
@@ -16911,9 +17031,9 @@ function processStartedAt(pid) {
|
|
|
16911
17031
|
|
|
16912
17032
|
// src/commands/backlog/isStaleLock.ts
|
|
16913
17033
|
var clockSlackMs = 5e3;
|
|
16914
|
-
function isStaleLock(pid,
|
|
16915
|
-
if (typeof
|
|
16916
|
-
const lockedAt = Date.parse(
|
|
17034
|
+
function isStaleLock(pid, timestamp8) {
|
|
17035
|
+
if (typeof timestamp8 !== "string") return false;
|
|
17036
|
+
const lockedAt = Date.parse(timestamp8);
|
|
16917
17037
|
if (Number.isNaN(lockedAt)) return false;
|
|
16918
17038
|
if (lockedAt < bootedAt() - clockSlackMs) return true;
|
|
16919
17039
|
const startedAt = processStartedAt(pid);
|
|
@@ -17219,12 +17339,12 @@ function message(error) {
|
|
|
17219
17339
|
import chalk70 from "chalk";
|
|
17220
17340
|
|
|
17221
17341
|
// src/shared/db/findPhaseBySessionId.ts
|
|
17222
|
-
import { and as and11, eq as
|
|
17342
|
+
import { and as and11, eq as eq35 } from "drizzle-orm";
|
|
17223
17343
|
async function findPhaseBySessionId(db, itemId2, claudeSessionId) {
|
|
17224
17344
|
const rows = await db.select({ phaseIdx: phaseUsage.phaseIdx }).from(phaseUsage).where(
|
|
17225
17345
|
and11(
|
|
17226
|
-
|
|
17227
|
-
|
|
17346
|
+
eq35(phaseUsage.itemId, itemId2),
|
|
17347
|
+
eq35(phaseUsage.claudeSessionId, claudeSessionId)
|
|
17228
17348
|
)
|
|
17229
17349
|
).limit(1);
|
|
17230
17350
|
return rows[0]?.phaseIdx;
|
|
@@ -17834,7 +17954,7 @@ import { randomUUID as randomUUID6 } from "crypto";
|
|
|
17834
17954
|
import os4 from "os";
|
|
17835
17955
|
|
|
17836
17956
|
// src/shared/db/recordPhaseSession.ts
|
|
17837
|
-
import { sql as
|
|
17957
|
+
import { sql as sql23 } from "drizzle-orm";
|
|
17838
17958
|
async function recordPhaseSession(db, itemId2, phaseIdx, claudeSessionId, hostname2, osUser) {
|
|
17839
17959
|
await db.insert(phaseSessions).values({ itemId: itemId2, phaseIdx, claudeSessionId, hostname: hostname2, osUser }).onConflictDoUpdate({
|
|
17840
17960
|
target: [
|
|
@@ -17843,7 +17963,7 @@ async function recordPhaseSession(db, itemId2, phaseIdx, claudeSessionId, hostna
|
|
|
17843
17963
|
phaseSessions.claudeSessionId
|
|
17844
17964
|
],
|
|
17845
17965
|
set: { hostname: hostname2, osUser },
|
|
17846
|
-
setWhere:
|
|
17966
|
+
setWhere: sql23`${phaseSessions.hostname} = 'unknown'`
|
|
17847
17967
|
});
|
|
17848
17968
|
}
|
|
17849
17969
|
|
|
@@ -18704,10 +18824,10 @@ async function start(id) {
|
|
|
18704
18824
|
|
|
18705
18825
|
// src/commands/backlog/stop.ts
|
|
18706
18826
|
import chalk93 from "chalk";
|
|
18707
|
-
import { and as and12, eq as
|
|
18827
|
+
import { and as and12, eq as eq36 } from "drizzle-orm";
|
|
18708
18828
|
async function stop() {
|
|
18709
18829
|
const { orm } = await getReady();
|
|
18710
|
-
const stopped = await orm.update(items).set({ status: "todo", currentPhase: 1 }).where(and12(
|
|
18830
|
+
const stopped = await orm.update(items).set({ status: "todo", currentPhase: 1 }).where(and12(eq36(items.status, "in-progress"), eq36(items.origin, getOrigin()))).returning({ id: items.id, name: items.name });
|
|
18711
18831
|
if (stopped.length === 0) {
|
|
18712
18832
|
console.log(chalk93.yellow("No in-progress items to stop."));
|
|
18713
18833
|
return;
|
|
@@ -18765,20 +18885,20 @@ function registerStatusCommands(cmd) {
|
|
|
18765
18885
|
|
|
18766
18886
|
// src/commands/backlog/movePhase.ts
|
|
18767
18887
|
import chalk96 from "chalk";
|
|
18768
|
-
import { count as count6, eq as
|
|
18888
|
+
import { count as count6, eq as eq39 } from "drizzle-orm";
|
|
18769
18889
|
|
|
18770
18890
|
// src/commands/backlog/reorderPhaseRows.ts
|
|
18771
|
-
import { and as and14, asc as asc10, eq as
|
|
18891
|
+
import { and as and14, asc as asc10, eq as eq38 } from "drizzle-orm";
|
|
18772
18892
|
|
|
18773
18893
|
// src/commands/backlog/reindexPhases.ts
|
|
18774
|
-
import { and as and13, asc as asc9, count as count5, eq as
|
|
18894
|
+
import { and as and13, asc as asc9, count as count5, eq as eq37 } from "drizzle-orm";
|
|
18775
18895
|
async function reindexPhases(db, itemId2) {
|
|
18776
|
-
const remaining = await db.select({ idx: planPhases.idx }).from(planPhases).where(
|
|
18896
|
+
const remaining = await db.select({ idx: planPhases.idx }).from(planPhases).where(eq37(planPhases.itemId, itemId2)).orderBy(asc9(planPhases.idx));
|
|
18777
18897
|
for (let i = 0; i < remaining.length; i++) {
|
|
18778
18898
|
const oldIdx = remaining[i].idx;
|
|
18779
18899
|
if (oldIdx === i) continue;
|
|
18780
|
-
await db.update(planTasks).set({ phaseIdx: i }).where(and13(
|
|
18781
|
-
await db.update(planPhases).set({ idx: i }).where(and13(
|
|
18900
|
+
await db.update(planTasks).set({ phaseIdx: i }).where(and13(eq37(planTasks.itemId, itemId2), eq37(planTasks.phaseIdx, oldIdx)));
|
|
18901
|
+
await db.update(planPhases).set({ idx: i }).where(and13(eq37(planPhases.itemId, itemId2), eq37(planPhases.idx, oldIdx)));
|
|
18782
18902
|
}
|
|
18783
18903
|
}
|
|
18784
18904
|
async function adjustCurrentPhase(db, item, removedIdx) {
|
|
@@ -18786,24 +18906,24 @@ async function adjustCurrentPhase(db, item, removedIdx) {
|
|
|
18786
18906
|
if (currentPhase === void 0) return;
|
|
18787
18907
|
const currentIdx = currentPhase - 1;
|
|
18788
18908
|
if (removedIdx < currentIdx) {
|
|
18789
|
-
await db.update(items).set({ currentPhase: currentPhase - 1 }).where(
|
|
18909
|
+
await db.update(items).set({ currentPhase: currentPhase - 1 }).where(eq37(items.id, item.id));
|
|
18790
18910
|
return;
|
|
18791
18911
|
}
|
|
18792
18912
|
if (removedIdx !== currentIdx) return;
|
|
18793
|
-
const [row3] = await db.select({ cnt: count5() }).from(planPhases).where(
|
|
18913
|
+
const [row3] = await db.select({ cnt: count5() }).from(planPhases).where(eq37(planPhases.itemId, item.id));
|
|
18794
18914
|
const cnt = row3?.cnt ?? 0;
|
|
18795
|
-
await db.update(items).set({ currentPhase: cnt === 0 ? null : Math.min(currentPhase, cnt) }).where(
|
|
18915
|
+
await db.update(items).set({ currentPhase: cnt === 0 ? null : Math.min(currentPhase, cnt) }).where(eq37(items.id, item.id));
|
|
18796
18916
|
}
|
|
18797
18917
|
|
|
18798
18918
|
// src/commands/backlog/reorderPhaseRows.ts
|
|
18799
18919
|
async function reorderPhaseRows(orm, itemId2, fromIdx, toIdx) {
|
|
18800
18920
|
await orm.transaction(async (tx) => {
|
|
18801
|
-
const [phaseRow] = await tx.select({ name: planPhases.name, manualChecks: planPhases.manualChecks }).from(planPhases).where(and14(
|
|
18802
|
-
const tasks = await tx.select({ idx: planTasks.idx, task: planTasks.task }).from(planTasks).where(and14(
|
|
18921
|
+
const [phaseRow] = await tx.select({ name: planPhases.name, manualChecks: planPhases.manualChecks }).from(planPhases).where(and14(eq38(planPhases.itemId, itemId2), eq38(planPhases.idx, fromIdx)));
|
|
18922
|
+
const tasks = await tx.select({ idx: planTasks.idx, task: planTasks.task }).from(planTasks).where(and14(eq38(planTasks.itemId, itemId2), eq38(planTasks.phaseIdx, fromIdx))).orderBy(asc10(planTasks.idx));
|
|
18803
18923
|
await tx.delete(planTasks).where(
|
|
18804
|
-
and14(
|
|
18924
|
+
and14(eq38(planTasks.itemId, itemId2), eq38(planTasks.phaseIdx, fromIdx))
|
|
18805
18925
|
);
|
|
18806
|
-
await tx.delete(planPhases).where(and14(
|
|
18926
|
+
await tx.delete(planPhases).where(and14(eq38(planPhases.itemId, itemId2), eq38(planPhases.idx, fromIdx)));
|
|
18807
18927
|
await reindexPhases(tx, itemId2);
|
|
18808
18928
|
await shiftPhasesUp(tx, itemId2, toIdx);
|
|
18809
18929
|
await tx.insert(planPhases).values({
|
|
@@ -18844,7 +18964,7 @@ async function movePhase(id, from, to) {
|
|
|
18844
18964
|
if (!found) return;
|
|
18845
18965
|
const { orm, item } = found;
|
|
18846
18966
|
const itemId2 = item.id;
|
|
18847
|
-
const [row3] = await orm.select({ cnt: count6() }).from(planPhases).where(
|
|
18967
|
+
const [row3] = await orm.select({ cnt: count6() }).from(planPhases).where(eq39(planPhases.itemId, itemId2));
|
|
18848
18968
|
const phaseCount = row3?.cnt ?? 0;
|
|
18849
18969
|
const fromIdx = toIndex2(from, phaseCount);
|
|
18850
18970
|
if (fromIdx === void 0) return;
|
|
@@ -18860,22 +18980,22 @@ async function movePhase(id, from, to) {
|
|
|
18860
18980
|
import chalk98 from "chalk";
|
|
18861
18981
|
|
|
18862
18982
|
// src/commands/backlog/applyPhaseUpdate.ts
|
|
18863
|
-
import { and as and15, eq as
|
|
18983
|
+
import { and as and15, eq as eq40 } from "drizzle-orm";
|
|
18864
18984
|
async function applyPhaseUpdate(orm, itemId2, phaseIdx, fields) {
|
|
18865
18985
|
await orm.transaction(async (tx) => {
|
|
18866
18986
|
if (fields.name) {
|
|
18867
18987
|
await tx.update(planPhases).set({ name: fields.name }).where(
|
|
18868
|
-
and15(
|
|
18988
|
+
and15(eq40(planPhases.itemId, itemId2), eq40(planPhases.idx, phaseIdx))
|
|
18869
18989
|
);
|
|
18870
18990
|
}
|
|
18871
18991
|
if (fields.manualCheck) {
|
|
18872
18992
|
await tx.update(planPhases).set({ manualChecks: JSON.stringify(fields.manualCheck) }).where(
|
|
18873
|
-
and15(
|
|
18993
|
+
and15(eq40(planPhases.itemId, itemId2), eq40(planPhases.idx, phaseIdx))
|
|
18874
18994
|
);
|
|
18875
18995
|
}
|
|
18876
18996
|
if (fields.task) {
|
|
18877
18997
|
await tx.delete(planTasks).where(
|
|
18878
|
-
and15(
|
|
18998
|
+
and15(eq40(planTasks.itemId, itemId2), eq40(planTasks.phaseIdx, phaseIdx))
|
|
18879
18999
|
);
|
|
18880
19000
|
if (fields.task.length) {
|
|
18881
19001
|
await tx.insert(planTasks).values(
|
|
@@ -18893,14 +19013,14 @@ async function applyPhaseUpdate(orm, itemId2, phaseIdx, fields) {
|
|
|
18893
19013
|
|
|
18894
19014
|
// src/commands/backlog/findPhase.ts
|
|
18895
19015
|
import chalk97 from "chalk";
|
|
18896
|
-
import { and as and16, count as count7, eq as
|
|
19016
|
+
import { and as and16, count as count7, eq as eq41 } from "drizzle-orm";
|
|
18897
19017
|
async function findPhase(id, phase) {
|
|
18898
19018
|
const found = await findOneItem(id);
|
|
18899
19019
|
if (!found) return void 0;
|
|
18900
19020
|
const { orm, item } = found;
|
|
18901
19021
|
const itemId2 = item.id;
|
|
18902
19022
|
const phaseIdx = Number.parseInt(phase, 10) - 1;
|
|
18903
|
-
const [row3] = await orm.select({ cnt: count7() }).from(planPhases).where(and16(
|
|
19023
|
+
const [row3] = await orm.select({ cnt: count7() }).from(planPhases).where(and16(eq41(planPhases.itemId, itemId2), eq41(planPhases.idx, phaseIdx)));
|
|
18904
19024
|
if (!row3 || row3.cnt === 0) {
|
|
18905
19025
|
console.log(
|
|
18906
19026
|
chalk97.red(
|
|
@@ -19073,16 +19193,16 @@ function registerUpdatePhaseCommand(cmd) {
|
|
|
19073
19193
|
|
|
19074
19194
|
// src/commands/backlog/removePhase.ts
|
|
19075
19195
|
import chalk99 from "chalk";
|
|
19076
|
-
import { and as and17, eq as
|
|
19196
|
+
import { and as and17, eq as eq42 } from "drizzle-orm";
|
|
19077
19197
|
async function removePhase(id, phase) {
|
|
19078
19198
|
const found = await findPhase(id, phase);
|
|
19079
19199
|
if (!found) return;
|
|
19080
19200
|
const { item, orm, itemId: itemId2, phaseIdx } = found;
|
|
19081
19201
|
await orm.transaction(async (tx) => {
|
|
19082
19202
|
await tx.delete(planTasks).where(
|
|
19083
|
-
and17(
|
|
19203
|
+
and17(eq42(planTasks.itemId, itemId2), eq42(planTasks.phaseIdx, phaseIdx))
|
|
19084
19204
|
);
|
|
19085
|
-
await tx.delete(planPhases).where(and17(
|
|
19205
|
+
await tx.delete(planPhases).where(and17(eq42(planPhases.itemId, itemId2), eq42(planPhases.idx, phaseIdx)));
|
|
19086
19206
|
await reindexPhases(tx, itemId2);
|
|
19087
19207
|
await adjustCurrentPhase(tx, item, phaseIdx);
|
|
19088
19208
|
});
|
|
@@ -19095,7 +19215,7 @@ async function removePhase(id, phase) {
|
|
|
19095
19215
|
|
|
19096
19216
|
// src/commands/backlog/update/update.ts
|
|
19097
19217
|
import chalk103 from "chalk";
|
|
19098
|
-
import { eq as
|
|
19218
|
+
import { eq as eq43 } from "drizzle-orm";
|
|
19099
19219
|
|
|
19100
19220
|
// src/commands/backlog/update/buildUpdateValues.ts
|
|
19101
19221
|
import chalk100 from "chalk";
|
|
@@ -19206,7 +19326,7 @@ async function update(id, options2) {
|
|
|
19206
19326
|
if (!built) return;
|
|
19207
19327
|
const { orm } = found;
|
|
19208
19328
|
const itemId2 = found.item.id;
|
|
19209
|
-
await orm.update(items).set(built.set).where(
|
|
19329
|
+
await orm.update(items).set(built.set).where(eq43(items.id, itemId2));
|
|
19210
19330
|
console.log(
|
|
19211
19331
|
chalk103.green(`Updated ${built.fields} on item ${formatItemId(itemId2)}.`)
|
|
19212
19332
|
);
|
|
@@ -19252,7 +19372,7 @@ function readPlanUpdate(source) {
|
|
|
19252
19372
|
}
|
|
19253
19373
|
|
|
19254
19374
|
// src/commands/backlog/updatePlan/replacePlan.ts
|
|
19255
|
-
import { eq as
|
|
19375
|
+
import { eq as eq44 } from "drizzle-orm";
|
|
19256
19376
|
|
|
19257
19377
|
// src/commands/backlog/updatePlan/clampCurrentPhase.ts
|
|
19258
19378
|
function clampCurrentPhase(currentPhase, phaseCount) {
|
|
@@ -19263,8 +19383,8 @@ function clampCurrentPhase(currentPhase, phaseCount) {
|
|
|
19263
19383
|
// src/commands/backlog/updatePlan/replacePlan.ts
|
|
19264
19384
|
async function replacePlan(orm, itemId2, phases, currentPhase) {
|
|
19265
19385
|
await orm.transaction(async (tx) => {
|
|
19266
|
-
await tx.delete(planTasks).where(
|
|
19267
|
-
await tx.delete(planPhases).where(
|
|
19386
|
+
await tx.delete(planTasks).where(eq44(planTasks.itemId, itemId2));
|
|
19387
|
+
await tx.delete(planPhases).where(eq44(planPhases.itemId, itemId2));
|
|
19268
19388
|
if (phases.length > 0) {
|
|
19269
19389
|
await tx.insert(planPhases).values(
|
|
19270
19390
|
phases.map((phase, idx) => ({
|
|
@@ -19282,7 +19402,7 @@ async function replacePlan(orm, itemId2, phases, currentPhase) {
|
|
|
19282
19402
|
if (currentPhase === void 0) return;
|
|
19283
19403
|
const clamped = clampCurrentPhase(currentPhase, phases.length);
|
|
19284
19404
|
if (clamped === currentPhase) return;
|
|
19285
|
-
await tx.update(items).set({ currentPhase: clamped }).where(
|
|
19405
|
+
await tx.update(items).set({ currentPhase: clamped }).where(eq44(items.id, itemId2));
|
|
19286
19406
|
});
|
|
19287
19407
|
}
|
|
19288
19408
|
|
|
@@ -23018,8 +23138,8 @@ async function setDbBackedConfigKey(key, value, useRepo) {
|
|
|
23018
23138
|
|
|
23019
23139
|
// src/commands/config/setFileConfigKey.ts
|
|
23020
23140
|
import chalk134 from "chalk";
|
|
23021
|
-
async function setFileConfigKey({ key, useRepo, repoName, global }, coerced) {
|
|
23022
|
-
const target = useRepo ? `repo: ${await applyRepoOrExit(key, coerced, repoName)}` : applyOrExit(key, coerced, global);
|
|
23141
|
+
async function setFileConfigKey({ key, useRepo, repoName, global, user }, coerced) {
|
|
23142
|
+
const target = useRepo ? `repo: ${await applyRepoOrExit(key, coerced, repoName)}` : user ? await applyUserOrExit(key, coerced) : applyOrExit(key, coerced, global);
|
|
23023
23143
|
const shown = JSON.stringify(maskConfigKeySecrets(key, coerced));
|
|
23024
23144
|
console.log(chalk134.green(`Set ${key} = ${shown} (${target})`));
|
|
23025
23145
|
}
|
|
@@ -23028,20 +23148,30 @@ function applyOrExit(key, coerced, global) {
|
|
|
23028
23148
|
if (!result.ok) exitWithConfigErrors(result.errors);
|
|
23029
23149
|
return result.target;
|
|
23030
23150
|
}
|
|
23151
|
+
async function applyUserOrExit(key, coerced) {
|
|
23152
|
+
const result = await applyUserConfigSet(key, coerced);
|
|
23153
|
+
if (!result.ok) exitWithConfigErrors(result.errors);
|
|
23154
|
+
return "user (db)";
|
|
23155
|
+
}
|
|
23031
23156
|
async function applyRepoOrExit(key, coerced, repoName) {
|
|
23032
23157
|
const result = await applySharedRepoConfigSet(key, coerced, repoName);
|
|
23033
23158
|
if (!result.ok) exitWithConfigErrors(result.errors);
|
|
23034
23159
|
return result.label;
|
|
23035
23160
|
}
|
|
23036
23161
|
|
|
23162
|
+
// src/commands/config/scopeOptionsError.ts
|
|
23163
|
+
function scopeOptionsError(options2, repoAction) {
|
|
23164
|
+
if (options2.user && (options2.global || options2.repo !== void 0))
|
|
23165
|
+
return "--user writes user (db); drop -g and --repo";
|
|
23166
|
+
if (options2.repo !== void 0 && !options2.global)
|
|
23167
|
+
return `--repo ${repoAction} the global config; add -g (e.g. -g --repo)`;
|
|
23168
|
+
return void 0;
|
|
23169
|
+
}
|
|
23170
|
+
|
|
23037
23171
|
// src/commands/config/configSet.ts
|
|
23038
23172
|
async function configSet(key, value, options2 = {}) {
|
|
23039
|
-
|
|
23040
|
-
|
|
23041
|
-
chalk135.red("--repo writes to the global config; add -g (e.g. -g --repo)")
|
|
23042
|
-
);
|
|
23043
|
-
process.exit(1);
|
|
23044
|
-
}
|
|
23173
|
+
const scopeError = scopeOptionsError(options2, "writes to");
|
|
23174
|
+
if (scopeError) exitWithConfigErrors([scopeError]);
|
|
23045
23175
|
const resolved = resolveRepoTarget(key, value, options2.repo);
|
|
23046
23176
|
if (resolved.value === void 0) {
|
|
23047
23177
|
console.error(chalk135.red(`Missing required argument for '${resolved.key}'`));
|
|
@@ -23052,7 +23182,11 @@ async function configSet(key, value, options2 = {}) {
|
|
|
23052
23182
|
if (isDbBackedConfigKey(resolved.key))
|
|
23053
23183
|
return setDbBackedConfigKey(resolved.key, coercion.value, resolved.useRepo);
|
|
23054
23184
|
await setFileConfigKey(
|
|
23055
|
-
{
|
|
23185
|
+
{
|
|
23186
|
+
...resolved,
|
|
23187
|
+
global: options2.global ?? false,
|
|
23188
|
+
user: options2.user ?? false
|
|
23189
|
+
},
|
|
23056
23190
|
coercion.value
|
|
23057
23191
|
);
|
|
23058
23192
|
}
|
|
@@ -23086,9 +23220,10 @@ async function unsetFileConfigKey({
|
|
|
23086
23220
|
key,
|
|
23087
23221
|
useRepo,
|
|
23088
23222
|
repoName,
|
|
23089
|
-
global
|
|
23223
|
+
global,
|
|
23224
|
+
user
|
|
23090
23225
|
}) {
|
|
23091
|
-
const result = useRepo ? await applySharedRepoConfigUnset(key, repoName) : applyConfigUnset(key, global);
|
|
23226
|
+
const result = useRepo ? await applySharedRepoConfigUnset(key, repoName) : user ? await applyUserConfigUnset(key) : applyConfigUnset(key, global);
|
|
23092
23227
|
if (!result.ok) exitWithConfigErrors(result.errors);
|
|
23093
23228
|
if (!result.removed) {
|
|
23094
23229
|
console.log(chalk137.yellow(`${key} is not set in ${whereLabel(result)}`));
|
|
@@ -23097,22 +23232,20 @@ async function unsetFileConfigKey({
|
|
|
23097
23232
|
console.log(chalk137.green(`Unset ${key} (${targetLabel(result)})`));
|
|
23098
23233
|
}
|
|
23099
23234
|
function whereLabel(result) {
|
|
23100
|
-
|
|
23235
|
+
if (result.target === "repo") return `repos.${result.label}`;
|
|
23236
|
+
if (result.target === "user") return "user (db)";
|
|
23237
|
+
return `the ${result.target} config`;
|
|
23101
23238
|
}
|
|
23102
23239
|
function targetLabel(result) {
|
|
23103
|
-
|
|
23240
|
+
if (result.target === "repo") return `repo: ${result.label}`;
|
|
23241
|
+
if (result.target === "user") return "user (db)";
|
|
23242
|
+
return result.target;
|
|
23104
23243
|
}
|
|
23105
23244
|
|
|
23106
23245
|
// src/commands/config/configUnset.ts
|
|
23107
23246
|
async function configUnset(key, options2 = {}) {
|
|
23108
|
-
|
|
23109
|
-
|
|
23110
|
-
chalk138.red(
|
|
23111
|
-
"--repo removes from the global config; add -g (e.g. -g --repo)"
|
|
23112
|
-
)
|
|
23113
|
-
);
|
|
23114
|
-
process.exit(1);
|
|
23115
|
-
}
|
|
23247
|
+
const scopeError = scopeOptionsError(options2, "removes from");
|
|
23248
|
+
if (scopeError) exitWithConfigErrors([scopeError]);
|
|
23116
23249
|
const resolved = resolveRepoUnsetTarget(key, options2.repo);
|
|
23117
23250
|
if (resolved.key === void 0) {
|
|
23118
23251
|
console.error(chalk138.red("Missing required argument 'key'"));
|
|
@@ -23125,25 +23258,34 @@ async function configUnset(key, options2 = {}) {
|
|
|
23125
23258
|
key: resolved.key,
|
|
23126
23259
|
useRepo: resolved.useRepo,
|
|
23127
23260
|
repoName: resolved.repoName,
|
|
23128
|
-
global: options2.global ?? false
|
|
23261
|
+
global: options2.global ?? false,
|
|
23262
|
+
user: options2.user ?? false
|
|
23129
23263
|
});
|
|
23130
23264
|
}
|
|
23131
23265
|
|
|
23132
|
-
// src/commands/
|
|
23133
|
-
function
|
|
23134
|
-
const configCommand = configHelp(
|
|
23135
|
-
program.command("config").description("View and modify assist.yml configuration"),
|
|
23136
|
-
configConfigHelp,
|
|
23137
|
-
"Run 'assist config keys [filter]' to list every config key with its default,\nwhat it does, and the command that sets it."
|
|
23138
|
-
);
|
|
23266
|
+
// src/commands/config/registerConfigWrites.ts
|
|
23267
|
+
function registerConfigWrites(configCommand) {
|
|
23139
23268
|
configCommand.command("set <key> [value]").description("Set a config value (e.g. commit.push true)").option("-g, --global", "Write to global ~/.assist.yml").option(
|
|
23140
23269
|
"-r, --repo [name]",
|
|
23141
23270
|
"Requires -g: write a repo's override to the shared db, seen by every node (defaults to the current repo)"
|
|
23271
|
+
).option(
|
|
23272
|
+
"-u, --user",
|
|
23273
|
+
"Write to user (db): the shared db, applied to every repo on every node"
|
|
23142
23274
|
).action((key, value, options2) => configSet(key, value, options2));
|
|
23143
23275
|
configCommand.command("unset [key]").description("Remove a config value (e.g. commit.push)").option("-g, --global", "Remove from global ~/.assist.yml").option(
|
|
23144
23276
|
"-r, --repo [name]",
|
|
23145
23277
|
"Requires -g: remove the key from a repo's shared db override (defaults to the current repo)"
|
|
23146
|
-
).action((key, options2) => configUnset(key, options2));
|
|
23278
|
+
).option("-u, --user", "Remove from user (db) in the shared db").action((key, options2) => configUnset(key, options2));
|
|
23279
|
+
}
|
|
23280
|
+
|
|
23281
|
+
// src/commands/registerConfig.ts
|
|
23282
|
+
function registerConfig(program) {
|
|
23283
|
+
const configCommand = configHelp(
|
|
23284
|
+
program.command("config").description("View and modify assist.yml configuration"),
|
|
23285
|
+
configConfigHelp,
|
|
23286
|
+
"Run 'assist config keys [filter]' to list every config key with its default,\nwhat it does, and the command that sets it."
|
|
23287
|
+
);
|
|
23288
|
+
registerConfigWrites(configCommand);
|
|
23147
23289
|
configCommand.command("import-repos").description(
|
|
23148
23290
|
"Move this machine's ~/.assist.yml repos: overrides into the shared db, showing a per-key diff and asking first"
|
|
23149
23291
|
).action(configImportRepos);
|
|
@@ -23246,8 +23388,8 @@ import { homedir as homedir21 } from "os";
|
|
|
23246
23388
|
import { join as join54 } from "path";
|
|
23247
23389
|
function snapshotPath(tabUrl, now) {
|
|
23248
23390
|
const host = new URL(tabUrl).host.replace(/[^\w.-]/g, "-");
|
|
23249
|
-
const
|
|
23250
|
-
return join54(homedir21(), ".assist", "browser", `${host}-${
|
|
23391
|
+
const timestamp8 = now.toISOString().replace(/[:.]/g, "-");
|
|
23392
|
+
return join54(homedir21(), ".assist", "browser", `${host}-${timestamp8}.html`);
|
|
23251
23393
|
}
|
|
23252
23394
|
|
|
23253
23395
|
// src/commands/browser/browserSnapshot.ts
|
|
@@ -27746,10 +27888,10 @@ async function list3() {
|
|
|
27746
27888
|
import chalk173 from "chalk";
|
|
27747
27889
|
|
|
27748
27890
|
// src/shared/db/readInboxLastScan.ts
|
|
27749
|
-
import { eq as
|
|
27891
|
+
import { eq as eq45 } from "drizzle-orm";
|
|
27750
27892
|
var INBOX_LAST_SCAN_KEY = "inbox.lastScanAt";
|
|
27751
27893
|
async function readInboxLastScan(orm) {
|
|
27752
|
-
const [row3] = await orm.select().from(metadata).where(
|
|
27894
|
+
const [row3] = await orm.select().from(metadata).where(eq45(metadata.key, INBOX_LAST_SCAN_KEY));
|
|
27753
27895
|
return row3 ? new Date(row3.value) : void 0;
|
|
27754
27896
|
}
|
|
27755
27897
|
|
|
@@ -30486,9 +30628,9 @@ async function list4() {
|
|
|
30486
30628
|
import chalk189 from "chalk";
|
|
30487
30629
|
|
|
30488
30630
|
// src/commands/backlog/removeFeed.ts
|
|
30489
|
-
import { eq as
|
|
30631
|
+
import { eq as eq46 } from "drizzle-orm";
|
|
30490
30632
|
async function removeFeed(db, url) {
|
|
30491
|
-
const deleted = await db.delete(feeds).where(
|
|
30633
|
+
const deleted = await db.delete(feeds).where(eq46(feeds.url, url)).returning({ id: feeds.id });
|
|
30492
30634
|
return deleted.length > 0;
|
|
30493
30635
|
}
|
|
30494
30636
|
|
|
@@ -32601,8 +32743,8 @@ function bucketPr(pr) {
|
|
|
32601
32743
|
}
|
|
32602
32744
|
|
|
32603
32745
|
// src/commands/prs/status/describeAge.ts
|
|
32604
|
-
function describeAge(
|
|
32605
|
-
const parsed = new Date(
|
|
32746
|
+
function describeAge(timestamp8, now = Date.now()) {
|
|
32747
|
+
const parsed = new Date(timestamp8).getTime();
|
|
32606
32748
|
if (Number.isNaN(parsed)) return { hours: null, label: "unknown" };
|
|
32607
32749
|
const hours = Math.max(0, Math.floor((now - parsed) / 36e5));
|
|
32608
32750
|
if (hours < 1) return { hours, label: "<1h" };
|
|
@@ -34173,8 +34315,8 @@ function buildOutputPath(outputDir, processName) {
|
|
|
34173
34315
|
if (!existsSync65(outputDir)) {
|
|
34174
34316
|
mkdirSync24(outputDir, { recursive: true });
|
|
34175
34317
|
}
|
|
34176
|
-
const
|
|
34177
|
-
return resolve24(outputDir, `${processName}-${
|
|
34318
|
+
const timestamp8 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
34319
|
+
return resolve24(outputDir, `${processName}-${timestamp8}.png`);
|
|
34178
34320
|
}
|
|
34179
34321
|
function runPowerShellScript(processName, outputPath) {
|
|
34180
34322
|
const scriptPath = join83(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
|
|
@@ -41132,8 +41274,8 @@ function filterToSql(filter) {
|
|
|
41132
41274
|
// src/commands/seq/fetchSeqData.ts
|
|
41133
41275
|
function buildDataParams(filter, count10, from, to) {
|
|
41134
41276
|
const sqlFilter = filterToSql(filter);
|
|
41135
|
-
const
|
|
41136
|
-
const params = new URLSearchParams({ q:
|
|
41277
|
+
const sql30 = `select @Timestamp, @Level, @Exception, @Message from stream where ${sqlFilter} order by @Timestamp desc limit ${count10}`;
|
|
41278
|
+
const params = new URLSearchParams({ q: sql30 });
|
|
41137
41279
|
if (from) params.set("rangeStartUtc", from);
|
|
41138
41280
|
if (to) params.set("rangeEndUtc", to);
|
|
41139
41281
|
return params;
|
|
@@ -41647,26 +41789,26 @@ import chalk259 from "chalk";
|
|
|
41647
41789
|
// src/commands/sql/loadConnections.ts
|
|
41648
41790
|
function loadConnections3() {
|
|
41649
41791
|
const raw = loadGlobalConfigRaw();
|
|
41650
|
-
const
|
|
41651
|
-
return
|
|
41792
|
+
const sql30 = raw.sql;
|
|
41793
|
+
return sql30?.connections ?? [];
|
|
41652
41794
|
}
|
|
41653
41795
|
function saveConnections3(connections) {
|
|
41654
41796
|
const raw = loadGlobalConfigRaw();
|
|
41655
|
-
const
|
|
41656
|
-
|
|
41657
|
-
raw.sql =
|
|
41797
|
+
const sql30 = raw.sql ?? {};
|
|
41798
|
+
sql30.connections = connections;
|
|
41799
|
+
raw.sql = sql30;
|
|
41658
41800
|
saveGlobalConfig(raw);
|
|
41659
41801
|
}
|
|
41660
41802
|
function getDefaultConnection2() {
|
|
41661
41803
|
const raw = loadGlobalConfigRaw();
|
|
41662
|
-
const
|
|
41663
|
-
return
|
|
41804
|
+
const sql30 = raw.sql;
|
|
41805
|
+
return sql30?.defaultConnection;
|
|
41664
41806
|
}
|
|
41665
41807
|
function setDefaultConnection2(name) {
|
|
41666
41808
|
const raw = loadGlobalConfigRaw();
|
|
41667
|
-
const
|
|
41668
|
-
|
|
41669
|
-
raw.sql =
|
|
41809
|
+
const sql30 = raw.sql ?? {};
|
|
41810
|
+
sql30.defaultConnection = name;
|
|
41811
|
+
raw.sql = sql30;
|
|
41670
41812
|
saveGlobalConfig(raw);
|
|
41671
41813
|
}
|
|
41672
41814
|
|
|
@@ -41737,9 +41879,9 @@ function resolveConnection3(name) {
|
|
|
41737
41879
|
}
|
|
41738
41880
|
|
|
41739
41881
|
// src/commands/sql/sqlConnect.ts
|
|
41740
|
-
import
|
|
41882
|
+
import sql24 from "mssql";
|
|
41741
41883
|
async function sqlConnect(conn) {
|
|
41742
|
-
return await
|
|
41884
|
+
return await sql24.connect({
|
|
41743
41885
|
server: conn.server,
|
|
41744
41886
|
port: conn.port,
|
|
41745
41887
|
user: conn.user,
|
|
@@ -41802,11 +41944,11 @@ var MUTATION_PATTERN = new RegExp(
|
|
|
41802
41944
|
`\\b(${MUTATION_KEYWORDS.join("|")})\\b`,
|
|
41803
41945
|
"i"
|
|
41804
41946
|
);
|
|
41805
|
-
function stripComments(
|
|
41806
|
-
return
|
|
41947
|
+
function stripComments(sql30) {
|
|
41948
|
+
return sql30.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/--[^\n]*/g, " ");
|
|
41807
41949
|
}
|
|
41808
|
-
function isMutation(
|
|
41809
|
-
const stripped = stripComments(
|
|
41950
|
+
function isMutation(sql30) {
|
|
41951
|
+
const stripped = stripComments(sql30);
|
|
41810
41952
|
if (MUTATION_PATTERN.test(stripped)) return true;
|
|
41811
41953
|
return /\bSELECT\b[\s\S]+\bINTO\s+\w/i.test(stripped);
|
|
41812
41954
|
}
|
|
@@ -44830,12 +44972,12 @@ function parseEnvPairs(pairs) {
|
|
|
44830
44972
|
if (pairs.length === 0) return void 0;
|
|
44831
44973
|
const env = {};
|
|
44832
44974
|
for (const pair of pairs) {
|
|
44833
|
-
const
|
|
44834
|
-
if (
|
|
44975
|
+
const eq49 = pair.indexOf("=");
|
|
44976
|
+
if (eq49 <= 0) {
|
|
44835
44977
|
console.error(`--env must be KEY=VALUE, got "${pair}"`);
|
|
44836
44978
|
process.exit(1);
|
|
44837
44979
|
}
|
|
44838
|
-
env[pair.slice(0,
|
|
44980
|
+
env[pair.slice(0, eq49)] = pair.slice(eq49 + 1);
|
|
44839
44981
|
}
|
|
44840
44982
|
return env;
|
|
44841
44983
|
}
|
|
@@ -44848,11 +44990,11 @@ function fail9(spec) {
|
|
|
44848
44990
|
process.exit(1);
|
|
44849
44991
|
}
|
|
44850
44992
|
function parseParamSpec(spec) {
|
|
44851
|
-
const
|
|
44852
|
-
const name =
|
|
44853
|
-
if (
|
|
44854
|
-
if (
|
|
44855
|
-
return { name, default: spec.slice(
|
|
44993
|
+
const eq49 = spec.indexOf("=");
|
|
44994
|
+
const name = eq49 === -1 ? spec : spec.slice(0, eq49);
|
|
44995
|
+
if (eq49 !== -1) {
|
|
44996
|
+
if (eq49 === 0 || name.endsWith("!")) fail9(spec);
|
|
44997
|
+
return { name, default: spec.slice(eq49 + 1) };
|
|
44856
44998
|
}
|
|
44857
44999
|
if (name.endsWith("!")) {
|
|
44858
45000
|
if (name.length === 1) fail9(spec);
|
|
@@ -45362,6 +45504,9 @@ function createAutoExit(exit, graceMs = DEFAULT_GRACE_MS) {
|
|
|
45362
45504
|
|
|
45363
45505
|
// src/commands/sessions/daemon/pollRepoConfigCache.ts
|
|
45364
45506
|
var POLL_MS = 6e4;
|
|
45507
|
+
function cacheSnapshot() {
|
|
45508
|
+
return JSON.stringify([readRepoConfigCache(), readUserConfigCache()]);
|
|
45509
|
+
}
|
|
45365
45510
|
function pollRepoConfigCache(intervalMs = POLL_MS) {
|
|
45366
45511
|
let inFlight2 = false;
|
|
45367
45512
|
let failing = false;
|
|
@@ -45369,11 +45514,11 @@ function pollRepoConfigCache(intervalMs = POLL_MS) {
|
|
|
45369
45514
|
if (inFlight2) return;
|
|
45370
45515
|
inFlight2 = true;
|
|
45371
45516
|
try {
|
|
45372
|
-
const before =
|
|
45517
|
+
const before = cacheSnapshot();
|
|
45373
45518
|
const count10 = await refreshRepoConfigCache();
|
|
45374
45519
|
if (failing) daemonLog("repo config cache poll recovered");
|
|
45375
45520
|
failing = false;
|
|
45376
|
-
if (
|
|
45521
|
+
if (cacheSnapshot() !== before)
|
|
45377
45522
|
daemonLog(`repo config cache updated (${count10} repos)`);
|
|
45378
45523
|
} catch (error) {
|
|
45379
45524
|
if (!failing)
|
|
@@ -47509,13 +47654,13 @@ function drainSessions(sessions, notify2) {
|
|
|
47509
47654
|
}
|
|
47510
47655
|
|
|
47511
47656
|
// src/shared/db/recordPhaseActiveMs.ts
|
|
47512
|
-
import { sql as
|
|
47657
|
+
import { sql as sql25 } from "drizzle-orm";
|
|
47513
47658
|
async function recordPhaseActiveMs(db, itemId2, phaseIdx, activeMs) {
|
|
47514
47659
|
if (activeMs <= 0) return;
|
|
47515
47660
|
await db.insert(phaseUsage).values({ itemId: itemId2, phaseIdx, activeMs }).onConflictDoUpdate({
|
|
47516
47661
|
target: [phaseUsage.itemId, phaseUsage.phaseIdx],
|
|
47517
47662
|
set: {
|
|
47518
|
-
activeMs:
|
|
47663
|
+
activeMs: sql25`${phaseUsage.activeMs} + excluded.active_ms`
|
|
47519
47664
|
}
|
|
47520
47665
|
});
|
|
47521
47666
|
}
|
|
@@ -48116,10 +48261,10 @@ function applyReviewPause(session, activity2) {
|
|
|
48116
48261
|
}
|
|
48117
48262
|
|
|
48118
48263
|
// src/shared/db/getPhaseActiveMs.ts
|
|
48119
|
-
import { and as and18, eq as
|
|
48264
|
+
import { and as and18, eq as eq47 } from "drizzle-orm";
|
|
48120
48265
|
async function getPhaseActiveMs(db, itemId2, phaseIdx) {
|
|
48121
48266
|
const [row3] = await db.select({ activeMs: phaseUsage.activeMs }).from(phaseUsage).where(
|
|
48122
|
-
and18(
|
|
48267
|
+
and18(eq47(phaseUsage.itemId, itemId2), eq47(phaseUsage.phaseIdx, phaseIdx))
|
|
48123
48268
|
);
|
|
48124
48269
|
return row3?.activeMs ?? 0;
|
|
48125
48270
|
}
|
|
@@ -48904,7 +49049,7 @@ async function readTranscriptUsage(transcriptPath2) {
|
|
|
48904
49049
|
}
|
|
48905
49050
|
|
|
48906
49051
|
// src/shared/db/recordPhaseCycleContext.ts
|
|
48907
|
-
import { sql as
|
|
49052
|
+
import { sql as sql26 } from "drizzle-orm";
|
|
48908
49053
|
async function recordPhaseCycleContext(db, itemId2, phaseIdx, window, resetsAt, pct) {
|
|
48909
49054
|
if (pct <= 0) return;
|
|
48910
49055
|
await db.insert(phaseCycleContext).values({ itemId: itemId2, phaseIdx, window, resetsAt, peakContextPct: pct }).onConflictDoUpdate({
|
|
@@ -48915,24 +49060,24 @@ async function recordPhaseCycleContext(db, itemId2, phaseIdx, window, resetsAt,
|
|
|
48915
49060
|
phaseCycleContext.resetsAt
|
|
48916
49061
|
],
|
|
48917
49062
|
set: {
|
|
48918
|
-
peakContextPct:
|
|
49063
|
+
peakContextPct: sql26`GREATEST(${phaseCycleContext.peakContextPct}, ${pct})`
|
|
48919
49064
|
}
|
|
48920
49065
|
});
|
|
48921
49066
|
}
|
|
48922
49067
|
|
|
48923
49068
|
// src/shared/db/recordPhasePeakContext.ts
|
|
48924
|
-
import { sql as
|
|
49069
|
+
import { sql as sql27 } from "drizzle-orm";
|
|
48925
49070
|
async function recordPhasePeakContext(db, itemId2, phaseIdx, pct) {
|
|
48926
49071
|
await db.insert(phaseUsage).values({ itemId: itemId2, phaseIdx, peakContextPct: pct }).onConflictDoUpdate({
|
|
48927
49072
|
target: [phaseUsage.itemId, phaseUsage.phaseIdx],
|
|
48928
49073
|
set: {
|
|
48929
|
-
peakContextPct:
|
|
49074
|
+
peakContextPct: sql27`GREATEST(${phaseUsage.peakContextPct}, ${pct})`
|
|
48930
49075
|
}
|
|
48931
49076
|
});
|
|
48932
49077
|
}
|
|
48933
49078
|
|
|
48934
49079
|
// src/shared/db/recordPhaseTranscriptUsage.ts
|
|
48935
|
-
import { sql as
|
|
49080
|
+
import { sql as sql28 } from "drizzle-orm";
|
|
48936
49081
|
async function recordPhaseTranscriptUsage(db, itemId2, phaseIdx, responses) {
|
|
48937
49082
|
const byId = /* @__PURE__ */ new Map();
|
|
48938
49083
|
for (const r of responses) byId.set(r.messageId, r);
|
|
@@ -48952,8 +49097,8 @@ async function recordPhaseTranscriptUsage(db, itemId2, phaseIdx, responses) {
|
|
|
48952
49097
|
await tx.insert(phaseUsage).values({ itemId: itemId2, phaseIdx, tokensUp, tokensDown }).onConflictDoUpdate({
|
|
48953
49098
|
target: [phaseUsage.itemId, phaseUsage.phaseIdx],
|
|
48954
49099
|
set: {
|
|
48955
|
-
tokensUp:
|
|
48956
|
-
tokensDown:
|
|
49100
|
+
tokensUp: sql28`${phaseUsage.tokensUp} + ${tokensUp}`,
|
|
49101
|
+
tokensDown: sql28`${phaseUsage.tokensDown} + ${tokensDown}`
|
|
48957
49102
|
}
|
|
48958
49103
|
});
|
|
48959
49104
|
return { tokensUp, tokensDown };
|
|
@@ -48961,17 +49106,17 @@ async function recordPhaseTranscriptUsage(db, itemId2, phaseIdx, responses) {
|
|
|
48961
49106
|
}
|
|
48962
49107
|
|
|
48963
49108
|
// src/shared/db/recordWindowTokens.ts
|
|
48964
|
-
import { and as and19, eq as
|
|
49109
|
+
import { and as and19, eq as eq48, sql as sql29 } from "drizzle-orm";
|
|
48965
49110
|
async function recordWindowTokens(db, window, resetsAt, tokensUp, tokensDown) {
|
|
48966
49111
|
if (tokensUp <= 0 && tokensDown <= 0) return;
|
|
48967
49112
|
await db.update(usagePeaks).set({
|
|
48968
|
-
tokensUp:
|
|
48969
|
-
tokensDown:
|
|
49113
|
+
tokensUp: sql29`${usagePeaks.tokensUp} + ${tokensUp}`,
|
|
49114
|
+
tokensDown: sql29`${usagePeaks.tokensDown} + ${tokensDown}`
|
|
48970
49115
|
}).where(
|
|
48971
49116
|
and19(
|
|
48972
|
-
|
|
48973
|
-
|
|
48974
|
-
|
|
49117
|
+
eq48(usagePeaks.window, window),
|
|
49118
|
+
eq48(usagePeaks.resetsAt, resetsAt),
|
|
49119
|
+
eq48(usagePeaks.segment, 0)
|
|
48975
49120
|
)
|
|
48976
49121
|
);
|
|
48977
49122
|
}
|