@agentdeck/bridge 1.1.0 → 1.2.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 (107) hide show
  1. package/README.md +14 -6
  2. package/assets/fonts/NOTICE-PocketSansWorld.md +10 -0
  3. package/assets/fonts/OFL-PocketSansWorld.txt +93 -0
  4. package/assets/fonts/PocketSansWorld_12.cpfont +0 -0
  5. package/assets/fonts/pocket-sans-world.manifest.json +49 -0
  6. package/assets/learning/LICENSE-CC-BY-SA-4.0.txt +10 -0
  7. package/assets/learning/NOTICE.md +33 -0
  8. package/assets/learning/jp-n3-ko.manifest.json +27 -0
  9. package/assets/learning/jp-n3-ko.pdl +0 -0
  10. package/dist/agent-cli-diagnostics.d.ts +20 -0
  11. package/dist/agent-cli-diagnostics.d.ts.map +1 -0
  12. package/dist/agent-cli-diagnostics.js +100 -0
  13. package/dist/agent-cli-diagnostics.js.map +1 -0
  14. package/dist/apme/collector.d.ts +18 -1
  15. package/dist/apme/collector.d.ts.map +1 -1
  16. package/dist/apme/collector.js +48 -3
  17. package/dist/apme/collector.js.map +1 -1
  18. package/dist/apme/dashboard-html.d.ts.map +1 -1
  19. package/dist/apme/dashboard-html.js +275 -35
  20. package/dist/apme/dashboard-html.js.map +1 -1
  21. package/dist/apme/http.d.ts.map +1 -1
  22. package/dist/apme/http.js +33 -5
  23. package/dist/apme/http.js.map +1 -1
  24. package/dist/apme/index.d.ts.map +1 -1
  25. package/dist/apme/index.js +6 -2
  26. package/dist/apme/index.js.map +1 -1
  27. package/dist/apme/store.d.ts +41 -1
  28. package/dist/apme/store.d.ts.map +1 -1
  29. package/dist/apme/store.js +153 -27
  30. package/dist/apme/store.js.map +1 -1
  31. package/dist/bridge-core.d.ts +15 -0
  32. package/dist/bridge-core.d.ts.map +1 -1
  33. package/dist/bridge-core.js +30 -4
  34. package/dist/bridge-core.js.map +1 -1
  35. package/dist/cli.d.ts +11 -0
  36. package/dist/cli.d.ts.map +1 -1
  37. package/dist/cli.js +55 -8
  38. package/dist/cli.js.map +1 -1
  39. package/dist/codex-rate-limits-live.d.ts +180 -10
  40. package/dist/codex-rate-limits-live.d.ts.map +1 -1
  41. package/dist/codex-rate-limits-live.js +475 -22
  42. package/dist/codex-rate-limits-live.js.map +1 -1
  43. package/dist/daemon-server.d.ts.map +1 -1
  44. package/dist/daemon-server.js +263 -1
  45. package/dist/daemon-server.js.map +1 -1
  46. package/dist/daemon-ws-client.d.ts +1 -0
  47. package/dist/daemon-ws-client.d.ts.map +1 -1
  48. package/dist/daemon-ws-client.js +25 -16
  49. package/dist/daemon-ws-client.js.map +1 -1
  50. package/dist/daemon.js +1 -1
  51. package/dist/esp32-serial.d.ts +4 -0
  52. package/dist/esp32-serial.d.ts.map +1 -1
  53. package/dist/esp32-serial.js +4 -0
  54. package/dist/esp32-serial.js.map +1 -1
  55. package/dist/font-pack.d.ts +15 -0
  56. package/dist/font-pack.d.ts.map +1 -0
  57. package/dist/font-pack.js +75 -0
  58. package/dist/font-pack.js.map +1 -0
  59. package/dist/glance-frame.d.ts.map +1 -1
  60. package/dist/glance-frame.js +2 -0
  61. package/dist/glance-frame.js.map +1 -1
  62. package/dist/http-auth-gate.d.ts.map +1 -1
  63. package/dist/http-auth-gate.js +9 -1
  64. package/dist/http-auth-gate.js.map +1 -1
  65. package/dist/index.js +2 -2
  66. package/dist/index.js.map +1 -1
  67. package/dist/learning-pack.d.ts +24 -0
  68. package/dist/learning-pack.d.ts.map +1 -0
  69. package/dist/learning-pack.js +125 -0
  70. package/dist/learning-pack.js.map +1 -0
  71. package/dist/mdns.js +1 -1
  72. package/dist/mdns.js.map +1 -1
  73. package/dist/pairing-knocks.d.ts +80 -0
  74. package/dist/pairing-knocks.d.ts.map +1 -0
  75. package/dist/pairing-knocks.js +312 -0
  76. package/dist/pairing-knocks.js.map +1 -0
  77. package/dist/pixoo/micro-glyphs.d.ts +4 -0
  78. package/dist/pixoo/micro-glyphs.d.ts.map +1 -1
  79. package/dist/pixoo/micro-glyphs.js +29 -0
  80. package/dist/pixoo/micro-glyphs.js.map +1 -1
  81. package/dist/pixoo/pixoo-font.d.ts.map +1 -1
  82. package/dist/pixoo/pixoo-font.js +3 -1
  83. package/dist/pixoo/pixoo-font.js.map +1 -1
  84. package/dist/pixoo/pixoo-renderer.d.ts +1 -1
  85. package/dist/pixoo/pixoo-renderer.d.ts.map +1 -1
  86. package/dist/pixoo/pixoo-renderer.js +17 -2
  87. package/dist/pixoo/pixoo-renderer.js.map +1 -1
  88. package/dist/pty-manager.d.ts +9 -0
  89. package/dist/pty-manager.d.ts.map +1 -1
  90. package/dist/pty-manager.js +63 -4
  91. package/dist/pty-manager.js.map +1 -1
  92. package/dist/relayed-usage.d.ts +30 -0
  93. package/dist/relayed-usage.d.ts.map +1 -1
  94. package/dist/relayed-usage.js +25 -2
  95. package/dist/relayed-usage.js.map +1 -1
  96. package/dist/surface-protocol.d.ts.map +1 -1
  97. package/dist/surface-protocol.js +2 -0
  98. package/dist/surface-protocol.js.map +1 -1
  99. package/dist/tui/dashboard.d.ts.map +1 -1
  100. package/dist/tui/dashboard.js +8 -1
  101. package/dist/tui/dashboard.js.map +1 -1
  102. package/dist/ws-server.d.ts +18 -0
  103. package/dist/ws-server.d.ts.map +1 -1
  104. package/dist/ws-server.js +40 -2
  105. package/dist/ws-server.js.map +1 -1
  106. package/package.json +4 -3
  107. package/src/timebox/sync_ble.py +35 -16
package/README.md CHANGED
@@ -17,17 +17,25 @@ npm install -g @agentdeck/bridge
17
17
  ## Usage
18
18
 
19
19
  ```bash
20
- agentdeck claude # run Claude Code inside an AgentDeck session bridge
21
- agentdeck codex # same for Codex
22
- agentdeck opencode # same for OpenCode
23
- agentdeck monitor # terminal dashboard
24
- agentdeck daemon start # start the daemon hub (port 9120)
20
+ agentdeck daemon install # install hooks and start the daemon on login
21
+ claude # or: codex / opencode
22
+ agentdeck dashboard # terminal dashboard
23
+ agentdeck daemon start # start the daemon hub manually (port 9120)
25
24
  agentdeck devices # list connected display devices
26
25
  agentdeck qr # pairing QR for the iOS/Android companion apps
27
26
  agentdeck --help # full command reference
28
27
  ```
29
28
 
30
- The daemon is the hub every dashboard client talks to; session bridges wrap your agent CLI in a PTY, report state via lifecycle hooks, and let paired devices steer the session (answer prompts, approve tools, switch modes).
29
+ The daemon is the hub every dashboard client talks to. Normal agent commands
30
+ report through lifecycle hooks or native event channels and can be steered where
31
+ the observed session exposes a real delivery path.
32
+
33
+ The legacy `agentdeck claude|codex|opencode|monitor` per-session bridges remain
34
+ functional compatibility paths with no removal date. Prefer daemon-first for
35
+ ordinary local sessions, but keep managed-only workflows working while
36
+ [Discussion #278](https://github.com/puritysb/AgentDeck/discussions/278) and
37
+ [#273](https://github.com/puritysb/AgentDeck/issues/273) define and validate
38
+ replacements.
31
39
 
32
40
  Full CLI reference: https://github.com/puritysb/AgentDeck/blob/master/docs/cli.md
33
41
 
@@ -0,0 +1,10 @@
1
+ # PocketSansWorld font pack notice
2
+
3
+ PocketSansWorld is an SD-paged binary font bundle generated for Pocket Daily.
4
+ It combines glyphs from Noto Sans KR, Noto Sans JP, Noto Sans SC, Noto Sans
5
+ Hebrew, and Noto Sans. The original fonts and this redistributed derivative
6
+ are licensed under the SIL Open Font License 1.1. See
7
+ `OFL-PocketSansWorld.txt`.
8
+
9
+ The provider validates the immutable pack size, MD5, SHA-256, cpfont format,
10
+ source ledger, and licence before advertising it.
@@ -0,0 +1,93 @@
1
+ Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ https://scripts.sil.org/OFL
6
+
7
+
8
+ -----------------------------------------------------------
9
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10
+ -----------------------------------------------------------
11
+
12
+ PREAMBLE
13
+ The goals of the Open Font License (OFL) are to stimulate worldwide
14
+ development of collaborative font projects, to support the font creation
15
+ efforts of academic and linguistic communities, and to provide a free and
16
+ open framework in which fonts may be shared and improved in partnership
17
+ with others.
18
+
19
+ The OFL allows the licensed fonts to be used, studied, modified and
20
+ redistributed freely as long as they are not sold by themselves. The
21
+ fonts, including any derivative works, can be bundled, embedded,
22
+ redistributed and/or sold with any software provided that any reserved
23
+ names are not used by derivative works. The fonts and derivatives,
24
+ however, cannot be released under any other type of license. The
25
+ requirement for fonts to remain under this license does not apply
26
+ to any document created using the fonts or their derivatives.
27
+
28
+ DEFINITIONS
29
+ "Font Software" refers to the set of files released by the Copyright
30
+ Holder(s) under this license and clearly marked as such. This may
31
+ include source files, build scripts and documentation.
32
+
33
+ "Reserved Font Name" refers to any names specified as such after the
34
+ copyright statement(s).
35
+
36
+ "Original Version" refers to the collection of Font Software components as
37
+ distributed by the Copyright Holder(s).
38
+
39
+ "Modified Version" refers to any derivative made by adding to, deleting,
40
+ or substituting -- in part or in whole -- any of the components of the
41
+ Original Version, by changing formats or by porting the Font Software to a
42
+ new environment.
43
+
44
+ "Author" refers to any designer, engineer, programmer, technical
45
+ writer or other person who contributed to the Font Software.
46
+
47
+ PERMISSION & CONDITIONS
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
50
+ redistribute, and sell modified and unmodified copies of the Font
51
+ Software, subject to the following conditions:
52
+
53
+ 1) Neither the Font Software nor any of its individual components,
54
+ in Original or Modified Versions, may be sold by itself.
55
+
56
+ 2) Original or Modified Versions of the Font Software may be bundled,
57
+ redistributed and/or sold with any software, provided that each copy
58
+ contains the above copyright notice and this license. These can be
59
+ included either as stand-alone text files, human-readable headers or
60
+ in the appropriate machine-readable metadata fields within text or
61
+ binary files as long as those fields can be easily viewed by the user.
62
+
63
+ 3) No Modified Version of the Font Software may use the Reserved Font
64
+ Name(s) unless explicit written permission is granted by the corresponding
65
+ Copyright Holder. This restriction only applies to the primary font name as
66
+ presented to the users.
67
+
68
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69
+ Software shall not be used to promote, endorse or advertise any
70
+ Modified Version, except to acknowledge the contribution(s) of the
71
+ Copyright Holder(s) and the Author(s) or with their explicit written
72
+ permission.
73
+
74
+ 5) The Font Software, modified or unmodified, in part or in whole,
75
+ must be distributed entirely under this license, and must not be
76
+ distributed under any other license. The requirement for fonts to
77
+ remain under this license does not apply to any document created
78
+ using the Font Software.
79
+
80
+ TERMINATION
81
+ This license becomes null and void if any of the above conditions are
82
+ not met.
83
+
84
+ DISCLAIMER
85
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,49 @@
1
+ {
2
+ "fontPack": {
3
+ "id": "pocket-sans-world",
4
+ "version": 1,
5
+ "format": 4,
6
+ "size": 10903872,
7
+ "md5": "a6844503c142be1a62e4bac8be7c7802",
8
+ "sha256": "a1a15a6e9cdccd114cbaf34adb29fce08ad67d3dcd52b7970a77ab89db9ee753",
9
+ "licenseSpdx": "OFL-1.1"
10
+ },
11
+ "attribution": "PocketSansWorld is built from Noto Sans KR, JP, SC, Hebrew, and Noto Sans under the SIL Open Font License 1.1.",
12
+ "sources": [
13
+ {
14
+ "name": "Noto Sans KR",
15
+ "url": "https://github.com/google/fonts/tree/ec626514f79f831f1ab848a82114a0ce7e2d6372/ofl/notosanskr",
16
+ "revision": "ec626514f79f831f1ab848a82114a0ce7e2d6372",
17
+ "licenseSpdx": "OFL-1.1",
18
+ "attribution": "Noto Sans KR contributors"
19
+ },
20
+ {
21
+ "name": "Noto Sans SC",
22
+ "url": "https://github.com/google/fonts/tree/ec626514f79f831f1ab848a82114a0ce7e2d6372/ofl/notosanssc",
23
+ "revision": "ec626514f79f831f1ab848a82114a0ce7e2d6372",
24
+ "licenseSpdx": "OFL-1.1",
25
+ "attribution": "Noto Sans SC contributors"
26
+ },
27
+ {
28
+ "name": "Noto Sans JP",
29
+ "url": "https://github.com/google/fonts/tree/295d98a7a0c17c68f1341eaeea354e7960ea70d3/ofl/notosansjp",
30
+ "revision": "295d98a7a0c17c68f1341eaeea354e7960ea70d3",
31
+ "licenseSpdx": "OFL-1.1",
32
+ "attribution": "Noto Sans JP contributors"
33
+ },
34
+ {
35
+ "name": "Noto Sans",
36
+ "url": "https://github.com/notofonts/latin-greek-cyrillic",
37
+ "revision": "crosspoint-bundled-source",
38
+ "licenseSpdx": "OFL-1.1",
39
+ "attribution": "Noto Sans contributors"
40
+ },
41
+ {
42
+ "name": "Noto Sans Hebrew",
43
+ "url": "https://github.com/crosspoint-reader/crosspoint-reader/tree/94c0ba466cbb225a07f653d1c27f2a7261f1fb08/lib/EpdFont/builtinFonts/source/NotoSansHebrew",
44
+ "revision": "94c0ba466cbb225a07f653d1c27f2a7261f1fb08",
45
+ "licenseSpdx": "OFL-1.1",
46
+ "attribution": "The Noto Project Authors"
47
+ }
48
+ ]
49
+ }
@@ -0,0 +1,10 @@
1
+ Pocket Daily Japanese learning content
2
+ Copyright (c) 2026 Pocket Daily contributors
3
+
4
+ This learning content is licensed under the Creative Commons
5
+ Attribution-ShareAlike 4.0 International License.
6
+
7
+ License text and terms:
8
+ https://creativecommons.org/licenses/by-sa/4.0/legalcode
9
+
10
+ Attribution: Original Korean study content by Pocket Daily contributors.
@@ -0,0 +1,33 @@
1
+ # Pocket Daily learning data — source and modification notice
2
+
3
+ The `jp-n3-ko` dataset is an adapted subset of **OpenJLPT**, pinned at commit
4
+ `c42fd9fa3777bfc1775446f7c418d549dfd6e4cf`. OpenJLPT distributes its dataset
5
+ under **CC BY-SA 4.0** and records the following upstream sources:
6
+
7
+ - **JMdict / EDICT and KANJIDIC2**, Electronic Dictionary Research and
8
+ Development Group (EDRDG): vocabulary and kanji readings and English
9
+ glosses; CC BY-SA 4.0. <https://www.edrdg.org/>
10
+ - **Jonathan Waller's JLPT Resources**: unofficial N5–N1 level assignments;
11
+ CC BY according to the pinned OpenJLPT notice.
12
+ <https://www.tanos.co.uk/jlpt/>
13
+ - **Tatoeba**: Japanese example sentences; CC BY 2.0 FR.
14
+ <https://tatoeba.org/>
15
+
16
+ OpenJLPT and its full notice are available at
17
+ <https://github.com/evanclan/OpenJLPT/tree/c42fd9fa3777bfc1775446f7c418d549dfd6e4cf>.
18
+
19
+ Pocket Daily modifications are distributed under **CC BY-SA 4.0**:
20
+
21
+ - retained the cumulative N5, N4, and N3 kanji subset (612 unique characters);
22
+ - selected one compact representative word and Japanese example per character;
23
+ - added Korean kanji glosses, word meanings, and example translations;
24
+ - normalized the data into the fixed-record PDLP format for bounded SD reads.
25
+
26
+ The Korean adaptations are by Pocket Daily contributors. Automated assistance
27
+ was used to draft translations; field alignment, required Korean text, record
28
+ counts, byte bounds, source pinning, and package checksums are validated before
29
+ distribution. Corrections remain welcome and must be shared under CC BY-SA 4.0.
30
+
31
+ The JLPT organization does not publish an official current vocabulary or kanji
32
+ list. The level labels are therefore **unofficial N3-oriented study curation**,
33
+ not a claim about the undisclosed contents of a particular examination.
@@ -0,0 +1,27 @@
1
+ {
2
+ "learningPack": {
3
+ "id": "jp-n3-ko",
4
+ "version": 3,
5
+ "format": 1,
6
+ "size": 568324,
7
+ "md5": "34681b78b5a1d65bc787dc57e863cba7",
8
+ "licenseSpdx": "CC-BY-SA-4.0"
9
+ },
10
+ "attribution": "OpenJLPT/EDRDG/Waller/Tatoeba 기반; Pocket Daily 한국어 각색; CC BY-SA 4.0",
11
+ "sources": [
12
+ {
13
+ "name": "OpenJLPT cumulative N5-N3 dataset",
14
+ "url": "https://github.com/evanclan/OpenJLPT",
15
+ "revision": "c42fd9fa3777bfc1775446f7c418d549dfd6e4cf",
16
+ "licenseSpdx": "CC-BY-SA-4.0",
17
+ "attribution": "OpenJLPT; upstream EDRDG KANJIDIC2/JMdict, Jonathan Waller JLPT resources, and Tatoeba"
18
+ },
19
+ {
20
+ "name": "Pocket Daily Korean adaptations",
21
+ "url": "https://github.com/puritysb/pocket-daily-reader",
22
+ "revision": "pocket-ko-2026-08-29",
23
+ "licenseSpdx": "CC-BY-SA-4.0",
24
+ "attribution": "Korean meanings and translations by Pocket Daily contributors"
25
+ }
26
+ ]
27
+ }
Binary file
@@ -0,0 +1,20 @@
1
+ export type DiagnosedAgent = 'claude' | 'codex' | 'opencode';
2
+ export interface AgentCliDiagnosticEntry {
3
+ id: DiagnosedAgent;
4
+ label: string;
5
+ installed: boolean;
6
+ version: string | null;
7
+ compatibleRange: string | null;
8
+ compatible: boolean | null;
9
+ installHint?: string;
10
+ }
11
+ export interface AgentCliDiagnosticReport {
12
+ kind: 'agent-cli-compatibility';
13
+ migration: string;
14
+ trackingIssue: string;
15
+ agents: AgentCliDiagnosticEntry[];
16
+ }
17
+ export type VersionCommandRunner = (command: string) => string;
18
+ export declare function collectAgentCliDiagnosticReport(run?: VersionCommandRunner): AgentCliDiagnosticReport;
19
+ export declare function formatAgentCliDiagnosticReport(report: AgentCliDiagnosticReport): string;
20
+ //# sourceMappingURL=agent-cli-diagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-cli-diagnostics.d.ts","sourceRoot":"","sources":["../src/agent-cli-diagnostics.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;AAiC7D,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,cAAc,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,UAAU,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,yBAAyB,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,uBAAuB,EAAE,CAAC;CACnC;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;AAW/D,wBAAgB,+BAA+B,CAC7C,GAAG,GAAE,oBAAwC,GAC5C,wBAAwB,CAiC1B;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,wBAAwB,GAAG,MAAM,CAyBvF"}
@@ -0,0 +1,100 @@
1
+ import { execSync } from 'child_process';
2
+ import { createRequire } from 'module';
3
+ import { satisfiesRange } from './version-check.js';
4
+ const require = createRequire(import.meta.url);
5
+ const packageJson = require('../package.json');
6
+ const AGENTS = [
7
+ {
8
+ id: 'claude',
9
+ label: 'Claude Code',
10
+ versionCommand: 'claude --version',
11
+ compatibleRange: packageJson.compatibleClaudeCode,
12
+ installHint: 'npm install -g @anthropic-ai/claude-code',
13
+ },
14
+ {
15
+ id: 'codex',
16
+ label: 'Codex CLI',
17
+ versionCommand: 'codex --version',
18
+ compatibleRange: packageJson.compatibleCodex,
19
+ installHint: 'npm install -g @openai/codex',
20
+ },
21
+ {
22
+ id: 'opencode',
23
+ label: 'OpenCode',
24
+ versionCommand: 'opencode --version',
25
+ installHint: 'brew install sst/tap/opencode (or: npm i -g opencode-ai)',
26
+ },
27
+ ];
28
+ function runVersionCommand(command) {
29
+ // Use the caller's PATH. A non-interactive login shell may skip interactive
30
+ // startup files and reorder PATH, causing diagnostics to inspect a stale
31
+ // installation instead of the executable `agentdeck` was launched beside.
32
+ return execSync(command, {
33
+ encoding: 'utf8', timeout: 5000, windowsHide: true,
34
+ }).trim();
35
+ }
36
+ export function collectAgentCliDiagnosticReport(run = runVersionCommand) {
37
+ return {
38
+ kind: 'agent-cli-compatibility',
39
+ migration: 'Run `agentdeck daemon install`, then start the agent normally.',
40
+ trackingIssue: 'https://github.com/puritysb/AgentDeck/issues/273',
41
+ agents: AGENTS.map((agent) => {
42
+ const compatibleRange = agent.compatibleRange?.trim() || null;
43
+ try {
44
+ const output = run(agent.versionCommand);
45
+ const version = output.match(/\b(\d+\.\d+\.\d+)\b/)?.[1] ?? null;
46
+ return {
47
+ id: agent.id,
48
+ label: agent.label,
49
+ installed: true,
50
+ version,
51
+ compatibleRange,
52
+ compatible: version && compatibleRange
53
+ ? satisfiesRange(version, compatibleRange)
54
+ : null,
55
+ };
56
+ }
57
+ catch {
58
+ return {
59
+ id: agent.id,
60
+ label: agent.label,
61
+ installed: false,
62
+ version: null,
63
+ compatibleRange,
64
+ compatible: null,
65
+ installHint: agent.installHint,
66
+ };
67
+ }
68
+ }),
69
+ };
70
+ }
71
+ export function formatAgentCliDiagnosticReport(report) {
72
+ const lines = [
73
+ 'Agent CLI compatibility (daemon-first)',
74
+ '',
75
+ report.migration,
76
+ '',
77
+ ];
78
+ for (const agent of report.agents) {
79
+ if (!agent.installed) {
80
+ lines.push(`- ${agent.label}: not found — install: ${agent.installHint}`);
81
+ continue;
82
+ }
83
+ const version = agent.version ?? 'version unknown';
84
+ if (!agent.compatibleRange) {
85
+ lines.push(`- ${agent.label}: ${version} — installed (no pinned compatibility range)`);
86
+ }
87
+ else if (agent.compatible === true) {
88
+ lines.push(`- ${agent.label}: ${version} — compatible (${agent.compatibleRange})`);
89
+ }
90
+ else if (agent.compatible === false) {
91
+ lines.push(`- ${agent.label}: ${version} — OUTSIDE supported range ${agent.compatibleRange}`);
92
+ }
93
+ else {
94
+ lines.push(`- ${agent.label}: ${version} — could not evaluate ${agent.compatibleRange}`);
95
+ }
96
+ }
97
+ lines.push('', `Managed-session compatibility: ${report.trackingIssue}`);
98
+ return lines.join('\n');
99
+ }
100
+ //# sourceMappingURL=agent-cli-diagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-cli-diagnostics.js","sourceRoot":"","sources":["../src/agent-cli-diagnostics.ts"],"names":[],"mappings":"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"}
@@ -69,6 +69,10 @@ export type OnTaskOpened = (args: {
69
69
  projectName: string | null;
70
70
  taskIndex: number;
71
71
  startedAt: number;
72
+ /** Display title derived from the task's first user prompt
73
+ * (`deriveTaskTitle` SSOT), or null when the prompt yields nothing
74
+ * meaningful — consumers keep their `Task N` fallback on null. */
75
+ title: string | null;
72
76
  }) => void;
73
77
  /** Callback fired when the agent declares its todos done mid-task (the
74
78
  * TodoWrite-all-completed soft hint). Non-segmenting — the task stays open —
@@ -92,6 +96,8 @@ export declare class ApmeCollector {
92
96
  * client abort, or never having run at all. Injectable for tests; the
93
97
  * default reads the Claude transcript tail once for all three. */
94
98
  private readonly openTurnProbe;
99
+ /** Injectable for tests only — production call sites take the default. */
100
+ private readonly idleGapMs;
95
101
  private readonly sessionToRun;
96
102
  private readonly sessionToAgentType;
97
103
  private readonly sessionToTurn;
@@ -121,11 +127,17 @@ export declare class ApmeCollector {
121
127
  /** Last milestone key (`taskId:turnIndex`) per session — a turn can carry
122
128
  * several all-completed TodoWrite calls; surface only the first. */
123
129
  private readonly sessionToLastMilestone;
130
+ /** Per-session idle-gap timers — armed in `closeTurn`, cleared on the next
131
+ * turn open / task close. See `AGENT_IDLE_GAP_MS` for the measurement the
132
+ * constant rests on. */
133
+ private readonly sessionToIdleGapTimer;
124
134
  constructor(store: ApmeStore, hwSampler?: ApmeHwSampler | undefined,
125
135
  /** What the transcript proves about a turn open since a timestamp — cancel,
126
136
  * client abort, or never having run at all. Injectable for tests; the
127
137
  * default reads the Claude transcript tail once for all three. */
128
- openTurnProbe?: (transcriptPath: string, sinceMs: number) => OpenTurnEvidence | null);
138
+ openTurnProbe?: (transcriptPath: string, sinceMs: number) => OpenTurnEvidence | null,
139
+ /** Injectable for tests only — production call sites take the default. */
140
+ idleGapMs?: number);
129
141
  /** Start a new run and return its id. Safe to call if store disabled (returns ''). */
130
142
  openRun(input: OpenRunInput): string;
131
143
  /** Record a hook event as a step + manage turn lifecycle.
@@ -223,6 +235,11 @@ export declare class ApmeCollector {
223
235
  * when a task proves itself "real" (second turn, or TodoWrite plan).
224
236
  * Mirrors ApmeCollector.swift `emitDeferredTaskStartIfNeeded`. */
225
237
  private emitDeferredTaskStartIfNeeded;
238
+ /** Arm the per-session idle-gap timer. Called from `closeTurn` — the turn
239
+ * just finished, so the gap being measured is genuine idle time, never the
240
+ * agent's own working time. Re-arming replaces any previous timer. */
241
+ private armIdleGapTimer;
242
+ private clearIdleGapTimer;
226
243
  /** Public wrapper for closeTask. Used by the manual-boundary CLI /
227
244
  * HTTP route + the macOS detail-pane button — lets the user declare
228
245
  * "this task is done" without `/clear` (which would also split the
@@ -1 +1 @@
1
- {"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../src/apme/collector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../src/apme/collector.ts"],"names":[],"mappings":"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"}
@@ -18,7 +18,7 @@ import { mkdirSync, writeFileSync } from 'fs';
18
18
  import { homedir } from 'os';
19
19
  import { debug } from '../logger.js';
20
20
  import { resolveProjectName } from '../utils/project-name.js';
21
- import { isPricedModel, normalizeModelProvider, priceUsd } from '@agentdeck/shared';
21
+ import { AGENT_IDLE_GAP_MS, deriveTaskTitle, isPricedModel, normalizeModelProvider, priceUsd } from '@agentdeck/shared';
22
22
  import { classifyRunSmart, computeSignals, classify } from './classifier.js';
23
23
  import { readOpenTurnEvidence } from './claude-transcript-reader.js';
24
24
  /** A turn_start with the same prompt landing on a fresh, still-empty turn
@@ -67,6 +67,7 @@ export class ApmeCollector {
67
67
  store;
68
68
  hwSampler;
69
69
  openTurnProbe;
70
+ idleGapMs;
70
71
  sessionToRun = new Map(); // sessionId → runId
71
72
  sessionToAgentType = new Map(); // sessionId → agentType (survives closeRun for late-attributed timeline rows)
72
73
  sessionToTurn = new Map(); // sessionId → current turn
@@ -96,14 +97,21 @@ export class ApmeCollector {
96
97
  /** Last milestone key (`taskId:turnIndex`) per session — a turn can carry
97
98
  * several all-completed TodoWrite calls; surface only the first. */
98
99
  sessionToLastMilestone = new Map();
100
+ /** Per-session idle-gap timers — armed in `closeTurn`, cleared on the next
101
+ * turn open / task close. See `AGENT_IDLE_GAP_MS` for the measurement the
102
+ * constant rests on. */
103
+ sessionToIdleGapTimer = new Map();
99
104
  constructor(store, hwSampler,
100
105
  /** What the transcript proves about a turn open since a timestamp — cancel,
101
106
  * client abort, or never having run at all. Injectable for tests; the
102
107
  * default reads the Claude transcript tail once for all three. */
103
- openTurnProbe = readOpenTurnEvidence) {
108
+ openTurnProbe = readOpenTurnEvidence,
109
+ /** Injectable for tests only — production call sites take the default. */
110
+ idleGapMs = AGENT_IDLE_GAP_MS) {
104
111
  this.store = store;
105
112
  this.hwSampler = hwSampler;
106
113
  this.openTurnProbe = openTurnProbe;
114
+ this.idleGapMs = idleGapMs;
107
115
  }
108
116
  /** Start a new run and return its id. Safe to call if store disabled (returns ''). */
109
117
  openRun(input) {
@@ -204,14 +212,18 @@ export class ApmeCollector {
204
212
  prompt, hasResponse: false,
205
213
  };
206
214
  this.sessionToTurn.set(sessionId, turn);
215
+ // A new turn is the "still working" signal the idle-gap timer waits on.
216
+ this.clearIdleGapTimer(sessionId);
207
217
  // Ensure an active task exists so this turn can attach to it. Tasks group
208
218
  // consecutive turns between boundary signals (TodoWrite all-completed,
209
219
  // /clear, session_end). First turn in a run opens task 0.
210
220
  const task = this.openTaskIfNone(sessionId, runId);
211
221
  if (task) {
212
222
  const wasFirstTurn = task.firstTurnIndex === null;
213
- if (wasFirstTurn)
223
+ if (wasFirstTurn) {
214
224
  task.firstTurnIndex = turnIndex;
225
+ task.firstPrompt = prompt ?? null;
226
+ }
215
227
  task.lastTurnIndex = turnIndex;
216
228
  // Second (or later) turn on the same task proves it's a real,
217
229
  // multi-turn work unit → promote the deferred TASK header so the
@@ -455,6 +467,9 @@ export class ApmeCollector {
455
467
  catch (err) {
456
468
  debug('APME', `closeTurn failed: ${String(err)}`);
457
469
  }
470
+ // Idle starts when the turn ends. The timer is cleared by the next turn
471
+ // open (still working) or by closeTask (boundary reached another way).
472
+ this.armIdleGapTimer(sessionId);
458
473
  }
459
474
  /** Get the current active turn ID for a session (if any). */
460
475
  getActiveTurnId(sessionId) {
@@ -519,6 +534,7 @@ export class ApmeCollector {
519
534
  startedAt: Date.now(),
520
535
  firstTurnIndex: null,
521
536
  lastTurnIndex: null,
537
+ firstPrompt: null,
522
538
  timelineEmitted: false,
523
539
  };
524
540
  this.sessionToTask.set(sessionId, task);
@@ -559,12 +575,40 @@ export class ApmeCollector {
559
575
  projectName: run?.projectName ?? null,
560
576
  taskIndex: task.index,
561
577
  startedAt: task.startedAt,
578
+ title: deriveTaskTitle(task.firstPrompt),
562
579
  });
563
580
  }
564
581
  catch (err) {
565
582
  debug('APME', `onTaskOpened listener threw: ${String(err)}`);
566
583
  }
567
584
  }
585
+ /** Arm the per-session idle-gap timer. Called from `closeTurn` — the turn
586
+ * just finished, so the gap being measured is genuine idle time, never the
587
+ * agent's own working time. Re-arming replaces any previous timer. */
588
+ armIdleGapTimer(sessionId) {
589
+ this.clearIdleGapTimer(sessionId);
590
+ const timer = setTimeout(() => {
591
+ this.sessionToIdleGapTimer.delete(sessionId);
592
+ // A turn opened since (and its clear lost a race), or work is mid-turn:
593
+ // never split under an active turn.
594
+ if (this.sessionToTurn.has(sessionId))
595
+ return;
596
+ if (!this.sessionToTask.has(sessionId))
597
+ return;
598
+ debug('APME', `idle gap (${Math.round(this.idleGapMs / 1000)}s) → closing task for ${sessionId.slice(0, 8)}`);
599
+ this.closeTask(sessionId, 'idle_gap');
600
+ }, this.idleGapMs);
601
+ // Never hold the process open for an idle bookkeeping timer.
602
+ timer.unref?.();
603
+ this.sessionToIdleGapTimer.set(sessionId, timer);
604
+ }
605
+ clearIdleGapTimer(sessionId) {
606
+ const timer = this.sessionToIdleGapTimer.get(sessionId);
607
+ if (timer) {
608
+ clearTimeout(timer);
609
+ this.sessionToIdleGapTimer.delete(sessionId);
610
+ }
611
+ }
568
612
  /** Public wrapper for closeTask. Used by the manual-boundary CLI /
569
613
  * HTTP route + the macOS detail-pane button — lets the user declare
570
614
  * "this task is done" without `/clear` (which would also split the
@@ -597,6 +641,7 @@ export class ApmeCollector {
597
641
  return;
598
642
  this.sessionToTask.delete(sessionId);
599
643
  this.sessionToLastMilestone.delete(sessionId);
644
+ this.clearIdleGapTimer(sessionId);
600
645
  // Empty task: no turns ever attached. Drop the row so the dashboard
601
646
  // doesn't show phantom entries from back-to-back boundary signals.
602
647
  if (task.firstTurnIndex === null) {