@staff0rd/assist 0.241.0 → 0.242.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.241.0",
9
+ version: "0.242.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -4113,6 +4113,12 @@ function createFallbackHandler(routes3, htmlHandler2, extra) {
4113
4113
  };
4114
4114
  }
4115
4115
 
4116
+ // src/commands/backlog/web/applyCwdFromReq.ts
4117
+ function applyCwdFromReq(req) {
4118
+ const url = new URL(req.url ?? "/", "http://localhost");
4119
+ setBacklogDir(url.searchParams.get("cwd") ?? void 0);
4120
+ }
4121
+
4116
4122
  // src/commands/backlog/web/parseItemBody.ts
4117
4123
  function readBody(req) {
4118
4124
  return new Promise((resolve15, reject) => {
@@ -4137,6 +4143,7 @@ async function parseRewindBody(req) {
4137
4143
  // src/commands/backlog/web/createItem.ts
4138
4144
  async function createItem(req, res) {
4139
4145
  const body = await parseItemBody(req);
4146
+ applyCwdFromReq(req);
4140
4147
  const orm = await getBacklogOrm();
4141
4148
  const newItem = {
4142
4149
  type: body.type ?? "story",
@@ -4149,11 +4156,29 @@ async function createItem(req, res) {
4149
4156
  respondJson(res, 201, { id, ...newItem });
4150
4157
  }
4151
4158
 
4159
+ // src/commands/backlog/web/getBacklogExists.ts
4160
+ async function getBacklogExists(req, res) {
4161
+ applyCwdFromReq(req);
4162
+ const items2 = await loadBacklog();
4163
+ respondJson(res, 200, { exists: items2.length > 0 });
4164
+ }
4165
+
4152
4166
  // src/commands/backlog/web/rewindItemPhase.ts
4153
- import { eq as eq10 } from "drizzle-orm";
4167
+ import { eq as eq11 } from "drizzle-orm";
4168
+
4169
+ // src/commands/backlog/deleteComment.ts
4170
+ import { and as and2, eq as eq10 } from "drizzle-orm";
4171
+ async function deleteComment(orm, itemId, commentId) {
4172
+ const [row] = await orm.select({ type: comments.type }).from(comments).where(and2(eq10(comments.id, commentId), eq10(comments.itemId, itemId)));
4173
+ if (!row) return "not-found";
4174
+ if (row.type === "summary") return "is-summary";
4175
+ await orm.delete(comments).where(and2(eq10(comments.id, commentId), eq10(comments.itemId, itemId)));
4176
+ return "deleted";
4177
+ }
4154
4178
 
4155
4179
  // src/commands/backlog/web/shared.ts
4156
4180
  async function listItems(req, res) {
4181
+ applyCwdFromReq(req);
4157
4182
  const url = new URL(req.url ?? "/", "http://localhost");
4158
4183
  const q = url.searchParams.get("q");
4159
4184
  respondJson(res, 200, q ? await searchBacklog(q) : await loadBacklog());
@@ -4177,6 +4202,24 @@ async function deleteItem2(res, id) {
4177
4202
  await deleteItem(result.orm, id);
4178
4203
  respondJson(res, 200, result.item);
4179
4204
  }
4205
+ async function deleteItemComment(res, itemId, commentId) {
4206
+ const result = await findItemOr404(res, itemId);
4207
+ if (!result) return;
4208
+ const outcome = await deleteComment(result.orm, itemId, commentId);
4209
+ if (outcome === "not-found") {
4210
+ respondJson(res, 404, {
4211
+ error: `Comment #${commentId} not found on item #${itemId}.`
4212
+ });
4213
+ return;
4214
+ }
4215
+ if (outcome === "is-summary") {
4216
+ respondJson(res, 400, {
4217
+ error: `Comment #${commentId} is a phase summary and cannot be deleted.`
4218
+ });
4219
+ return;
4220
+ }
4221
+ respondJson(res, 200, await loadItem(result.orm, itemId));
4222
+ }
4180
4223
  async function patchItemStatus(req, res, id) {
4181
4224
  const { status: status2 } = await parseStatusBody(req);
4182
4225
  const result = await findItemOr404(res, id);
@@ -4204,7 +4247,7 @@ async function rewindItemPhase(req, res, id) {
4204
4247
  `Rewound to phase ${phase} (${phaseName}): ${reason}`,
4205
4248
  { phase }
4206
4249
  );
4207
- await orm.update(items).set({ currentPhase: phase, status: "in-progress" }).where(eq10(items.id, id));
4250
+ await orm.update(items).set({ currentPhase: phase, status: "in-progress" }).where(eq11(items.id, id));
4208
4251
  respondJson(res, 200, await loadItem(orm, id));
4209
4252
  }
4210
4253
  function validateRewind(item, phase) {
@@ -4222,7 +4265,7 @@ function validateRewind(item, phase) {
4222
4265
  }
4223
4266
 
4224
4267
  // src/commands/backlog/web/updateItem.ts
4225
- import { eq as eq11 } from "drizzle-orm";
4268
+ import { eq as eq12 } from "drizzle-orm";
4226
4269
  async function updateItem(req, res, id) {
4227
4270
  const body = await parseItemBody(req);
4228
4271
  const result = await findItemOr404(res, id);
@@ -4233,7 +4276,7 @@ async function updateItem(req, res, id) {
4233
4276
  name: body.name,
4234
4277
  description: body.description ?? null,
4235
4278
  acceptanceCriteria: JSON.stringify(body.acceptanceCriteria ?? [])
4236
- }).where(eq11(items.id, id));
4279
+ }).where(eq12(items.id, id));
4237
4280
  respondJson(res, 200, await loadItem(orm, id));
4238
4281
  }
4239
4282
 
@@ -4247,17 +4290,47 @@ var itemRoutes = {
4247
4290
  async function handleItemRoute(req, res, pathname) {
4248
4291
  const rewindMatch = pathname.match(/^\/api\/items\/(\d+)\/rewind$/);
4249
4292
  if (rewindMatch && req.method === "POST") {
4293
+ applyCwdFromReq(req);
4250
4294
  await rewindItemPhase(req, res, Number.parseInt(rewindMatch[1], 10));
4251
4295
  return true;
4252
4296
  }
4297
+ const commentMatch = pathname.match(/^\/api\/items\/(\d+)\/comments\/(\d+)$/);
4298
+ if (commentMatch && req.method === "DELETE") {
4299
+ applyCwdFromReq(req);
4300
+ await deleteItemComment(
4301
+ res,
4302
+ Number.parseInt(commentMatch[1], 10),
4303
+ Number.parseInt(commentMatch[2], 10)
4304
+ );
4305
+ return true;
4306
+ }
4253
4307
  const match = pathname.match(/^\/api\/items\/(\d+)$/);
4254
4308
  if (!match) return false;
4255
4309
  const handler = itemRoutes[req.method ?? "GET"];
4256
4310
  if (!handler) return false;
4311
+ applyCwdFromReq(req);
4257
4312
  await handler(req, res, Number.parseInt(match[1], 10));
4258
4313
  return true;
4259
4314
  }
4260
4315
 
4316
+ // src/commands/backlog/init/index.ts
4317
+ import chalk44 from "chalk";
4318
+ async function init6() {
4319
+ await getBacklogOrm();
4320
+ console.log(
4321
+ chalk44.green(
4322
+ `Backlog database ready. This repository maps to origin: ${getOrigin()}`
4323
+ )
4324
+ );
4325
+ }
4326
+
4327
+ // src/commands/backlog/web/initBacklog.ts
4328
+ async function initBacklog(req, res) {
4329
+ applyCwdFromReq(req);
4330
+ await init6();
4331
+ respondJson(res, 200, { ok: true });
4332
+ }
4333
+
4261
4334
  // src/commands/sessions/web/getHtml.ts
4262
4335
  function getHtml() {
4263
4336
  return `<!DOCTYPE html>
@@ -4309,7 +4382,9 @@ var routes = {
4309
4382
  ),
4310
4383
  "GET /xterm.css": createCssHandler("@xterm/xterm/css/xterm.css"),
4311
4384
  "GET /api/items": listItems,
4312
- "POST /api/items": createItem
4385
+ "POST /api/items": createItem,
4386
+ "GET /api/backlog/exists": getBacklogExists,
4387
+ "POST /api/backlog/init": initBacklog
4313
4388
  };
4314
4389
  var handleRequest = createFallbackHandler(
4315
4390
  routes,
@@ -4869,37 +4944,37 @@ async function web2(options2) {
4869
4944
  }
4870
4945
 
4871
4946
  // src/commands/backlog/refine.ts
4872
- import chalk46 from "chalk";
4947
+ import chalk47 from "chalk";
4873
4948
  import enquirer6 from "enquirer";
4874
4949
 
4875
4950
  // src/commands/backlog/launchMode.ts
4876
- import chalk45 from "chalk";
4951
+ import chalk46 from "chalk";
4877
4952
 
4878
4953
  // src/commands/backlog/tryRunById.ts
4879
- import chalk44 from "chalk";
4954
+ import chalk45 from "chalk";
4880
4955
  async function tryRunById(id, options2) {
4881
4956
  const items2 = await loadBacklog();
4882
4957
  const numericId = Number.parseInt(id, 10);
4883
4958
  const item = Number.isNaN(numericId) ? void 0 : items2.find((i) => i.id === numericId);
4884
4959
  if (!item) {
4885
- console.log(chalk44.red(`Item #${id} not found.`));
4960
+ console.log(chalk45.red(`Item #${id} not found.`));
4886
4961
  return false;
4887
4962
  }
4888
4963
  if (item.status === "done") {
4889
- console.log(chalk44.red(`Item #${id} is already done.`));
4964
+ console.log(chalk45.red(`Item #${id} is already done.`));
4890
4965
  return false;
4891
4966
  }
4892
4967
  if (item.status === "wontdo") {
4893
- console.log(chalk44.red(`Item #${id} is marked won't do.`));
4968
+ console.log(chalk45.red(`Item #${id} is marked won't do.`));
4894
4969
  return false;
4895
4970
  }
4896
4971
  if (isBlocked(item, items2)) {
4897
4972
  console.log(
4898
- chalk44.red(`Item #${id} is blocked by unresolved dependencies.`)
4973
+ chalk45.red(`Item #${id} is blocked by unresolved dependencies.`)
4899
4974
  );
4900
4975
  return false;
4901
4976
  }
4902
- console.log(chalk44.bold(`
4977
+ console.log(chalk45.bold(`
4903
4978
  Running backlog item #${id}...
4904
4979
  `));
4905
4980
  await run2(id, options2);
@@ -4920,7 +4995,7 @@ async function launchMode(slashCommand) {
4920
4995
  if (typeof signal.id === "string" && signal.id) {
4921
4996
  if (await tryRunById(signal.id, { allowEdits: true })) return;
4922
4997
  }
4923
- console.log(chalk45.bold("\nChaining into assist next...\n"));
4998
+ console.log(chalk46.bold("\nChaining into assist next...\n"));
4924
4999
  await next({ allowEdits: true });
4925
5000
  }
4926
5001
  }
@@ -4932,12 +5007,12 @@ async function pickItemForRefine() {
4932
5007
  (i) => i.status === "todo" || i.status === "in-progress"
4933
5008
  );
4934
5009
  if (active.length === 0) {
4935
- console.log(chalk46.yellow("No active backlog items to refine."));
5010
+ console.log(chalk47.yellow("No active backlog items to refine."));
4936
5011
  return void 0;
4937
5012
  }
4938
5013
  if (active.length === 1) {
4939
5014
  const item = active[0];
4940
- console.log(chalk46.bold(`Auto-selecting item #${item.id}: ${item.name}`));
5015
+ console.log(chalk47.bold(`Auto-selecting item #${item.id}: ${item.name}`));
4941
5016
  return String(item.id);
4942
5017
  }
4943
5018
  const { selected } = await exitOnCancel(
@@ -4959,26 +5034,26 @@ async function refine(id) {
4959
5034
  }
4960
5035
 
4961
5036
  // src/commands/backlog/comment/index.ts
4962
- import chalk47 from "chalk";
5037
+ import chalk48 from "chalk";
4963
5038
  async function comment(id, text2) {
4964
5039
  const found = await findOneItem(id);
4965
5040
  if (!found) process.exit(1);
4966
5041
  await appendComment(found.orm, found.item.id, text2);
4967
- console.log(chalk47.green(`Comment added to item #${id}.`));
5042
+ console.log(chalk48.green(`Comment added to item #${id}.`));
4968
5043
  }
4969
5044
 
4970
5045
  // src/commands/backlog/comments/index.ts
4971
- import chalk48 from "chalk";
5046
+ import chalk49 from "chalk";
4972
5047
  async function comments2(id) {
4973
5048
  const found = await findOneItem(id);
4974
5049
  if (!found) process.exit(1);
4975
5050
  const { item } = found;
4976
5051
  const entries = item.comments ?? [];
4977
5052
  if (entries.length === 0) {
4978
- console.log(chalk48.dim(`No comments on item #${id}.`));
5053
+ console.log(chalk49.dim(`No comments on item #${id}.`));
4979
5054
  return;
4980
5055
  }
4981
- console.log(chalk48.bold(`Comments for #${id}: ${item.name}
5056
+ console.log(chalk49.bold(`Comments for #${id}: ${item.name}
4982
5057
  `));
4983
5058
  for (const entry of entries) {
4984
5059
  console.log(`${formatComment(entry)}
@@ -4987,19 +5062,7 @@ async function comments2(id) {
4987
5062
  }
4988
5063
 
4989
5064
  // src/commands/backlog/delete-comment/index.ts
4990
- import chalk49 from "chalk";
4991
-
4992
- // src/commands/backlog/deleteComment.ts
4993
- import { and as and2, eq as eq12 } from "drizzle-orm";
4994
- async function deleteComment(orm, itemId, commentId) {
4995
- const [row] = await orm.select({ type: comments.type }).from(comments).where(and2(eq12(comments.id, commentId), eq12(comments.itemId, itemId)));
4996
- if (!row) return "not-found";
4997
- if (row.type === "summary") return "is-summary";
4998
- await orm.delete(comments).where(and2(eq12(comments.id, commentId), eq12(comments.itemId, itemId)));
4999
- return "deleted";
5000
- }
5001
-
5002
- // src/commands/backlog/delete-comment/index.ts
5065
+ import chalk50 from "chalk";
5003
5066
  async function deleteCommentCmd(id, commentId) {
5004
5067
  const found = await findOneItem(id);
5005
5068
  if (!found) process.exit(1);
@@ -5011,16 +5074,16 @@ async function deleteCommentCmd(id, commentId) {
5011
5074
  switch (outcome) {
5012
5075
  case "deleted":
5013
5076
  console.log(
5014
- chalk49.green(`Comment #${commentId} deleted from item #${id}.`)
5077
+ chalk50.green(`Comment #${commentId} deleted from item #${id}.`)
5015
5078
  );
5016
5079
  break;
5017
5080
  case "not-found":
5018
- console.log(chalk49.red(`Comment #${commentId} not found on item #${id}.`));
5081
+ console.log(chalk50.red(`Comment #${commentId} not found on item #${id}.`));
5019
5082
  process.exit(1);
5020
5083
  break;
5021
5084
  case "is-summary":
5022
5085
  console.log(
5023
- chalk49.red(
5086
+ chalk50.red(
5024
5087
  `Comment #${commentId} is a phase summary and cannot be deleted.`
5025
5088
  )
5026
5089
  );
@@ -5038,7 +5101,7 @@ function registerCommentCommands(cmd) {
5038
5101
 
5039
5102
  // src/commands/backlog/export/index.ts
5040
5103
  import { writeFile } from "fs/promises";
5041
- import chalk50 from "chalk";
5104
+ import chalk51 from "chalk";
5042
5105
 
5043
5106
  // src/commands/backlog/dump/DumpTable.ts
5044
5107
  var DUMP_FORMAT = "assist-backlog-dump";
@@ -5105,7 +5168,7 @@ async function exportBacklog(file) {
5105
5168
  if (file) {
5106
5169
  await writeFile(file, dump);
5107
5170
  console.error(
5108
- chalk50.green(`Exported backlog to ${file} (${dump.length} bytes).`)
5171
+ chalk51.green(`Exported backlog to ${file} (${dump.length} bytes).`)
5109
5172
  );
5110
5173
  return;
5111
5174
  }
@@ -5121,7 +5184,7 @@ function registerExportCommand(cmd) {
5121
5184
 
5122
5185
  // src/commands/backlog/import/index.ts
5123
5186
  import { readFile } from "fs/promises";
5124
- import chalk52 from "chalk";
5187
+ import chalk53 from "chalk";
5125
5188
 
5126
5189
  // src/commands/backlog/dump/countCopyRows.ts
5127
5190
  function countCopyRows(data) {
@@ -5198,7 +5261,7 @@ function validateDump({ header, sections }) {
5198
5261
  }
5199
5262
 
5200
5263
  // src/commands/backlog/import/confirmReplace.ts
5201
- import chalk51 from "chalk";
5264
+ import chalk52 from "chalk";
5202
5265
  async function countRows(client, table) {
5203
5266
  const { rows } = await client.query(
5204
5267
  `SELECT count(*)::int AS n FROM ${table}`
@@ -5209,7 +5272,7 @@ function printSummary(current, incoming) {
5209
5272
  const lines = DUMP_TABLES.map(
5210
5273
  (t, i) => ` ${t.name}: ${current[i]} \u2192 ${incoming[i]} rows`
5211
5274
  );
5212
- console.error(chalk51.bold("\nThis will REPLACE all backlog data:"));
5275
+ console.error(chalk52.bold("\nThis will REPLACE all backlog data:"));
5213
5276
  console.error(`${lines.join("\n")}
5214
5277
  `);
5215
5278
  }
@@ -5285,13 +5348,13 @@ async function importBacklog(file, options2 = {}) {
5285
5348
  );
5286
5349
  await withBacklogClient(async (client) => {
5287
5350
  if (!options2.yes && !await confirmReplace(client, incoming, !file)) {
5288
- console.error(chalk52.yellow("Import cancelled; no changes made."));
5351
+ console.error(chalk53.yellow("Import cancelled; no changes made."));
5289
5352
  return;
5290
5353
  }
5291
5354
  await restore(client, parsed);
5292
5355
  const total = incoming.reduce((sum, n) => sum + n, 0);
5293
5356
  console.error(
5294
- chalk52.green(
5357
+ chalk53.green(
5295
5358
  `Imported backlog: ${total} rows restored across ${DUMP_TABLES.length} tables.`
5296
5359
  )
5297
5360
  );
@@ -5308,7 +5371,7 @@ function registerImportCommand(cmd) {
5308
5371
  }
5309
5372
 
5310
5373
  // src/commands/backlog/add/index.ts
5311
- import chalk53 from "chalk";
5374
+ import chalk54 from "chalk";
5312
5375
 
5313
5376
  // src/commands/backlog/add/shared.ts
5314
5377
  import { spawnSync } from "child_process";
@@ -5398,11 +5461,11 @@ async function add(options2) {
5398
5461
  },
5399
5462
  getOrigin()
5400
5463
  );
5401
- console.log(chalk53.green(`Added item #${id}: ${name}`));
5464
+ console.log(chalk54.green(`Added item #${id}: ${name}`));
5402
5465
  }
5403
5466
 
5404
5467
  // src/commands/backlog/addPhase.ts
5405
- import chalk55 from "chalk";
5468
+ import chalk56 from "chalk";
5406
5469
 
5407
5470
  // src/commands/backlog/insertPhaseAt.ts
5408
5471
  import { count, eq as eq14 } from "drizzle-orm";
@@ -5435,7 +5498,7 @@ async function insertPhaseAt(orm, itemId, phaseIdx, name, tasks, manualChecks, c
5435
5498
  }
5436
5499
 
5437
5500
  // src/commands/backlog/resolveInsertPosition.ts
5438
- import chalk54 from "chalk";
5501
+ import chalk55 from "chalk";
5439
5502
  import { count as count2, eq as eq15 } from "drizzle-orm";
5440
5503
  async function resolveInsertPosition(orm, itemId, position) {
5441
5504
  const [row] = await orm.select({ cnt: count2() }).from(planPhases).where(eq15(planPhases.itemId, itemId));
@@ -5444,7 +5507,7 @@ async function resolveInsertPosition(orm, itemId, position) {
5444
5507
  const pos = Number.parseInt(position, 10);
5445
5508
  if (pos < 1 || pos > phaseCount + 1) {
5446
5509
  console.log(
5447
- chalk54.red(
5510
+ chalk55.red(
5448
5511
  `Position ${pos} is out of range. Must be between 1 and ${phaseCount + 1}.`
5449
5512
  )
5450
5513
  );
@@ -5465,7 +5528,7 @@ async function addPhase(id, name, options2) {
5465
5528
  if (!found) return;
5466
5529
  const tasks = options2.task ?? [];
5467
5530
  if (tasks.length === 0) {
5468
- console.log(chalk55.red("At least one --task is required."));
5531
+ console.log(chalk56.red("At least one --task is required."));
5469
5532
  process.exitCode = 1;
5470
5533
  return;
5471
5534
  }
@@ -5483,20 +5546,9 @@ async function addPhase(id, name, options2) {
5483
5546
  found.item.currentPhase
5484
5547
  );
5485
5548
  const verb = options2.position !== void 0 ? "Inserted" : "Added";
5486
- console.log(
5487
- chalk55.green(
5488
- `${verb} phase ${phaseIdx + 1} "${name}" to item #${itemId} with ${tasks.length} task(s).`
5489
- )
5490
- );
5491
- }
5492
-
5493
- // src/commands/backlog/init/index.ts
5494
- import chalk56 from "chalk";
5495
- async function init6() {
5496
- await getBacklogOrm();
5497
5549
  console.log(
5498
5550
  chalk56.green(
5499
- `Backlog database ready. This repository maps to origin: ${getOrigin()}`
5551
+ `${verb} phase ${phaseIdx + 1} "${name}" to item #${itemId} with ${tasks.length} task(s).`
5500
5552
  )
5501
5553
  );
5502
5554
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staff0rd/assist",
3
- "version": "0.241.0",
3
+ "version": "0.242.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {