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