@kosuke-ai/kosuke 1.0.46 → 1.0.48

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/program.js CHANGED
@@ -6,15 +6,13 @@ import { attachIntegrationsCommands } from './commands/integrations.js';
6
6
  import { attachWatchCommand } from './commands/watch.js';
7
7
  import { operations } from './generated/commands/index.js';
8
8
  import { attachCommand } from './runtime/attach.js';
9
- import { attachFormerCommands } from './runtime/former-commands.js';
10
9
  import { formsOf } from './runtime/variants.js';
11
10
  import { agentTokenOf, isReachable } from './runtime/agent-tokens.js';
12
11
  import { createRuntime, ExitSignal } from './runtime/runtime.js';
13
12
  import { version } from './runtime/version.js';
14
13
  /**
15
14
  * The command tree: the commands `commands/hand-written.ts` lists by hand, everything else
16
- * from the generated descriptors, one leaf per command over its forms, then the former
17
- * names as hidden aliases. Global flags are read
15
+ * from the generated descriptors, one leaf per command over its forms. Global flags are read
18
16
  * before any subcommand runs, so the runtime the subcommands share is built once, from them.
19
17
  */
20
18
  export function createProgram(options = {}) {
@@ -61,7 +59,6 @@ export function createProgram(options = {}) {
61
59
  // The job stream admits a member's API key only; it closes 4401 on every narrower token.
62
60
  if (narrowedTo === null)
63
61
  attachWatchCommand(program, lazy, options.watch);
64
- attachFormerCommands(program, operations.filter(reaches), lazy);
65
62
  return program;
66
63
  }
67
64
  /** Run to completion; an ExitSignal has already reported and set the exit code. */
@@ -13,16 +13,13 @@ export function attachCommand(root, forms, runtime, { reachable = () => true } =
13
13
  const [only] = forms;
14
14
  if (forms.length === 1 && !only.variant) {
15
15
  // A hidden operation sits beside a hand-written command in a visible group.
16
- return attachLeaf(root, only.command, only, runtime, {
17
- hidden: only.hidden === true,
18
- groupsHidden: false,
19
- });
16
+ return attachLeaf(root, only.command, only, runtime, only.hidden === true);
20
17
  }
21
18
  return attachForms(root, forms, runtime, reachable);
22
19
  }
23
- /** A single-form leaf: the command as it was before forms, which aliases reuse. */
24
- export function attachLeaf(root, path, operation, runtime, { hidden, groupsHidden = hidden, fixed = {}, formerFlags = {} }) {
25
- const parent = groupFor(root, path.slice(0, -1), { hidden: groupsHidden });
20
+ /** A leaf for an operation with a single form. */
21
+ function attachLeaf(root, path, operation, runtime, hidden) {
22
+ const parent = groupFor(root, path.slice(0, -1));
26
23
  const leaf = parent.command(path[path.length - 1], { hidden });
27
24
  leaf.description(operation.summary);
28
25
  for (const name of operation.pathParams) {
@@ -31,25 +28,13 @@ export function attachLeaf(root, path, operation, runtime, { hidden, groupsHidde
31
28
  const fields = fieldsOf(operation);
32
29
  for (const field of fields)
33
30
  addFieldOptions(leaf, field, field.description ?? '');
34
- for (const [former, current] of Object.entries(formerFlags)) {
35
- const field = fields.find((candidate) => candidate.flag === current);
36
- if (!field) {
37
- throw new Error(`kosuke ${path.join(' ')}: --${former} names --${current}, not a flag.`);
38
- }
39
- const option = new Option(`--${former} <value>`).hideHelp();
40
- // Repeated as it was, `--project-ids a --project-ids b`, or one JSON list.
41
- if (field.repeated)
42
- option.argParser(collect).default(undefined);
43
- leaf.addOption(option);
44
- }
45
31
  addBodyOptions(leaf, operation);
46
32
  leaf.action(async (...args) => {
47
33
  const options = args[args.length - 2];
48
34
  const positionals = args.slice(0, operation.pathParams.length);
49
35
  try {
50
36
  checkFileFlags(options, fields.filter((field) => field.file).map((field) => field.flag));
51
- // `personal` where a workspace id goes, on a command with no personal form. An alias
52
- // leaf runs a personal form by its old path, which takes no workspace id at all.
37
+ // Refuse `personal` where a workspace id goes on a command with no personal form.
53
38
  if (!operation.variant)
54
39
  selectForm([operation], { first: positionals[0], flags: {} });
55
40
  }
@@ -58,19 +43,13 @@ export function attachLeaf(root, path, operation, runtime, { hidden, groupsHidde
58
43
  leaf.error(error.message);
59
44
  throw error;
60
45
  }
61
- const values = Object.fromEntries(fields.map((field) => {
62
- const former = Object.entries(formerFlags).find(([, current]) => current === field.flag);
63
- const formerValue = former
64
- ? formerValueOf(field, options[optionKey(former[0])])
65
- : undefined;
66
- return [
67
- field.name,
68
- options[optionKey(field.flag)] ?? fileValue(field, options) ?? formerValue,
69
- ];
70
- }));
46
+ const values = Object.fromEntries(fields.map((field) => [
47
+ field.name,
48
+ options[optionKey(field.flag)] ?? fileValue(field, options),
49
+ ]));
71
50
  await run(leaf, runtime, operation, {
72
51
  pathParams: Object.fromEntries(operation.pathParams.map((name, i) => [name, positionals[i]])),
73
- fields: { ...values, ...fixed },
52
+ fields: values,
74
53
  wholeBody: readWholeBody({
75
54
  body: options.body,
76
55
  bodyFile: options.bodyFile,
@@ -242,22 +221,6 @@ function parseForForm(field, raw) {
242
221
  return raw === 'true';
243
222
  return field.repeated ? [raw] : raw;
244
223
  }
245
- /** The value of a renamed flag, by the rule its field had: one JSON list, or the values given. */
246
- function formerValueOf(field, raw) {
247
- if (Array.isArray(raw))
248
- return raw.flatMap((value) => formerValueOf(field, value));
249
- if (typeof raw !== 'string')
250
- return raw;
251
- if (!field.repeated)
252
- return field.kind === 'json' ? jsonParser(raw) : raw;
253
- try {
254
- const parsed = JSON.parse(raw);
255
- return Array.isArray(parsed) ? parsed : [raw];
256
- }
257
- catch {
258
- return [raw];
259
- }
260
- }
261
224
  function addFieldOptions(leaf, field, description) {
262
225
  leaf.addOption(optionFor({ ...field, description }));
263
226
  if (field.file) {
@@ -279,13 +242,12 @@ function addBodyOptions(leaf, operation) {
279
242
  leaf.option('--attach <path>', 'Attach a file; repeat for several. Sends the request as multipart.', collect, []);
280
243
  }
281
244
  }
282
- /** A group created here is hidden when asked; one that already exists keeps what it is. */
283
- export function groupFor(root, path, { hidden = false } = {}) {
245
+ /** Find or create the command groups on the way to a leaf. */
246
+ export function groupFor(root, path) {
284
247
  let current = root;
285
248
  for (const segment of path) {
286
249
  const existing = current.commands.find((command) => command.name() === segment);
287
- current =
288
- existing ?? current.command(segment, { hidden }).description(`${humanize(segment)} commands`);
250
+ current = existing ?? current.command(segment).description(`${humanize(segment)} commands`);
289
251
  }
290
252
  return current;
291
253
  }
package/openapi.json CHANGED
@@ -10958,6 +10958,84 @@
10958
10958
  }
10959
10959
  }
10960
10960
  },
10961
+ "/api/projects/{projectId}/batch-merging/picks": {
10962
+ "put": {
10963
+ "operationId": "projectsBatchMergingPicksSet",
10964
+ "summary": "The open Batch's own session only, running or pipelined: replace the list of task pull requests merged into its branch. Their tasks show the Batch while it runs, and stop once it ends. Safe to repeat.",
10965
+ "tags": ["projects"],
10966
+ "x-kosuke-command": ["projects", "batch-merging", "picks", "set"],
10967
+ "x-kosuke-sandbox-token": true,
10968
+ "x-kosuke-cron-token": true,
10969
+ "x-kosuke-sensei-token": true,
10970
+ "parameters": [
10971
+ {
10972
+ "name": "projectId",
10973
+ "in": "path",
10974
+ "required": true,
10975
+ "schema": {
10976
+ "type": "string",
10977
+ "format": "uuid",
10978
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
10979
+ }
10980
+ }
10981
+ ],
10982
+ "requestBody": {
10983
+ "required": true,
10984
+ "content": {
10985
+ "application/json": {
10986
+ "schema": {
10987
+ "type": "object",
10988
+ "properties": {
10989
+ "pullRequests": {
10990
+ "maxItems": 500,
10991
+ "type": "array",
10992
+ "items": {
10993
+ "type": "integer",
10994
+ "exclusiveMinimum": 0,
10995
+ "maximum": 2147483647
10996
+ },
10997
+ "description": "Every task pull request merged into this Batch's branch now, in merge order: the whole list, never its base Batch's. An empty list clears it."
10998
+ }
10999
+ },
11000
+ "required": ["pullRequests"]
11001
+ }
11002
+ }
11003
+ }
11004
+ },
11005
+ "responses": {
11006
+ "2XX": {
11007
+ "description": "Success envelope",
11008
+ "content": {
11009
+ "application/json": {
11010
+ "schema": {
11011
+ "$ref": "#/components/schemas/ApiSuccess"
11012
+ }
11013
+ }
11014
+ }
11015
+ },
11016
+ "4XX": {
11017
+ "description": "Error envelope",
11018
+ "content": {
11019
+ "application/json": {
11020
+ "schema": {
11021
+ "$ref": "#/components/schemas/ApiError"
11022
+ }
11023
+ }
11024
+ }
11025
+ },
11026
+ "5XX": {
11027
+ "description": "Error envelope",
11028
+ "content": {
11029
+ "application/json": {
11030
+ "schema": {
11031
+ "$ref": "#/components/schemas/ApiError"
11032
+ }
11033
+ }
11034
+ }
11035
+ }
11036
+ }
11037
+ }
11038
+ },
10961
11039
  "/api/projects/{projectId}/branches": {
10962
11040
  "get": {
10963
11041
  "operationId": "projectsBranchesList",
@@ -12254,6 +12332,72 @@
12254
12332
  }
12255
12333
  }
12256
12334
  },
12335
+ "/api/projects/{projectId}/chat-sessions/{sessionId}/env-sync": {
12336
+ "post": {
12337
+ "operationId": "sessionsEnvSync",
12338
+ "summary": "Deliver the project's saved environment variables, with its services and setup commands, to a chat session's running sandbox and restart its setup and services, so a variable added after the sandbox booted reaches them. Answers status synced with the variable names, never their values, once the services answer again, or status running when setup outlasts ten minutes and the sync goes on. Refused, never queued: 409 TURN_RUNNING while a turn runs, SANDBOX_NOT_RUNNING when the sandbox is not up (it is not woken), SANDBOX_PROVISIONING or SANDBOX_NOT_READY while it is created or boots, APP_STACK_STARTING during an App stack start and SANDBOX_BUSY while another update changes it; 422 ENV_SYNC_FAILED when setup or a service did not come back.",
12339
+ "tags": ["sessions"],
12340
+ "x-kosuke-command": ["sessions", "env", "sync"],
12341
+ "x-kosuke-answer-timeout-ms": 660000,
12342
+ "x-kosuke-sandbox-token": true,
12343
+ "x-kosuke-cron-token": true,
12344
+ "x-kosuke-sensei-token": true,
12345
+ "parameters": [
12346
+ {
12347
+ "name": "projectId",
12348
+ "in": "path",
12349
+ "required": true,
12350
+ "schema": {
12351
+ "type": "string",
12352
+ "format": "uuid",
12353
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
12354
+ }
12355
+ },
12356
+ {
12357
+ "name": "sessionId",
12358
+ "in": "path",
12359
+ "required": true,
12360
+ "schema": {
12361
+ "type": "string",
12362
+ "format": "uuid",
12363
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
12364
+ }
12365
+ }
12366
+ ],
12367
+ "responses": {
12368
+ "2XX": {
12369
+ "description": "Success envelope",
12370
+ "content": {
12371
+ "application/json": {
12372
+ "schema": {
12373
+ "$ref": "#/components/schemas/ApiSuccess"
12374
+ }
12375
+ }
12376
+ }
12377
+ },
12378
+ "4XX": {
12379
+ "description": "Error envelope",
12380
+ "content": {
12381
+ "application/json": {
12382
+ "schema": {
12383
+ "$ref": "#/components/schemas/ApiError"
12384
+ }
12385
+ }
12386
+ }
12387
+ },
12388
+ "5XX": {
12389
+ "description": "Error envelope",
12390
+ "content": {
12391
+ "application/json": {
12392
+ "schema": {
12393
+ "$ref": "#/components/schemas/ApiError"
12394
+ }
12395
+ }
12396
+ }
12397
+ }
12398
+ }
12399
+ }
12400
+ },
12257
12401
  "/api/projects/{projectId}/chat-sessions/{sessionId}/go-ahead": {
12258
12402
  "put": {
12259
12403
  "operationId": "sessionsGoAheadSet",
@@ -14394,7 +14538,7 @@
14394
14538
  "/api/projects/{projectId}/chat-sessions/{sessionId}/qa-passed": {
14395
14539
  "put": {
14396
14540
  "operationId": "sessionsQaSet",
14397
- "summary": "Record the commit QA passed on as the session's qaPassedSha: a member's override, or the session's own agent. `sessions qa runs finish` records it when the whole checklist passed. A pull request is done when qaPassedSha equals its head.",
14541
+ "summary": "Record the commit QA passed on as the session's qaPassedSha: a member's override. `sessions qa runs finish` records it when the whole checklist passed. A pull request is done when qaPassedSha equals its head.",
14398
14542
  "tags": ["sessions"],
14399
14543
  "x-kosuke-command": ["sessions", "qa", "set"],
14400
14544
  "x-kosuke-sandbox-token": true,
@@ -18911,7 +19055,7 @@
18911
19055
  "/api/projects/{projectId}/settings/agentic-deploy/queue/{queuedMessageId}/steer": {
18912
19056
  "post": {
18913
19057
  "operationId": "deploysQueueSteer",
18914
- "summary": "Send your own queued Deploy Chat message into the running deploy agent Turn as a steer. Claude deploys only; the message stays queued when nothing can take it.",
19058
+ "summary": "Send your own queued Deploy Chat message into the running deploy agent Turn as a steer, on any deploy model whose runtime takes one; the message stays queued when nothing can take it.",
18915
19059
  "tags": ["deploys"],
18916
19060
  "x-kosuke-command": ["deploys", "queue", "steer"],
18917
19061
  "x-kosuke-sandbox-token": true,
@@ -24248,6 +24392,74 @@
24248
24392
  }
24249
24393
  }
24250
24394
  },
24395
+ "/api/sensei/thread-create": {
24396
+ "post": {
24397
+ "operationId": "senseiThreadsCreate",
24398
+ "summary": "Open a new thread for the member, at any point of this Turn, on a prompt you write. Only Sensei calls it, for a separate topic that should not go on in this thread. Never for the asks of the member’s message that started this thread: `sensei threads split` does that. The new thread gets its own Turn, which may read Queued, and links back here; nothing of this thread goes with it, so the prompt says all it needs. A Turn opens at most 3 threads, and so do the threads opened from one thread in all. Answers the new thread id and turn id: do not do that work here.",
24399
+ "tags": ["sensei"],
24400
+ "x-kosuke-command": ["sensei", "threads", "create"],
24401
+ "x-kosuke-sandbox-token": true,
24402
+ "x-kosuke-cron-token": true,
24403
+ "x-kosuke-sensei-token": true,
24404
+ "requestBody": {
24405
+ "required": true,
24406
+ "content": {
24407
+ "application/json": {
24408
+ "schema": {
24409
+ "type": "object",
24410
+ "properties": {
24411
+ "prompt": {
24412
+ "type": "string",
24413
+ "minLength": 1,
24414
+ "maxLength": 20000,
24415
+ "description": "What the new thread’s Turn does, whole, in words that stand without this thread: it reads nothing else of it."
24416
+ },
24417
+ "title": {
24418
+ "description": "A short title for the new thread. Without it, the thread is named by the prompt.",
24419
+ "type": "string",
24420
+ "minLength": 1,
24421
+ "maxLength": 200
24422
+ }
24423
+ },
24424
+ "required": ["prompt"]
24425
+ }
24426
+ }
24427
+ }
24428
+ },
24429
+ "responses": {
24430
+ "2XX": {
24431
+ "description": "Success envelope",
24432
+ "content": {
24433
+ "application/json": {
24434
+ "schema": {
24435
+ "$ref": "#/components/schemas/ApiSuccess"
24436
+ }
24437
+ }
24438
+ }
24439
+ },
24440
+ "4XX": {
24441
+ "description": "Error envelope",
24442
+ "content": {
24443
+ "application/json": {
24444
+ "schema": {
24445
+ "$ref": "#/components/schemas/ApiError"
24446
+ }
24447
+ }
24448
+ }
24449
+ },
24450
+ "5XX": {
24451
+ "description": "Error envelope",
24452
+ "content": {
24453
+ "application/json": {
24454
+ "schema": {
24455
+ "$ref": "#/components/schemas/ApiError"
24456
+ }
24457
+ }
24458
+ }
24459
+ }
24460
+ }
24461
+ }
24462
+ },
24251
24463
  "/api/sensei/thread-move": {
24252
24464
  "post": {
24253
24465
  "operationId": "senseiThreadsMove",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kosuke-ai/kosuke",
3
- "version": "1.0.46",
3
+ "version": "1.0.48",
4
4
  "description": "Kosuke platform CLI. The client customers install to drive app.kosuke.ai from their own machine.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -40,10 +40,13 @@
40
40
  "vitest": "^4.1.12"
41
41
  },
42
42
  "kosukeRelease": {
43
- "sourceCommit": "f4683aa88f4cb9eb6912d2a4200eb6c1f200bcf7",
44
- "sourceIdentity": "fdca0a6ab0b23ad62544a8f7e689f390510d911a476dee7ab45956bfb173e44b",
43
+ "sourceCommit": "f75c0ef51a675f14fa5bcc79de7d275f7084b580",
44
+ "sourceIdentity": "f07745a38e5f377026b443e17377c207475f86d04bec95ddce5886fb7adc9ffd",
45
45
  "fragments": [
46
- "go-ahead-marks-ready-h7yijc.json"
46
+ "command-grammar-aliases-removed-mlwinm.json",
47
+ "sensei-threads-create-puzuue.json",
48
+ "session-env-sync-bk2sgu.json",
49
+ "skill-marker-result-help-pkivi6.json"
47
50
  ]
48
51
  }
49
52
  }