@tekmidian/pai 0.61.0 → 0.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/{async-CLvuY7b-.mjs → async-DNVWtQl2.mjs} +2 -2
  2. package/dist/{async-CLvuY7b-.mjs.map → async-DNVWtQl2.mjs.map} +1 -1
  3. package/dist/{chain-C5oeyUg4.mjs → chain-CUfE6WYK.mjs} +2 -2
  4. package/dist/{chain-C5oeyUg4.mjs.map → chain-CUfE6WYK.mjs.map} +1 -1
  5. package/dist/cli/index.mjs +11 -11
  6. package/dist/cli/program.mjs +11 -11
  7. package/dist/{context-handover-cache-BdtJZpgv.mjs → context-handover-cache-DFNnlWv2.mjs} +2 -2
  8. package/dist/{context-handover-cache-BdtJZpgv.mjs.map → context-handover-cache-DFNnlWv2.mjs.map} +1 -1
  9. package/dist/daemon/index.mjs +8 -8
  10. package/dist/daemon-C8-uzOuV.mjs +19 -0
  11. package/dist/{daemon-DSsIEqzW.mjs → daemon-Cex3dT9f.mjs} +32 -18
  12. package/dist/{daemon-DSsIEqzW.mjs.map → daemon-Cex3dT9f.mjs.map} +1 -1
  13. package/dist/daemon-mcp/index.mjs +4 -4
  14. package/dist/{factory-EUUhSSoq.mjs → factory-BozZa81q.mjs} +3 -3
  15. package/dist/{factory-EUUhSSoq.mjs.map → factory-BozZa81q.mjs.map} +1 -1
  16. package/dist/{factory-DW7BCJJT.mjs → factory-UO9_DFMN.mjs} +1 -1
  17. package/dist/{fallback-DDbJVaR8.mjs → fallback-ktbR0aR7.mjs} +2 -2
  18. package/dist/{fallback-DDbJVaR8.mjs.map → fallback-ktbR0aR7.mjs.map} +1 -1
  19. package/dist/{helpers-D9WkIf9R.mjs → helpers-Dj-B314s.mjs} +3 -2
  20. package/dist/{helpers-D9WkIf9R.mjs.map → helpers-Dj-B314s.mjs.map} +1 -1
  21. package/dist/hooks/block-sleep-poll.mjs.map +2 -2
  22. package/dist/hooks/load-project-context.mjs +8519 -133
  23. package/dist/hooks/load-project-context.mjs.map +4 -4
  24. package/dist/hooks/security-validator.mjs.map +1 -1
  25. package/dist/hooks/worker-guard.mjs +7859 -0
  26. package/dist/hooks/worker-guard.mjs.map +7 -0
  27. package/dist/hooks/worker-status-line.mjs +101 -8
  28. package/dist/hooks/worker-status-line.mjs.map +4 -4
  29. package/dist/index.mjs +1 -1
  30. package/dist/{indexer-backend-DcDtin1O.mjs → indexer-backend-BN9rpp9O.mjs} +2 -2
  31. package/dist/{main-resolver-DIQ6m_RA.mjs → main-resolver-BIft_FVF.mjs} +3 -3
  32. package/dist/{main-resolver-DIQ6m_RA.mjs.map → main-resolver-BIft_FVF.mjs.map} +1 -1
  33. package/dist/{main-resolver-CxOsxtOr.mjs → main-resolver-C9-poMdi.mjs} +1 -1
  34. package/dist/{planner-D8jAr_sx.mjs → planner-DAQMTMjP.mjs} +4 -4
  35. package/dist/{planner-D8jAr_sx.mjs.map → planner-DAQMTMjP.mjs.map} +1 -1
  36. package/dist/{postgres-nvU5pShF.mjs → postgres-CxD6_Dca.mjs} +3 -3
  37. package/dist/{postgres-nvU5pShF.mjs.map → postgres-CxD6_Dca.mjs.map} +1 -1
  38. package/dist/{program-BTdspOOa.mjs → program-De1GVVM4.mjs} +178 -48
  39. package/dist/program-De1GVVM4.mjs.map +1 -0
  40. package/dist/{run-CxxZKEZw.mjs → run-CZVCCvXE.mjs} +353 -133
  41. package/dist/run-CZVCCvXE.mjs.map +1 -0
  42. package/dist/{session-keepalive-urk--pfa.mjs → session-keepalive-CWGzLBVU.mjs} +2 -2
  43. package/dist/{session-keepalive-urk--pfa.mjs.map → session-keepalive-CWGzLBVU.mjs.map} +1 -1
  44. package/dist/{sqlite-D9p5a4qe.mjs → sqlite-CfKfuggn.mjs} +2 -2
  45. package/dist/{sqlite-D9p5a4qe.mjs.map → sqlite-CfKfuggn.mjs.map} +1 -1
  46. package/dist/{tools-r-7ZG8B5.mjs → tools-B52IvaU6.mjs} +3 -3
  47. package/dist/{tools-qXyHFwNj.mjs → tools-DFdPbX-X.mjs} +2 -2
  48. package/dist/{tools-qXyHFwNj.mjs.map → tools-DFdPbX-X.mjs.map} +1 -1
  49. package/dist/{vault-indexer-DHYBpRZ5.mjs → vault-indexer-mCFus_AM.mjs} +2 -2
  50. package/dist/{vault-indexer-DHYBpRZ5.mjs.map → vault-indexer-mCFus_AM.mjs.map} +1 -1
  51. package/dist/{wakeup-C48hcN6O.mjs → wakeup-DO1O4udw.mjs} +2 -2
  52. package/dist/{wakeup-C48hcN6O.mjs.map → wakeup-DO1O4udw.mjs.map} +1 -1
  53. package/dist/{work-queue-worker-DUvPiwGO.mjs → work-queue-worker-BbrC3I_R.mjs} +2 -2
  54. package/dist/{work-queue-worker-DUvPiwGO.mjs.map → work-queue-worker-BbrC3I_R.mjs.map} +1 -1
  55. package/dist/{work-queue-worker-1_VBfI_k.mjs → work-queue-worker-z-AATZ2t.mjs} +3 -3
  56. package/docs/commands/README.md +4 -0
  57. package/docs/commands/project.md +14 -5
  58. package/docs/commands/projects.md +14 -5
  59. package/docs/commands/worker.md +27 -0
  60. package/package.json +2 -2
  61. package/scripts/build-hooks.mjs +6 -5
  62. package/scripts/build-skill-stubs.mjs +6 -5
  63. package/src/hooks/ts/lib/worker-guard.test.ts +188 -0
  64. package/src/hooks/ts/lib/worker-guard.ts +315 -0
  65. package/src/hooks/ts/pre-tool-use/worker-guard.ts +75 -0
  66. package/src/hooks/ts/session-start/load-project-context.ts +23 -0
  67. package/dist/daemon-MoFF4oeg.mjs +0 -19
  68. package/dist/program-BTdspOOa.mjs.map +0 -1
  69. package/dist/run-CxxZKEZw.mjs.map +0 -1
@@ -3,26 +3,26 @@ import { a as slugify$1, i as parseSessionFilename } from "./migrate-BD7D8EEh.mj
3
3
  import { n as ensurePaiMarker } from "./pai-marker-D1MMswkz.mjs";
4
4
  import { t as STOP_WORDS } from "./stop-words-ClCwO8mZ.mjs";
5
5
  import { t as applyRecencyBoost } from "./search-BaTbyWjK.mjs";
6
- import { a as getStorageBackend, i as getRegistryBackend, r as createStorageBackend, s as humanDuration } from "./factory-EUUhSSoq.mjs";
7
- import { a as formatDetectionJson, i as formatDetection, n as migrateIdentityFile, r as detectProject } from "./wakeup-C48hcN6O.mjs";
8
- import { B as claudeProjectsDir, C as findLatestNote, H as scanTranscriptFolders, I as resolveHome, L as saveScanConfig, M as cmdScan, N as loadScanConfig, P as migrateScanConfig, R as upsertProject, S as applyContinue, T as readBodyFile, U as transcriptFiles, V as findMovedProjects, d as migrateWorkQueue, g as migrateSummaryCooldowns, t as readContextHandoverCache, v as extractAndStoreTriples, w as findNotesDir$1, x as appendCheckpointToNote, z as upsertSession } from "./context-handover-cache-BdtJZpgv.mjs";
6
+ import { a as getStorageBackend, i as getRegistryBackend, r as createStorageBackend, s as humanDuration } from "./factory-BozZa81q.mjs";
7
+ import { a as formatDetectionJson, i as formatDetection, n as migrateIdentityFile, r as detectProject } from "./wakeup-DO1O4udw.mjs";
8
+ import { B as claudeProjectsDir, C as findLatestNote, H as scanTranscriptFolders, I as resolveHome, L as saveScanConfig, M as cmdScan, N as loadScanConfig, P as migrateScanConfig, R as upsertProject, S as applyContinue, T as readBodyFile, U as transcriptFiles, V as findMovedProjects, d as migrateWorkQueue, g as migrateSummaryCooldowns, t as readContextHandoverCache, v as extractAndStoreTriples, w as findNotesDir$1, x as appendCheckpointToNote, z as upsertSession } from "./context-handover-cache-DFNnlWv2.mjs";
9
9
  import { a as paiHomePath, i as paiHomeDir, n as migratePaiDir, o as resolvePaiFile, r as migratePaiFile, t as PaiFileMigrationError } from "./pai-home-CeOIYltV.mjs";
10
10
  import { b as OWNER_LABEL_PREFIX, c as migrateConfigFile, d as readMainConfigRaw, f as writeMainConfigRaw, h as resolvedMainConfigPath, l as paiConfigFilePath, m as migrateMainConfigToYaml, n as CONFIG_FILE$2, o as expandHome, p as MainConfigError, s as loadConfig, t as CONFIG_DIR, u as paiConfigYamlFilePath, v as readJsonStrict, x as UNROUTED, y as writeJsonAtomic } from "./config-CQCmH_gV.mjs";
11
11
  import { a as schedulerLogPath, i as paiSocketPath, n as daemonLogPath, r as daemonPidPath } from "./runtime-paths-BRwDeBEg.mjs";
12
12
  import { B as contextWindowFromModelId, C as nativeAnthropicProvider, E as readWorkersSection, F as parseWorkersYamlDocument, I as relocateWorkersYaml, L as workersYamlLegacyNotice, M as inlineWorkersYamlKeys, N as migrateWorkersToYaml, P as needsWorkersYamlRelocation, R as workersYamlPath, S as maskKey, V as stripModelVariant, b as isModelCapability, f as PROVIDER_TAGS, j as initWorkersYaml, m as WorkersConfigError, r as ANTHROPIC_NATIVE, t as buildRunEnv, u as MODEL_CAPABILITIES, v as expandHome$1, y as getProviderOrNative, z as DEFAULT_CONTEXT_WINDOW } from "./run-env-BE5xyCwy.mjs";
13
- import { A as UNLABELED, E as mergeWorker, G as waitForTerminalStatus, H as ownsPid, I as isChatPane, K as longInlinePromptHint, L as isLive, O as appendLedger, R as loadStatus, U as saveStatus, W as setWorkerLabel, X as expandMcpNames, Y as describeMcp, a as projectLaunchConfig, c as handoffFromInside, f as checkPaneForWorker, g as markControlsHeld, h as clickrControlsArgv, i as usageContextTokens, m as openPaneForWorker, n as runWorker, o as parseWorkerReport, p as openFollowPane, q as parseRunnerArgs, r as testProvider, u as sayToWorker, w as discardWorker, z as loadStatuses } from "./run-CxxZKEZw.mjs";
13
+ import { $ as expandMcpNames, B as loadStatuses, C as discardWorker, D as uncommittedPaths, E as mergeWorker, G as setWorkerLabel, J as parseRunnerArgs, K as waitForTerminalStatus, L as isChatPane, Q as describeMcp, R as isLive, T as git, U as ownsPid, W as saveStatus, X as pinNotices, Z as projectLaunchConfig, a as parseWorkerReport, d as checkPaneForWorker, f as openFollowPane, h as markControlsHeld, i as usageContextTokens, j as UNLABELED, k as appendLedger, l as sayToWorker, m as clickrControlsArgv, n as runWorker, p as openPaneForWorker, q as longInlinePromptHint, r as testProvider, s as handoffFromInside, w as gcWorktrees, z as loadStatus } from "./run-CZVCCvXE.mjs";
14
14
  import { t as MergeError } from "./merge-xoyfZQ4W.mjs";
15
15
  import { n as oldFederationPath, t as federationDbPath } from "./federation-db-w8e-sKjp.mjs";
16
16
  import { r as registryDbPath, t as oldRegistryPath } from "./registry-db-Bkpbp7Gf.mjs";
17
- import { i as indexProjectWithBackend } from "./async-CLvuY7b-.mjs";
17
+ import { i as indexProjectWithBackend } from "./async-DNVWtQl2.mjs";
18
18
  import { t as PaiClient } from "./ipc-client-Dasm515c.mjs";
19
- import { A as getConfigValueOp, C as psOutput, D as resolveSpecPath, E as readSpecPrompt, M as setConfigValueOp, N as unsetConfigValueOp, O as MainConfigOpsError, S as followWorkers, T as statusLineOutput, _ as setWorkersEnabled, a as addProvider, b as updateProvider, c as describeModels, d as removeProvider, f as resolveProviderName, g as setProviderModel, h as setProviderEnabled, i as fallbackStatusText, j as listConfigOp, k as formatConfigGetOutput, l as describeProviders, m as setClass, n as fallbackOn, o as classTargetText, p as setCapabilityPreference, r as fallbackStatus, s as describeCapabilities, t as fallbackOff, u as modelPrefsText, v as unsetCapabilityPreference, w as replayOutput, x as useProvider, y as unsetClass } from "./fallback-DDbJVaR8.mjs";
20
- import { _ as resolveSessionByNameOrId, a as buildDeduped, c as hasConversation, d as providerResumePlan, f as restoreTopLevel, g as migrateSessionScanCache, h as fmtAge, l as launchInDir, m as printExitDir, o as normalizeName$2, p as resumeArgvText, s as renderDedupedSessions, t as cmdMain, u as launchPrompt, v as scanCacheFilePath, y as scanSessions } from "./main-resolver-DIQ6m_RA.mjs";
19
+ import { A as getConfigValueOp, C as psOutput, D as resolveSpecPath, E as readSpecPrompt, M as setConfigValueOp, N as unsetConfigValueOp, O as MainConfigOpsError, S as followWorkers, T as statusLineOutput, _ as setWorkersEnabled, a as addProvider, b as updateProvider, c as describeModels, d as removeProvider, f as resolveProviderName, g as setProviderModel, h as setProviderEnabled, i as fallbackStatusText, j as listConfigOp, k as formatConfigGetOutput, l as describeProviders, m as setClass, n as fallbackOn, o as classTargetText, p as setCapabilityPreference, r as fallbackStatus, s as describeCapabilities, t as fallbackOff, u as modelPrefsText, v as unsetCapabilityPreference, w as replayOutput, x as useProvider, y as unsetClass } from "./fallback-ktbR0aR7.mjs";
20
+ import { _ as resolveSessionByNameOrId, a as buildDeduped, c as hasConversation, d as providerResumePlan, f as restoreTopLevel, g as migrateSessionScanCache, h as fmtAge$1, l as launchInDir, m as printExitDir, o as normalizeName$2, p as resumeArgvText, s as renderDedupedSessions, t as cmdMain, u as launchPrompt, v as scanCacheFilePath, y as scanSessions } from "./main-resolver-BIft_FVF.mjs";
21
21
  import { n as queriesDirPath, t as migrateQueriesDir } from "./query-feedback-xz5axTj3.mjs";
22
- import { h as ledgerPath, m as eventsPath, n as ensureProxyRunning, p as ensureNoMcpConfig, r as stopProxy, t as DEFAULT_PROXY_PORT, v as workersLogDir } from "./server-BY6AedmC.mjs";
22
+ import { _ as statusPath, h as ledgerPath, m as eventsPath, n as ensureProxyRunning, p as ensureNoMcpConfig, r as stopProxy, t as DEFAULT_PROXY_PORT, v as workersLogDir } from "./server-BY6AedmC.mjs";
23
23
  import { i as sendToSession, n as fetchLiveSessions, r as revealItermSession, t as callAiBroker } from "./aibroker-client-BK1h--W_.mjs";
24
- import { a as totalUsageTokens, i as parseSessionUsage, r as sessionKeepaliveLedgerSummary, t as loadSessionKeepaliveState } from "./session-keepalive-urk--pfa.mjs";
25
- import { t as runChain } from "./chain-C5oeyUg4.mjs";
24
+ import { a as totalUsageTokens, i as parseSessionUsage, r as sessionKeepaliveLedgerSummary, t as loadSessionKeepaliveState } from "./session-keepalive-CWGzLBVU.mjs";
25
+ import { t as runChain } from "./chain-CUfE6WYK.mjs";
26
26
  import { appendFileSync, chmodSync, closeSync, copyFileSync, cpSync, createReadStream, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
27
27
  import { homedir, platform, tmpdir, userInfo } from "node:os";
28
28
  import { basename, dirname, join, relative, resolve, sep } from "node:path";
@@ -161,7 +161,7 @@ async function cmdPromote(opts) {
161
161
  console.error(dim$1(` Pick a durable location for the new project.`));
162
162
  process.exit(1);
163
163
  }
164
- const { getRegistryBackend } = await import("./factory-DW7BCJJT.mjs");
164
+ const { getRegistryBackend } = await import("./factory-UO9_DFMN.mjs");
165
165
  const registryBackend = await getRegistryBackend();
166
166
  const encodedDir = encodeDir(targetPath);
167
167
  if (await registryBackend.getProjectBySlug(slug) ?? await registryBackend.getProjectByRootPath(targetPath) ?? await registryBackend.getProjectByEncodedDir(encodedDir)) {
@@ -1324,7 +1324,7 @@ async function cmdConfig(identifier, opts) {
1324
1324
  console.log();
1325
1325
  }
1326
1326
  /**
1327
- * `pai project mcp [names...]` — the MCP servers this project's interactive
1327
+ * `pai project mcp [--set names | --clear]` — the MCP servers this project's interactive
1328
1328
  * supervisor session loads. Operates on whichever registered project's
1329
1329
  * root_path covers `opts.cwd` (default: process.cwd()) — run it from inside
1330
1330
  * the project, same as `pai projects here`. Unset (the default) means every
@@ -1332,6 +1332,11 @@ async function cmdConfig(identifier, opts) {
1332
1332
  * ~/.claude.json's mcpServers / workers.mcpSets the same way `--mcp` is.
1333
1333
  */
1334
1334
  async function cmdMcp$1(names, opts = {}) {
1335
+ if (names.length) {
1336
+ console.error(err("use --set <names> to change the pin; `pai project mcp` shows it"));
1337
+ process.exitCode = 1;
1338
+ return;
1339
+ }
1335
1340
  const project = await currentProject(opts.cwd);
1336
1341
  if (!project) {
1337
1342
  console.error(err("No registered project matches the current directory."));
@@ -1346,23 +1351,28 @@ async function cmdMcp$1(names, opts = {}) {
1346
1351
  console.log(ok$1(`MCP servers unset for ${bold$1(project.slug)} — all servers load again.`));
1347
1352
  return;
1348
1353
  }
1349
- if (!names.length) {
1354
+ if (opts.set === void 0) {
1350
1355
  console.log(config.mcp?.length ? config.mcp.join(",") : "unset (all)");
1351
1356
  return;
1352
1357
  }
1353
1358
  const { workers } = readWorkersSection();
1354
- config.mcp = expandMcpNames(splitNames(names), workers);
1359
+ config.mcp = expandMcpNames(splitNames([opts.set]), workers);
1355
1360
  await saveSessionConfig(project, config);
1356
1361
  console.log(ok$1(`MCP servers set for ${bold$1(project.slug)}: ${config.mcp.join(", ")}`));
1357
1362
  }
1358
1363
  /**
1359
- * `pai project tools [names...]` — the built-in tool schemas this project's
1364
+ * `pai project tools [--set names | --clear]` — the built-in tool schemas this project's
1360
1365
  * interactive supervisor session loads (Read, Edit, Bash, …). Same cwd-based
1361
1366
  * project resolution and unset semantics as `cmdMcp`. Unlike MCP names, tool
1362
1367
  * names are not validated against a fixed list — the harness itself rejects
1363
1368
  * an unrecognised one at launch.
1364
1369
  */
1365
1370
  async function cmdTools(names, opts = {}) {
1371
+ if (names.length) {
1372
+ console.error(err("use --set <names> to change the pin; `pai project tools` shows it"));
1373
+ process.exitCode = 1;
1374
+ return;
1375
+ }
1366
1376
  const project = await currentProject(opts.cwd);
1367
1377
  if (!project) {
1368
1378
  console.error(err("No registered project matches the current directory."));
@@ -1377,11 +1387,11 @@ async function cmdTools(names, opts = {}) {
1377
1387
  console.log(ok$1(`Tools unset for ${bold$1(project.slug)} — all built-in tools load again.`));
1378
1388
  return;
1379
1389
  }
1380
- if (!names.length) {
1390
+ if (opts.set === void 0) {
1381
1391
  console.log(config.tools?.length ? config.tools.join(",") : "unset (all)");
1382
1392
  return;
1383
1393
  }
1384
- config.tools = splitNames(names);
1394
+ config.tools = splitNames([opts.set]);
1385
1395
  await saveSessionConfig(project, config);
1386
1396
  console.log(ok$1(`Tools set for ${bold$1(project.slug)}: ${config.tools.join(", ")}`));
1387
1397
  }
@@ -2035,7 +2045,7 @@ async function cmdUnregister(slug, opts = {}) {
2035
2045
  //#region src/cli/commands/project/projects-index.ts
2036
2046
  function registerProjectsCommands(projectsCmd) {
2037
2047
  projectsCmd.command("list", { isDefault: true }).description("Show the unified deduped listing (same as `pai`).\nUse --all to include cold / zero-session / archived projects.").option("--all", "Show all entries including cold / zero-session / archived projects").option("-n, --n <count>", "Max rows to show", "20").action(async (opts) => {
2038
- const { cmdMain } = await import("./main-resolver-CxOsxtOr.mjs");
2048
+ const { cmdMain } = await import("./main-resolver-C9-poMdi.mjs");
2039
2049
  await cmdMain(void 0, void 0, opts);
2040
2050
  });
2041
2051
  projectsCmd.command("list-raw").description("Raw registry listing with slug, path, status, last_active columns").option("--all", "Include archived projects (default: active only)").option("--status <status>", "Filter by status: active | archived").option("--tag <tag>", "Filter by tag").option("--type <type>", "Filter by type").action(async (opts) => {
@@ -2139,10 +2149,13 @@ function registerProjectsCommands(projectsCmd) {
2139
2149
  projectsCmd.command("config [identifier]").description("View or modify session launch config for a project.\nUse --options to discover available keys and presets.").option("--set <key=value...>", "Set config values (repeatable)", (v, prev) => [...prev, v], []).option("--unset <key...>", "Remove config keys (repeatable, use env.KEY for env vars)", (v, prev) => [...prev, v], []).option("--preset <name>", "Apply a permission preset: full | trusted | default").option("--defaults", "Manage global session defaults instead of a project").option("--options", "List available config keys and presets").option("--json", "Output JSON").option("--reset", "Reset config to empty (inherit global defaults)").action(async (identifier, opts) => {
2140
2150
  await cmdConfig(identifier, opts);
2141
2151
  });
2142
- projectsCmd.command("mcp [names...]").description("View or set the MCP servers this project's interactive supervisor session\nloads (run from inside the project, like `pai projects here`).\nNo names: print the current value. Names (comma-separated or repeated\nargs): set it, validated against ~/.claude.json's mcpServers.\n--clear: unset (all servers load — today's default).").option("--clear", "Unset — all MCP servers load again").action(async (names, opts) => {
2152
+ projectsCmd.command("mcp [names...]").description("View or set the MCP servers this project's interactive supervisor session\nloads (run from inside the project, like `pai projects here`).\nNo args: print the current value. --set <names> (comma-separated): set it,\nvalidated against ~/.claude.json's mcpServers. --clear: unset (all\nservers load — today's default). Positional names are an error.").option("--set <names>", "Set the pin (comma-separated server or set names)").option("--clear", "Unset — all MCP servers load again").action(async (names, opts) => {
2143
2153
  await cmdMcp$1(names, opts);
2144
2154
  });
2145
- projectsCmd.command("tools [names...]").description("View or set the built-in tool schemas this project's interactive\nsupervisor session loads (run from inside the project, like `pai projects\nhere`). No names: print the current value. Names (comma-separated or\nrepeated args): set it. --clear: unset (all tools load — today's default).").option("--clear", "Unset — all built-in tools load again").action(async (names, opts) => {
2155
+ projectsCmd.command("pins").description("Print one line per active MCP/tools pin for the current directory's project (nothing when unpinned)").action(async () => {
2156
+ for (const line of pinNotices(await projectLaunchConfig(process.cwd()))) console.log(line);
2157
+ });
2158
+ projectsCmd.command("tools [names...]").description("View or set the built-in tool schemas this project's interactive\nsupervisor session loads (run from inside the project, like `pai projects\nhere`). No args: print the current value. --set <names> (comma-separated):\nset it. --clear: unset (all tools load — today's default). Positional\nnames are an error.").option("--set <names>", "Set the pin (comma-separated tool names)").option("--clear", "Unset — all built-in tools load again").action(async (names, opts) => {
2146
2159
  await cmdTools(names, opts);
2147
2160
  });
2148
2161
  }
@@ -3247,7 +3260,7 @@ function registerStatsCommands(memoryCmd) {
3247
3260
  //#region src/cli/commands/memory/sources-cmd.ts
3248
3261
  function registerSourcesCommand(memoryCmd) {
3249
3262
  memoryCmd.command("sources").description("Show what the indexer has taken in: composition by source, which roots\ncontent enters from, the heaviest single files, and how many chunks are\nrewritten per day (which distinguishes a finite backlog from a treadmill).").option("--limit <n>", "Rows per section (default 8)", "8").action(async (opts) => {
3250
- const { createStorageBackend } = await import("./factory-DW7BCJJT.mjs");
3263
+ const { createStorageBackend } = await import("./factory-UO9_DFMN.mjs");
3251
3264
  const { loadConfig } = await import("./config-DjXq_W42.mjs");
3252
3265
  const { cmdMemorySources } = await import("./sources-BBe3AZ-W.mjs");
3253
3266
  let backend;
@@ -7073,7 +7086,7 @@ function cmdLogs(opts) {
7073
7086
  }
7074
7087
  function registerDaemonCommands(daemonCmd) {
7075
7088
  daemonCmd.command("serve").description("Start the PAI daemon in the foreground").action(async () => {
7076
- const { serve } = await import("./daemon-MoFF4oeg.mjs");
7089
+ const { serve } = await import("./daemon-C8-uzOuV.mjs");
7077
7090
  const { loadConfig: lc, ensureConfigDir } = await import("./config-DjXq_W42.mjs");
7078
7091
  ensureConfigDir();
7079
7092
  await serve(lc());
@@ -8408,6 +8421,11 @@ async function stepSettings(rl, daName) {
8408
8421
  matcher: "Bash",
8409
8422
  command: "${ADAPTER_DIR}/Hooks/security-validator.mjs"
8410
8423
  },
8424
+ {
8425
+ hookType: "PreToolUse",
8426
+ matcher: "Bash|Edit|Write|MultiEdit|NotebookEdit",
8427
+ command: "${ADAPTER_DIR}/Hooks/worker-guard.mjs"
8428
+ },
8411
8429
  {
8412
8430
  hookType: "PreToolUse",
8413
8431
  matcher: "*",
@@ -16086,7 +16104,7 @@ async function migrateToPostgres(opts = {}) {
16086
16104
  const dump = pgDump(container, pgConfig, dumpPath);
16087
16105
  if (!dump.ok) return refused(dump.reason, dryRun);
16088
16106
  }
16089
- const { PostgresBackend } = await import("./postgres-nvU5pShF.mjs");
16107
+ const { PostgresBackend } = await import("./postgres-CxD6_Dca.mjs");
16090
16108
  await PostgresBackend.ensureDatabase(pgConfig);
16091
16109
  const sqlite = new BetterSqlite3(sqliteFederationPath, { readonly: true });
16092
16110
  const registrySqlite = sqliteRegistryPath === sqliteFederationPath ? sqlite : new BetterSqlite3(sqliteRegistryPath, { readonly: true });
@@ -16657,7 +16675,7 @@ async function getSessionTags(registryBackend, sessionId) {
16657
16675
  * Session CRUD commands: list, info, rename, slug, tag, route, active, auto-route.
16658
16676
  */
16659
16677
  async function cmdList(projectSlug, opts) {
16660
- const { getRegistryBackend } = await import("./factory-DW7BCJJT.mjs");
16678
+ const { getRegistryBackend } = await import("./factory-UO9_DFMN.mjs");
16661
16679
  const registryBackend = await getRegistryBackend();
16662
16680
  const limit = parseInt(opts.limit ?? "20", 10);
16663
16681
  let project;
@@ -16722,7 +16740,7 @@ async function cmdList(projectSlug, opts) {
16722
16740
  console.log(dim$1(` ${rows.length} session(s) shown (limit: ${limit})`));
16723
16741
  }
16724
16742
  async function cmdInfo(projectSlug, sessionNumber) {
16725
- const { getRegistryBackend } = await import("./factory-DW7BCJJT.mjs");
16743
+ const { getRegistryBackend } = await import("./factory-UO9_DFMN.mjs");
16726
16744
  const registryBackend = await getRegistryBackend();
16727
16745
  const project = await getProject$1(registryBackend, projectSlug);
16728
16746
  if (!project) {
@@ -16746,7 +16764,7 @@ async function cmdInfo(projectSlug, sessionNumber) {
16746
16764
  console.log();
16747
16765
  }
16748
16766
  async function cmdRename(projectSlug, numberOrLatest, newSlug) {
16749
- const { getRegistryBackend } = await import("./factory-DW7BCJJT.mjs");
16767
+ const { getRegistryBackend } = await import("./factory-UO9_DFMN.mjs");
16750
16768
  await cmdRenameWith(await getRegistryBackend(), projectSlug, numberOrLatest, newSlug);
16751
16769
  }
16752
16770
  async function cmdRenameWith(registryBackend, projectSlug, numberOrLatest, newSlug) {
@@ -16809,7 +16827,7 @@ async function cmdRenameWith(registryBackend, projectSlug, numberOrLatest, newSl
16809
16827
  console.log();
16810
16828
  }
16811
16829
  async function cmdSlug(projectSlug, numberOrLatest, opts) {
16812
- const { getRegistryBackend } = await import("./factory-DW7BCJJT.mjs");
16830
+ const { getRegistryBackend } = await import("./factory-UO9_DFMN.mjs");
16813
16831
  const registryBackend = await getRegistryBackend();
16814
16832
  const project = await getProject$1(registryBackend, projectSlug);
16815
16833
  if (!project) {
@@ -16839,7 +16857,7 @@ async function cmdSlug(projectSlug, numberOrLatest, opts) {
16839
16857
  }
16840
16858
  }
16841
16859
  async function cmdTag(projectSlug, sessionNumber, rawTags) {
16842
- const { getRegistryBackend } = await import("./factory-DW7BCJJT.mjs");
16860
+ const { getRegistryBackend } = await import("./factory-UO9_DFMN.mjs");
16843
16861
  const registryBackend = await getRegistryBackend();
16844
16862
  const project = await getProject$1(registryBackend, projectSlug);
16845
16863
  if (!project) {
@@ -16879,7 +16897,7 @@ async function cmdTag(projectSlug, sessionNumber, rawTags) {
16879
16897
  console.log();
16880
16898
  }
16881
16899
  async function cmdRoute(projectSlug, sessionNumber, targetProjectSlug, opts) {
16882
- const { getRegistryBackend } = await import("./factory-DW7BCJJT.mjs");
16900
+ const { getRegistryBackend } = await import("./factory-UO9_DFMN.mjs");
16883
16901
  const registryBackend = await getRegistryBackend();
16884
16902
  const project = await getProject$1(registryBackend, projectSlug);
16885
16903
  if (!project) {
@@ -16921,7 +16939,7 @@ async function cmdRoute(projectSlug, sessionNumber, targetProjectSlug, opts) {
16921
16939
  console.log();
16922
16940
  }
16923
16941
  async function cmdActive(opts) {
16924
- const { getRegistryBackend } = await import("./factory-DW7BCJJT.mjs");
16942
+ const { getRegistryBackend } = await import("./factory-UO9_DFMN.mjs");
16925
16943
  const registryBackend = await getRegistryBackend();
16926
16944
  const minutes = parseInt(opts.minutes ?? "60", 10);
16927
16945
  const cutoff = Date.now() - minutes * 60 * 1e3;
@@ -17009,7 +17027,7 @@ async function cmdActive(opts) {
17009
17027
  }
17010
17028
  async function cmdAutoRoute(opts) {
17011
17029
  const { autoRoute, formatAutoRouteJson } = await import("./auto-route-CF8WNaoy.mjs");
17012
- const { getRegistryBackend, createStorageBackend } = await import("./factory-DW7BCJJT.mjs");
17030
+ const { getRegistryBackend, createStorageBackend } = await import("./factory-UO9_DFMN.mjs");
17013
17031
  const { loadConfig } = await import("./config-DjXq_W42.mjs");
17014
17032
  const config = loadConfig();
17015
17033
  const registryBackend = await getRegistryBackend();
@@ -17246,7 +17264,7 @@ async function cmdPause(opts) {
17246
17264
  process.exitCode = 1;
17247
17265
  return;
17248
17266
  }
17249
- const { getRegistryBackend } = await import("./factory-DW7BCJJT.mjs");
17267
+ const { getRegistryBackend } = await import("./factory-UO9_DFMN.mjs");
17250
17268
  const registryBackend = await getRegistryBackend();
17251
17269
  const cwd = process.cwd();
17252
17270
  const project = await resolveProjectByCwd(registryBackend, cwd);
@@ -17641,7 +17659,7 @@ function buildStopBody(project, sessionId) {
17641
17659
  }
17642
17660
  }
17643
17661
  async function cmdHandover(projectSlug, numberOrLatest, sessionId) {
17644
- const { getRegistryBackend } = await import("./factory-DW7BCJJT.mjs");
17662
+ const { getRegistryBackend } = await import("./factory-UO9_DFMN.mjs");
17645
17663
  const registryBackend = await getRegistryBackend();
17646
17664
  let project;
17647
17665
  if (projectSlug) {
@@ -17937,7 +17955,7 @@ function touchSentinel(rootPath) {
17937
17955
  async function cmdAutosave(opts) {
17938
17956
  const minGap = parseInt(opts.minGap ?? String(DEFAULT_MIN_GAP), 10);
17939
17957
  const cwd = process.cwd();
17940
- const { getRegistryBackend } = await import("./factory-DW7BCJJT.mjs");
17958
+ const { getRegistryBackend } = await import("./factory-UO9_DFMN.mjs");
17941
17959
  const registryBackend = await getRegistryBackend();
17942
17960
  const project = await resolveProjectByCwd(registryBackend, cwd);
17943
17961
  if (!project) return;
@@ -18062,7 +18080,7 @@ async function cmdRecent(opts) {
18062
18080
  shortId: s.shortId,
18063
18081
  resumable: s.resumable,
18064
18082
  sessionStatus: s.sessionStatus,
18065
- age: fmtAge(s.mtime),
18083
+ age: fmtAge$1(s.mtime),
18066
18084
  mtime: s.mtime,
18067
18085
  name: s.friendlyName,
18068
18086
  lastUserPrompt: s.lastUserPrompt,
@@ -18100,7 +18118,7 @@ async function cmdRecent(opts) {
18100
18118
  return [
18101
18119
  chalk.dim(String(idx + 1)),
18102
18120
  chalk.cyan(s.shortId),
18103
- dim$1(fmtAge(s.mtime)),
18121
+ dim$1(fmtAge$1(s.mtime)),
18104
18122
  name.length > 26 ? name.slice(0, 25) + "…" : name,
18105
18123
  prompt,
18106
18124
  s.userLines > 0 ? String(s.userLines) : dim$1("—"),
@@ -18200,7 +18218,7 @@ async function cmdGoto(query, opts) {
18200
18218
  console.log(` fallback: ${chalk.yellow(argvFresh)}`);
18201
18219
  if (resumableSession) {
18202
18220
  console.log(`\n uuid: ${resumableSession.uuid}`);
18203
- console.log(` age: ${fmtAge(resumableSession.mtime)}`);
18221
+ console.log(` age: ${fmtAge$1(resumableSession.mtime)}`);
18204
18222
  console.log(` status: ${resumableSession.sessionStatus}`);
18205
18223
  console.log(` sys: ${resumableSession.topLevelSystemLines} system lines`);
18206
18224
  }
@@ -19010,6 +19028,89 @@ function registerWorkerConfigCommands(workerCmd) {
19010
19028
  });
19011
19029
  }
19012
19030
 
19031
+ //#endregion
19032
+ //#region src/workers/pending.ts
19033
+ /**
19034
+ * Pending worker results: finished workers whose worktree branch still holds
19035
+ * work that never reached the repo (commits not in HEAD, or uncommitted
19036
+ * files). Surfaced by `pai worker ps/pending`, the SessionStart hook, the
19037
+ * status line and the prepublish gate so an unmerged fix cannot be forgotten.
19038
+ */
19039
+ /** Stale after this long: `pai worker gc` (archive) instead of merge. */
19040
+ const STALE_HOURS = 24;
19041
+ function toplevel(dir) {
19042
+ try {
19043
+ return git(dir, ["rev-parse", "--show-toplevel"]);
19044
+ } catch {
19045
+ return null;
19046
+ }
19047
+ }
19048
+ function fmtAge(ms) {
19049
+ const h = Math.floor(ms / 36e5);
19050
+ return h >= 48 ? `${Math.floor(h / 24)}d` : h >= 1 ? `${h}h` : `${Math.floor(ms / 6e4)}m`;
19051
+ }
19052
+ /** Finished workers with unmerged work; `repoRoot` limits to one repo, else every repo. */
19053
+ function pendingResults(logDir, repoRoot, now = Date.now()) {
19054
+ const want = repoRoot ? toplevel(repoRoot) : null;
19055
+ if (repoRoot && !want) return [];
19056
+ const out = [];
19057
+ for (const st of loadStatuses(logDir)) {
19058
+ if (st.archived || st.merged || isLive(st)) continue;
19059
+ if (!st.worktreeDir || !existsSync(st.worktreeDir)) continue;
19060
+ const repo = toplevel(st.cwd);
19061
+ if (!repo || want && repo !== want) continue;
19062
+ let commits = 0;
19063
+ let dirty = 0;
19064
+ try {
19065
+ if (st.branch) commits = git(repo, [
19066
+ "cherry",
19067
+ "HEAD",
19068
+ `refs/heads/${st.branch}`
19069
+ ]).split("\n").filter((l) => l.startsWith("+")).length;
19070
+ dirty = uncommittedPaths(st.worktreeDir).filter((p) => !/(^|\/)node_modules(\/|$)/.test(p)).length;
19071
+ } catch {
19072
+ continue;
19073
+ }
19074
+ if (!commits && !dirty) continue;
19075
+ let ageMs = 0;
19076
+ try {
19077
+ ageMs = Math.max(0, now - statSync(statusPath(logDir, st.id)).mtimeMs);
19078
+ } catch {}
19079
+ out.push({
19080
+ id: st.id,
19081
+ label: st.label,
19082
+ repo,
19083
+ ageMs,
19084
+ age: fmtAge(ageMs),
19085
+ commits,
19086
+ dirty
19087
+ });
19088
+ }
19089
+ return out;
19090
+ }
19091
+ /** One human line per result, with the exact next command. */
19092
+ function formatPending(results, showRepo = false) {
19093
+ return results.map((r) => {
19094
+ const next = r.ageMs > STALE_HOURS * 36e5 ? "pai worker gc" : `pai worker merge ${r.id}`;
19095
+ const repo = showRepo ? ` ${r.repo}` : "";
19096
+ return `${r.id} ${r.age} ${r.commits} commit(s), ${r.dirty} dirty ${r.label}${repo} -> ${next}`;
19097
+ }).join("\n");
19098
+ }
19099
+ /**
19100
+ * Release gate: exit code and message for `pai worker pending --gate`.
19101
+ * PAI_ALLOW_PENDING=1 overrides.
19102
+ */
19103
+ function pendingGate(results, env = process.env) {
19104
+ if (!results.length || env.PAI_ALLOW_PENDING === "1") return {
19105
+ code: 0,
19106
+ message: ""
19107
+ };
19108
+ return {
19109
+ code: 1,
19110
+ message: `${results.length} unmerged worker result(s) in this repo — merge or discard before publishing:\n${formatPending(results)}\nOverride deliberately with PAI_ALLOW_PENDING=1.`
19111
+ };
19112
+ }
19113
+
19013
19114
  //#endregion
19014
19115
  //#region src/workers/wait.ts
19015
19116
  /**
@@ -19191,7 +19292,24 @@ function registerWorkerCommands(workerCmd) {
19191
19292
  });
19192
19293
  workerCmd.command("ps").description("List workers of this session (RUNNING + FINISHED); --all for every worker").option("--all", "Show workers of all sessions, not just this terminal's").action((opts) => {
19193
19294
  try {
19194
- console.log(psOutput(currentLogDir(), opts.all === true));
19295
+ const logDir = currentLogDir();
19296
+ const pending = pendingResults(logDir, process.cwd()).length;
19297
+ if (pending) console.log(`${pending} unmerged result(s) — pai worker pending`);
19298
+ console.log(psOutput(logDir, opts.all === true));
19299
+ } catch (e) {
19300
+ fail(e);
19301
+ }
19302
+ });
19303
+ workerCmd.command("pending").description("Finished workers whose branch or worktree holds work not yet merged into this repo").option("--all", "Every repo in the log dir, not just the current one").option("--json", "Machine-readable output").option("--gate", "Release gate: exit 1 with the list unless PAI_ALLOW_PENDING=1").action((opts) => {
19304
+ try {
19305
+ const res = pendingResults(currentLogDir(), opts.all ? void 0 : process.cwd());
19306
+ if (opts.gate) {
19307
+ const g = pendingGate(res);
19308
+ if (g.message) console.error(g.message);
19309
+ process.exit(g.code);
19310
+ }
19311
+ if (opts.json) console.log(JSON.stringify(res, null, 2));
19312
+ else console.log(res.length ? formatPending(res, opts.all === true) : "no pending worker results");
19195
19313
  } catch (e) {
19196
19314
  fail(e);
19197
19315
  }
@@ -19340,6 +19458,18 @@ function registerWorkerCommands(workerCmd) {
19340
19458
  fail(e);
19341
19459
  }
19342
19460
  });
19461
+ workerCmd.command("gc").description("Archive leftover worker worktrees (state kept under refs/pai-archive/<id>; gitignored files are not kept)").option("--older-than <hours>", "minimum age of a finished worker", "24").option("--dry-run", "print what would be archived, change nothing").action((opts) => {
19462
+ try {
19463
+ const hours = Number(opts.olderThan);
19464
+ if (!Number.isFinite(hours) || hours < 0) throw new Error(`bad --older-than "${opts.olderThan}"`);
19465
+ const res = gcWorktrees(currentLogDir(), hours, opts.dryRun === true);
19466
+ const verb = opts.dryRun ? "would archive" : "archived";
19467
+ for (const r of res) console.log(r.skipped ? `skipped ${r.id}: ${r.skipped}` : `${verb} ${r.id} -> ${r.archive}`);
19468
+ console.log(`${res.filter((r) => r.archive).length} ${opts.dryRun ? "would be archived" : "archived"}`);
19469
+ } catch (e) {
19470
+ fail(e);
19471
+ }
19472
+ });
19343
19473
  workerCmd.command("kill <id>").description("Send SIGTERM to a running worker process").action(async (id) => {
19344
19474
  try {
19345
19475
  const logDir = currentLogDir();
@@ -20220,7 +20350,7 @@ async function countVectorDbPaths(oldPaths) {
20220
20350
  if (oldPaths.length === 0) return 0;
20221
20351
  try {
20222
20352
  const { loadConfig } = await import("./config-DjXq_W42.mjs");
20223
- const { createStorageBackend } = await import("./factory-DW7BCJJT.mjs");
20353
+ const { createStorageBackend } = await import("./factory-UO9_DFMN.mjs");
20224
20354
  const config = loadConfig();
20225
20355
  if (config.storageBackend !== "postgres") return 0;
20226
20356
  const backend = await createStorageBackend(config);
@@ -20238,7 +20368,7 @@ async function updateVectorDbPaths(moves) {
20238
20368
  if (moves.length === 0) return 0;
20239
20369
  try {
20240
20370
  const { loadConfig } = await import("./config-DjXq_W42.mjs");
20241
- const { createStorageBackend } = await import("./factory-DW7BCJJT.mjs");
20371
+ const { createStorageBackend } = await import("./factory-UO9_DFMN.mjs");
20242
20372
  const config = loadConfig();
20243
20373
  if (config.storageBackend !== "postgres") return 0;
20244
20374
  const backend = await createStorageBackend(config);
@@ -20325,7 +20455,7 @@ async function displayDryRun(plans) {
20325
20455
  console.log();
20326
20456
  }
20327
20457
  async function executeCleanup(plans, skipReindex) {
20328
- const { getRegistryBackend } = await import("./factory-DW7BCJJT.mjs");
20458
+ const { getRegistryBackend } = await import("./factory-UO9_DFMN.mjs");
20329
20459
  const registryBackend = await getRegistryBackend();
20330
20460
  let deleted = 0;
20331
20461
  let renamed = 0;
@@ -20522,7 +20652,7 @@ async function executeCleanup(plans, skipReindex) {
20522
20652
  //#region src/cli/commands/session-cleanup/index.ts
20523
20653
  function registerSessionCleanupCommand(sessionCmd) {
20524
20654
  sessionCmd.command("cleanup [project-slug]").description("Clean up session notes: delete empties, auto-name unnamed, move into YYYY/MM/ hierarchy, renumber").option("--execute", "Actually perform the cleanup (default is dry-run)").option("--no-renumber", "Skip renumbering sessions after deletions").option("--no-reindex", "Skip triggering memory re-index after moves").action(async (projectSlug, opts) => {
20525
- const { getRegistryBackend } = await import("./factory-DW7BCJJT.mjs");
20655
+ const { getRegistryBackend } = await import("./factory-UO9_DFMN.mjs");
20526
20656
  const registryBackend = await getRegistryBackend();
20527
20657
  const dryRun = !opts.execute;
20528
20658
  const skipReindex = opts.reindex === false;
@@ -20592,7 +20722,7 @@ function finalizeNote(notePath) {
20592
20722
  }
20593
20723
  async function cmdEnd(opts) {
20594
20724
  await cmdPause(opts);
20595
- const { getRegistryBackend } = await import("./factory-DW7BCJJT.mjs");
20725
+ const { getRegistryBackend } = await import("./factory-UO9_DFMN.mjs");
20596
20726
  const registryBackend = await getRegistryBackend();
20597
20727
  const cwd = process.cwd();
20598
20728
  const project = await registryBackend.findProjectByCwdPrefix(cwd);
@@ -21040,7 +21170,7 @@ async function cmdFind(query, opts) {
21040
21170
  */
21041
21171
  async function getProjects(includeArchived) {
21042
21172
  try {
21043
- const { getRegistryBackend } = await import("./factory-DW7BCJJT.mjs");
21173
+ const { getRegistryBackend } = await import("./factory-UO9_DFMN.mjs");
21044
21174
  const rows = await (await getRegistryBackend()).listProjectsWithSessionStats();
21045
21175
  return includeArchived ? rows : rows.filter((p) => p.status === "active");
21046
21176
  } catch {
@@ -21181,7 +21311,7 @@ function buildFeedFrom(allSessions, projects, liveSessions, allProjects) {
21181
21311
  const tag = tagFor(e.status);
21182
21312
  const name = chalk.white(pad(e.name, 22));
21183
21313
  const where = dir ? dim$1(shorten(dir, 40)) : chalk.green("(running in another tab)");
21184
- const age = e.status === "live" ? chalk.green("now") : e.lastActivity > 0 ? dim$1(fmtAge(e.lastActivity)) : dim$1("—");
21314
+ const age = e.status === "live" ? chalk.green("now") : e.lastActivity > 0 ? dim$1(fmtAge$1(e.lastActivity)) : dim$1("—");
21185
21315
  const kwDisp = kw ? dim$1(" " + kw) : "";
21186
21316
  const display = `${tag} ${name} ${pad(age, 5)} ${where}${kwDisp}`;
21187
21317
  const search = `${e.name} ${dir ?? ""} ${kw}`.toLowerCase();
@@ -21247,7 +21377,7 @@ function contextFor(rec) {
21247
21377
  const notes = recentMarkdown(rec.dir, 4);
21248
21378
  if (notes.length) {
21249
21379
  lines.push(dim$1("recent notes:"));
21250
- for (const n of notes) lines.push(" " + dim$1(n.rel.slice(0, 60)) + " " + dim$1(fmtAge(n.mtime)));
21380
+ for (const n of notes) lines.push(" " + dim$1(n.rel.slice(0, 60)) + " " + dim$1(fmtAge$1(n.mtime)));
21251
21381
  } else lines.push(dim$1("(no notes here yet)"));
21252
21382
  ctxCache.set(rec.dir, lines);
21253
21383
  return lines;
@@ -21514,7 +21644,7 @@ async function cmdPick(opts = {}) {
21514
21644
  const onRemove = async (rec) => {
21515
21645
  if (!rec.slug) return false;
21516
21646
  try {
21517
- const { getRegistryBackend } = await import("./factory-DW7BCJJT.mjs");
21647
+ const { getRegistryBackend } = await import("./factory-UO9_DFMN.mjs");
21518
21648
  const registryBackend = await getRegistryBackend();
21519
21649
  const project = await registryBackend.getProjectBySlug(rec.slug);
21520
21650
  if (!project || project.status !== "active") return false;
@@ -21799,4 +21929,4 @@ claude() {
21799
21929
 
21800
21930
  //#endregion
21801
21931
  export { drainStdio as n, buildProgram as t };
21802
- //# sourceMappingURL=program-BTdspOOa.mjs.map
21932
+ //# sourceMappingURL=program-De1GVVM4.mjs.map