@jskit-ai/agent-docs 0.1.297 → 0.1.299

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.
@@ -1274,8 +1274,17 @@ supplied binding never blocks on message sending or unknown delivery.
1274
1274
  An active goal flashes red; a paused goal stays orange. `elapsedSeconds` is the
1275
1275
  accumulated **active running time**, and `sampledAt` is its sample time in epoch
1276
1276
  **milliseconds**. The UI adds time only while active. Omit elapsed time if the
1277
- backend cannot supply it truthfully. The clock hides in a narrow conversation
1278
- pane; the light stays visible and details retain the time. Reduced motion uses
1277
+ backend cannot supply it truthfully. Only an active goal's chip shows its clock;
1278
+ a `paused`, `blocked`, `usageLimited` or `budgetLimited` goal's chip shows its
1279
+ status label (for example "Goal paused") instead, and its details keep the
1280
+ elapsed time. A `usageLimited` goal is waiting at its AI account's limit: its
1281
+ label names the limit and, from an optional `resetsAt` (epoch **seconds**), when it
1282
+ resets ("Waiting: AI usage limit, resets at 05:00", with the day when the reset is
1283
+ not today); with `outOfCredit: true` it reads "Out of credit: top up or switch AI
1284
+ account". Its details say the goal does not continue by itself and offer Resume
1285
+ and Cancel, and Pause when `pauseBlocked` is set. In a narrow conversation pane
1286
+ the clock hides and a long label ends in an ellipsis; the light stays visible
1287
+ and details retain the time and full label. Reduced motion uses
1279
1288
  a steady red light. Pause follows the command's declared behavior:
1280
1289
  `pauseInterruptsTurn: true` means it stops the current turn and keeps the goal;
1281
1290
  otherwise it prevents further automatic turns while Stop interrupts current work.
@@ -1286,10 +1295,18 @@ adapter. For a low-level adapter, omit `goal` or use `enabled: false` when goals
1286
1295
  are unsupported. The supplied binding hides unsupported controls automatically.
1287
1296
 
1288
1297
  Claude Pause retains the objective and native identity in the existing conversation
1289
- binding before interrupting execution. When another message starts a process, the
1290
- native owner clears the restored checker with Claude's local command and requires
1291
- its exact successful receipt before admitting user input. Ordinary messages and
1292
- process restart keep the goal paused. Explicit Resume reinstalls the objective;
1298
+ binding before interrupting execution. It sends nothing to Claude, so it works when
1299
+ the account is out of credit. When another message starts a process, the
1300
+ native owner clears the restored checker with Claude's local command (no model
1301
+ request) and requires its exact successful receipt before admitting user input.
1302
+ Ordinary messages and process restart keep the goal paused. Only that retained
1303
+ Pause reads `paused`: a Claude goal whose turn ended any other way (an interrupt,
1304
+ a process restart) keeps its checker armed, so the next turn continues it and it
1305
+ reads `active`. When Claude's own history ends the goal's turn with its usage-limit
1306
+ message, the goal reads `usageLimited` with that message's `resetsAt`; its
1307
+ credit-balance message reads `usageLimited` with `outOfCredit: true`. A later
1308
+ answer returns it to `active`. Hosts that restart goals must not resume a waiting
1309
+ goal: Resume after the reset stays the person's choice. Explicit Resume reinstalls the objective;
1293
1310
  Cancel removes the retained goal. A failed native clear leaves the new message
1294
1311
  unsent and retains Pause for recovery. Hosts supplying their own Claude store must
1295
1312
  round-trip the optional `pausedGoal` field with the existing conversation state.
@@ -325,6 +325,12 @@ export const roleCatalog = {
325
325
  };
326
326
  ```
327
327
 
328
+ The check cannot see a permission the application checks in its own code, so
329
+ before removing or renaming a reported grant, search the code for it
330
+ (`hasPermission()`, `can()`, permission string checks, including built names
331
+ such as `crud.${resource}.list`). If the application checks it, list it in
332
+ `customPermissions`; remove the grant only when nothing uses it.
333
+
328
334
  ## Role display labels
329
335
 
330
336
  Set optional `label` strings in the existing `roleCatalog.roles` definitions,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/agent-docs",
3
- "version": "0.1.297",
3
+ "version": "0.1.299",
4
4
  "description": "Distributed JSKIT agent references, prompts, guides, and generated reference maps.",
5
5
  "type": "module",
6
6
  "files": [
@@ -1,4 +1,7 @@
1
1
  import { spawn } from "node:child_process";
2
+ import { readFileSync } from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import path from "node:path";
2
5
  import { startServer } from "../server.js";
3
6
  import { DEFAULT_PORT } from "../server/lib/runtimeEnv.js";
4
7
 
@@ -43,10 +46,13 @@ process.once("SIGTERM", () => requestShutdown("SIGTERM"));
43
46
  try {
44
47
  apiServer = await startServer({ host: LOOPBACK_HOST, port: 0 });
45
48
  const apiPort = /** @type {import("node:net").AddressInfo} */ (apiServer.server.address()).port;
46
- const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
49
+ // Vite runs directly under node rather than through `npm run dev`: npm exits on SIGTERM without stopping
50
+ // the script it started, which left Vite serving the port after this launcher stopped.
51
+ const vitePackageFile = createRequire(import.meta.url).resolve("vite/package.json");
52
+ const viteCli = path.join(path.dirname(vitePackageFile), JSON.parse(readFileSync(vitePackageFile, "utf8")).bin.vite);
47
53
  viteProcess = spawn(
48
- npmCommand,
49
- ["run", "dev", "--", "--host", previewHost, "--port", String(previewPort), "--strictPort"],
54
+ process.execPath,
55
+ [viteCli, "--host", previewHost, "--port", String(previewPort), "--strictPort"],
50
56
  {
51
57
  cwd: process.cwd(),
52
58
  env: {
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "devDependencies": {
52
52
  "@jskit-ai/config-eslint": "0.1.250",
53
- "@jskit-ai/jskit-catalog": "0.2.49",
53
+ "@jskit-ai/jskit-catalog": "0.2.51",
54
54
  "@playwright/test": "1.61.1",
55
55
  "@vitejs/plugin-vue": "^6.0.7",
56
56
  "eslint": "^10.8.0",
@@ -1,4 +1,7 @@
1
1
  import { spawn } from "node:child_process";
2
+ import { readFileSync } from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import path from "node:path";
2
5
  import { startServer } from "../server.js";
3
6
  import { DEFAULT_PORT } from "../server/lib/runtimeEnv.js";
4
7
 
@@ -43,10 +46,13 @@ process.once("SIGTERM", () => requestShutdown("SIGTERM"));
43
46
  try {
44
47
  apiServer = await startServer({ host: LOOPBACK_HOST, port: 0 });
45
48
  const apiPort = /** @type {import("node:net").AddressInfo} */ (apiServer.server.address()).port;
46
- const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
49
+ // Vite runs directly under node rather than through `npm run dev`: npm exits on SIGTERM without stopping
50
+ // the script it started, which left Vite serving the port after this launcher stopped.
51
+ const vitePackageFile = createRequire(import.meta.url).resolve("vite/package.json");
52
+ const viteCli = path.join(path.dirname(vitePackageFile), JSON.parse(readFileSync(vitePackageFile, "utf8")).bin.vite);
47
53
  viteProcess = spawn(
48
- npmCommand,
49
- ["run", "dev", "--", "--host", previewHost, "--port", String(previewPort), "--strictPort"],
54
+ process.execPath,
55
+ [viteCli, "--host", previewHost, "--port", String(previewPort), "--strictPort"],
50
56
  {
51
57
  cwd: process.cwd(),
52
58
  env: {
@@ -51,7 +51,7 @@
51
51
  },
52
52
  "devDependencies": {
53
53
  "@jskit-ai/config-eslint": "0.1.250",
54
- "@jskit-ai/jskit-catalog": "0.2.49",
54
+ "@jskit-ai/jskit-catalog": "0.2.51",
55
55
  "@playwright/test": "1.61.1",
56
56
  "@vitejs/plugin-vue": "^6.0.7",
57
57
  "eslint": "^10.8.0",
@@ -15,7 +15,7 @@ A concrete Fastify, Vue, and JSKIT application foundation for products that do n
15
15
 
16
16
  - Id: `app/minimal-foundation`
17
17
  - Keywords: `app`, `fastify`, `foundation`, `minimal`, `server`, `vite`, `vue`
18
- - Owner: `@jskit-ai/agent-docs@0.1.297`
18
+ - Owner: `@jskit-ai/agent-docs@0.1.299`
19
19
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/app/minimal-foundation/PATTERN.md)
20
20
  - Examples: [example/](../../skills/jskit/references/patterns/app/minimal-foundation/example/)
21
21
  - Requires: `@jskit-ai/http-runtime`, `@jskit-ai/kernel`
@@ -26,7 +26,7 @@ A concrete JSKIT web application foundation with responsive shell navigation, se
26
26
 
27
27
  - Id: `app/shell-foundation`
28
28
  - Keywords: `app`, `foundation`, `material`, `navigation`, `placements`, `shell`, `vite`, `vue`
29
- - Owner: `@jskit-ai/agent-docs@0.1.297`
29
+ - Owner: `@jskit-ai/agent-docs@0.1.299`
30
30
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/app/shell-foundation/PATTERN.md)
31
31
  - Examples: [example/](../../skills/jskit/references/patterns/app/shell-foundation/example/)
32
32
  - Requires: `@jskit-ai/http-runtime`, `@jskit-ai/kernel`, `@jskit-ai/shell-web`
@@ -37,7 +37,7 @@ Configure an assistant runtime for one application surface and expose its chat a
37
37
 
38
38
  - Id: `assistant/assistant-surface`
39
39
  - Keywords: `ai`, `assistant`, `chat`, `config`, `environment`, `page`, `placement`, `settings`, `surface`
40
- - Owner: `@jskit-ai/assistant-runtime@0.2.43`
40
+ - Owner: `@jskit-ai/assistant-runtime@0.2.44`
41
41
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/assistant/assistant-surface/PATTERN.md)
42
42
  - Examples: [example/](../../skills/jskit/references/patterns/assistant/assistant-surface/example/)
43
43
  - Requires: `@jskit-ai/assistant-runtime`, `@jskit-ai/connectors-catalog`, `@jskit-ai/connectors-core`, `@jskit-ai/shell-web`
@@ -246,7 +246,7 @@ Add a protected administration surface, settings shell, and semantic navigation
246
246
 
247
247
  - Id: `console/console-surface`
248
248
  - Keywords: `admin`, `console`, `navigation`, `owner`, `placement`, `settings`, `surface`
249
- - Owner: `@jskit-ai/console-web@0.1.254`
249
+ - Owner: `@jskit-ai/console-web@0.1.255`
250
250
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/console/console-surface/PATTERN.md)
251
251
  - Examples: [example/](../../skills/jskit/references/patterns/console/console-surface/example/)
252
252
  - Requires: `@jskit-ai/console-core`, `@jskit-ai/console-web`, `@jskit-ai/shell-web`
@@ -345,7 +345,7 @@ Compose application-owned Google Publisher Tag delivery with the generic rewarde
345
345
 
346
346
  - Id: `rewards/google-rewarded`
347
347
  - Keywords: `ads`, `google`, `publisher tag`, `rewarded`, `unlock`
348
- - Owner: `@jskit-ai/rewarded-web@0.2.32`
348
+ - Owner: `@jskit-ai/rewarded-web@0.2.33`
349
349
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/rewards/google-rewarded/PATTERN.md)
350
350
  - Examples: [example/](../../skills/jskit/references/patterns/rewards/google-rewarded/example/)
351
351
  - Requires: `@jskit-ai/rewarded-web`
@@ -356,7 +356,7 @@ Define a server feature through explicit capabilities and first-class actions, a
356
356
 
357
357
  - Id: `server/feature-package`
358
358
  - Keywords: `actions`, `aggregate`, `feature`, `handle`, `orchestration`, `owns`, `package`, `provider`, `repository`, `routes`, `server`, `table resource`
359
- - Owner: `@jskit-ai/agent-docs@0.1.297`
359
+ - Owner: `@jskit-ai/agent-docs@0.1.299`
360
360
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/server/feature-package/PATTERN.md)
361
361
  - Examples: [example/](../../skills/jskit/references/patterns/server/feature-package/example/)
362
362
  - Requires: `@jskit-ai/kernel`
@@ -389,7 +389,7 @@ Compose an account settings route and profile, preference, notification, and sig
389
389
 
390
390
  - Id: `users/account-settings`
391
391
  - Keywords: `account`, `link provider`, `notifications`, `oauth`, `preferences`, `profile`, `settings`, `sign-in methods`, `user`, `vue`
392
- - Owner: `@jskit-ai/users-web@0.2.37`
392
+ - Owner: `@jskit-ai/users-web@0.2.38`
393
393
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/users/account-settings/PATTERN.md)
394
394
  - Examples: [example/](../../skills/jskit/references/patterns/users/account-settings/example/)
395
395
  - Requires: `@jskit-ai/shell-web`, `@jskit-ai/users-core`, `@jskit-ai/users-web`
@@ -400,7 +400,7 @@ Expose user administration and workspace-scoped member operations through app-ow
400
400
 
401
401
  - Id: `users/user-administration-server`
402
402
  - Keywords: `account`, `admin`, `member`, `repository`, `resource`, `routes`, `service`, `user`, `workspace`
403
- - Owner: `@jskit-ai/users-core@0.2.28`
403
+ - Owner: `@jskit-ai/users-core@0.2.29`
404
404
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/users/user-administration-server/PATTERN.md)
405
405
  - Examples: [example/](../../skills/jskit/references/patterns/users/user-administration-server/example/)
406
406
  - Requires: `@jskit-ai/crud-core`, `@jskit-ai/users-core`
@@ -411,7 +411,7 @@ Configure roles, workspace access policy, invitations, and app-owned invitation
411
411
 
412
412
  - Id: `workspaces/workspace-server`
413
413
  - Keywords: `access`, `invite`, `membership`, `multitenancy`, `policy`, `role`, `tenancy`, `workspace`
414
- - Owner: `@jskit-ai/workspaces-core@0.2.28`
414
+ - Owner: `@jskit-ai/workspaces-core@0.2.29`
415
415
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/workspaces/workspace-server/PATTERN.md)
416
416
  - Examples: [example/](../../skills/jskit/references/patterns/workspaces/workspace-server/example/)
417
417
  - Requires: `@jskit-ai/users-core`, `@jskit-ai/workspaces-core`
@@ -422,7 +422,7 @@ Compose workspace selection, invitation, member administration, settings, and re
422
422
 
423
423
  - Id: `workspaces/workspace-surfaces`
424
424
  - Keywords: `admin`, `invite`, `member`, `navigation`, `settings`, `surface`, `switcher`, `workspace`
425
- - Owner: `@jskit-ai/workspaces-web@0.2.37`
425
+ - Owner: `@jskit-ai/workspaces-web@0.2.38`
426
426
  - Read: [PATTERN.md](../../skills/jskit/references/patterns/workspaces/workspace-surfaces/PATTERN.md)
427
427
  - Examples: [example/](../../skills/jskit/references/patterns/workspaces/workspace-surfaces/example/)
428
428
  - Requires: `@jskit-ai/shell-web`, `@jskit-ai/workspaces-core`, `@jskit-ai/workspaces-web`
@@ -463,7 +463,7 @@ Local functions
463
463
  Exports
464
464
  - `waitForClaudeConversationTurn(conversation, input = {}, { signal, defaultTimeoutMs = 180_000, maximumTimeoutMs = Infinity, createError = claudeTurnFailure, interruptedMessage = "Claude was interrupted when the application disconnected." } = {})`
465
465
  - `runClaudeRenewalTurn(conversation, { clientMessageId, prompt, outputSchema, expectedThreadId, forbiddenThreadId, requireFreshHistory = false, timeoutMs = 180_000 }, { createError = claudeTurnFailure, unreadableCode = "assistant_claude_turn_unreadable", failedCode = "assistant_claude_turn_failed", acceptedField = "inputAccepted" } = {})`
466
- - `createClaudeConversationGoals({ conversationId, readHistory, readState, interrupt, send, readRetainedGoal, saveRetainedGoal })`
466
+ - `createClaudeConversationGoals({ conversationId, readHistory, interrupt, send, readRetainedGoal, saveRetainedGoal })`
467
467
  - `createClaudeConversationOwner({ configRoot, store, preparation, process, onEvent, createError = claudeTurnFailure, disconnectedMessage = "Claude was interrupted when the application disconnected." })`
468
468
  - `type ClaudeConversationEntry`
469
469
  - `type ClaudeConversationStore`
@@ -325,6 +325,12 @@ export const roleCatalog = {
325
325
  };
326
326
  ```
327
327
 
328
+ The check cannot see a permission the application checks in its own code, so
329
+ before removing or renaming a reported grant, search the code for it
330
+ (`hasPermission()`, `can()`, permission string checks, including built names
331
+ such as `crud.${resource}.list`). If the application checks it, list it in
332
+ `customPermissions`; remove the grant only when nothing uses it.
333
+
328
334
  ## Role display labels
329
335
 
330
336
  Set optional `label` strings in the existing `roleCatalog.roles` definitions,
@@ -15,7 +15,7 @@ A concrete Fastify, Vue, and JSKIT application foundation for products that do n
15
15
 
16
16
  - Id: `app/minimal-foundation`
17
17
  - Keywords: `app`, `fastify`, `foundation`, `minimal`, `server`, `vite`, `vue`
18
- - Owner: `@jskit-ai/agent-docs@0.1.297`
18
+ - Owner: `@jskit-ai/agent-docs@0.1.299`
19
19
  - Read: [PATTERN.md](patterns/app/minimal-foundation/PATTERN.md)
20
20
  - Examples: [example/](patterns/app/minimal-foundation/example/)
21
21
  - Requires: `@jskit-ai/http-runtime`, `@jskit-ai/kernel`
@@ -26,7 +26,7 @@ A concrete JSKIT web application foundation with responsive shell navigation, se
26
26
 
27
27
  - Id: `app/shell-foundation`
28
28
  - Keywords: `app`, `foundation`, `material`, `navigation`, `placements`, `shell`, `vite`, `vue`
29
- - Owner: `@jskit-ai/agent-docs@0.1.297`
29
+ - Owner: `@jskit-ai/agent-docs@0.1.299`
30
30
  - Read: [PATTERN.md](patterns/app/shell-foundation/PATTERN.md)
31
31
  - Examples: [example/](patterns/app/shell-foundation/example/)
32
32
  - Requires: `@jskit-ai/http-runtime`, `@jskit-ai/kernel`, `@jskit-ai/shell-web`
@@ -37,7 +37,7 @@ Configure an assistant runtime for one application surface and expose its chat a
37
37
 
38
38
  - Id: `assistant/assistant-surface`
39
39
  - Keywords: `ai`, `assistant`, `chat`, `config`, `environment`, `page`, `placement`, `settings`, `surface`
40
- - Owner: `@jskit-ai/assistant-runtime@0.2.43`
40
+ - Owner: `@jskit-ai/assistant-runtime@0.2.44`
41
41
  - Read: [PATTERN.md](patterns/assistant/assistant-surface/PATTERN.md)
42
42
  - Examples: [example/](patterns/assistant/assistant-surface/example/)
43
43
  - Requires: `@jskit-ai/assistant-runtime`, `@jskit-ai/connectors-catalog`, `@jskit-ai/connectors-core`, `@jskit-ai/shell-web`
@@ -246,7 +246,7 @@ Add a protected administration surface, settings shell, and semantic navigation
246
246
 
247
247
  - Id: `console/console-surface`
248
248
  - Keywords: `admin`, `console`, `navigation`, `owner`, `placement`, `settings`, `surface`
249
- - Owner: `@jskit-ai/console-web@0.1.254`
249
+ - Owner: `@jskit-ai/console-web@0.1.255`
250
250
  - Read: [PATTERN.md](patterns/console/console-surface/PATTERN.md)
251
251
  - Examples: [example/](patterns/console/console-surface/example/)
252
252
  - Requires: `@jskit-ai/console-core`, `@jskit-ai/console-web`, `@jskit-ai/shell-web`
@@ -345,7 +345,7 @@ Compose application-owned Google Publisher Tag delivery with the generic rewarde
345
345
 
346
346
  - Id: `rewards/google-rewarded`
347
347
  - Keywords: `ads`, `google`, `publisher tag`, `rewarded`, `unlock`
348
- - Owner: `@jskit-ai/rewarded-web@0.2.32`
348
+ - Owner: `@jskit-ai/rewarded-web@0.2.33`
349
349
  - Read: [PATTERN.md](patterns/rewards/google-rewarded/PATTERN.md)
350
350
  - Examples: [example/](patterns/rewards/google-rewarded/example/)
351
351
  - Requires: `@jskit-ai/rewarded-web`
@@ -356,7 +356,7 @@ Define a server feature through explicit capabilities and first-class actions, a
356
356
 
357
357
  - Id: `server/feature-package`
358
358
  - Keywords: `actions`, `aggregate`, `feature`, `handle`, `orchestration`, `owns`, `package`, `provider`, `repository`, `routes`, `server`, `table resource`
359
- - Owner: `@jskit-ai/agent-docs@0.1.297`
359
+ - Owner: `@jskit-ai/agent-docs@0.1.299`
360
360
  - Read: [PATTERN.md](patterns/server/feature-package/PATTERN.md)
361
361
  - Examples: [example/](patterns/server/feature-package/example/)
362
362
  - Requires: `@jskit-ai/kernel`
@@ -389,7 +389,7 @@ Compose an account settings route and profile, preference, notification, and sig
389
389
 
390
390
  - Id: `users/account-settings`
391
391
  - Keywords: `account`, `link provider`, `notifications`, `oauth`, `preferences`, `profile`, `settings`, `sign-in methods`, `user`, `vue`
392
- - Owner: `@jskit-ai/users-web@0.2.37`
392
+ - Owner: `@jskit-ai/users-web@0.2.38`
393
393
  - Read: [PATTERN.md](patterns/users/account-settings/PATTERN.md)
394
394
  - Examples: [example/](patterns/users/account-settings/example/)
395
395
  - Requires: `@jskit-ai/shell-web`, `@jskit-ai/users-core`, `@jskit-ai/users-web`
@@ -400,7 +400,7 @@ Expose user administration and workspace-scoped member operations through app-ow
400
400
 
401
401
  - Id: `users/user-administration-server`
402
402
  - Keywords: `account`, `admin`, `member`, `repository`, `resource`, `routes`, `service`, `user`, `workspace`
403
- - Owner: `@jskit-ai/users-core@0.2.28`
403
+ - Owner: `@jskit-ai/users-core@0.2.29`
404
404
  - Read: [PATTERN.md](patterns/users/user-administration-server/PATTERN.md)
405
405
  - Examples: [example/](patterns/users/user-administration-server/example/)
406
406
  - Requires: `@jskit-ai/crud-core`, `@jskit-ai/users-core`
@@ -411,7 +411,7 @@ Configure roles, workspace access policy, invitations, and app-owned invitation
411
411
 
412
412
  - Id: `workspaces/workspace-server`
413
413
  - Keywords: `access`, `invite`, `membership`, `multitenancy`, `policy`, `role`, `tenancy`, `workspace`
414
- - Owner: `@jskit-ai/workspaces-core@0.2.28`
414
+ - Owner: `@jskit-ai/workspaces-core@0.2.29`
415
415
  - Read: [PATTERN.md](patterns/workspaces/workspace-server/PATTERN.md)
416
416
  - Examples: [example/](patterns/workspaces/workspace-server/example/)
417
417
  - Requires: `@jskit-ai/users-core`, `@jskit-ai/workspaces-core`
@@ -422,7 +422,7 @@ Compose workspace selection, invitation, member administration, settings, and re
422
422
 
423
423
  - Id: `workspaces/workspace-surfaces`
424
424
  - Keywords: `admin`, `invite`, `member`, `navigation`, `settings`, `surface`, `switcher`, `workspace`
425
- - Owner: `@jskit-ai/workspaces-web@0.2.37`
425
+ - Owner: `@jskit-ai/workspaces-web@0.2.38`
426
426
  - Read: [PATTERN.md](patterns/workspaces/workspace-surfaces/PATTERN.md)
427
427
  - Examples: [example/](patterns/workspaces/workspace-surfaces/example/)
428
428
  - Requires: `@jskit-ai/shell-web`, `@jskit-ai/workspaces-core`, `@jskit-ai/workspaces-web`
@@ -1,4 +1,7 @@
1
1
  import { spawn } from "node:child_process";
2
+ import { readFileSync } from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import path from "node:path";
2
5
  import { startServer } from "../server.js";
3
6
  import { DEFAULT_PORT } from "../server/lib/runtimeEnv.js";
4
7
 
@@ -43,10 +46,13 @@ process.once("SIGTERM", () => requestShutdown("SIGTERM"));
43
46
  try {
44
47
  apiServer = await startServer({ host: LOOPBACK_HOST, port: 0 });
45
48
  const apiPort = /** @type {import("node:net").AddressInfo} */ (apiServer.server.address()).port;
46
- const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
49
+ // Vite runs directly under node rather than through `npm run dev`: npm exits on SIGTERM without stopping
50
+ // the script it started, which left Vite serving the port after this launcher stopped.
51
+ const vitePackageFile = createRequire(import.meta.url).resolve("vite/package.json");
52
+ const viteCli = path.join(path.dirname(vitePackageFile), JSON.parse(readFileSync(vitePackageFile, "utf8")).bin.vite);
47
53
  viteProcess = spawn(
48
- npmCommand,
49
- ["run", "dev", "--", "--host", previewHost, "--port", String(previewPort), "--strictPort"],
54
+ process.execPath,
55
+ [viteCli, "--host", previewHost, "--port", String(previewPort), "--strictPort"],
50
56
  {
51
57
  cwd: process.cwd(),
52
58
  env: {
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "devDependencies": {
52
52
  "@jskit-ai/config-eslint": "0.1.250",
53
- "@jskit-ai/jskit-catalog": "0.2.49",
53
+ "@jskit-ai/jskit-catalog": "0.2.51",
54
54
  "@playwright/test": "1.61.1",
55
55
  "@vitejs/plugin-vue": "^6.0.7",
56
56
  "eslint": "^10.8.0",
@@ -1,4 +1,7 @@
1
1
  import { spawn } from "node:child_process";
2
+ import { readFileSync } from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import path from "node:path";
2
5
  import { startServer } from "../server.js";
3
6
  import { DEFAULT_PORT } from "../server/lib/runtimeEnv.js";
4
7
 
@@ -43,10 +46,13 @@ process.once("SIGTERM", () => requestShutdown("SIGTERM"));
43
46
  try {
44
47
  apiServer = await startServer({ host: LOOPBACK_HOST, port: 0 });
45
48
  const apiPort = /** @type {import("node:net").AddressInfo} */ (apiServer.server.address()).port;
46
- const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
49
+ // Vite runs directly under node rather than through `npm run dev`: npm exits on SIGTERM without stopping
50
+ // the script it started, which left Vite serving the port after this launcher stopped.
51
+ const vitePackageFile = createRequire(import.meta.url).resolve("vite/package.json");
52
+ const viteCli = path.join(path.dirname(vitePackageFile), JSON.parse(readFileSync(vitePackageFile, "utf8")).bin.vite);
47
53
  viteProcess = spawn(
48
- npmCommand,
49
- ["run", "dev", "--", "--host", previewHost, "--port", String(previewPort), "--strictPort"],
54
+ process.execPath,
55
+ [viteCli, "--host", previewHost, "--port", String(previewPort), "--strictPort"],
50
56
  {
51
57
  cwd: process.cwd(),
52
58
  env: {
@@ -51,7 +51,7 @@
51
51
  },
52
52
  "devDependencies": {
53
53
  "@jskit-ai/config-eslint": "0.1.250",
54
- "@jskit-ai/jskit-catalog": "0.2.49",
54
+ "@jskit-ai/jskit-catalog": "0.2.51",
55
55
  "@playwright/test": "1.61.1",
56
56
  "@vitejs/plugin-vue": "^6.0.7",
57
57
  "eslint": "^10.8.0",
@@ -12,7 +12,7 @@
12
12
  "dependencies": {
13
13
  "@jskit-ai/crud-core": "0.2.27",
14
14
  "@jskit-ai/resource-crud-core": "0.1.212",
15
- "@jskit-ai/users-core": "0.2.28"
15
+ "@jskit-ai/users-core": "0.2.29"
16
16
  },
17
17
  "jskit": {
18
18
  "kind": "runtime",
@@ -12,8 +12,8 @@
12
12
  "dependencies": {
13
13
  "@jskit-ai/crud-core": "0.2.27",
14
14
  "@jskit-ai/resource-crud-core": "0.1.212",
15
- "@jskit-ai/users-core": "0.2.28",
16
- "@jskit-ai/workspaces-core": "0.2.28"
15
+ "@jskit-ai/users-core": "0.2.29",
16
+ "@jskit-ai/workspaces-core": "0.2.29"
17
17
  },
18
18
  "peerDependencies": {
19
19
  "@jskit-ai/kernel": "0.2.19",
@@ -46,9 +46,11 @@ A role's `permissions` grant names that something requires:
46
46
 
47
47
  At startup a grant that covers no permission an action, a route's `permission`
48
48
  or a surface access policy requires stops the server outside production, with
49
- a "did you mean"; production logs it. List a permission the application checks
50
- itself (a service, a row policy, `access.can()`) in
51
- `roleCatalog.customPermissions`.
49
+ a "did you mean"; production logs it. The check cannot see a permission the
50
+ application checks itself (a service, a row policy, `access.can()`): before
51
+ removing or renaming a reported grant, search the code for it, including built
52
+ names such as `crud.${resource}.list`. List one the application checks in
53
+ `roleCatalog.customPermissions`; remove a grant only when nothing uses it.
52
54
 
53
55
  ## Role display labels
54
56