neuvikon 0.2.30 → 0.2.32
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.mjs +104 -29
- 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$
|
|
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$
|
|
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$
|
|
295
|
-
const ticketRef = resolveTicketRef$
|
|
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$
|
|
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$
|
|
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$
|
|
355
|
-
const ticketRef = resolveTicketRef$
|
|
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$
|
|
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$
|
|
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$
|
|
417
|
-
const ticketRef = resolveTicketRef$
|
|
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.");
|
|
@@ -746,7 +750,7 @@ function parsePayload(raw) {
|
|
|
746
750
|
* in front of the model at the one moment it's actually relevant instead of
|
|
747
751
|
* buried in a rules file next to a dozen other instructions.
|
|
748
752
|
*/
|
|
749
|
-
const MODEL_TRIAGE_CONTEXT = "A Neuvikon ticket just landed in this prompt. Before reading any file or running `start`: judge how difficult it actually is. If it's a small, mechanical change (button placement, a copy/label edit, a trivial styling tweak, a one-line config change), send `/model haiku` and `/effort low` now, as their own messages, before touching the ticket — there's no reason to spend a frontier model thinking hard about something this small. If it needs real design judgment, touches multiple systems, or you're unsure, stay on the current model and effort level instead.";
|
|
753
|
+
const MODEL_TRIAGE_CONTEXT = "A Neuvikon ticket just landed in this prompt. Before reading any file or running `start`: judge how difficult it actually is. If it's a small, mechanical change (button placement, a copy/label edit, a trivial styling tweak, a one-line config change), send `/model haiku` and `/effort low` now, as their own messages, before touching the ticket — there's no reason to spend a frontier model thinking hard about something this small. If it needs real design judgment, touches multiple systems, or you're unsure, stay on the current model and effort level instead. Either way, don't stop and wait after sending those commands — keep going immediately into the ticket itself in the same turn, exactly as if the model/effort switch were one more step in starting the ticket, not the end of your response.";
|
|
750
754
|
function hookResponse(additionalContext) {
|
|
751
755
|
return JSON.stringify({ hookSpecificOutput: {
|
|
752
756
|
hookEventName: "UserPromptSubmit",
|
|
@@ -894,6 +898,10 @@ on its own, before you touch the ticket:
|
|
|
894
898
|
- Your CLI doesn't expose a way to change model or effort mid-session: skip
|
|
895
899
|
this and go straight to the ticket.
|
|
896
900
|
|
|
901
|
+
Don't stop and wait after sending a \`/model\`/\`/effort\` command — continue
|
|
902
|
+
immediately into the ticket in the same turn, as one more step in starting
|
|
903
|
+
it, not as the end of your response.
|
|
904
|
+
|
|
897
905
|
Only after that's decided, run this before you start working on the ticket:
|
|
898
906
|
|
|
899
907
|
npx neuvikon start --ticket EWWQ-1
|
|
@@ -1294,12 +1302,12 @@ async function logout() {
|
|
|
1294
1302
|
}
|
|
1295
1303
|
//#endregion
|
|
1296
1304
|
//#region src/commands/move.ts
|
|
1297
|
-
function requireCredentials$
|
|
1305
|
+
function requireCredentials$2() {
|
|
1298
1306
|
const credentials = readCredentials();
|
|
1299
1307
|
if (!credentials) fail("Not logged in.", "Run `npx neuvikon login` first.");
|
|
1300
1308
|
return credentials;
|
|
1301
1309
|
}
|
|
1302
|
-
function resolveTicketRef$
|
|
1310
|
+
function resolveTicketRef$2(flags) {
|
|
1303
1311
|
const ref = flags.get("ticket") ?? readSession()?.ticket;
|
|
1304
1312
|
if (!ref) fail("No ticket to move.", "Pass --ticket EWWQ-1, or run this where `npx neuvikon start` is already tracking one.");
|
|
1305
1313
|
return ref;
|
|
@@ -1311,8 +1319,8 @@ function resolveTicketRef$1(flags) {
|
|
|
1311
1319
|
* that silently.
|
|
1312
1320
|
*/
|
|
1313
1321
|
async function move(flags) {
|
|
1314
|
-
const credentials = requireCredentials$
|
|
1315
|
-
const ticketRef = resolveTicketRef$
|
|
1322
|
+
const credentials = requireCredentials$2();
|
|
1323
|
+
const ticketRef = resolveTicketRef$2(flags);
|
|
1316
1324
|
const column = flags.get("column");
|
|
1317
1325
|
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
1326
|
const comment = (flags.get("comment") || await readStdin()).trim();
|
|
@@ -1337,13 +1345,13 @@ async function move(flags) {
|
|
|
1337
1345
|
}
|
|
1338
1346
|
//#endregion
|
|
1339
1347
|
//#region src/commands/pages.ts
|
|
1340
|
-
function requireCredentials() {
|
|
1348
|
+
function requireCredentials$1() {
|
|
1341
1349
|
const credentials = readCredentials();
|
|
1342
1350
|
if (!credentials) fail("Not logged in.", "Run `npx neuvikon login` first.");
|
|
1343
1351
|
return credentials;
|
|
1344
1352
|
}
|
|
1345
1353
|
/** `--ticket` wins; otherwise fall back to whatever this directory is already tracking. */
|
|
1346
|
-
function resolveTicketRef(flags) {
|
|
1354
|
+
function resolveTicketRef$1(flags) {
|
|
1347
1355
|
const ref = flags.get("ticket") ?? readSession()?.ticket;
|
|
1348
1356
|
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
1357
|
return ref;
|
|
@@ -1362,8 +1370,8 @@ async function request(credentials, path, body) {
|
|
|
1362
1370
|
}
|
|
1363
1371
|
}
|
|
1364
1372
|
async function list(flags) {
|
|
1365
|
-
const credentials = requireCredentials();
|
|
1366
|
-
const ticketRef = resolveTicketRef(flags);
|
|
1373
|
+
const credentials = requireCredentials$1();
|
|
1374
|
+
const ticketRef = resolveTicketRef$1(flags);
|
|
1367
1375
|
const { pages } = await request(credentials, "/api/agent/pages", {
|
|
1368
1376
|
token: credentials.token,
|
|
1369
1377
|
ticketRef
|
|
@@ -1375,9 +1383,9 @@ async function list(flags) {
|
|
|
1375
1383
|
const body = pages.map((page) => `# ${page.title}\n\n${page.text}`).join("\n\n---\n\n");
|
|
1376
1384
|
process.stdout.write(`${body}\n`);
|
|
1377
1385
|
}
|
|
1378
|
-
async function update(flags, positional) {
|
|
1379
|
-
const credentials = requireCredentials();
|
|
1380
|
-
const ticketRef = resolveTicketRef(flags);
|
|
1386
|
+
async function update$1(flags, positional) {
|
|
1387
|
+
const credentials = requireCredentials$1();
|
|
1388
|
+
const ticketRef = resolveTicketRef$1(flags);
|
|
1381
1389
|
const title = flags.get("title") ?? positional[0];
|
|
1382
1390
|
if (!title) fail("A page title is required.", `Pass --title "Auth flow notes", or give it as the first argument.`);
|
|
1383
1391
|
const text = (flags.get("text") || await readStdin()).trim();
|
|
@@ -1394,7 +1402,7 @@ async function pages(flags, positional) {
|
|
|
1394
1402
|
switch (subcommand) {
|
|
1395
1403
|
case void 0:
|
|
1396
1404
|
case "list": return list(flags);
|
|
1397
|
-
case "update": return update(flags, rest);
|
|
1405
|
+
case "update": return update$1(flags, rest);
|
|
1398
1406
|
default: fail(`Unknown "pages ${subcommand}".`, "Try `pages` or `pages update`.");
|
|
1399
1407
|
}
|
|
1400
1408
|
}
|
|
@@ -1910,6 +1918,67 @@ async function stop(flags) {
|
|
|
1910
1918
|
success(`Stopped tracking ${session.ticket}`);
|
|
1911
1919
|
}
|
|
1912
1920
|
//#endregion
|
|
1921
|
+
//#region src/commands/update.ts
|
|
1922
|
+
const PRIORITIES = /* @__PURE__ */ new Set([
|
|
1923
|
+
"low",
|
|
1924
|
+
"medium",
|
|
1925
|
+
"high",
|
|
1926
|
+
"urgent"
|
|
1927
|
+
]);
|
|
1928
|
+
/** What `--assignee none` / `--sprint none` means: clear the field. */
|
|
1929
|
+
const NONE = "none";
|
|
1930
|
+
function requireCredentials() {
|
|
1931
|
+
const credentials = readCredentials();
|
|
1932
|
+
if (!credentials) fail("Not logged in.", "Run `npx neuvikon login` first.");
|
|
1933
|
+
return credentials;
|
|
1934
|
+
}
|
|
1935
|
+
function resolveTicketRef(flags) {
|
|
1936
|
+
const ref = flags.get("ticket") ?? readSession()?.ticket;
|
|
1937
|
+
if (!ref) fail("No ticket to update.", "Pass --ticket EWWQ-1, or run this where `npx neuvikon start` is already tracking one.");
|
|
1938
|
+
return ref;
|
|
1939
|
+
}
|
|
1940
|
+
/** `undefined` means "leave it alone", `null` means "clear it", a string means "set it to this". */
|
|
1941
|
+
function resolveClearable(flags, name) {
|
|
1942
|
+
const value = flags.get(name);
|
|
1943
|
+
if (value === void 0) return void 0;
|
|
1944
|
+
return value.toLowerCase() === NONE ? null : value;
|
|
1945
|
+
}
|
|
1946
|
+
/**
|
|
1947
|
+
* Changes fields on a ticket that already exists, e.g.
|
|
1948
|
+
* `npx neuvikon update --ticket NS-91 --assignee Ogulcan --sprint "Sprint 1"`.
|
|
1949
|
+
* `--assignee none` / `--sprint none` clears that field instead of setting it.
|
|
1950
|
+
*/
|
|
1951
|
+
async function update(flags) {
|
|
1952
|
+
const credentials = requireCredentials();
|
|
1953
|
+
const ticketRef = resolveTicketRef(flags);
|
|
1954
|
+
const assignee = resolveClearable(flags, "assignee");
|
|
1955
|
+
const sprint = resolveClearable(flags, "sprint");
|
|
1956
|
+
const priority = flags.get("priority");
|
|
1957
|
+
if (priority && !PRIORITIES.has(priority)) fail(`Unknown priority "${priority}".`, "Expected low, medium, high, or urgent.");
|
|
1958
|
+
const labelsFlag = flags.get("labels");
|
|
1959
|
+
const labels = labelsFlag !== void 0 ? labelsFlag.split(",").map((label) => label.trim()).filter(Boolean) : void 0;
|
|
1960
|
+
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.");
|
|
1961
|
+
let result;
|
|
1962
|
+
try {
|
|
1963
|
+
result = await post(credentials.url, "/api/agent/tickets/update", {
|
|
1964
|
+
token: credentials.token,
|
|
1965
|
+
ticketRef,
|
|
1966
|
+
assignee,
|
|
1967
|
+
sprint,
|
|
1968
|
+
priority,
|
|
1969
|
+
labels
|
|
1970
|
+
});
|
|
1971
|
+
} catch (error) {
|
|
1972
|
+
if (error instanceof NetworkError) fail("Could not reach Neuvikon.");
|
|
1973
|
+
if (error instanceof ApiError) {
|
|
1974
|
+
if (error.status === 401) fail(error.message, "Run `npx neuvikon login` again.");
|
|
1975
|
+
fail(error.message);
|
|
1976
|
+
}
|
|
1977
|
+
throw error;
|
|
1978
|
+
}
|
|
1979
|
+
success(`Updated ${bold(result.ref)}: ${result.changed.join(", ")}`);
|
|
1980
|
+
}
|
|
1981
|
+
//#endregion
|
|
1913
1982
|
//#region src/index.ts
|
|
1914
1983
|
const HELP = `${bold("neuvikon")} — tell Neuvikon which ticket your coding agent is on
|
|
1915
1984
|
|
|
@@ -1933,7 +2002,12 @@ ${bold("Board")}
|
|
|
1933
2002
|
File something you noticed as its own ticket, same project
|
|
1934
2003
|
npx neuvikon create "Add French copy" --sub
|
|
1935
2004
|
...or as a sub-ticket (--sub for this one, --parent NS-12 for another)
|
|
1936
|
-
|
|
2005
|
+
npx neuvikon create "..." --assignee Ogulcan --sprint "Sprint 1"
|
|
2006
|
+
File it already assigned and/or planned in a sprint
|
|
2007
|
+
npx neuvikon update --assignee Ogulcan --sprint "Sprint 1" --priority high
|
|
2008
|
+
Change assignee, sprint, priority, or labels on an existing ticket
|
|
2009
|
+
("none" clears --assignee/--sprint)
|
|
2010
|
+
All five accept --ticket EWWQ-1 instead of relying on a tracked session.
|
|
1937
2011
|
|
|
1938
2012
|
${bold("Project pages")}
|
|
1939
2013
|
npx neuvikon pages List the current ticket's project pages
|
|
@@ -1995,6 +2069,7 @@ async function main() {
|
|
|
1995
2069
|
case "move": return move(flags);
|
|
1996
2070
|
case "comment": return comment(flags);
|
|
1997
2071
|
case "create": return create(flags, positional);
|
|
2072
|
+
case "update": return update(flags);
|
|
1998
2073
|
case void 0:
|
|
1999
2074
|
case "help":
|
|
2000
2075
|
case "--help":
|