@kosuke-ai/kosuke 1.0.11 → 1.0.13

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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.13
4
+
5
+ - Update help text: Sensei deletes Backlog sessions, imports into Personal and reuses browser sign-ins in any Turn, whatever started it.
6
+
7
+ ## 1.0.12
8
+
9
+ - Add `kosuke user usage get`: what used your AI work, with calendar-day counts by work, repository and model.
10
+ - Keep personal usage metadata with member credentials and correct usage attribution and busiest items.
11
+ - `sensei watch-reads finish` records a LinkedIn or X Watching read from its own Sensei Turn, and takes the Sensei token only. `integrations list` says a browser site such as LinkedIn or X is used in the browser on its Mac.
12
+
3
13
  ## 1.0.11
4
14
 
5
15
  - Add `--accept-failed` to `sessions qa runs finish`, which lets a running Batch accept minor FAILED items, never critical or major ones, beside the BLOCKED items it accepts.
@@ -226,107 +226,109 @@ import { operation as o224 } from './sensei/threads-list.js';
226
226
  import { operation as o225 } from './sensei/threads-move.js';
227
227
  import { operation as o226 } from './sensei/threads-split.js';
228
228
  import { operation as o227 } from './sensei/tickets-merge.js';
229
- import { operation as o228 } from './sensei/widgets-get.js';
230
- import { operation as o229 } from './sessions/app-stack-start.js';
231
- import { operation as o230 } from './sessions/artifacts-create.js';
232
- import { operation as o231 } from './sessions/artifacts-get.js';
233
- import { operation as o232 } from './sessions/artifacts-list.js';
234
- import { operation as o233 } from './sessions/create.js';
235
- import { operation as o234 } from './sessions/delete.js';
236
- import { operation as o235 } from './sessions/desktop-control-set.js';
237
- import { operation as o236 } from './sessions/desktop-get.js';
238
- import { operation as o237 } from './sessions/desktop-start.js';
239
- import { operation as o238 } from './sessions/diff-comments-create.js';
240
- import { operation as o239 } from './sessions/diff-comments-delete.js';
241
- import { operation as o240 } from './sessions/diff-comments-list.js';
242
- import { operation as o241 } from './sessions/diff-comments-update.js';
243
- import { operation as o242 } from './sessions/diff-commits-list.js';
244
- import { operation as o243 } from './sessions/diff-files-list.js';
245
- import { operation as o244 } from './sessions/diff-patch-get.js';
246
- import { operation as o245 } from './sessions/files-get.js';
247
- import { operation as o246 } from './sessions/files-list.js';
248
- import { operation as o247 } from './sessions/files-set.js';
249
- import { operation as o248 } from './sessions/get.js';
250
- import { operation as o249 } from './sessions/git-commit.js';
251
- import { operation as o250 } from './sessions/git-commit-message-create.js';
252
- import { operation as o251 } from './sessions/git-push.js';
253
- import { operation as o252 } from './sessions/git-state-get.js';
254
- import { operation as o253 } from './sessions/go-ahead-delete.js';
255
- import { operation as o254 } from './sessions/go-ahead-set.js';
256
- import { operation as o255 } from './sessions/jobs-cancel.js';
257
- import { operation as o256 } from './sessions/jobs-get.js';
258
- import { operation as o257 } from './sessions/jobs-list.js';
259
- import { operation as o258 } from './sessions/labels-set.js';
260
- import { operation as o259 } from './sessions/labels-update.js';
261
- import { operation as o260 } from './sessions/list.js';
262
- import { operation as o261 } from './sessions/list--all.js';
263
- import { operation as o262 } from './sessions/mark-read.js';
264
- import { operation as o263 } from './sessions/messages-get.js';
265
- import { operation as o264 } from './sessions/messages-list.js';
266
- import { operation as o265 } from './sessions/prompt-update.js';
267
- import { operation as o266 } from './sessions/pull-request-mark-ready.js';
268
- import { operation as o267 } from './sessions/qa-runs-finish.js';
269
- import { operation as o268 } from './sessions/qa-runs-fixes-create.js';
270
- import { operation as o269 } from './sessions/qa-runs-get.js';
271
- import { operation as o270 } from './sessions/qa-runs-results-create.js';
272
- import { operation as o271 } from './sessions/qa-runs-start.js';
273
- import { operation as o272 } from './sessions/qa-runs-stop.js';
274
- import { operation as o273 } from './sessions/qa-set.js';
275
- import { operation as o274 } from './sessions/queue-delete.js';
276
- import { operation as o275 } from './sessions/queue-list.js';
277
- import { operation as o276 } from './sessions/queue-move.js';
278
- import { operation as o277 } from './sessions/queue-resume.js';
279
- import { operation as o278 } from './sessions/queue-send.js';
280
- import { operation as o279 } from './sessions/queue-steer.js';
281
- import { operation as o280 } from './sessions/queue-update.js';
282
- import { operation as o281 } from './sessions/review-set.js';
283
- import { operation as o282 } from './sessions/runtime-commands-run.js';
284
- import { operation as o283 } from './sessions/search.js';
285
- import { operation as o284 } from './sessions/send.js';
286
- import { operation as o285 } from './sessions/start.js';
287
- import { operation as o286 } from './sessions/steer.js';
288
- import { operation as o287 } from './sessions/sync.js';
289
- import { operation as o288 } from './sessions/update.js';
290
- import { operation as o289 } from './skills/create.js';
291
- import { operation as o290 } from './skills/create--personal.js';
292
- import { operation as o291 } from './skills/delete.js';
293
- import { operation as o292 } from './skills/delete--personal.js';
294
- import { operation as o293 } from './skills/get.js';
295
- import { operation as o294 } from './skills/get--personal.js';
296
- import { operation as o295 } from './skills/list.js';
297
- import { operation as o296 } from './skills/list--personal.js';
298
- import { operation as o297 } from './skills/update.js';
299
- import { operation as o298 } from './skills/update--personal.js';
300
- import { operation as o299 } from './tasks/create.js';
301
- import { operation as o300 } from './tasks/create--personal.js';
302
- import { operation as o301 } from './tasks/delete.js';
303
- import { operation as o302 } from './tasks/delete--personal.js';
304
- import { operation as o303 } from './tasks/get.js';
305
- import { operation as o304 } from './tasks/get--personal.js';
306
- import { operation as o305 } from './tasks/labels-list.js';
307
- import { operation as o306 } from './tasks/list.js';
308
- import { operation as o307 } from './tasks/list--all.js';
309
- import { operation as o308 } from './tasks/list--personal.js';
310
- import { operation as o309 } from './tasks/move.js';
311
- import { operation as o310 } from './tasks/move--personal.js';
312
- import { operation as o311 } from './tasks/start.js';
313
- import { operation as o312 } from './tasks/start--personal.js';
314
- import { operation as o313 } from './tasks/update.js';
315
- import { operation as o314 } from './tasks/update--personal.js';
316
- import { operation as o315 } from './user/api-keys-delete.js';
317
- import { operation as o316 } from './user/profile-get.js';
318
- import { operation as o317 } from './user/push-devices-create.js';
319
- import { operation as o318 } from './user/push-devices-delete.js';
320
- import { operation as o319 } from './workspaces/artifacts-search.js';
321
- import { operation as o320 } from './workspaces/credits-get.js';
322
- import { operation as o321 } from './workspaces/get.js';
323
- import { operation as o322 } from './workspaces/list.js';
324
- import { operation as o323 } from './workspaces/members-list.js';
325
- import { operation as o324 } from './workspaces/members-list--all.js';
326
- import { operation as o325 } from './workspaces/sandbox-limit-get.js';
327
- import { operation as o326 } from './workspaces/sandboxes-stop.js';
328
- import { operation as o327 } from './workspaces/timezone-set.js';
329
- import { operation as o328 } from './workspaces/usage-get.js';
229
+ import { operation as o228 } from './sensei/watch-reads-finish.js';
230
+ import { operation as o229 } from './sensei/widgets-get.js';
231
+ import { operation as o230 } from './sessions/app-stack-start.js';
232
+ import { operation as o231 } from './sessions/artifacts-create.js';
233
+ import { operation as o232 } from './sessions/artifacts-get.js';
234
+ import { operation as o233 } from './sessions/artifacts-list.js';
235
+ import { operation as o234 } from './sessions/create.js';
236
+ import { operation as o235 } from './sessions/delete.js';
237
+ import { operation as o236 } from './sessions/desktop-control-set.js';
238
+ import { operation as o237 } from './sessions/desktop-get.js';
239
+ import { operation as o238 } from './sessions/desktop-start.js';
240
+ import { operation as o239 } from './sessions/diff-comments-create.js';
241
+ import { operation as o240 } from './sessions/diff-comments-delete.js';
242
+ import { operation as o241 } from './sessions/diff-comments-list.js';
243
+ import { operation as o242 } from './sessions/diff-comments-update.js';
244
+ import { operation as o243 } from './sessions/diff-commits-list.js';
245
+ import { operation as o244 } from './sessions/diff-files-list.js';
246
+ import { operation as o245 } from './sessions/diff-patch-get.js';
247
+ import { operation as o246 } from './sessions/files-get.js';
248
+ import { operation as o247 } from './sessions/files-list.js';
249
+ import { operation as o248 } from './sessions/files-set.js';
250
+ import { operation as o249 } from './sessions/get.js';
251
+ import { operation as o250 } from './sessions/git-commit.js';
252
+ import { operation as o251 } from './sessions/git-commit-message-create.js';
253
+ import { operation as o252 } from './sessions/git-push.js';
254
+ import { operation as o253 } from './sessions/git-state-get.js';
255
+ import { operation as o254 } from './sessions/go-ahead-delete.js';
256
+ import { operation as o255 } from './sessions/go-ahead-set.js';
257
+ import { operation as o256 } from './sessions/jobs-cancel.js';
258
+ import { operation as o257 } from './sessions/jobs-get.js';
259
+ import { operation as o258 } from './sessions/jobs-list.js';
260
+ import { operation as o259 } from './sessions/labels-set.js';
261
+ import { operation as o260 } from './sessions/labels-update.js';
262
+ import { operation as o261 } from './sessions/list.js';
263
+ import { operation as o262 } from './sessions/list--all.js';
264
+ import { operation as o263 } from './sessions/mark-read.js';
265
+ import { operation as o264 } from './sessions/messages-get.js';
266
+ import { operation as o265 } from './sessions/messages-list.js';
267
+ import { operation as o266 } from './sessions/prompt-update.js';
268
+ import { operation as o267 } from './sessions/pull-request-mark-ready.js';
269
+ import { operation as o268 } from './sessions/qa-runs-finish.js';
270
+ import { operation as o269 } from './sessions/qa-runs-fixes-create.js';
271
+ import { operation as o270 } from './sessions/qa-runs-get.js';
272
+ import { operation as o271 } from './sessions/qa-runs-results-create.js';
273
+ import { operation as o272 } from './sessions/qa-runs-start.js';
274
+ import { operation as o273 } from './sessions/qa-runs-stop.js';
275
+ import { operation as o274 } from './sessions/qa-set.js';
276
+ import { operation as o275 } from './sessions/queue-delete.js';
277
+ import { operation as o276 } from './sessions/queue-list.js';
278
+ import { operation as o277 } from './sessions/queue-move.js';
279
+ import { operation as o278 } from './sessions/queue-resume.js';
280
+ import { operation as o279 } from './sessions/queue-send.js';
281
+ import { operation as o280 } from './sessions/queue-steer.js';
282
+ import { operation as o281 } from './sessions/queue-update.js';
283
+ import { operation as o282 } from './sessions/review-set.js';
284
+ import { operation as o283 } from './sessions/runtime-commands-run.js';
285
+ import { operation as o284 } from './sessions/search.js';
286
+ import { operation as o285 } from './sessions/send.js';
287
+ import { operation as o286 } from './sessions/start.js';
288
+ import { operation as o287 } from './sessions/steer.js';
289
+ import { operation as o288 } from './sessions/sync.js';
290
+ import { operation as o289 } from './sessions/update.js';
291
+ import { operation as o290 } from './skills/create.js';
292
+ import { operation as o291 } from './skills/create--personal.js';
293
+ import { operation as o292 } from './skills/delete.js';
294
+ import { operation as o293 } from './skills/delete--personal.js';
295
+ import { operation as o294 } from './skills/get.js';
296
+ import { operation as o295 } from './skills/get--personal.js';
297
+ import { operation as o296 } from './skills/list.js';
298
+ import { operation as o297 } from './skills/list--personal.js';
299
+ import { operation as o298 } from './skills/update.js';
300
+ import { operation as o299 } from './skills/update--personal.js';
301
+ import { operation as o300 } from './tasks/create.js';
302
+ import { operation as o301 } from './tasks/create--personal.js';
303
+ import { operation as o302 } from './tasks/delete.js';
304
+ import { operation as o303 } from './tasks/delete--personal.js';
305
+ import { operation as o304 } from './tasks/get.js';
306
+ import { operation as o305 } from './tasks/get--personal.js';
307
+ import { operation as o306 } from './tasks/labels-list.js';
308
+ import { operation as o307 } from './tasks/list.js';
309
+ import { operation as o308 } from './tasks/list--all.js';
310
+ import { operation as o309 } from './tasks/list--personal.js';
311
+ import { operation as o310 } from './tasks/move.js';
312
+ import { operation as o311 } from './tasks/move--personal.js';
313
+ import { operation as o312 } from './tasks/start.js';
314
+ import { operation as o313 } from './tasks/start--personal.js';
315
+ import { operation as o314 } from './tasks/update.js';
316
+ import { operation as o315 } from './tasks/update--personal.js';
317
+ import { operation as o316 } from './user/api-keys-delete.js';
318
+ import { operation as o317 } from './user/profile-get.js';
319
+ import { operation as o318 } from './user/push-devices-create.js';
320
+ import { operation as o319 } from './user/push-devices-delete.js';
321
+ import { operation as o320 } from './user/usage-get.js';
322
+ import { operation as o321 } from './workspaces/artifacts-search.js';
323
+ import { operation as o322 } from './workspaces/credits-get.js';
324
+ import { operation as o323 } from './workspaces/get.js';
325
+ import { operation as o324 } from './workspaces/list.js';
326
+ import { operation as o325 } from './workspaces/members-list.js';
327
+ import { operation as o326 } from './workspaces/members-list--all.js';
328
+ import { operation as o327 } from './workspaces/sandbox-limit-get.js';
329
+ import { operation as o328 } from './workspaces/sandboxes-stop.js';
330
+ import { operation as o329 } from './workspaces/timezone-set.js';
331
+ import { operation as o330 } from './workspaces/usage-get.js';
330
332
  export const operations = [
331
333
  o0,
332
334
  o1,
@@ -657,4 +659,6 @@ export const operations = [
657
659
  o326,
658
660
  o327,
659
661
  o328,
662
+ o329,
663
+ o330,
660
664
  ];
@@ -7,7 +7,7 @@ export const operation = {
7
7
  "call"
8
8
  ],
9
9
  "hidden": true,
10
- "summary": "Run one integration tool. An agent runs it for its own workspace, or on the member’s personal connection when that member started the turn. With an API key, name a workspace you belong to: the call runs only on your own personal connections, and one on a workspace connection is refused. The answer names the connection it ran on, or lists the connections to choose from when the call needs one. A tool failure answers 200 with isError true. Some integrations require an enabled workspace to be named. A Connector Token or a browser session is refused.",
10
+ "summary": "Run one integration tool. An agent runs it for its own workspace, or on the member’s personal connection in any of their Sensei Turns or a session turn that member started. With an API key, name a workspace you belong to: the call runs only on your own personal connections, and one on a workspace connection is refused. The answer names the connection it ran on, or lists the connections to choose from when the call needs one. A tool failure answers 200 with isError true. Some integrations require an enabled workspace to be named. A Connector Token or a browser session is refused.",
11
11
  "pathParams": [],
12
12
  "query": [
13
13
  {
@@ -7,7 +7,7 @@ export const operation = {
7
7
  "list"
8
8
  ],
9
9
  "hidden": true,
10
- "summary": "List the integration tools you can run now, with the connections that run them. An agent reads its own workspace. With an API key, name a workspace you belong to: it shows that workspace’s connections and your own personal ones. Some integrations require an enabled workspace to be named. A Connector Token or a browser session is refused. Each toolkit is personal or workspace, never both. A personal connection reaches only a Turn its member started (in a workspace chat, only the session's Assignee); a workspace Cron, Deploy Chat, a Turn another member sent and unassigned work reach workspace connections only. In the Personal space the owner's own Turns reach both kinds.",
10
+ "summary": "List the integration tools you can run now, with the connections that run them. An agent reads its own workspace. With an API key, name a workspace you belong to: it shows that workspace’s connections and your own personal ones. Some integrations require an enabled workspace to be named. A Connector Token or a browser session is refused. Each toolkit is personal or workspace, never both. A personal connection reaches every Sensei Turn of its member, and a session turn its member started (in a workspace chat, only the session's Assignee); a workspace Cron, Deploy Chat, a Turn another member sent and unassigned work reach workspace connections only. In the Personal space the owner's own Turns reach both kinds.",
11
11
  "pathParams": [],
12
12
  "query": [
13
13
  {
@@ -7,7 +7,7 @@ export const operation = {
7
7
  "connections",
8
8
  "list"
9
9
  ],
10
- "summary": "List the member's LinkedIn and X browser connections, oldest first: each is one account Sensei may act as, with its id, revision, account (null until Sensei fills it in), device (id, name, removed), profile (id, name), the last check (unchecked, connected, signed_out, other_account) with checkedAt, and connectThreadId, the only thread whose Turn may fill the account in. Pass its device id and profile id to every browser call for it. Only Sensei calls it, in a Turn the member's own message started.",
10
+ "summary": "List the member's LinkedIn and X browser connections, oldest first: each is one account Sensei may act as, with its id, revision, account (null until Sensei fills it in), device (id, name, removed), profile (id, name), the last check (unchecked, connected, signed_out, other_account) with checkedAt, and connectThreadId, the only thread whose Turn may fill the account in. Pass its device id and profile id to every browser call for it. Only Sensei calls it.",
11
11
  "pathParams": [],
12
12
  "query": [
13
13
  {
@@ -7,7 +7,7 @@ export const operation = {
7
7
  "connections",
8
8
  "update"
9
9
  ],
10
- "summary": "Report what one check of the live page saw for a browser connection, with the revision `kosuke mac browser connections list` answered: connected with the account's name and handle, signed_out, or other_account with the name found. The first connected fills the account in, only from a Turn of its connectThreadId (else 403 NOT_CONNECT_THREAD); afterwards the handle must match it (else 409 ACCOUNT_MISMATCH). 409 STALE_REVISION after a newer Connect or Reconnect: read again. 404 once the member disconnected it. Only Sensei calls it, in a Turn the member's own message started.",
10
+ "summary": "Report what one check of the live page saw for a browser connection, with the revision `kosuke mac browser connections list` answered: connected with the account's name and handle, signed_out, or other_account with the name found. The first connected fills the account in, only from a Turn of its connectThreadId (else 403 NOT_CONNECT_THREAD); afterwards the handle must match it (else 409 ACCOUNT_MISMATCH). 409 STALE_REVISION after a newer Connect or Reconnect: read again. 404 once the member disconnected it. Only Sensei calls it.",
11
11
  "pathParams": [],
12
12
  "query": [],
13
13
  "body": {
@@ -6,7 +6,7 @@ export const operation = {
6
6
  "browser",
7
7
  "login"
8
8
  ],
9
- "summary": "Get a site signed in in this Sensei Thread's browser from the member's everyday Chrome: pass the browser call's profile and deviceId, and the site as a bare hostname (twitter.com is x.com; Google's sites are refused). --reuse picks up the sign-in that profile in their Chrome holds by itself, with no tap: only in a Turn the member's own message started, once per site and profile in a Turn, with the profile's exact ID. It never opens Chrome or waits for anyone, and answers opened false and signedIn false with chrome none (their Chrome holds no sign-in for the site, so nothing changed), same (the one this thread's browser already holds) or different (taken into this thread's browser, taken true). Then, unless it answered none or same, open the site with browser and check the account. On SIGN_IN_NEEDS_TAP or UPDATE_REQUIRED, put the sign-in card. A --reuse spends no tap, so it gives no card back. Every tapped mode (`sign-in`, `take`, `waitNew`) needs the member's tap on the sign-in card in this thread; `--forget` and `--reuse` need none. A sign-in takes the sign-in that profile in their Chrome holds when it differs from this thread's, without opening anything, and answers taken true, opened false and signedIn false, since the site has not confirmed it; or else it opens --url, or the site's page, in their Chrome and waits up to 8 minutes for the member to sign in. On LinkedIn and X it answers signedIn true and opened true. On any other site a change of the site's cookies is taken and answered taken true and signedIn false, since a change is not a sign-in, and an end with no change answers taken false; a desktop app too old to watch the site opens it and answers at once, with no taken. Every answer with taken true carries waitNewLeft: while it is above 0 and the site is still signed out, --wait-new (with the same --url), in the same Turn and with no new tap, waits for a newer sign-in, never taking the one taken already, and opens the site only when this Turn has not; once the tap's time has run out it fails with SIGN_IN_WINDOW_ENDED, and no card comes back. After the member's I'm signed in tap, --take takes that site's cookies, never Google's, and answers taken. --forget removes a sign-in this Turn took, a --reuse's included, for an account other than the one expected, and needs no tap. Each tap allows one call: a call without one, or a --wait-new that no take armed, fails with SIGN_IN_NEEDS_TAP. Then open the site with browser and check the account before account-specific work. On DEVICE_OFFLINE, TIMEOUT, SIGN_IN_TIMEOUT and KEYCHAIN_UNAVAILABLE Kosuke gives the member's card back by itself. Fails with SIGN_IN_TIMEOUT when Kosuke saw no new sign-in to LinkedIn or X within 8 minutes, PROFILE_DISCONNECTED for a profile turned off in Settings → Devices, KEYCHAIN_UNAVAILABLE when macOS did not let Kosuke read Chrome's sign-ins, STALE_TURN when the Turn stopped, and UPDATE_REQUIRED on a desktop app too old for it. Only Sensei calls it.",
9
+ "summary": "Get a site signed in in this Sensei Thread's browser from the member's everyday Chrome: pass the browser call's profile and deviceId, and the site as a bare hostname (twitter.com is x.com; Google's sites are refused). --reuse picks up the sign-in that profile in their Chrome holds by itself, with no tap: once per site and profile in a Turn, with the profile's exact ID. It never opens Chrome or waits for anyone, and answers opened false and signedIn false with chrome none (their Chrome holds no sign-in for the site, so nothing changed), same (the one this thread's browser already holds) or different (taken into this thread's browser, taken true). Then, unless it answered none or same, open the site with browser and check the account. On SIGN_IN_NEEDS_TAP or UPDATE_REQUIRED, put the sign-in card. A --reuse spends no tap, so it gives no card back. Every tapped mode (`sign-in`, `take`, `waitNew`) needs the member's tap on the sign-in card in this thread; `--forget` and `--reuse` need none. A sign-in takes the sign-in that profile in their Chrome holds when it differs from this thread's, without opening anything, and answers taken true, opened false and signedIn false, since the site has not confirmed it; or else it opens --url, or the site's page, in their Chrome and waits up to 8 minutes for the member to sign in. On LinkedIn and X it answers signedIn true and opened true. On any other site a change of the site's cookies is taken and answered taken true and signedIn false, since a change is not a sign-in, and an end with no change answers taken false; a desktop app too old to watch the site opens it and answers at once, with no taken. Every answer with taken true carries waitNewLeft: while it is above 0 and the site is still signed out, --wait-new (with the same --url), in the same Turn and with no new tap, waits for a newer sign-in, never taking the one taken already, and opens the site only when this Turn has not; once the tap's time has run out it fails with SIGN_IN_WINDOW_ENDED, and no card comes back. After the member's I'm signed in tap, --take takes that site's cookies, never Google's, and answers taken. --forget removes a sign-in this Turn took, a --reuse's included, for an account other than the one expected, and needs no tap. Each tap allows one call: a call without one, or a --wait-new that no take armed, fails with SIGN_IN_NEEDS_TAP. Then open the site with browser and check the account before account-specific work. On DEVICE_OFFLINE, TIMEOUT, SIGN_IN_TIMEOUT and KEYCHAIN_UNAVAILABLE Kosuke gives the member's card back by itself. Fails with SIGN_IN_TIMEOUT when Kosuke saw no new sign-in to LinkedIn or X within 8 minutes, PROFILE_DISCONNECTED for a profile turned off in Settings → Devices, KEYCHAIN_UNAVAILABLE when macOS did not let Kosuke read Chrome's sign-ins, STALE_TURN when the Turn stopped, and UPDATE_REQUIRED on a desktop app too old for it. Only Sensei calls it.",
10
10
  "pathParams": [],
11
11
  "query": [],
12
12
  "body": {
@@ -65,7 +65,7 @@ export const operation = {
65
65
  "flag": "reuse",
66
66
  "kind": "boolean",
67
67
  "required": false,
68
- "description": "Pick up the site’s sign-in from everyday Chrome by itself, without opening anything and with no tap: in a Turn the member’s own message started, once per site and profile. Name the profile by its exact ID. Answers chrome none, same or different, with taken."
68
+ "description": "Pick up the site’s sign-in from everyday Chrome by itself, without opening anything and with no tap: once per site and profile in a Turn. Name the profile by its exact ID. Answers chrome none, same or different, with taken."
69
69
  }
70
70
  ],
71
71
  "required": true
@@ -5,7 +5,7 @@ export const operation = {
5
5
  "projects",
6
6
  "create"
7
7
  ],
8
- "summary": "Connect a GitHub repository as a project in a workspace, or describe what to build to create a YOLO project on a new Kosuke-Org repository. Pass workflow yolo with a repository to import it in YOLO mode, with an optional prompt as its first message. Pass personal instead of orgId to create it in your Personal: your own credential, or your Sensei in a Turn you started. Its first Deploy starts by itself, as the caller's; sessions start once it lands. Imports only a repository your own GitHub Connection can write to: 403 GITHUB_REPOSITORY_ACCESS_REQUIRED otherwise, 401 GITHUB_RECONNECT_REQUIRED when GitHub no longer accepts your connection. Pass workflow yolo or personal only when the member asked for it. Report a chatError; on BRANCH_PROTECTED give its message and do not retry.",
8
+ "summary": "Connect a GitHub repository as a project in a workspace, or describe what to build to create a YOLO project on a new Kosuke-Org repository. Pass workflow yolo with a repository to import it in YOLO mode, with an optional prompt as its first message. Pass personal instead of orgId to create it in your Personal: your own credential, or your Sensei. Its first Deploy starts by itself, as the caller's; sessions start once it lands. Imports only a repository your own GitHub Connection can write to: 403 GITHUB_REPOSITORY_ACCESS_REQUIRED otherwise, 401 GITHUB_RECONNECT_REQUIRED when GitHub no longer accepts your connection. Pass workflow yolo or personal only when the member asked for it. Report a chatError; on BRANCH_PROTECTED give its message and do not retry.",
9
9
  "pathParams": [],
10
10
  "query": [],
11
11
  "body": {
@@ -60,7 +60,7 @@ export const operation = {
60
60
  "flag": "personal",
61
61
  "kind": "boolean",
62
62
  "required": false,
63
- "description": "Create a personal project instead of naming a workspace with orgId. Requires your own credential, or your Sensei in a Turn you started."
63
+ "description": "Create a personal project instead of naming a workspace with orgId. Requires your own credential, or your Sensei."
64
64
  }
65
65
  ],
66
66
  "required": true
@@ -0,0 +1,77 @@
1
+ export const operation = {
2
+ "method": "post",
3
+ "path": "/api/sensei/watch/report",
4
+ "command": [
5
+ "sensei",
6
+ "watch-reads",
7
+ "finish"
8
+ ],
9
+ "summary": "Report a LinkedIn or X Watching read once: the conversation list it read, or why it could not read it. Only the read’s own Turn reports.",
10
+ "pathParams": [],
11
+ "query": [],
12
+ "body": {
13
+ "fields": [
14
+ {
15
+ "name": "status",
16
+ "flag": "status",
17
+ "kind": "string",
18
+ "required": true,
19
+ "description": "What the read found",
20
+ "choices": [
21
+ "ok",
22
+ "signed_out",
23
+ "other_account",
24
+ "unreadable",
25
+ "device_unavailable"
26
+ ]
27
+ },
28
+ {
29
+ "name": "deviceCode",
30
+ "flag": "device-code",
31
+ "kind": "string",
32
+ "required": false,
33
+ "description": "With device_unavailable: what the browser answered",
34
+ "choices": [
35
+ "profile_off",
36
+ "mac_removed",
37
+ "update_required",
38
+ "offline",
39
+ "busy"
40
+ ]
41
+ },
42
+ {
43
+ "name": "account",
44
+ "flag": "account",
45
+ "kind": "json",
46
+ "required": false,
47
+ "description": "With ok: the signed-in account the page shows"
48
+ },
49
+ {
50
+ "name": "conversations",
51
+ "flag": "conversations",
52
+ "kind": "json",
53
+ "required": false,
54
+ "description": "With ok: the conversation list, newest first"
55
+ },
56
+ {
57
+ "name": "more",
58
+ "flag": "more",
59
+ "kind": "boolean",
60
+ "required": false,
61
+ "description": "The list went on past what was read"
62
+ },
63
+ {
64
+ "name": "detail",
65
+ "flag": "detail",
66
+ "kind": "string",
67
+ "required": false,
68
+ "description": "Why the list could not be read"
69
+ }
70
+ ],
71
+ "required": true
72
+ },
73
+ "multipart": null,
74
+ "attachments": false,
75
+ "anonymous": false,
76
+ "agents": "all"
77
+ };
@@ -5,7 +5,7 @@ export const operation = {
5
5
  "sessions",
6
6
  "delete"
7
7
  ],
8
- "summary": "Delete a chat session. Sensei deletes only a Backlog ticket, refused with 409 NOT_IN_BACKLOG once it started, and only in a Turn its member started.",
8
+ "summary": "Delete a chat session. Sensei deletes only a Backlog ticket, refused with 409 NOT_IN_BACKLOG once it started, whatever started the Turn.",
9
9
  "pathParams": [
10
10
  "projectId",
11
11
  "sessionId"
@@ -0,0 +1,36 @@
1
+ export const operation = {
2
+ "method": "get",
3
+ "path": "/api/user/usage/breakdown",
4
+ "command": [
5
+ "user",
6
+ "usage",
7
+ "get"
8
+ ],
9
+ "summary": "Read what used your AI work over range (7d by default, 30d or all) in calendar days of tz (an IANA time zone, UTC by default): totals and per-day counts, then rows grouped by work, repository and model, each with its Providers and busiest Chat Sessions or Sensei Threads (the top five by every count, so sort by the one you show). Counts your personal Subscription attempts and Kosuke free Turns since recording began on 22 October 2026; days before it have recorded false and are never 0. turns counts every attempt; the four token counts are sums of reported counts only, never added together, with missing and inProgress counted apart. A repository or session in a workspace you no longer belong to keeps its counts but no name, title or link. Workspace Credentials and platform work are excluded. Your own sign-in or API key only; agent tokens are refused. 400 on another range or an unknown time zone.",
10
+ "pathParams": [],
11
+ "query": [
12
+ {
13
+ "name": "range",
14
+ "flag": "range",
15
+ "kind": "string",
16
+ "required": false,
17
+ "description": "Calendar days to include: 7d, 30d or all recorded days.",
18
+ "choices": [
19
+ "7d",
20
+ "30d",
21
+ "all"
22
+ ]
23
+ },
24
+ {
25
+ "name": "tz",
26
+ "flag": "tz",
27
+ "kind": "string",
28
+ "required": false,
29
+ "description": "IANA time zone for calendar days. Default: UTC."
30
+ }
31
+ ],
32
+ "body": null,
33
+ "multipart": null,
34
+ "attachments": false,
35
+ "anonymous": false
36
+ };
@@ -25,8 +25,10 @@ export function renderOverview(overview, filtered) {
25
25
  return 'No connected tool matches.\n';
26
26
  const width = Math.max(0, ...(tools ?? []).map((tool) => tool.name.length));
27
27
  const blocks = toolkits.map((toolkit) => {
28
+ // A browser site lists no tools, so its line names how it is used: an agent told that only
29
+ // listed actions exist would read "no tools" as a site it cannot use.
28
30
  const offer = toolkit.browser
29
- ? 'browser, no tools'
31
+ ? 'browser, no tools: use it in the browser on its Mac (kosuke mac browser run)'
30
32
  : `${toolkit.read} read, ${toolkit.write} write tools`;
31
33
  const lines = [
32
34
  `${toolkit.name} (${toolkit.toolkit}): ${offer}`,
package/openapi.json CHANGED
@@ -143,7 +143,7 @@
143
143
  "/api/agent-integrations/execute": {
144
144
  "post": {
145
145
  "operationId": "integrationsToolsCall",
146
- "summary": "Run one integration tool. An agent runs it for its own workspace, or on the member’s personal connection when that member started the turn. With an API key, name a workspace you belong to: the call runs only on your own personal connections, and one on a workspace connection is refused. The answer names the connection it ran on, or lists the connections to choose from when the call needs one. A tool failure answers 200 with isError true. Some integrations require an enabled workspace to be named. A Connector Token or a browser session is refused.",
146
+ "summary": "Run one integration tool. An agent runs it for its own workspace, or on the member’s personal connection in any of their Sensei Turns or a session turn that member started. With an API key, name a workspace you belong to: the call runs only on your own personal connections, and one on a workspace connection is refused. The answer names the connection it ran on, or lists the connections to choose from when the call needs one. A tool failure answers 200 with isError true. Some integrations require an enabled workspace to be named. A Connector Token or a browser session is refused.",
147
147
  "tags": ["integrations"],
148
148
  "x-kosuke-command": ["integrations", "tools", "call"],
149
149
  "x-kosuke-hidden": true,
@@ -235,7 +235,7 @@
235
235
  "/api/agent-integrations/tools": {
236
236
  "get": {
237
237
  "operationId": "integrationsToolsList",
238
- "summary": "List the integration tools you can run now, with the connections that run them. An agent reads its own workspace. With an API key, name a workspace you belong to: it shows that workspace’s connections and your own personal ones. Some integrations require an enabled workspace to be named. A Connector Token or a browser session is refused. Each toolkit is personal or workspace, never both. A personal connection reaches only a Turn its member started (in a workspace chat, only the session's Assignee); a workspace Cron, Deploy Chat, a Turn another member sent and unassigned work reach workspace connections only. In the Personal space the owner's own Turns reach both kinds.",
238
+ "summary": "List the integration tools you can run now, with the connections that run them. An agent reads its own workspace. With an API key, name a workspace you belong to: it shows that workspace’s connections and your own personal ones. Some integrations require an enabled workspace to be named. A Connector Token or a browser session is refused. Each toolkit is personal or workspace, never both. A personal connection reaches every Sensei Turn of its member, and a session turn its member started (in a workspace chat, only the session's Assignee); a workspace Cron, Deploy Chat, a Turn another member sent and unassigned work reach workspace connections only. In the Personal space the owner's own Turns reach both kinds.",
239
239
  "tags": ["integrations"],
240
240
  "x-kosuke-command": ["integrations", "tools", "list"],
241
241
  "x-kosuke-hidden": true,
@@ -1116,7 +1116,7 @@
1116
1116
  "/api/devices/mac/browser-connections": {
1117
1117
  "get": {
1118
1118
  "operationId": "macBrowserConnectionsList",
1119
- "summary": "List the member's LinkedIn and X browser connections, oldest first: each is one account Sensei may act as, with its id, revision, account (null until Sensei fills it in), device (id, name, removed), profile (id, name), the last check (unchecked, connected, signed_out, other_account) with checkedAt, and connectThreadId, the only thread whose Turn may fill the account in. Pass its device id and profile id to every browser call for it. Only Sensei calls it, in a Turn the member's own message started.",
1119
+ "summary": "List the member's LinkedIn and X browser connections, oldest first: each is one account Sensei may act as, with its id, revision, account (null until Sensei fills it in), device (id, name, removed), profile (id, name), the last check (unchecked, connected, signed_out, other_account) with checkedAt, and connectThreadId, the only thread whose Turn may fill the account in. Pass its device id and profile id to every browser call for it. Only Sensei calls it.",
1120
1120
  "tags": ["mac"],
1121
1121
  "x-kosuke-command": ["mac", "browser", "connections", "list"],
1122
1122
  "x-kosuke-sandbox-token": true,
@@ -1170,7 +1170,7 @@
1170
1170
  },
1171
1171
  "post": {
1172
1172
  "operationId": "macBrowserConnectionsUpdate",
1173
- "summary": "Report what one check of the live page saw for a browser connection, with the revision `kosuke mac browser connections list` answered: connected with the account's name and handle, signed_out, or other_account with the name found. The first connected fills the account in, only from a Turn of its connectThreadId (else 403 NOT_CONNECT_THREAD); afterwards the handle must match it (else 409 ACCOUNT_MISMATCH). 409 STALE_REVISION after a newer Connect or Reconnect: read again. 404 once the member disconnected it. Only Sensei calls it, in a Turn the member's own message started.",
1173
+ "summary": "Report what one check of the live page saw for a browser connection, with the revision `kosuke mac browser connections list` answered: connected with the account's name and handle, signed_out, or other_account with the name found. The first connected fills the account in, only from a Turn of its connectThreadId (else 403 NOT_CONNECT_THREAD); afterwards the handle must match it (else 409 ACCOUNT_MISMATCH). 409 STALE_REVISION after a newer Connect or Reconnect: read again. 404 once the member disconnected it. Only Sensei calls it.",
1174
1174
  "tags": ["mac"],
1175
1175
  "x-kosuke-command": ["mac", "browser", "connections", "update"],
1176
1176
  "x-kosuke-sandbox-token": true,
@@ -1328,7 +1328,7 @@
1328
1328
  "/api/devices/mac/browser-sign-in": {
1329
1329
  "post": {
1330
1330
  "operationId": "macBrowserLogin",
1331
- "summary": "Get a site signed in in this Sensei Thread's browser from the member's everyday Chrome: pass the browser call's profile and deviceId, and the site as a bare hostname (twitter.com is x.com; Google's sites are refused). --reuse picks up the sign-in that profile in their Chrome holds by itself, with no tap: only in a Turn the member's own message started, once per site and profile in a Turn, with the profile's exact ID. It never opens Chrome or waits for anyone, and answers opened false and signedIn false with chrome none (their Chrome holds no sign-in for the site, so nothing changed), same (the one this thread's browser already holds) or different (taken into this thread's browser, taken true). Then, unless it answered none or same, open the site with browser and check the account. On SIGN_IN_NEEDS_TAP or UPDATE_REQUIRED, put the sign-in card. A --reuse spends no tap, so it gives no card back. Every tapped mode (`sign-in`, `take`, `waitNew`) needs the member's tap on the sign-in card in this thread; `--forget` and `--reuse` need none. A sign-in takes the sign-in that profile in their Chrome holds when it differs from this thread's, without opening anything, and answers taken true, opened false and signedIn false, since the site has not confirmed it; or else it opens --url, or the site's page, in their Chrome and waits up to 8 minutes for the member to sign in. On LinkedIn and X it answers signedIn true and opened true. On any other site a change of the site's cookies is taken and answered taken true and signedIn false, since a change is not a sign-in, and an end with no change answers taken false; a desktop app too old to watch the site opens it and answers at once, with no taken. Every answer with taken true carries waitNewLeft: while it is above 0 and the site is still signed out, --wait-new (with the same --url), in the same Turn and with no new tap, waits for a newer sign-in, never taking the one taken already, and opens the site only when this Turn has not; once the tap's time has run out it fails with SIGN_IN_WINDOW_ENDED, and no card comes back. After the member's I'm signed in tap, --take takes that site's cookies, never Google's, and answers taken. --forget removes a sign-in this Turn took, a --reuse's included, for an account other than the one expected, and needs no tap. Each tap allows one call: a call without one, or a --wait-new that no take armed, fails with SIGN_IN_NEEDS_TAP. Then open the site with browser and check the account before account-specific work. On DEVICE_OFFLINE, TIMEOUT, SIGN_IN_TIMEOUT and KEYCHAIN_UNAVAILABLE Kosuke gives the member's card back by itself. Fails with SIGN_IN_TIMEOUT when Kosuke saw no new sign-in to LinkedIn or X within 8 minutes, PROFILE_DISCONNECTED for a profile turned off in Settings → Devices, KEYCHAIN_UNAVAILABLE when macOS did not let Kosuke read Chrome's sign-ins, STALE_TURN when the Turn stopped, and UPDATE_REQUIRED on a desktop app too old for it. Only Sensei calls it.",
1331
+ "summary": "Get a site signed in in this Sensei Thread's browser from the member's everyday Chrome: pass the browser call's profile and deviceId, and the site as a bare hostname (twitter.com is x.com; Google's sites are refused). --reuse picks up the sign-in that profile in their Chrome holds by itself, with no tap: once per site and profile in a Turn, with the profile's exact ID. It never opens Chrome or waits for anyone, and answers opened false and signedIn false with chrome none (their Chrome holds no sign-in for the site, so nothing changed), same (the one this thread's browser already holds) or different (taken into this thread's browser, taken true). Then, unless it answered none or same, open the site with browser and check the account. On SIGN_IN_NEEDS_TAP or UPDATE_REQUIRED, put the sign-in card. A --reuse spends no tap, so it gives no card back. Every tapped mode (`sign-in`, `take`, `waitNew`) needs the member's tap on the sign-in card in this thread; `--forget` and `--reuse` need none. A sign-in takes the sign-in that profile in their Chrome holds when it differs from this thread's, without opening anything, and answers taken true, opened false and signedIn false, since the site has not confirmed it; or else it opens --url, or the site's page, in their Chrome and waits up to 8 minutes for the member to sign in. On LinkedIn and X it answers signedIn true and opened true. On any other site a change of the site's cookies is taken and answered taken true and signedIn false, since a change is not a sign-in, and an end with no change answers taken false; a desktop app too old to watch the site opens it and answers at once, with no taken. Every answer with taken true carries waitNewLeft: while it is above 0 and the site is still signed out, --wait-new (with the same --url), in the same Turn and with no new tap, waits for a newer sign-in, never taking the one taken already, and opens the site only when this Turn has not; once the tap's time has run out it fails with SIGN_IN_WINDOW_ENDED, and no card comes back. After the member's I'm signed in tap, --take takes that site's cookies, never Google's, and answers taken. --forget removes a sign-in this Turn took, a --reuse's included, for an account other than the one expected, and needs no tap. Each tap allows one call: a call without one, or a --wait-new that no take armed, fails with SIGN_IN_NEEDS_TAP. Then open the site with browser and check the account before account-specific work. On DEVICE_OFFLINE, TIMEOUT, SIGN_IN_TIMEOUT and KEYCHAIN_UNAVAILABLE Kosuke gives the member's card back by itself. Fails with SIGN_IN_TIMEOUT when Kosuke saw no new sign-in to LinkedIn or X within 8 minutes, PROFILE_DISCONNECTED for a profile turned off in Settings → Devices, KEYCHAIN_UNAVAILABLE when macOS did not let Kosuke read Chrome's sign-ins, STALE_TURN when the Turn stopped, and UPDATE_REQUIRED on a desktop app too old for it. Only Sensei calls it.",
1332
1332
  "tags": ["mac"],
1333
1333
  "x-kosuke-command": ["mac", "browser", "login"],
1334
1334
  "x-kosuke-answer-timeout-ms": 590000,
@@ -1379,7 +1379,7 @@
1379
1379
  "type": "boolean"
1380
1380
  },
1381
1381
  "reuse": {
1382
- "description": "Pick up the site’s sign-in from everyday Chrome by itself, without opening anything and with no tap: in a Turn the member’s own message started, once per site and profile. Name the profile by its exact ID. Answers chrome none, same or different, with taken.",
1382
+ "description": "Pick up the site’s sign-in from everyday Chrome by itself, without opening anything and with no tap: once per site and profile in a Turn. Name the profile by its exact ID. Answers chrome none, same or different, with taken.",
1383
1383
  "type": "boolean"
1384
1384
  }
1385
1385
  },
@@ -9525,7 +9525,7 @@
9525
9525
  },
9526
9526
  "post": {
9527
9527
  "operationId": "projectsCreate",
9528
- "summary": "Connect a GitHub repository as a project in a workspace, or describe what to build to create a YOLO project on a new Kosuke-Org repository. Pass workflow yolo with a repository to import it in YOLO mode, with an optional prompt as its first message. Pass personal instead of orgId to create it in your Personal: your own credential, or your Sensei in a Turn you started. Its first Deploy starts by itself, as the caller's; sessions start once it lands. Imports only a repository your own GitHub Connection can write to: 403 GITHUB_REPOSITORY_ACCESS_REQUIRED otherwise, 401 GITHUB_RECONNECT_REQUIRED when GitHub no longer accepts your connection. Pass workflow yolo or personal only when the member asked for it. Report a chatError; on BRANCH_PROTECTED give its message and do not retry.",
9528
+ "summary": "Connect a GitHub repository as a project in a workspace, or describe what to build to create a YOLO project on a new Kosuke-Org repository. Pass workflow yolo with a repository to import it in YOLO mode, with an optional prompt as its first message. Pass personal instead of orgId to create it in your Personal: your own credential, or your Sensei. Its first Deploy starts by itself, as the caller's; sessions start once it lands. Imports only a repository your own GitHub Connection can write to: 403 GITHUB_REPOSITORY_ACCESS_REQUIRED otherwise, 401 GITHUB_RECONNECT_REQUIRED when GitHub no longer accepts your connection. Pass workflow yolo or personal only when the member asked for it. Report a chatError; on BRANCH_PROTECTED give its message and do not retry.",
9529
9529
  "tags": ["projects"],
9530
9530
  "x-kosuke-command": ["projects", "create"],
9531
9531
  "x-kosuke-sandbox-token": true,
@@ -9571,7 +9571,7 @@
9571
9571
  "minLength": 1
9572
9572
  },
9573
9573
  "personal": {
9574
- "description": "Create a personal project instead of naming a workspace with orgId. Requires your own credential, or your Sensei in a Turn you started.",
9574
+ "description": "Create a personal project instead of naming a workspace with orgId. Requires your own credential, or your Sensei.",
9575
9575
  "type": "boolean",
9576
9576
  "const": true
9577
9577
  }
@@ -11203,7 +11203,7 @@
11203
11203
  },
11204
11204
  "delete": {
11205
11205
  "operationId": "sessionsDelete",
11206
- "summary": "Delete a chat session. Sensei deletes only a Backlog ticket, refused with 409 NOT_IN_BACKLOG once it started, and only in a Turn its member started.",
11206
+ "summary": "Delete a chat session. Sensei deletes only a Backlog ticket, refused with 409 NOT_IN_BACKLOG once it started, whatever started the Turn.",
11207
11207
  "tags": ["sessions"],
11208
11208
  "x-kosuke-command": ["sessions", "delete"],
11209
11209
  "x-kosuke-sandbox-token": true,
@@ -23825,6 +23825,176 @@
23825
23825
  }
23826
23826
  }
23827
23827
  },
23828
+ "/api/sensei/watch/report": {
23829
+ "post": {
23830
+ "operationId": "senseiWatchReadsFinish",
23831
+ "summary": "Report a LinkedIn or X Watching read once: the conversation list it read, or why it could not read it. Only the read’s own Turn reports.",
23832
+ "tags": ["sensei"],
23833
+ "x-kosuke-command": ["sensei", "watch-reads", "finish"],
23834
+ "x-kosuke-sandbox-token": true,
23835
+ "x-kosuke-cron-token": true,
23836
+ "x-kosuke-sensei-token": true,
23837
+ "requestBody": {
23838
+ "required": true,
23839
+ "content": {
23840
+ "application/json": {
23841
+ "schema": {
23842
+ "type": "object",
23843
+ "properties": {
23844
+ "status": {
23845
+ "type": "string",
23846
+ "enum": [
23847
+ "ok",
23848
+ "signed_out",
23849
+ "other_account",
23850
+ "unreadable",
23851
+ "device_unavailable"
23852
+ ],
23853
+ "description": "What the read found"
23854
+ },
23855
+ "deviceCode": {
23856
+ "description": "With device_unavailable: what the browser answered",
23857
+ "type": "string",
23858
+ "enum": ["profile_off", "mac_removed", "update_required", "offline", "busy"]
23859
+ },
23860
+ "account": {
23861
+ "description": "With ok: the signed-in account the page shows",
23862
+ "type": "object",
23863
+ "properties": {
23864
+ "handle": {
23865
+ "type": "string",
23866
+ "maxLength": 200
23867
+ },
23868
+ "name": {
23869
+ "anyOf": [
23870
+ {
23871
+ "type": "string",
23872
+ "maxLength": 200
23873
+ },
23874
+ {
23875
+ "type": "null"
23876
+ }
23877
+ ]
23878
+ }
23879
+ },
23880
+ "required": ["handle"],
23881
+ "additionalProperties": false
23882
+ },
23883
+ "conversations": {
23884
+ "description": "With ok: the conversation list, newest first",
23885
+ "maxItems": 50,
23886
+ "type": "array",
23887
+ "items": {
23888
+ "type": "object",
23889
+ "properties": {
23890
+ "link": {
23891
+ "type": "string",
23892
+ "maxLength": 500,
23893
+ "description": "The conversation's own link, as the list names it"
23894
+ },
23895
+ "name": {
23896
+ "anyOf": [
23897
+ {
23898
+ "type": "string",
23899
+ "maxLength": 200
23900
+ },
23901
+ {
23902
+ "type": "null"
23903
+ }
23904
+ ]
23905
+ },
23906
+ "kind": {
23907
+ "type": "string",
23908
+ "enum": ["direct", "group"]
23909
+ },
23910
+ "muted": {
23911
+ "type": "boolean"
23912
+ },
23913
+ "unread": {
23914
+ "type": "boolean"
23915
+ },
23916
+ "newest": {
23917
+ "type": "object",
23918
+ "properties": {
23919
+ "sender": {
23920
+ "anyOf": [
23921
+ {
23922
+ "type": "string",
23923
+ "maxLength": 200
23924
+ },
23925
+ {
23926
+ "type": "null"
23927
+ }
23928
+ ]
23929
+ },
23930
+ "fromMe": {
23931
+ "description": "The preview is the member’s own message",
23932
+ "type": ["boolean", "null"]
23933
+ },
23934
+ "text": {
23935
+ "type": "string",
23936
+ "maxLength": 4000
23937
+ },
23938
+ "truncated": {
23939
+ "type": "boolean"
23940
+ }
23941
+ },
23942
+ "required": ["text"]
23943
+ }
23944
+ },
23945
+ "required": ["link", "newest"]
23946
+ }
23947
+ },
23948
+ "more": {
23949
+ "description": "The list went on past what was read",
23950
+ "type": "boolean"
23951
+ },
23952
+ "detail": {
23953
+ "description": "Why the list could not be read",
23954
+ "type": "string",
23955
+ "maxLength": 500
23956
+ }
23957
+ },
23958
+ "required": ["status"],
23959
+ "additionalProperties": false
23960
+ }
23961
+ }
23962
+ }
23963
+ },
23964
+ "responses": {
23965
+ "2XX": {
23966
+ "description": "Success envelope",
23967
+ "content": {
23968
+ "application/json": {
23969
+ "schema": {
23970
+ "$ref": "#/components/schemas/ApiSuccess"
23971
+ }
23972
+ }
23973
+ }
23974
+ },
23975
+ "4XX": {
23976
+ "description": "Error envelope",
23977
+ "content": {
23978
+ "application/json": {
23979
+ "schema": {
23980
+ "$ref": "#/components/schemas/ApiError"
23981
+ }
23982
+ }
23983
+ }
23984
+ },
23985
+ "5XX": {
23986
+ "description": "Error envelope",
23987
+ "content": {
23988
+ "application/json": {
23989
+ "schema": {
23990
+ "$ref": "#/components/schemas/ApiError"
23991
+ }
23992
+ }
23993
+ }
23994
+ }
23995
+ }
23996
+ }
23997
+ },
23828
23998
  "/api/sensei/widgets": {
23829
23999
  "get": {
23830
24000
  "operationId": "senseiWidgetsGet",
@@ -27791,6 +27961,71 @@
27791
27961
  }
27792
27962
  }
27793
27963
  }
27964
+ },
27965
+ "/api/user/usage/breakdown": {
27966
+ "get": {
27967
+ "operationId": "userUsageGet",
27968
+ "summary": "Read what used your AI work over range (7d by default, 30d or all) in calendar days of tz (an IANA time zone, UTC by default): totals and per-day counts, then rows grouped by work, repository and model, each with its Providers and busiest Chat Sessions or Sensei Threads (the top five by every count, so sort by the one you show). Counts your personal Subscription attempts and Kosuke free Turns since recording began on 22 October 2026; days before it have recorded false and are never 0. turns counts every attempt; the four token counts are sums of reported counts only, never added together, with missing and inProgress counted apart. A repository or session in a workspace you no longer belong to keeps its counts but no name, title or link. Workspace Credentials and platform work are excluded. Your own sign-in or API key only; agent tokens are refused. 400 on another range or an unknown time zone.",
27969
+ "tags": ["user"],
27970
+ "x-kosuke-command": ["user", "usage", "get"],
27971
+ "parameters": [
27972
+ {
27973
+ "name": "range",
27974
+ "in": "query",
27975
+ "required": false,
27976
+ "description": "Calendar days to include: 7d, 30d or all recorded days.",
27977
+ "schema": {
27978
+ "default": "7d",
27979
+ "description": "Calendar days to include: 7d, 30d or all recorded days.",
27980
+ "type": "string",
27981
+ "enum": ["7d", "30d", "all"]
27982
+ }
27983
+ },
27984
+ {
27985
+ "name": "tz",
27986
+ "in": "query",
27987
+ "required": false,
27988
+ "description": "IANA time zone for calendar days. Default: UTC.",
27989
+ "schema": {
27990
+ "default": "UTC",
27991
+ "description": "IANA time zone for calendar days. Default: UTC.",
27992
+ "type": "string"
27993
+ }
27994
+ }
27995
+ ],
27996
+ "responses": {
27997
+ "2XX": {
27998
+ "description": "Success envelope",
27999
+ "content": {
28000
+ "application/json": {
28001
+ "schema": {
28002
+ "$ref": "#/components/schemas/ApiSuccess"
28003
+ }
28004
+ }
28005
+ }
28006
+ },
28007
+ "4XX": {
28008
+ "description": "Error envelope",
28009
+ "content": {
28010
+ "application/json": {
28011
+ "schema": {
28012
+ "$ref": "#/components/schemas/ApiError"
28013
+ }
28014
+ }
28015
+ }
28016
+ },
28017
+ "5XX": {
28018
+ "description": "Error envelope",
28019
+ "content": {
28020
+ "application/json": {
28021
+ "schema": {
28022
+ "$ref": "#/components/schemas/ApiError"
28023
+ }
28024
+ }
28025
+ }
28026
+ }
28027
+ }
28028
+ }
27794
28029
  }
27795
28030
  },
27796
28031
  "components": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kosuke-ai/kosuke",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
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,10 @@
40
40
  "vitest": "^4.1.12"
41
41
  },
42
42
  "kosukeRelease": {
43
- "sourceCommit": "940b9cc27e2815007516548641532567872966c3",
44
- "sourceIdentity": "fd1c70204fda8aab2a377653f78a3f6a36567cefe4ffeb99b072f1a663bd7729",
43
+ "sourceCommit": "6a882d48dc8afd6970071bffe05194bda2efb758",
44
+ "sourceIdentity": "e21e09139e14ef237ab372758a821554ef499449d0068c261567d4d898925b0c",
45
45
  "fragments": [
46
- "qa-accept-minor-failed-b7m3qe.json"
46
+ "sensei-any-turn-acts-q7m2tz.json"
47
47
  ]
48
48
  }
49
49
  }