@staff0rd/assist 0.310.1 → 0.310.2

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.310.1",
9
+ version: "0.310.2",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -1141,8 +1141,8 @@ var options = [
1141
1141
  ];
1142
1142
 
1143
1143
  // src/commands/verify/init/getAvailableOptions/index.ts
1144
- function resolveDescription(desc5, setup2) {
1145
- return typeof desc5 === "function" ? desc5(setup2) : desc5;
1144
+ function resolveDescription(desc6, setup2) {
1145
+ return typeof desc6 === "function" ? desc6(setup2) : desc6;
1146
1146
  }
1147
1147
  function toVerifyOption(def, setup2) {
1148
1148
  return {
@@ -3038,10 +3038,10 @@ function gitPullBacklog(dir) {
3038
3038
 
3039
3039
  // src/shared/db/schema.ts
3040
3040
  import {
3041
- boolean,
3041
+ boolean as boolean2,
3042
3042
  foreignKey,
3043
3043
  index as index2,
3044
- integer as integer2,
3044
+ integer as integer3,
3045
3045
  pgTable as pgTable3,
3046
3046
  primaryKey as primaryKey2,
3047
3047
  text as text3
@@ -3065,60 +3065,66 @@ var handovers = pgTable(
3065
3065
  // src/shared/db/usagePeaks.ts
3066
3066
  import {
3067
3067
  bigint,
3068
+ boolean,
3068
3069
  doublePrecision,
3070
+ integer as integer2,
3069
3071
  pgTable as pgTable2,
3070
3072
  primaryKey,
3071
- text as text2
3073
+ text as text2,
3074
+ timestamp as timestamp2
3072
3075
  } from "drizzle-orm/pg-core";
3073
3076
  var usagePeaks = pgTable2(
3074
3077
  "usage_peaks",
3075
3078
  {
3076
3079
  window: text2().$type().notNull(),
3077
3080
  resetsAt: bigint("resets_at", { mode: "number" }).notNull(),
3078
- usedPercentage: doublePrecision("used_percentage").notNull()
3081
+ segment: integer2().notNull().default(0),
3082
+ usedPercentage: doublePrecision("used_percentage").notNull(),
3083
+ resetDetected: boolean("reset_detected").notNull().default(false),
3084
+ createdAt: timestamp2("created_at", { withTimezone: true }).notNull().defaultNow()
3079
3085
  },
3080
- (t) => [primaryKey({ columns: [t.window, t.resetsAt] })]
3086
+ (t) => [primaryKey({ columns: [t.window, t.resetsAt, t.segment] })]
3081
3087
  );
3082
3088
 
3083
3089
  // src/shared/db/schema.ts
3084
3090
  var items = pgTable3(
3085
3091
  "items",
3086
3092
  {
3087
- id: integer2().generatedByDefaultAsIdentity().primaryKey(),
3093
+ id: integer3().generatedByDefaultAsIdentity().primaryKey(),
3088
3094
  origin: text3().notNull(),
3089
3095
  type: text3().notNull().default("story"),
3090
3096
  name: text3().notNull(),
3091
3097
  description: text3(),
3092
3098
  acceptanceCriteria: text3("acceptance_criteria").notNull().default("[]"),
3093
3099
  status: text3().notNull().default("todo"),
3094
- currentPhase: integer2("current_phase"),
3095
- starred: boolean().notNull().default(false)
3100
+ currentPhase: integer3("current_phase"),
3101
+ starred: boolean2().notNull().default(false)
3096
3102
  },
3097
3103
  (t) => [index2("items_origin_idx").on(t.origin)]
3098
3104
  );
3099
3105
  var comments = pgTable3("comments", {
3100
- id: integer2().generatedByDefaultAsIdentity().primaryKey(),
3101
- itemId: integer2("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
3102
- idx: integer2().notNull(),
3106
+ id: integer3().generatedByDefaultAsIdentity().primaryKey(),
3107
+ itemId: integer3("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
3108
+ idx: integer3().notNull(),
3103
3109
  text: text3().notNull(),
3104
- phase: integer2(),
3110
+ phase: integer3(),
3105
3111
  timestamp: text3().notNull(),
3106
3112
  type: text3().notNull().default("comment")
3107
3113
  });
3108
3114
  var links = pgTable3(
3109
3115
  "links",
3110
3116
  {
3111
- itemId: integer2("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
3117
+ itemId: integer3("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
3112
3118
  type: text3().notNull(),
3113
- targetId: integer2("target_id").notNull()
3119
+ targetId: integer3("target_id").notNull()
3114
3120
  },
3115
3121
  (t) => [primaryKey2({ columns: [t.itemId, t.type, t.targetId] })]
3116
3122
  );
3117
3123
  var planPhases = pgTable3(
3118
3124
  "plan_phases",
3119
3125
  {
3120
- itemId: integer2("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
3121
- idx: integer2().notNull(),
3126
+ itemId: integer3("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
3127
+ idx: integer3().notNull(),
3122
3128
  name: text3().notNull(),
3123
3129
  manualChecks: text3("manual_checks")
3124
3130
  },
@@ -3127,9 +3133,9 @@ var planPhases = pgTable3(
3127
3133
  var planTasks = pgTable3(
3128
3134
  "plan_tasks",
3129
3135
  {
3130
- itemId: integer2("item_id").notNull(),
3131
- phaseIdx: integer2("phase_idx").notNull(),
3132
- idx: integer2().notNull(),
3136
+ itemId: integer3("item_id").notNull(),
3137
+ phaseIdx: integer3("phase_idx").notNull(),
3138
+ idx: integer3().notNull(),
3133
3139
  task: text3().notNull()
3134
3140
  },
3135
3141
  (t) => [
@@ -3145,7 +3151,7 @@ var metadata = pgTable3("metadata", {
3145
3151
  value: text3().notNull()
3146
3152
  });
3147
3153
  var feeds = pgTable3("feeds", {
3148
- id: integer2().generatedByDefaultAsIdentity().primaryKey(),
3154
+ id: integer3().generatedByDefaultAsIdentity().primaryKey(),
3149
3155
  url: text3().notNull().unique()
3150
3156
  });
3151
3157
  var schema = {
@@ -3602,9 +3608,34 @@ var SCHEMA = `
3602
3608
  CREATE TABLE IF NOT EXISTS usage_peaks (
3603
3609
  "window" TEXT NOT NULL,
3604
3610
  resets_at BIGINT NOT NULL,
3611
+ segment INTEGER NOT NULL DEFAULT 0,
3605
3612
  used_percentage DOUBLE PRECISION NOT NULL,
3606
- PRIMARY KEY ("window", resets_at)
3613
+ reset_detected BOOLEAN NOT NULL DEFAULT false,
3614
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
3615
+ PRIMARY KEY ("window", resets_at, segment)
3607
3616
  );
3617
+
3618
+ -- Backfill columns on databases created before reset/segment tracking existed.
3619
+ ALTER TABLE usage_peaks ADD COLUMN IF NOT EXISTS reset_detected BOOLEAN NOT NULL DEFAULT false;
3620
+ ALTER TABLE usage_peaks ADD COLUMN IF NOT EXISTS segment INTEGER NOT NULL DEFAULT 0;
3621
+ ALTER TABLE usage_peaks ADD COLUMN IF NOT EXISTS created_at TIMESTAMPTZ NOT NULL DEFAULT now();
3622
+
3623
+ -- Widen the primary key to include segment so a cycle can hold both its
3624
+ -- pre-reset peak and its post-reset continuation. Idempotent: only fires
3625
+ -- while the legacy two-column key is still in place.
3626
+ DO $$
3627
+ BEGIN
3628
+ IF EXISTS (
3629
+ SELECT 1 FROM pg_constraint
3630
+ WHERE conname = 'usage_peaks_pkey'
3631
+ AND conrelid = 'usage_peaks'::regclass
3632
+ AND array_length(conkey, 1) = 2
3633
+ ) THEN
3634
+ ALTER TABLE usage_peaks DROP CONSTRAINT usage_peaks_pkey;
3635
+ ALTER TABLE usage_peaks ADD CONSTRAINT usage_peaks_pkey
3636
+ PRIMARY KEY ("window", resets_at, segment);
3637
+ END IF;
3638
+ END $$;
3608
3639
  `;
3609
3640
  async function ensureSchema(exec3) {
3610
3641
  await exec3(SCHEMA);
@@ -5490,7 +5521,7 @@ async function listNewsItems(_req, res) {
5490
5521
  // src/shared/db/listUsagePeaks.ts
5491
5522
  import { desc } from "drizzle-orm";
5492
5523
  async function listUsagePeaks(db) {
5493
- return db.select().from(usagePeaks).orderBy(desc(usagePeaks.resetsAt), usagePeaks.window);
5524
+ return db.select().from(usagePeaks).orderBy(desc(usagePeaks.resetsAt), usagePeaks.window, usagePeaks.segment);
5494
5525
  }
5495
5526
 
5496
5527
  // src/commands/sessions/web/listUsageHistory.ts
@@ -7382,8 +7413,8 @@ function applyAcMutations(current, options2) {
7382
7413
  // src/commands/backlog/update/buildUpdateValues.ts
7383
7414
  import chalk81 from "chalk";
7384
7415
  function buildUpdateValues(options2) {
7385
- const { name, desc: desc5, type, ac } = options2;
7386
- if (!name && !desc5 && !type && !ac) {
7416
+ const { name, desc: desc6, type, ac } = options2;
7417
+ if (!name && !desc6 && !type && !ac) {
7387
7418
  console.log(chalk81.red("Nothing to update. Provide at least one flag."));
7388
7419
  process.exitCode = 1;
7389
7420
  return void 0;
@@ -7399,8 +7430,8 @@ function buildUpdateValues(options2) {
7399
7430
  set.name = name;
7400
7431
  fieldNames.push("name");
7401
7432
  }
7402
- if (desc5) {
7403
- set.description = desc5;
7433
+ if (desc6) {
7434
+ set.description = desc6;
7404
7435
  fieldNames.push("description");
7405
7436
  }
7406
7437
  if (type) {
@@ -19148,8 +19179,8 @@ function buildOutputPath(outputDir, processName) {
19148
19179
  if (!existsSync49(outputDir)) {
19149
19180
  mkdirSync21(outputDir, { recursive: true });
19150
19181
  }
19151
- const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
19152
- return resolve14(outputDir, `${processName}-${timestamp2}.png`);
19182
+ const timestamp3 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
19183
+ return resolve14(outputDir, `${processName}-${timestamp3}.png`);
19153
19184
  }
19154
19185
  function runPowerShellScript(processName, outputPath) {
19155
19186
  const scriptPath = join59(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
@@ -19451,26 +19482,46 @@ function broadcastSessions(sessions, clients, windowsSessions = [], active) {
19451
19482
  });
19452
19483
  }
19453
19484
 
19485
+ // src/shared/db/recordWindowPeak.ts
19486
+ import { and as and13, desc as desc5, eq as eq31, sql as sql5 } from "drizzle-orm";
19487
+ var RESET_DROP_THRESHOLD = 1;
19488
+ async function recordWindowPeak(db, window, resetsAt, usedPercentage) {
19489
+ const [active] = await db.select().from(usagePeaks).where(
19490
+ and13(eq31(usagePeaks.window, window), eq31(usagePeaks.resetsAt, resetsAt))
19491
+ ).orderBy(desc5(usagePeaks.segment)).limit(1);
19492
+ if (!active) {
19493
+ await db.insert(usagePeaks).values({ window, resetsAt, segment: 0, usedPercentage });
19494
+ return;
19495
+ }
19496
+ const matchActive = and13(
19497
+ eq31(usagePeaks.window, window),
19498
+ eq31(usagePeaks.resetsAt, resetsAt),
19499
+ eq31(usagePeaks.segment, active.segment)
19500
+ );
19501
+ if (usedPercentage < active.usedPercentage - RESET_DROP_THRESHOLD) {
19502
+ await db.update(usagePeaks).set({ resetDetected: true }).where(matchActive);
19503
+ await db.insert(usagePeaks).values({
19504
+ window,
19505
+ resetsAt,
19506
+ segment: active.segment + 1,
19507
+ usedPercentage
19508
+ });
19509
+ return;
19510
+ }
19511
+ await db.update(usagePeaks).set({
19512
+ usedPercentage: sql5`GREATEST(${usagePeaks.usedPercentage}, ${usedPercentage})`
19513
+ }).where(matchActive);
19514
+ }
19515
+
19454
19516
  // src/shared/db/recordUsagePeak.ts
19455
- import { sql as sql5 } from "drizzle-orm";
19456
19517
  var WINDOWS = ["five_hour", "seven_day"];
19457
19518
  async function recordUsagePeak(db, rateLimits) {
19458
- const rows = WINDOWS.flatMap((window) => {
19519
+ for (const window of WINDOWS) {
19459
19520
  const w = rateLimits[window];
19460
- if (!w) return [];
19461
- if (typeof w.resets_at !== "number" || typeof w.used_percentage !== "number")
19462
- return [];
19463
- return [
19464
- { window, resetsAt: w.resets_at, usedPercentage: w.used_percentage }
19465
- ];
19466
- });
19467
- if (rows.length === 0) return;
19468
- await db.insert(usagePeaks).values(rows).onConflictDoUpdate({
19469
- target: [usagePeaks.window, usagePeaks.resetsAt],
19470
- set: {
19471
- usedPercentage: sql5`GREATEST(${usagePeaks.usedPercentage}, excluded.used_percentage)`
19472
- }
19473
- });
19521
+ if (!w || typeof w.resets_at !== "number" || typeof w.used_percentage !== "number")
19522
+ continue;
19523
+ await recordWindowPeak(db, window, w.resets_at, w.used_percentage);
19524
+ }
19474
19525
  }
19475
19526
 
19476
19527
  // src/commands/sessions/daemon/persistUsagePeak.ts
@@ -20723,7 +20774,7 @@ function backlogRunMarkers(text5) {
20723
20774
  function extractSessionMeta(lines) {
20724
20775
  let sessionId = "";
20725
20776
  let cwd = "";
20726
- let timestamp2 = "";
20777
+ let timestamp3 = "";
20727
20778
  let name = "";
20728
20779
  let commandName = "";
20729
20780
  let commandArgs = "";
@@ -20731,14 +20782,14 @@ function extractSessionMeta(lines) {
20731
20782
  const entry = safeParse(line);
20732
20783
  if (!entry) continue;
20733
20784
  sessionId ||= strField(entry, "sessionId");
20734
- timestamp2 ||= strField(entry, "timestamp");
20785
+ timestamp3 ||= strField(entry, "timestamp");
20735
20786
  cwd ||= strField(entry, "cwd");
20736
20787
  if (entry.type === "user" && !entry.isMeta) {
20737
20788
  ({ name, commandName, commandArgs } = parseFirstUserEntry(entry));
20738
20789
  break;
20739
20790
  }
20740
20791
  }
20741
- return { sessionId, cwd, timestamp: timestamp2, name, commandName, commandArgs };
20792
+ return { sessionId, cwd, timestamp: timestamp3, name, commandName, commandArgs };
20742
20793
  }
20743
20794
  function parseFirstUserEntry(entry) {
20744
20795
  const raw = messageText(entry);
@@ -20779,13 +20830,13 @@ async function parseSessionFile(filePath, origin = "wsl") {
20779
20830
  handle = await fs29.promises.open(filePath, "r");
20780
20831
  const meta = extractSessionMeta(await readHeadLines(handle));
20781
20832
  if (!meta.sessionId) return null;
20782
- const timestamp2 = meta.timestamp || (await fs29.promises.stat(filePath)).mtime.toISOString();
20833
+ const timestamp3 = meta.timestamp || (await fs29.promises.stat(filePath)).mtime.toISOString();
20783
20834
  return {
20784
20835
  sessionId: meta.sessionId,
20785
20836
  name: meta.name || `Session ${meta.sessionId.slice(0, 8)}`,
20786
20837
  project: deriveProject(meta.cwd, filePath, origin),
20787
20838
  cwd: meta.cwd,
20788
- timestamp: timestamp2,
20839
+ timestamp: timestamp3,
20789
20840
  origin,
20790
20841
  ...deriveHistoryFields(meta.commandName, meta.commandArgs, meta.name)
20791
20842
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staff0rd/assist",
3
- "version": "0.310.1",
3
+ "version": "0.310.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {