neuvikon 0.2.30 → 0.2.31

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.
Files changed (2) hide show
  1. package/dist/index.mjs +99 -28
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -276,12 +276,12 @@ function fail(message, hint) {
276
276
  }
277
277
  //#endregion
278
278
  //#region src/commands/board.ts
279
- function requireCredentials$4() {
279
+ function requireCredentials$5() {
280
280
  const credentials = readCredentials();
281
281
  if (!credentials) fail("Not logged in.", "Run `npx neuvikon login` first.");
282
282
  return credentials;
283
283
  }
284
- function resolveTicketRef$4(flags) {
284
+ function resolveTicketRef$5(flags) {
285
285
  const ref = flags.get("ticket") ?? readSession()?.ticket;
286
286
  if (!ref) fail("No ticket to look up a board for.", "Pass --ticket EWWQ-1, or run this where `npx neuvikon start` is already tracking one.");
287
287
  return ref;
@@ -291,8 +291,8 @@ function resolveTicketRef$4(flags) {
291
291
  * a column name — boards vary per project, and some have no "done" at all.
292
292
  */
293
293
  async function board(flags) {
294
- const credentials = requireCredentials$4();
295
- const ticketRef = resolveTicketRef$4(flags);
294
+ const credentials = requireCredentials$5();
295
+ const ticketRef = resolveTicketRef$5(flags);
296
296
  let result;
297
297
  try {
298
298
  result = await post(credentials.url, "/api/agent/board", {
@@ -339,20 +339,20 @@ async function readStdin() {
339
339
  }
340
340
  //#endregion
341
341
  //#region src/commands/comment.ts
342
- function requireCredentials$3() {
342
+ function requireCredentials$4() {
343
343
  const credentials = readCredentials();
344
344
  if (!credentials) fail("Not logged in.", "Run `npx neuvikon login` first.");
345
345
  return credentials;
346
346
  }
347
- function resolveTicketRef$3(flags) {
347
+ function resolveTicketRef$4(flags) {
348
348
  const ref = flags.get("ticket") ?? readSession()?.ticket;
349
349
  if (!ref) fail("No ticket to comment on.", "Pass --ticket EWWQ-1, or run this where `npx neuvikon start` is already tracking one.");
350
350
  return ref;
351
351
  }
352
352
  /** A note on a ticket that doesn't move it — e.g. explaining a handoff mid-ticket. */
353
353
  async function comment(flags) {
354
- const credentials = requireCredentials$3();
355
- const ticketRef = resolveTicketRef$3(flags);
354
+ const credentials = requireCredentials$4();
355
+ const ticketRef = resolveTicketRef$4(flags);
356
356
  const text = (flags.get("text") || await readStdin()).trim();
357
357
  if (!text) fail("No comment text given.", "Pipe the comment in on stdin, or pass --text.");
358
358
  try {
@@ -374,18 +374,18 @@ async function comment(flags) {
374
374
  //#endregion
375
375
  //#region src/commands/create.ts
376
376
  const TYPES = /* @__PURE__ */ new Set(["feature", "bug"]);
377
- const PRIORITIES = /* @__PURE__ */ new Set([
377
+ const PRIORITIES$1 = /* @__PURE__ */ new Set([
378
378
  "low",
379
379
  "medium",
380
380
  "high",
381
381
  "urgent"
382
382
  ]);
383
- function requireCredentials$2() {
383
+ function requireCredentials$3() {
384
384
  const credentials = readCredentials();
385
385
  if (!credentials) fail("Not logged in.", "Run `npx neuvikon login` first.");
386
386
  return credentials;
387
387
  }
388
- function resolveTicketRef$2(flags) {
388
+ function resolveTicketRef$3(flags) {
389
389
  const ref = flags.get("ticket") ?? readSession()?.ticket;
390
390
  if (!ref) fail("No ticket to file this against.", "Pass --ticket EWWQ-1, or run this where `npx neuvikon start` is already tracking one.");
391
391
  return ref;
@@ -413,16 +413,18 @@ function resolveParentRef(flags, ticketRef) {
413
413
  * own "+ sub-ticket" control.
414
414
  */
415
415
  async function create(flags, positional) {
416
- const credentials = requireCredentials$2();
417
- const ticketRef = resolveTicketRef$2(flags);
416
+ const credentials = requireCredentials$3();
417
+ const ticketRef = resolveTicketRef$3(flags);
418
418
  const parentRef = resolveParentRef(flags, ticketRef);
419
419
  const title = flags.get("title") ?? positional[0];
420
420
  if (!title) fail("A ticket title is required.", `Pass --title "Invite emails aren't localized", or give it as the first argument.`);
421
421
  const type = flags.get("type");
422
422
  if (type && !TYPES.has(type)) fail(`Unknown type "${type}".`, "Expected feature or bug.");
423
423
  const priority = flags.get("priority");
424
- if (priority && !PRIORITIES.has(priority)) fail(`Unknown priority "${priority}".`, "Expected low, medium, high, or urgent.");
424
+ if (priority && !PRIORITIES$1.has(priority)) fail(`Unknown priority "${priority}".`, "Expected low, medium, high, or urgent.");
425
425
  const description = (flags.get("description") || await readStdin()).trim() || void 0;
426
+ const assignee = flags.get("assignee");
427
+ const sprint = flags.get("sprint");
426
428
  let result;
427
429
  try {
428
430
  result = await post(credentials.url, "/api/agent/tickets/create", {
@@ -432,7 +434,9 @@ async function create(flags, positional) {
432
434
  description,
433
435
  type,
434
436
  priority,
435
- parentRef
437
+ parentRef,
438
+ assignee,
439
+ sprint
436
440
  });
437
441
  } catch (error) {
438
442
  if (error instanceof NetworkError) fail("Could not reach Neuvikon.");
@@ -1294,12 +1298,12 @@ async function logout() {
1294
1298
  }
1295
1299
  //#endregion
1296
1300
  //#region src/commands/move.ts
1297
- function requireCredentials$1() {
1301
+ function requireCredentials$2() {
1298
1302
  const credentials = readCredentials();
1299
1303
  if (!credentials) fail("Not logged in.", "Run `npx neuvikon login` first.");
1300
1304
  return credentials;
1301
1305
  }
1302
- function resolveTicketRef$1(flags) {
1306
+ function resolveTicketRef$2(flags) {
1303
1307
  const ref = flags.get("ticket") ?? readSession()?.ticket;
1304
1308
  if (!ref) fail("No ticket to move.", "Pass --ticket EWWQ-1, or run this where `npx neuvikon start` is already tracking one.");
1305
1309
  return ref;
@@ -1311,8 +1315,8 @@ function resolveTicketRef$1(flags) {
1311
1315
  * that silently.
1312
1316
  */
1313
1317
  async function move(flags) {
1314
- const credentials = requireCredentials$1();
1315
- const ticketRef = resolveTicketRef$1(flags);
1318
+ const credentials = requireCredentials$2();
1319
+ const ticketRef = resolveTicketRef$2(flags);
1316
1320
  const column = flags.get("column");
1317
1321
  if (!column) fail("A target column is required.", `Pass --column "Code Review" — run \`npx neuvikon board\` first if you're not sure what this project calls it.`);
1318
1322
  const comment = (flags.get("comment") || await readStdin()).trim();
@@ -1337,13 +1341,13 @@ async function move(flags) {
1337
1341
  }
1338
1342
  //#endregion
1339
1343
  //#region src/commands/pages.ts
1340
- function requireCredentials() {
1344
+ function requireCredentials$1() {
1341
1345
  const credentials = readCredentials();
1342
1346
  if (!credentials) fail("Not logged in.", "Run `npx neuvikon login` first.");
1343
1347
  return credentials;
1344
1348
  }
1345
1349
  /** `--ticket` wins; otherwise fall back to whatever this directory is already tracking. */
1346
- function resolveTicketRef(flags) {
1350
+ function resolveTicketRef$1(flags) {
1347
1351
  const ref = flags.get("ticket") ?? readSession()?.ticket;
1348
1352
  if (!ref) fail("No ticket to look up pages for.", "Pass --ticket EWWQ-1, or run this where `npx neuvikon start` is already tracking one.");
1349
1353
  return ref;
@@ -1362,8 +1366,8 @@ async function request(credentials, path, body) {
1362
1366
  }
1363
1367
  }
1364
1368
  async function list(flags) {
1365
- const credentials = requireCredentials();
1366
- const ticketRef = resolveTicketRef(flags);
1369
+ const credentials = requireCredentials$1();
1370
+ const ticketRef = resolveTicketRef$1(flags);
1367
1371
  const { pages } = await request(credentials, "/api/agent/pages", {
1368
1372
  token: credentials.token,
1369
1373
  ticketRef
@@ -1375,9 +1379,9 @@ async function list(flags) {
1375
1379
  const body = pages.map((page) => `# ${page.title}\n\n${page.text}`).join("\n\n---\n\n");
1376
1380
  process.stdout.write(`${body}\n`);
1377
1381
  }
1378
- async function update(flags, positional) {
1379
- const credentials = requireCredentials();
1380
- const ticketRef = resolveTicketRef(flags);
1382
+ async function update$1(flags, positional) {
1383
+ const credentials = requireCredentials$1();
1384
+ const ticketRef = resolveTicketRef$1(flags);
1381
1385
  const title = flags.get("title") ?? positional[0];
1382
1386
  if (!title) fail("A page title is required.", `Pass --title "Auth flow notes", or give it as the first argument.`);
1383
1387
  const text = (flags.get("text") || await readStdin()).trim();
@@ -1394,7 +1398,7 @@ async function pages(flags, positional) {
1394
1398
  switch (subcommand) {
1395
1399
  case void 0:
1396
1400
  case "list": return list(flags);
1397
- case "update": return update(flags, rest);
1401
+ case "update": return update$1(flags, rest);
1398
1402
  default: fail(`Unknown "pages ${subcommand}".`, "Try `pages` or `pages update`.");
1399
1403
  }
1400
1404
  }
@@ -1910,6 +1914,67 @@ async function stop(flags) {
1910
1914
  success(`Stopped tracking ${session.ticket}`);
1911
1915
  }
1912
1916
  //#endregion
1917
+ //#region src/commands/update.ts
1918
+ const PRIORITIES = /* @__PURE__ */ new Set([
1919
+ "low",
1920
+ "medium",
1921
+ "high",
1922
+ "urgent"
1923
+ ]);
1924
+ /** What `--assignee none` / `--sprint none` means: clear the field. */
1925
+ const NONE = "none";
1926
+ function requireCredentials() {
1927
+ const credentials = readCredentials();
1928
+ if (!credentials) fail("Not logged in.", "Run `npx neuvikon login` first.");
1929
+ return credentials;
1930
+ }
1931
+ function resolveTicketRef(flags) {
1932
+ const ref = flags.get("ticket") ?? readSession()?.ticket;
1933
+ if (!ref) fail("No ticket to update.", "Pass --ticket EWWQ-1, or run this where `npx neuvikon start` is already tracking one.");
1934
+ return ref;
1935
+ }
1936
+ /** `undefined` means "leave it alone", `null` means "clear it", a string means "set it to this". */
1937
+ function resolveClearable(flags, name) {
1938
+ const value = flags.get(name);
1939
+ if (value === void 0) return void 0;
1940
+ return value.toLowerCase() === NONE ? null : value;
1941
+ }
1942
+ /**
1943
+ * Changes fields on a ticket that already exists, e.g.
1944
+ * `npx neuvikon update --ticket NS-91 --assignee Ogulcan --sprint "Sprint 1"`.
1945
+ * `--assignee none` / `--sprint none` clears that field instead of setting it.
1946
+ */
1947
+ async function update(flags) {
1948
+ const credentials = requireCredentials();
1949
+ const ticketRef = resolveTicketRef(flags);
1950
+ const assignee = resolveClearable(flags, "assignee");
1951
+ const sprint = resolveClearable(flags, "sprint");
1952
+ const priority = flags.get("priority");
1953
+ if (priority && !PRIORITIES.has(priority)) fail(`Unknown priority "${priority}".`, "Expected low, medium, high, or urgent.");
1954
+ const labelsFlag = flags.get("labels");
1955
+ const labels = labelsFlag !== void 0 ? labelsFlag.split(",").map((label) => label.trim()).filter(Boolean) : void 0;
1956
+ if (assignee === void 0 && sprint === void 0 && priority === void 0 && labels === void 0) fail("Nothing to update.", "Pass at least one of --assignee, --sprint, --priority, --labels.");
1957
+ let result;
1958
+ try {
1959
+ result = await post(credentials.url, "/api/agent/tickets/update", {
1960
+ token: credentials.token,
1961
+ ticketRef,
1962
+ assignee,
1963
+ sprint,
1964
+ priority,
1965
+ labels
1966
+ });
1967
+ } catch (error) {
1968
+ if (error instanceof NetworkError) fail("Could not reach Neuvikon.");
1969
+ if (error instanceof ApiError) {
1970
+ if (error.status === 401) fail(error.message, "Run `npx neuvikon login` again.");
1971
+ fail(error.message);
1972
+ }
1973
+ throw error;
1974
+ }
1975
+ success(`Updated ${bold(result.ref)}: ${result.changed.join(", ")}`);
1976
+ }
1977
+ //#endregion
1913
1978
  //#region src/index.ts
1914
1979
  const HELP = `${bold("neuvikon")} — tell Neuvikon which ticket your coding agent is on
1915
1980
 
@@ -1933,7 +1998,12 @@ ${bold("Board")}
1933
1998
  File something you noticed as its own ticket, same project
1934
1999
  npx neuvikon create "Add French copy" --sub
1935
2000
  ...or as a sub-ticket (--sub for this one, --parent NS-12 for another)
1936
- All four accept --ticket EWWQ-1 instead of relying on a tracked session.
2001
+ npx neuvikon create "..." --assignee Ogulcan --sprint "Sprint 1"
2002
+ File it already assigned and/or planned in a sprint
2003
+ npx neuvikon update --assignee Ogulcan --sprint "Sprint 1" --priority high
2004
+ Change assignee, sprint, priority, or labels on an existing ticket
2005
+ ("none" clears --assignee/--sprint)
2006
+ All five accept --ticket EWWQ-1 instead of relying on a tracked session.
1937
2007
 
1938
2008
  ${bold("Project pages")}
1939
2009
  npx neuvikon pages List the current ticket's project pages
@@ -1995,6 +2065,7 @@ async function main() {
1995
2065
  case "move": return move(flags);
1996
2066
  case "comment": return comment(flags);
1997
2067
  case "create": return create(flags, positional);
2068
+ case "update": return update(flags);
1998
2069
  case void 0:
1999
2070
  case "help":
2000
2071
  case "--help":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neuvikon",
3
- "version": "0.2.30",
3
+ "version": "0.2.31",
4
4
  "description": "Tell Neuvikon which ticket your coding agent is working on.",
5
5
  "keywords": [
6
6
  "neuvikon",