larkin 0.5.3 → 0.5.5

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 (49) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +22 -1
  3. package/artifacts/release/THIRD_PARTY_NOTICES.txt +1 -100
  4. package/dist/agent/agent-cli-capabilities.cjs +1 -1
  5. package/dist/agent/agent-cli-capabilities.mjs +1 -1
  6. package/dist/agent/config-cli-contract.cjs +3 -1
  7. package/dist/agent/config-cli-contract.mjs +3 -1
  8. package/dist/agent/context-prompt.cjs +16 -17
  9. package/dist/agent/context-prompt.mjs +15 -16
  10. package/dist/agent/inbox-audit-heartbeat.cjs +157 -37
  11. package/dist/agent/inbox-audit-heartbeat.mjs +122 -36
  12. package/dist/agent/missed-outbound-scan.cjs +326 -54
  13. package/dist/agent/missed-outbound-scan.mjs +319 -53
  14. package/dist/app/agent-cli.mjs +37 -6
  15. package/dist/app/agent-config.mjs +36 -5
  16. package/dist/app/cli.mjs +1 -0
  17. package/dist/dashboard/dashboard-config-controller.mjs +15 -0
  18. package/dist/dashboard/web/assets/dashboard.css +1 -1
  19. package/dist/dashboard/web/assets/dashboard.js +15 -15
  20. package/dist/feishu/host-shell.cjs +63 -5
  21. package/dist/feishu/host-shell.mjs +66 -8
  22. package/dist/platform/config.cjs +173 -5
  23. package/dist/platform/config.mjs +167 -4
  24. package/dist/runtime/pi-state-dir.cjs +105 -0
  25. package/dist/runtime/pi-state-dir.mjs +94 -0
  26. package/dist/runtime/pi-tmux-extension.mjs +137 -0
  27. package/dist/runtime/pi-tmux-injection.mjs +49 -0
  28. package/dist/runtime/pi-tmux.bundle.js +600 -0
  29. package/dist/runtime/pi-tmux.mjs +408 -0
  30. package/dist/runtime/runtime-adapters.mjs +26 -113
  31. package/dist/runtime/runtime-host.cjs +3 -413
  32. package/dist/runtime/runtime-host.mjs +2 -412
  33. package/package.json +2 -8
  34. package/dist/runtime/pi-bash-timeout-extension.mjs +0 -60
  35. package/dist/runtime/pi-bash-timeout-injection.mjs +0 -54
  36. package/dist/runtime/pi-bash-timeout.bundle.js +0 -43
  37. package/dist/runtime/pi-extension-api.mjs +0 -1
  38. package/dist/runtime/pi-subagent-injection.mjs +0 -290
  39. package/dist/runtime/pi-subagent-ledger.cjs +0 -632
  40. package/dist/runtime/pi-subagent-ledger.mjs +0 -594
  41. package/dist/runtime/pi-subagent-record-watchdog-injection.mjs +0 -43
  42. package/dist/runtime/pi-subagent-record-watchdog.bundle.js +0 -183
  43. package/dist/runtime/pi-subagent-record-watchdog.mjs +0 -46
  44. package/dist/runtime/pi-subagents-notification.mjs +0 -175
  45. package/dist/runtime/pi-subagents.bundle.js +0 -9110
  46. package/dist/runtime/pi-supervised-command-extension.mjs +0 -72
  47. package/dist/runtime/pi-supervised-command.bundle.js +0 -4735
  48. package/dist/runtime/pi-supervised-command.mjs +0 -420
  49. package/patches/@tintinweb%2Fpi-subagents@0.14.3.patch +0 -945
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.5
4
+
5
+ Pi uses a small Larkin-owned tmux Bash extension when tmux is available on macOS/Linux. Commands preserve their working directory, including non-Git paths with spaces; a foreground wait can return while the same command continues. The returned task ID supports inspection and cancellation, and background completion resumes the Agent. Native Windows and environments without tmux retain Pi's native Bash.
6
+
7
+ Removed the injected subagent plugin, its ledger/watchdog and supervised-command infrastructure, the 60-second Bash hard-kill rule, and mandatory delegation guidance. Pi-owned turns now occupy Runtime busy state without a second host prompt. Historical subagent files are left untouched. Background commands survive Pi shutdown in tmux; notification recovery across Pi restarts is not provided. No third-party tmux plugin is installed or redistributed.
8
+
9
+ ## 0.5.4
10
+
11
+ Inbox Audit is now optional and off by default. The Dashboard and CLI support global and per-Agent switches and inspection gaps. Saving a gap updates scheduling without replacing Runtime sessions; editing a gap alone does not enable auditing. Only originally wake-eligible human group/topic work is audited.
12
+
13
+ Audit reads no longer mark work complete. Agents explicitly confirm a receipt after checking; receipts are scoped to an observation generation, and durable canonical sequence ordering protects newer work from stale completion or deferred registration. Contended registrations are retried durably. Unproven legacy audit-index rows are ignored while ordinary Inbox and conversation history remain intact.
14
+
3
15
  ## 0.5.3
4
16
 
5
17
  External Pi initialization now runs with bounded concurrency and recovers from isolated startup-probe timeouts through the existing retry policy. Shutdown waits for pending initialization and closes late sessions. Generic Runtime and delivery failures show unavailable instead of incompatible, while explicit prerequisite failures and useful provider diagnostics are preserved. Recovery workflow tests wait for delivery consumption and Inbox watermarks to converge and isolate temporary state.
package/README.md CHANGED
@@ -91,7 +91,28 @@ Feishu (https://open.feishu.cn) and Lark (https://open.larksuite.com) are differ
91
91
 
92
92
  During setup, choose one of the three externally installed runtimes: Pi (`pi`), Codex (`codex`), or Claude Code (`claude`). Larkin does not ship a runtime and does not store provider credentials. Install the runtime yourself and complete its own login (`pi` login flow, `codex login`, or `claude login`) before setup. Interactive setup lists each runtime as installed or not installed and refuses a missing binary; non-interactive setup requires `--runtime` and exits non-zero with the same missing-install message.
93
93
 
94
- `larkin setup --model <id>` optionally stores a catalog model for that runtime. After setup, use `larkin model` and `larkin runtime` to inspect or switch. For Pi, Larkin talks to your installed `pi --mode rpc`, verifies the RPC handshake and compaction capability contract, and injects its supported extensions through `pi -e` (background subagents and the 60-second foreground bash timeout guard).
94
+ `larkin setup --model <id>` optionally stores a catalog model for that runtime. After setup, use `larkin model` and `larkin runtime` to inspect or switch. For Pi, Larkin talks to your installed `pi --mode rpc` and verifies the RPC handshake and compaction capability contract.
95
+
96
+ ### Optional Pi tmux-backed bash
97
+
98
+ On macOS and Linux with `tmux` 3.2 or newer installed, Larkin provides a small tmux-backed Bash tool. Commands run in their requested directory, including non-Git directories and paths with spaces. By default the tool waits up to 30 seconds, then returns a `taskId` while the same command continues; `background: true` returns immediately. The `tmux` tool lists, inspects and stops tasks owned by that Pi instance. Completed background commands notify the Agent. There is no Larkin-imposed 60-second kill or ten-minute command limit.
99
+
100
+ Without a supported tmux version, or on native Windows, Pi keeps native bash. After Pi shuts down, background commands remain in tmux, but automatic completion notifications are not restored; use `tmux list-sessions` to find the session containing the task ID and attach manually. Larkin does not require a third-party tmux plugin.
101
+
102
+ ### Optional Inbox Audit
103
+
104
+ Inbox Audit is **off by default**. In the Dashboard, use **Global settings → Inbox 巡检** to configure the switch and inspection gap, or the selected Agent's **Configuration → Inbox 巡检** to override either value. The gap defaults to 15 minutes and supports 1 minute to 24 hours. Saving a gap alone keeps auditing disabled; saved settings survive restart and update later scheduling without replacing the Agent Runtime session.
105
+
106
+ The same settings are available through the CLI:
107
+
108
+ ```bash
109
+ larkin config inbox-audit global on --interval 15m
110
+ larkin config inbox-audit agent off --agent <App-ID>
111
+ larkin config inbox-audit agent inherit --agent <App-ID> --interval inherit
112
+ larkin config inbox-audit global off
113
+ ```
114
+
115
+ When enabled, audit only revisits originally wake-eligible human group/topic work and does not wake a model for an empty work list. Reading an audit list does not complete it: the managed Agent follows the returned inspection instructions and explicitly confirms the receipt after checking. A failed check remains retryable; newer messages cannot be completed by an older receipt. Old audit-index records without proven eligibility or observation identity are ignored; ordinary Inbox messages and conversation history are preserved.
95
116
 
96
117
  <details>
97
118
  <summary>Windows support and optional autostart</summary>
@@ -4,7 +4,7 @@ Generated at release time from Larkin's installed runtime dependency closure.
4
4
  Development-only dependencies are intentionally excluded. Packages without a bundled license file
5
5
  use an explicitly audited, version- and hash-pinned license source and remain identified by locked package name and version.
6
6
 
7
- Runtime package versions: 101
7
+ Runtime package versions: 97
8
8
 
9
9
  | Package | Version | Relationship | Declared license | License texts (SHA-256) | Lock integrity |
10
10
  | --- | ---: | --- | --- | --- | --- |
@@ -43,8 +43,6 @@ Runtime package versions: 101
43
43
  | @radix-ui/react-use-controllable-state | 1.2.6 | runtime transitive | MIT | LICENSE (0e80a2d229d2fd4fc7e8636142ec5d0ff0bc031f14c15b682e2ac01dfd5b5138) | sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ== |
44
44
  | @radix-ui/react-use-effect-event | 0.0.5 | runtime transitive | MIT | LICENSE (0e80a2d229d2fd4fc7e8636142ec5d0ff0bc031f14c15b682e2ac01dfd5b5138) | sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg== |
45
45
  | @radix-ui/react-use-layout-effect | 1.1.4 | runtime transitive | MIT | LICENSE (0e80a2d229d2fd4fc7e8636142ec5d0ff0bc031f14c15b682e2ac01dfd5b5138) | sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw== |
46
- | @sinclair/typebox | 0.34.52 | runtime transitive | MIT | license (411f1c560755e27b3dec9622c13b8b7a3ec1c83f4ffb8c56a8847528aa96911a) | sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw== |
47
- | @tintinweb/pi-subagents | 0.14.3 | runtime direct | MIT | LICENSE (e7d9d11c28cce34f09dc7d2b0a3a6609ccba5fbc8e926e6d1bfdf060930e9f05) | sha512-iDqeadh6114AZvw8HYe1PEq8M0MZ9czJKTAIsklCPUbV9vUMS+g/LAV0vW3O9PiBXKNJh8hkrY8L6iIr8XNEqA== |
48
46
  | agent-base | 6.0.2 | runtime transitive | MIT | AUDITED-agent-base@9.0.0-LICENSE (71368fd0f5b4129191e9afcd1e1ef2dc89a9090d3e4d80bbab92dafd032b3bef) | sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== |
49
47
  | agent-base | 9.0.0 | runtime transitive | MIT | LICENSE (71368fd0f5b4129191e9afcd1e1ef2dc89a9090d3e4d80bbab92dafd032b3bef) | sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA== |
50
48
  | aria-hidden | 1.2.6 | runtime transitive | MIT | LICENSE (30f0cfddf483d1128e3610205020f2041a6c5e837aa999e0aa82e5576187d4a9) | sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA== |
@@ -53,7 +51,6 @@ Runtime package versions: 101
53
51
  | call-bind-apply-helpers | 1.0.2 | runtime transitive | MIT | LICENSE (5e325595b4ea8cfec3802f545b1def5d7b73e4a5b8e9ba63e32a320f67732292) | sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== |
54
52
  | call-bound | 1.0.4 | runtime transitive | MIT | LICENSE (5e325595b4ea8cfec3802f545b1def5d7b73e4a5b8e9ba63e32a320f67732292) | sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== |
55
53
  | combined-stream | 1.0.8 | runtime transitive | MIT | License (47eb8ca82c798246774946d1be0f9aa08f025fa8325ced0947aeeb4c05fe5547) | sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== |
56
- | croner | 10.0.1 | runtime transitive | MIT | LICENSE (ad9aa40aaab4bee08121a0180096cc6a72abf29e19e606328b66c0178f41d267) | sha512-ixNtAJndqh173VQ4KodSdJEI6nuioBWI0V1ITNKhZZsO0pEMoDxz539T4FTTbSZ/xIOSuDnzxLVRqBVSvPNE2g== |
57
54
  | debug | 4.4.3 | runtime transitive | MIT | LICENSE (23eb8602cd5902bcfca56b23aa08e8672a809f5a12eaf8bb56abfa9d44e1a4fd) | sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== |
58
55
  | delayed-stream | 1.0.0 | runtime transitive | MIT | License (47eb8ca82c798246774946d1be0f9aa08f025fa8325ced0947aeeb4c05fe5547) | sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== |
59
56
  | detect-node-es | 1.1.0 | runtime transitive | MIT | LICENSE (54b32293ea560d22cd9b62af9b2cda1a030d910a48c6601d227c5ff2338d95f8) | sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== |
@@ -84,7 +81,6 @@ Runtime package versions: 101
84
81
  | mime-db | 1.52.0 | runtime transitive | MIT | LICENSE (cc1dfd4dafa27271e8212cd3b274eeb3f262e40a6fdab36ddc3f9696f706f58b) | sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== |
85
82
  | mime-types | 2.1.35 | runtime transitive | MIT | LICENSE (71f83c4c0621102a56d9853812777b85751bce7e9726f686f5b056c1f8a4b0e6) | sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== |
86
83
  | ms | 2.1.3 | runtime transitive | MIT | license.md (1662fae9b5314d11cf51284e2dcd1f006a354f7343f08712a730fcff9a359801) | sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== |
87
- | nanoid | 5.1.16 | runtime transitive | MIT | LICENSE (4383cb2c3608397ce7a4159502614ed66890f8999c2a9c056dd3b1024d6721f0) | sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ== |
88
84
  | object-inspect | 1.13.4 | runtime transitive | MIT | LICENSE (bd40cc437e28a3ad7bef2ad34e6b72e757b182e67bda1acadbab4ef0476f8232) | sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== |
89
85
  | proper-lockfile | 4.1.2 | runtime direct | MIT | LICENSE (aaa78451b6fecd1b9c4594c796c133c0e90cad100372ff8bc6de615e9ef9adf1) | sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== |
90
86
  | protobufjs | 7.6.5 | runtime transitive | BSD-3-Clause | LICENSE (49d6a1c9a623784c61c6cb70f773f3457faceb1914a13c8560a9823b7631950c) | sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw== |
@@ -414,55 +410,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
414
410
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
415
411
  SOFTWARE.
416
412
 
417
- --- SHA-256 411f1c560755e27b3dec9622c13b8b7a3ec1c83f4ffb8c56a8847528aa96911a ---
418
- TypeBox
419
-
420
- Json Schema Type Builder with Static Type Resolution for TypeScript
421
-
422
- The MIT License (MIT)
423
-
424
- Copyright (c) 2017-2026 Haydn Paterson
425
-
426
- Permission is hereby granted, free of charge, to any person obtaining a copy
427
- of this software and associated documentation files (the "Software"), to deal
428
- in the Software without restriction, including without limitation the rights
429
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
430
- copies of the Software, and to permit persons to whom the Software is
431
- furnished to do so, subject to the following conditions:
432
-
433
- The above copyright notice and this permission notice shall be included in
434
- all copies or substantial portions of the Software.
435
-
436
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
437
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
438
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
439
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
440
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
441
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
442
- THE SOFTWARE.
443
-
444
- --- SHA-256 4383cb2c3608397ce7a4159502614ed66890f8999c2a9c056dd3b1024d6721f0 ---
445
- The MIT License (MIT)
446
-
447
- Copyright 2017 Andrey Sitnik <andrey@sitnik.es>
448
-
449
- Permission is hereby granted, free of charge, to any person obtaining a copy of
450
- this software and associated documentation files (the "Software"), to deal in
451
- the Software without restriction, including without limitation the rights to
452
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
453
- the Software, and to permit persons to whom the Software is furnished to do so,
454
- subject to the following conditions:
455
-
456
- The above copyright notice and this permission notice shall be included in all
457
- copies or substantial portions of the Software.
458
-
459
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
460
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
461
- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
462
- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
463
- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
464
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
465
-
466
413
  --- SHA-256 47eb8ca82c798246774946d1be0f9aa08f025fa8325ced0947aeeb4c05fe5547 ---
467
414
  Copyright (c) 2011 Debuggable Limited <felix@debuggable.com>
468
415
 
@@ -968,29 +915,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
968
915
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
969
916
  SOFTWARE.
970
917
 
971
- --- SHA-256 ad9aa40aaab4bee08121a0180096cc6a72abf29e19e606328b66c0178f41d267 ---
972
- The MIT License (MIT)
973
-
974
- Copyright (c) 2015-2021 Hexagon <github.com/Hexagon>
975
-
976
- Permission is hereby granted, free of charge, to any person obtaining a copy
977
- of this software and associated documentation files (the "Software"), to deal
978
- in the Software without restriction, including without limitation the rights
979
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
980
- copies of the Software, and to permit persons to whom the Software is
981
- furnished to do so, subject to the following conditions:
982
-
983
- The above copyright notice and this permission notice shall be included in all
984
- copies or substantial portions of the Software.
985
-
986
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
987
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
988
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
989
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
990
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
991
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
992
- SOFTWARE.
993
-
994
918
  --- SHA-256 b495047bd93a9b06913511076f504daba17d5bbeb3e0650f3bb53a4220329c57 ---
995
919
  ISC License
996
920
 
@@ -1711,29 +1635,6 @@ Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors
1711
1635
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1712
1636
  THE SOFTWARE.
1713
1637
 
1714
- --- SHA-256 e7d9d11c28cce34f09dc7d2b0a3a6609ccba5fbc8e926e6d1bfdf060930e9f05 ---
1715
- MIT License
1716
-
1717
- Copyright (c) 2026 tintinweb
1718
-
1719
- Permission is hereby granted, free of charge, to any person obtaining a copy
1720
- of this software and associated documentation files (the "Software"), to deal
1721
- in the Software without restriction, including without limitation the rights
1722
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1723
- copies of the Software, and to permit persons to whom the Software is
1724
- furnished to do so, subject to the following conditions:
1725
-
1726
- The above copyright notice and this permission notice shall be included in all
1727
- copies or substantial portions of the Software.
1728
-
1729
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1730
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1731
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1732
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1733
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1734
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1735
- SOFTWARE.
1736
-
1737
1638
  --- SHA-256 e7dc37bf662d7f786efcb46c545615e70c1daf458a38385521c63cf6607cdfe1 ---
1738
1639
  BSD 3-Clause License
1739
1640
 
@@ -32,7 +32,7 @@ function agentCliPromptCapabilities(executable = "larkin") {
32
32
  const commands = Object.entries(exports.AGENT_CLI_CAPABILITIES.commands).flatMap(([group, operations]) => operations.map((operation) => ({
33
33
  command: `${group} ${operation}`,
34
34
  purpose: group === "inbox" ? (operation === "check" ? "Read pending target summaries without consuming messages."
35
- : operation === "audit" ? "Read bounded observed group/topic audit targets and instructions."
35
+ : operation === "audit" ? "Read bounded observed group/topic audit targets; inspect first, then explicitly confirm the returned receipt."
36
36
  : "Poll full messages and direct-ack the returned batch.") :
37
37
  group === "comment" ? "Reply once to the exact cloud-document comment bound by a polled Inbox message id." :
38
38
  group === "reminder" ? "Manage this Agent's durable reminders." :
@@ -24,7 +24,7 @@ export function agentCliPromptCapabilities(executable = "larkin") {
24
24
  const commands = Object.entries(AGENT_CLI_CAPABILITIES.commands).flatMap(([group, operations]) => operations.map((operation) => ({
25
25
  command: `${group} ${operation}`,
26
26
  purpose: group === "inbox" ? (operation === "check" ? "Read pending target summaries without consuming messages."
27
- : operation === "audit" ? "Read bounded observed group/topic audit targets and instructions."
27
+ : operation === "audit" ? "Read bounded observed group/topic audit targets; inspect first, then explicitly confirm the returned receipt."
28
28
  : "Poll full messages and direct-ack the returned batch.") :
29
29
  group === "comment" ? "Reply once to the exact cloud-document comment bound by a polled Inbox message id." :
30
30
  group === "reminder" ? "Manage this Agent's durable reminders." :
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CONFIG_CLI_VALUES = exports.CONFIG_CLI_USAGE = exports.CONFIG_CLI_OPERATIONS = void 0;
4
- exports.CONFIG_CLI_OPERATIONS = Object.freeze(["show", "runtime", "model", "effort", "mention", "apply"]);
4
+ exports.CONFIG_CLI_OPERATIONS = Object.freeze(["show", "runtime", "model", "effort", "mention", "inbox-audit", "apply"]);
5
5
  exports.CONFIG_CLI_USAGE = Object.freeze([
6
6
  "larkin config show [--agent <App ID>] [--chat <oc_id>] [--json]",
7
7
  "larkin config runtime <runtime> [--model <model>] [--agent <App ID>]",
@@ -10,6 +10,8 @@ exports.CONFIG_CLI_USAGE = Object.freeze([
10
10
  "larkin config mention global <require|free>",
11
11
  "larkin config mention agent <inherit|require|free> [--agent <App ID>]",
12
12
  "larkin config mention chat <oc_id> <inherit|require|free> [--agent <App ID>]",
13
+ "larkin config inbox-audit global <on|off> [--interval <15m|1h>]",
14
+ "larkin config inbox-audit agent <inherit|on|off> [--agent <App ID>] [--interval <15m|inherit>]",
13
15
  "larkin config apply [--agent <App ID>]",
14
16
  ]);
15
17
  exports.CONFIG_CLI_VALUES = Object.freeze({
@@ -1,4 +1,4 @@
1
- export const CONFIG_CLI_OPERATIONS = Object.freeze(["show", "runtime", "model", "effort", "mention", "apply"]);
1
+ export const CONFIG_CLI_OPERATIONS = Object.freeze(["show", "runtime", "model", "effort", "mention", "inbox-audit", "apply"]);
2
2
  export const CONFIG_CLI_USAGE = Object.freeze([
3
3
  "larkin config show [--agent <App ID>] [--chat <oc_id>] [--json]",
4
4
  "larkin config runtime <runtime> [--model <model>] [--agent <App ID>]",
@@ -7,6 +7,8 @@ export const CONFIG_CLI_USAGE = Object.freeze([
7
7
  "larkin config mention global <require|free>",
8
8
  "larkin config mention agent <inherit|require|free> [--agent <App ID>]",
9
9
  "larkin config mention chat <oc_id> <inherit|require|free> [--agent <App ID>]",
10
+ "larkin config inbox-audit global <on|off> [--interval <15m|1h>]",
11
+ "larkin config inbox-audit agent <inherit|on|off> [--agent <App ID>] [--interval <15m|inherit>]",
10
12
  "larkin config apply [--agent <App ID>]",
11
13
  ]);
12
14
  export const CONFIG_CLI_VALUES = Object.freeze({
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ContextPromptBuilder = exports.AGENT_MENTION_GUIDANCE = exports.LARKIN_STANDING_PROMPT_VERSION = void 0;
3
+ exports.ContextPromptBuilder = exports.AGENT_MENTION_GUIDANCE = exports.PI_TMUX_BASH_GUIDANCE = exports.LARKIN_STANDING_PROMPT_VERSION = void 0;
4
4
  const node_crypto_1 = require("node:crypto");
5
5
  const agent_cli_capabilities_js_1 = require("./agent-cli-capabilities.cjs");
6
6
  /**
@@ -16,7 +16,18 @@ const agent_cli_capabilities_js_1 = require("./agent-cli-capabilities.cjs");
16
16
  * 5. 版本化:每次实质改动 bump LARKIN_STANDING_PROMPT_VERSION,并同步 eval 数据集/graders/断言。
17
17
  * 6. 用 eval 验证:行为变化必须配套固定场景 + rubric(evals/*、test/support/*-grader.mjs、live 测试)。
18
18
  */
19
- exports.LARKIN_STANDING_PROMPT_VERSION = "larkin-standing-v28";
19
+ exports.LARKIN_STANDING_PROMPT_VERSION = "larkin-standing-v30";
20
+ /**
21
+ * Pi 长命令引导的唯一来源。仅在当前工具列表出现 tmux-backed bash 时适用;
22
+ * 不声明 tmux 一定可用,也不复述扩展的工具细节。
23
+ * 工具拒绝当前 workspace 时只要求如实报告,不因此禁止其它已授权工具。
24
+ */
25
+ exports.PI_TMUX_BASH_GUIDANCE = [
26
+ "If the current tools include a tmux-backed bash, long-running work may continue after a wait timeout. That timeout is not process failure.",
27
+ "Use the identifiers those tools return to inspect or stop the same process. When a command finishes, handle the completion notification in this originating conversation.",
28
+ "The user-installed extension owns tool names, arguments, and other details. Do not assume tmux or extra inspect/stop tools exist unless they appear in the current tool list.",
29
+ "If an available tool refuses the current workspace, report that limitation. Other authorized tools in the current list remain available. Do not assume the refusing tool works in every workspace.",
30
+ ];
20
31
  /**
21
32
  * Agent 间协作唤醒引导(issue #75):纯文本 @ 不会产生飞书 mention 事件,
22
33
  * 必须由模型直接构造真实的 mention 元素;`--mention` 扩展参数已移除。
@@ -123,21 +134,9 @@ class ContextPromptBuilder {
123
134
  "Larkin Runtime Host is the only production runtime path. Do not start a second runtime or a legacy daemon.",
124
135
  ...(input.runtime === "pi" ? [
125
136
  "",
126
- "## Background subagents (pi)",
127
- "Long-running, independent work MUST use the Agent tool with run_in_background: true. It is the ONLY supported background mechanism. nohup, `&`, disown, and shell background jobs are forbidden for delegated work.",
128
- "Foreground bash is hard-capped at 60 seconds. Never pass a bash timeout above 60. Never use nested bash to outlive 60s. If work must outlive 60s, Agent({ prompt, description, run_in_background: true }) and inside that background agent use supervised_start (executable+args, shell:false) once, then loop supervised_wait (timeout <= 60). Wait timeout returns still running and does NOT kill the process; Steer can arrive after each wait. Total lifetime is 600s. Abort/cancel/shutdown reaps the process tree. Do not use nohup / '&' / disown.",
129
- "Correct pattern:",
130
- "1. Call Agent with arguments like {\"prompt\": \"<task>\", \"description\": \"<short label>\", \"run_in_background\": true}.",
131
- "2. The tool returns an agent id immediately. Report it to the user and end the turn.",
132
- "3. Do NOT poll or sleep; a completion notification arrives automatically.",
133
- "4. On the notification, check the Inbox, then publish exactly one final summary.",
134
- "If you explicitly use get_subagent_result with wait: true, make at most one bounded wait call per turn. If it returns timedOut: true, do not loop or call wait again in the same turn; yield and let the completion notification wake you.",
135
- "Forbidden pattern (never acceptable): `nohup sh -c '...' > /tmp/x.out 2>&1 &`, `sleep N; cat ...`, disown, or any shell background substitute. These bypass subagent isolation.",
136
- "Keep corrections, approvals, short commands, and Feishu writes in the foreground; do not delegate them.",
137
- "Parallel independent tasks: when the user clearly asks for two or more independent tasks with no dependencies between them, delegate EACH task to its own background subagent in a single message with multiple Agent tool calls (one per task, all with run_in_background: true), report every job id, and end the turn. Do not run them one-by-one in the foreground and do not merge them into one subagent.",
138
- "Sequential dependent tasks: when tasks depend on each other, sending the user an order message is a REQUIRED first step: before executing any follow-up work, send a message stating the execution order (for example: first I will do A, then B; I will report back after each step). Then execute in order and report as promised; never stay silent while chaining long work.",
139
- "Reporting location: always report job ids and final summaries in the same conversation and thread where the user's message arrived (reply-in-thread when the request arrived in a thread). Never start a new conversation or DM for subagent status reports.",
140
- ""
137
+ "## Long-running commands (pi)",
138
+ ...exports.PI_TMUX_BASH_GUIDANCE,
139
+ "",
141
140
  ] : []),
142
141
  "",
143
142
  "## Available Larkin agent commands",
@@ -13,7 +13,18 @@ import { agentCliPromptCapabilities } from "./agent-cli-capabilities.mjs";
13
13
  * 5. 版本化:每次实质改动 bump LARKIN_STANDING_PROMPT_VERSION,并同步 eval 数据集/graders/断言。
14
14
  * 6. 用 eval 验证:行为变化必须配套固定场景 + rubric(evals/*、test/support/*-grader.mjs、live 测试)。
15
15
  */
16
- export const LARKIN_STANDING_PROMPT_VERSION = "larkin-standing-v28";
16
+ export const LARKIN_STANDING_PROMPT_VERSION = "larkin-standing-v30";
17
+ /**
18
+ * Pi 长命令引导的唯一来源。仅在当前工具列表出现 tmux-backed bash 时适用;
19
+ * 不声明 tmux 一定可用,也不复述扩展的工具细节。
20
+ * 工具拒绝当前 workspace 时只要求如实报告,不因此禁止其它已授权工具。
21
+ */
22
+ export const PI_TMUX_BASH_GUIDANCE = [
23
+ "If the current tools include a tmux-backed bash, long-running work may continue after a wait timeout. That timeout is not process failure.",
24
+ "Use the identifiers those tools return to inspect or stop the same process. When a command finishes, handle the completion notification in this originating conversation.",
25
+ "The user-installed extension owns tool names, arguments, and other details. Do not assume tmux or extra inspect/stop tools exist unless they appear in the current tool list.",
26
+ "If an available tool refuses the current workspace, report that limitation. Other authorized tools in the current list remain available. Do not assume the refusing tool works in every workspace.",
27
+ ];
17
28
  /**
18
29
  * Agent 间协作唤醒引导(issue #75):纯文本 @ 不会产生飞书 mention 事件,
19
30
  * 必须由模型直接构造真实的 mention 元素;`--mention` 扩展参数已移除。
@@ -120,21 +131,9 @@ export class ContextPromptBuilder {
120
131
  "Larkin Runtime Host is the only production runtime path. Do not start a second runtime or a legacy daemon.",
121
132
  ...(input.runtime === "pi" ? [
122
133
  "",
123
- "## Background subagents (pi)",
124
- "Long-running, independent work MUST use the Agent tool with run_in_background: true. It is the ONLY supported background mechanism. nohup, `&`, disown, and shell background jobs are forbidden for delegated work.",
125
- "Foreground bash is hard-capped at 60 seconds. Never pass a bash timeout above 60. Never use nested bash to outlive 60s. If work must outlive 60s, Agent({ prompt, description, run_in_background: true }) and inside that background agent use supervised_start (executable+args, shell:false) once, then loop supervised_wait (timeout <= 60). Wait timeout returns still running and does NOT kill the process; Steer can arrive after each wait. Total lifetime is 600s. Abort/cancel/shutdown reaps the process tree. Do not use nohup / '&' / disown.",
126
- "Correct pattern:",
127
- "1. Call Agent with arguments like {\"prompt\": \"<task>\", \"description\": \"<short label>\", \"run_in_background\": true}.",
128
- "2. The tool returns an agent id immediately. Report it to the user and end the turn.",
129
- "3. Do NOT poll or sleep; a completion notification arrives automatically.",
130
- "4. On the notification, check the Inbox, then publish exactly one final summary.",
131
- "If you explicitly use get_subagent_result with wait: true, make at most one bounded wait call per turn. If it returns timedOut: true, do not loop or call wait again in the same turn; yield and let the completion notification wake you.",
132
- "Forbidden pattern (never acceptable): `nohup sh -c '...' > /tmp/x.out 2>&1 &`, `sleep N; cat ...`, disown, or any shell background substitute. These bypass subagent isolation.",
133
- "Keep corrections, approvals, short commands, and Feishu writes in the foreground; do not delegate them.",
134
- "Parallel independent tasks: when the user clearly asks for two or more independent tasks with no dependencies between them, delegate EACH task to its own background subagent in a single message with multiple Agent tool calls (one per task, all with run_in_background: true), report every job id, and end the turn. Do not run them one-by-one in the foreground and do not merge them into one subagent.",
135
- "Sequential dependent tasks: when tasks depend on each other, sending the user an order message is a REQUIRED first step: before executing any follow-up work, send a message stating the execution order (for example: first I will do A, then B; I will report back after each step). Then execute in order and report as promised; never stay silent while chaining long work.",
136
- "Reporting location: always report job ids and final summaries in the same conversation and thread where the user's message arrived (reply-in-thread when the request arrived in a thread). Never start a new conversation or DM for subagent status reports.",
137
- ""
134
+ "## Long-running commands (pi)",
135
+ ...PI_TMUX_BASH_GUIDANCE,
136
+ "",
138
137
  ] : []),
139
138
  "",
140
139
  "## Available Larkin agent commands",
@@ -1,62 +1,182 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.InboxAuditHeartbeat = exports.INBOX_AUDIT_CADENCE_MS = void 0;
36
+ exports.InboxAuditHeartbeat = exports.MAX_INBOX_AUDIT_DIAGNOSTIC_CHARS = exports.INBOX_AUDIT_CADENCE_MS = void 0;
37
+ exports.boundedInboxAuditDiagnostic = boundedInboxAuditDiagnostic;
38
+ const fs = __importStar(require("node:fs"));
39
+ const path = __importStar(require("node:path"));
4
40
  const inbox_projection_js_1 = require("./inbox-projection.cjs");
5
41
  exports.INBOX_AUDIT_CADENCE_MS = 15 * 60_000;
6
- /** One Host-owned timer fans a targetless internal wake to each active Agent. */
42
+ exports.MAX_INBOX_AUDIT_DIAGNOSTIC_CHARS = 120;
43
+ function boundedInboxAuditDiagnostic(error) {
44
+ const max = exports.MAX_INBOX_AUDIT_DIAGNOSTIC_CHARS;
45
+ const code = error && typeof error === "object" && "code" in error && typeof error.code === "string"
46
+ ? error.code.slice(0, max) : "";
47
+ const raw = error instanceof Error ? error.message : String(error);
48
+ const text = String(raw).slice(0, max).replace(/[\u0000-\u001f\u007f]+/g, " ").replace(/\s+/g, " ").trim();
49
+ return [code, text].filter(Boolean).join(" ").slice(0, max);
50
+ }
51
+ function safeIntervalMs(intervalMs) {
52
+ if (!Number.isSafeInteger(intervalMs) || intervalMs < 1)
53
+ throw new Error("inbox audit cadence must be a positive integer");
54
+ return intervalMs;
55
+ }
56
+ /** A Host-owned, config-file-reactive single timer per enabled Agent. */
7
57
  class InboxAuditHeartbeat {
8
58
  options;
9
- timer = null;
59
+ timers = new Map();
60
+ generations = new Map();
10
61
  running = false;
11
62
  sequence = 0;
12
- cadenceMs;
63
+ watcher = null;
64
+ refreshTimer = null;
13
65
  constructor(options) {
14
66
  this.options = options;
15
- this.cadenceMs = options.cadenceMs ?? exports.INBOX_AUDIT_CADENCE_MS;
16
- if (!Number.isSafeInteger(this.cadenceMs) || this.cadenceMs < 1)
17
- throw new Error("inbox audit cadence must be a positive integer");
67
+ for (const agent of options.agents)
68
+ safeIntervalMs(options.schedule(agent).intervalMs);
18
69
  }
19
70
  start() {
20
71
  if (this.running)
21
72
  return;
22
73
  this.running = true;
23
- this.schedule();
74
+ for (const agent of this.options.agents)
75
+ this.reschedule(agent);
76
+ this.watchConfig();
24
77
  }
25
78
  stop() {
26
79
  this.running = false;
27
- if (this.timer)
28
- (this.options.clearTimer ?? clearTimeout)(this.timer);
29
- this.timer = null;
80
+ const clearTimer = this.options.clearTimer ?? clearTimeout;
81
+ for (const timer of this.timers.values())
82
+ clearTimer(timer);
83
+ this.timers.clear();
84
+ if (this.refreshTimer)
85
+ clearTimer(this.refreshTimer);
86
+ this.refreshTimer = null;
87
+ this.watcher?.close();
88
+ this.watcher = null;
89
+ }
90
+ /** Safe for a Host config watcher or a direct in-process config mutation hook. */
91
+ refresh() {
92
+ if (!this.running)
93
+ return;
94
+ for (const agent of this.options.agents)
95
+ this.reschedule(agent);
30
96
  }
31
- schedule() {
32
- if (!this.running || this.timer)
97
+ watchConfig() {
98
+ if (!this.options.configFile || this.watcher)
33
99
  return;
34
- this.timer = (this.options.setTimer ?? setTimeout)(() => {
35
- this.timer = null;
36
- return this.fire().finally(() => { if (this.running)
37
- this.schedule(); });
38
- }, this.cadenceMs);
39
- this.timer.unref?.();
100
+ const file = path.resolve(this.options.configFile);
101
+ const parent = path.dirname(file);
102
+ const basename = path.basename(file);
103
+ try {
104
+ this.watcher = (this.options.watch ?? fs.watch)(parent, (_event, changed) => {
105
+ if (changed && String(changed) !== basename)
106
+ return;
107
+ this.scheduleRefresh();
108
+ });
109
+ }
110
+ catch (error) {
111
+ this.options.log?.(`inbox audit config watch failed: ${boundedInboxAuditDiagnostic(error)}`);
112
+ }
40
113
  }
41
- async fire() {
114
+ scheduleRefresh() {
115
+ if (!this.running || this.refreshTimer)
116
+ return;
117
+ this.refreshTimer = (this.options.setTimer ?? setTimeout)(() => {
118
+ this.refreshTimer = null;
119
+ this.refresh();
120
+ }, 30);
121
+ this.refreshTimer.unref?.();
122
+ }
123
+ reschedule(agent) {
124
+ const clearTimer = this.options.clearTimer ?? clearTimeout;
125
+ const prior = this.timers.get(agent.agentId);
126
+ if (prior)
127
+ clearTimer(prior);
128
+ this.timers.delete(agent.agentId);
129
+ const generation = (this.generations.get(agent.agentId) ?? 0) + 1;
130
+ this.generations.set(agent.agentId, generation);
131
+ let schedule;
132
+ try {
133
+ schedule = this.options.schedule(agent);
134
+ safeIntervalMs(schedule.intervalMs);
135
+ }
136
+ catch (error) {
137
+ this.options.log?.(`inbox audit schedule failed agent=${agent.agentId}: ${boundedInboxAuditDiagnostic(error)}`);
138
+ return;
139
+ }
140
+ // Disabled means no future audit timer or model wake at all.
141
+ if (!schedule.enabled || !this.running)
142
+ return;
143
+ let timer;
144
+ timer = (this.options.setTimer ?? setTimeout)(() => {
145
+ // A cancelled callback can still be queued. It must not remove the
146
+ // replacement timer installed by a newer config revision.
147
+ if (this.timers.get(agent.agentId) === timer)
148
+ this.timers.delete(agent.agentId);
149
+ void this.fire(agent, generation).finally(() => {
150
+ if (this.running && this.generations.get(agent.agentId) === generation)
151
+ this.reschedule(agent);
152
+ });
153
+ }, schedule.intervalMs);
154
+ timer.unref?.();
155
+ this.timers.set(agent.agentId, timer);
156
+ }
157
+ async fire(agent, generation) {
158
+ if (this.generations.get(agent.agentId) !== generation)
159
+ return;
160
+ try {
161
+ const schedule = this.options.schedule(agent);
162
+ if (!schedule.enabled || !this.options.shouldDispatch(agent))
163
+ return;
164
+ }
165
+ catch (error) {
166
+ this.options.log?.(`inbox audit schedule failed agent=${agent.agentId}: ${boundedInboxAuditDiagnostic(error)}`);
167
+ return;
168
+ }
42
169
  const now = this.options.now ?? Date.now;
43
- for (const agent of this.options.agents) {
44
- const message_id = `rem_inbox_audit_${now()}_${++this.sequence}_${agent.agentId}`;
45
- const envelope = {
46
- kind: "reminder",
47
- message_id,
48
- target: inbox_projection_js_1.RUNTIME_REMINDER_TARGET,
49
- wake: true,
50
- content: "Internal inbox audit wake. Poll runtime:reminder, then run larkin inbox audit --json. No finding stays silent.",
51
- };
52
- try {
53
- const appended = this.options.stateStore(agent).appendCanonicalInboxOnce(envelope);
54
- if (appended.status === "appended")
55
- await this.options.runtimeHost.deliver(agent.agentId, appended.envelope);
56
- }
57
- catch (error) {
58
- this.options.log?.(`inbox audit heartbeat failed agent=${agent.agentId}: ${error instanceof Error ? error.message : String(error)}`);
59
- }
170
+ const message_id = `rem_inbox_audit_${now()}_${++this.sequence}_${agent.agentId}`;
171
+ const envelope = { kind: "reminder", message_id, target: inbox_projection_js_1.RUNTIME_REMINDER_TARGET, wake: true,
172
+ content: "Internal inbox audit wake. Poll runtime:reminder, then run larkin inbox audit --json. Inspect first and explicitly complete its receipt; no finding stays silent." };
173
+ try {
174
+ const appended = this.options.stateStore(agent).appendCanonicalInboxOnce(envelope);
175
+ if (appended.status === "appended")
176
+ await this.options.runtimeHost.deliver(agent.agentId, appended.envelope);
177
+ }
178
+ catch (error) {
179
+ this.options.log?.(`inbox audit heartbeat failed agent=${agent.agentId}: ${boundedInboxAuditDiagnostic(error)}`);
60
180
  }
61
181
  }
62
182
  }