@hwip/cli 0.0.1 → 0.1.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 (245) hide show
  1. package/LICENSE +190 -0
  2. package/NOTICE +11 -0
  3. package/README.md +1979 -0
  4. package/dist/agent-list.d.ts +76 -0
  5. package/dist/agent-list.js +102 -0
  6. package/dist/agent-read.d.ts +105 -0
  7. package/dist/agent-read.js +309 -0
  8. package/dist/agent-rules-fetch.d.ts +51 -0
  9. package/dist/agent-rules-fetch.js +275 -0
  10. package/dist/agent-rules.default.d.ts +30 -0
  11. package/dist/agent-rules.default.js +292 -0
  12. package/dist/agent-session.d.ts +23 -0
  13. package/dist/agent-session.js +44 -0
  14. package/dist/agent-state.d.ts +84 -0
  15. package/dist/agent-state.js +188 -0
  16. package/dist/agent-target.d.ts +60 -0
  17. package/dist/agent-target.js +81 -0
  18. package/dist/agents.d.ts +31 -0
  19. package/dist/agents.js +75 -0
  20. package/dist/api.d.ts +28 -0
  21. package/dist/api.js +76 -0
  22. package/dist/args.d.ts +74 -0
  23. package/dist/args.js +254 -0
  24. package/dist/ask-context-attach.d.ts +73 -0
  25. package/dist/ask-context-attach.js +151 -0
  26. package/dist/ask-context-screen.d.ts +21 -0
  27. package/dist/ask-context-screen.js +49 -0
  28. package/dist/ask-context-switch.d.ts +31 -0
  29. package/dist/ask-context-switch.js +74 -0
  30. package/dist/ask-context.d.ts +84 -0
  31. package/dist/ask-context.js +172 -0
  32. package/dist/ask-pending.d.ts +47 -0
  33. package/dist/ask-pending.js +221 -0
  34. package/dist/ask-seal.d.ts +120 -0
  35. package/dist/ask-seal.js +179 -0
  36. package/dist/ask.d.ts +107 -0
  37. package/dist/ask.js +551 -0
  38. package/dist/blocked-prompt-seal.d.ts +35 -0
  39. package/dist/blocked-prompt-seal.js +89 -0
  40. package/dist/blocked-prompt.d.ts +57 -0
  41. package/dist/blocked-prompt.js +181 -0
  42. package/dist/channel.d.ts +67 -0
  43. package/dist/channel.js +136 -0
  44. package/dist/check-update.d.ts +28 -0
  45. package/dist/check-update.js +153 -0
  46. package/dist/cli.d.ts +3 -0
  47. package/dist/cli.js +813 -0
  48. package/dist/codex-config.d.ts +24 -0
  49. package/dist/codex-config.js +169 -0
  50. package/dist/codex-transcript.d.ts +59 -0
  51. package/dist/codex-transcript.js +373 -0
  52. package/dist/command-refusal.d.ts +56 -0
  53. package/dist/command-refusal.js +127 -0
  54. package/dist/command-scan.d.ts +46 -0
  55. package/dist/command-scan.js +154 -0
  56. package/dist/command-seal.d.ts +57 -0
  57. package/dist/command-seal.js +88 -0
  58. package/dist/command-seq.d.ts +30 -0
  59. package/dist/command-seq.js +150 -0
  60. package/dist/config.d.ts +156 -0
  61. package/dist/config.js +392 -0
  62. package/dist/core-sections.d.ts +18 -0
  63. package/dist/core-sections.js +28 -0
  64. package/dist/crypto.d.ts +278 -0
  65. package/dist/crypto.js +698 -0
  66. package/dist/desktop-notify.d.ts +33 -0
  67. package/dist/desktop-notify.js +49 -0
  68. package/dist/device-directory.d.ts +36 -0
  69. package/dist/device-directory.js +97 -0
  70. package/dist/device-presence.d.ts +17 -0
  71. package/dist/device-presence.js +62 -0
  72. package/dist/downloads.d.ts +29 -0
  73. package/dist/downloads.js +106 -0
  74. package/dist/errors.d.ts +12 -0
  75. package/dist/errors.js +28 -0
  76. package/dist/file-crypto.d.ts +94 -0
  77. package/dist/file-crypto.js +272 -0
  78. package/dist/file-view-budget.d.ts +15 -0
  79. package/dist/file-view-budget.js +34 -0
  80. package/dist/file-view-switch.d.ts +28 -0
  81. package/dist/file-view-switch.js +122 -0
  82. package/dist/file-view.d.ts +108 -0
  83. package/dist/file-view.js +327 -0
  84. package/dist/gate.d.ts +141 -0
  85. package/dist/gate.js +336 -0
  86. package/dist/gemini-transcript.d.ts +32 -0
  87. package/dist/gemini-transcript.js +189 -0
  88. package/dist/http-failure.d.ts +98 -0
  89. package/dist/http-failure.js +349 -0
  90. package/dist/hwip-core.generated.d.ts +7 -0
  91. package/dist/hwip-core.generated.js +14 -0
  92. package/dist/hwip-hook.d.ts +77 -0
  93. package/dist/hwip-hook.js +340 -0
  94. package/dist/index.d.ts +7 -0
  95. package/dist/index.js +14 -0
  96. package/dist/input-sequencer.d.ts +65 -0
  97. package/dist/input-sequencer.js +142 -0
  98. package/dist/insecure-url.d.ts +16 -0
  99. package/dist/insecure-url.js +76 -0
  100. package/dist/installer.d.ts +96 -0
  101. package/dist/installer.js +850 -0
  102. package/dist/inventory-offload.d.ts +49 -0
  103. package/dist/inventory-offload.js +209 -0
  104. package/dist/inventory-worker.d.ts +2 -0
  105. package/dist/inventory-worker.js +27 -0
  106. package/dist/jsonc-doc.d.ts +106 -0
  107. package/dist/jsonc-doc.js +354 -0
  108. package/dist/keep-awake.d.ts +32 -0
  109. package/dist/keep-awake.js +46 -0
  110. package/dist/key-changes.d.ts +48 -0
  111. package/dist/key-changes.js +140 -0
  112. package/dist/lan-auth.d.ts +140 -0
  113. package/dist/lan-auth.js +217 -0
  114. package/dist/lan-endpoint.d.ts +41 -0
  115. package/dist/lan-endpoint.js +115 -0
  116. package/dist/lan-receiver.d.ts +122 -0
  117. package/dist/lan-receiver.js +510 -0
  118. package/dist/lan-sender.d.ts +76 -0
  119. package/dist/lan-sender.js +184 -0
  120. package/dist/lan-transfer.d.ts +36 -0
  121. package/dist/lan-transfer.js +54 -0
  122. package/dist/listener-device-id.d.ts +20 -0
  123. package/dist/listener-device-id.js +133 -0
  124. package/dist/listener-log.d.ts +4 -0
  125. package/dist/listener-log.js +23 -0
  126. package/dist/listener-process.d.ts +200 -0
  127. package/dist/listener-process.js +470 -0
  128. package/dist/listener-service.d.ts +225 -0
  129. package/dist/listener-service.js +682 -0
  130. package/dist/listener-worktree-cleanup.d.ts +27 -0
  131. package/dist/listener-worktree-cleanup.js +62 -0
  132. package/dist/listener.d.ts +1325 -0
  133. package/dist/listener.js +5680 -0
  134. package/dist/login-address.d.ts +25 -0
  135. package/dist/login-address.js +97 -0
  136. package/dist/login-page.d.ts +29 -0
  137. package/dist/login-page.js +93 -0
  138. package/dist/login.d.ts +98 -0
  139. package/dist/login.js +388 -0
  140. package/dist/mcp-command.d.ts +45 -0
  141. package/dist/mcp-command.js +50 -0
  142. package/dist/mcp.d.ts +19 -0
  143. package/dist/mcp.js +29 -0
  144. package/dist/node-support.d.ts +19 -0
  145. package/dist/node-support.js +38 -0
  146. package/dist/notify-failure.d.ts +57 -0
  147. package/dist/notify-failure.js +150 -0
  148. package/dist/opencode-transcript.d.ts +139 -0
  149. package/dist/opencode-transcript.js +390 -0
  150. package/dist/optional-features.d.ts +6 -0
  151. package/dist/optional-features.js +19 -0
  152. package/dist/pane-fit.d.ts +40 -0
  153. package/dist/pane-fit.js +119 -0
  154. package/dist/peer-key.d.ts +33 -0
  155. package/dist/peer-key.js +34 -0
  156. package/dist/pi-transcript.d.ts +26 -0
  157. package/dist/pi-transcript.js +255 -0
  158. package/dist/presence.d.ts +14 -0
  159. package/dist/presence.js +124 -0
  160. package/dist/private-files.d.ts +51 -0
  161. package/dist/private-files.js +218 -0
  162. package/dist/project-switch.d.ts +19 -0
  163. package/dist/project-switch.js +60 -0
  164. package/dist/redact.d.ts +10 -0
  165. package/dist/redact.js +21 -0
  166. package/dist/remote-agents.d.ts +410 -0
  167. package/dist/remote-agents.js +1218 -0
  168. package/dist/remote-hook.d.ts +12 -0
  169. package/dist/remote-hook.js +196 -0
  170. package/dist/replace-file.d.ts +50 -0
  171. package/dist/replace-file.js +328 -0
  172. package/dist/schedule-command.d.ts +35 -0
  173. package/dist/schedule-command.js +260 -0
  174. package/dist/schedule-launch.d.ts +15 -0
  175. package/dist/schedule-launch.js +24 -0
  176. package/dist/schedule-ready.d.ts +44 -0
  177. package/dist/schedule-ready.js +71 -0
  178. package/dist/schedule-remote.d.ts +77 -0
  179. package/dist/schedule-remote.js +167 -0
  180. package/dist/schedule-runner.d.ts +89 -0
  181. package/dist/schedule-runner.js +452 -0
  182. package/dist/schedule.d.ts +149 -0
  183. package/dist/schedule.js +428 -0
  184. package/dist/secret-mask.d.ts +29 -0
  185. package/dist/secret-mask.js +245 -0
  186. package/dist/self-register.d.ts +45 -0
  187. package/dist/self-register.js +67 -0
  188. package/dist/send.d.ts +56 -0
  189. package/dist/send.js +104 -0
  190. package/dist/session-diff.d.ts +161 -0
  191. package/dist/session-diff.js +445 -0
  192. package/dist/session-registry.d.ts +143 -0
  193. package/dist/session-registry.js +216 -0
  194. package/dist/sessions-report.d.ts +59 -0
  195. package/dist/sessions-report.js +99 -0
  196. package/dist/shell-audit.d.ts +34 -0
  197. package/dist/shell-audit.js +47 -0
  198. package/dist/subagent-transcripts.d.ts +167 -0
  199. package/dist/subagent-transcripts.js +437 -0
  200. package/dist/subscriber-trust.d.ts +128 -0
  201. package/dist/subscriber-trust.js +397 -0
  202. package/dist/templates.d.ts +105 -0
  203. package/dist/templates.js +871 -0
  204. package/dist/tmux-install.d.ts +44 -0
  205. package/dist/tmux-install.js +65 -0
  206. package/dist/tmux-liveness.d.ts +45 -0
  207. package/dist/tmux-liveness.js +71 -0
  208. package/dist/tmux-pane.d.ts +55 -0
  209. package/dist/tmux-pane.js +126 -0
  210. package/dist/tmux-socket.d.ts +20 -0
  211. package/dist/tmux-socket.js +292 -0
  212. package/dist/todo-fold.d.ts +31 -0
  213. package/dist/todo-fold.js +102 -0
  214. package/dist/transcript-tail.d.ts +312 -0
  215. package/dist/transcript-tail.js +718 -0
  216. package/dist/trust-command.d.ts +49 -0
  217. package/dist/trust-command.js +200 -0
  218. package/dist/trust-lock.d.ts +26 -0
  219. package/dist/trust-lock.js +94 -0
  220. package/dist/trust-pins.d.ts +37 -0
  221. package/dist/trust-pins.js +82 -0
  222. package/dist/turn-recorder-wire.d.ts +70 -0
  223. package/dist/turn-recorder-wire.js +165 -0
  224. package/dist/turn-recorder.d.ts +190 -0
  225. package/dist/turn-recorder.js +695 -0
  226. package/dist/turn-ring.d.ts +93 -0
  227. package/dist/turn-ring.js +418 -0
  228. package/dist/turn-watch.d.ts +177 -0
  229. package/dist/turn-watch.js +630 -0
  230. package/dist/types.d.ts +63 -0
  231. package/dist/types.js +2 -0
  232. package/dist/uninstall.d.ts +55 -0
  233. package/dist/uninstall.js +507 -0
  234. package/dist/usage.d.ts +17 -0
  235. package/dist/usage.js +421 -0
  236. package/dist/verify.d.ts +47 -0
  237. package/dist/verify.js +396 -0
  238. package/dist/worktree.d.ts +144 -0
  239. package/dist/worktree.js +310 -0
  240. package/dist/wrapper.d.ts +254 -0
  241. package/dist/wrapper.js +704 -0
  242. package/dist/ws-url.d.ts +109 -0
  243. package/dist/ws-url.js +202 -0
  244. package/package.json +78 -10
  245. package/bin/hwip.js +0 -3
package/dist/usage.js ADDED
@@ -0,0 +1,421 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.usageTarget = exports.commandUsage = exports.usageText = void 0;
4
+ const args_js_1 = require("./args.js");
5
+ const remote_agents_js_1 = require("./remote-agents.js");
6
+ /**
7
+ * What `hwip --help` prints, and what `hwip <command> --help` cuts out of it
8
+ * (C3). One text, so a command's short usage cannot drift from the full one:
9
+ * `commandUsage` reads the command's entry and its options section back out of
10
+ * the same string. The shapes it relies on — an entry is a two-space-indented
11
+ * head and a description that continues on lines indented 18 columns, an
12
+ * options section is a `<Name> options:` heading to the next blank line — are
13
+ * pinned by `usage.test.ts`.
14
+ */
15
+ /** One usage line per registered remote agent — generated so help text can't drift from the table. */
16
+ const usageAgentLines = () => remote_agents_js_1.REMOTE_AGENTS.map((a) => ` ${`${a.subcommands[0]} [args…]`.padEnd(15)} Run '${a.binary}' in a named tmux session ('hwip-<project>')`).join('\n');
17
+ const usageText = () => `Usage: hwip <command> [options]
18
+
19
+ Commands:
20
+ install One-command setup: detect agents, save config, install rules
21
+ login Browser sign-in: auto-fetch API key + hook into ~/.hwip/config.json
22
+ uninstall Remove Hwip from all detected agents
23
+ verify Check installation health across detected agents
24
+ check-update Check whether a newer Hwip version is available
25
+ notify Send a push notification
26
+ ask Ask the phone a question and WAIT for the answer
27
+ (--title required, --body, --actions id:Label,…,
28
+ --timeout secs [default: 60]; --api-key = --key;
29
+ --hook <hook-id> instead of the saved one)
30
+ Prints one JSON line: {"answered":true,"actionId":…} or
31
+ {"value":…}, else {"answered":false,"reason":…}.
32
+ Exit 0 answered, 1 not. Built for hooks, which cannot
33
+ call the MCP hwip_ask tool.
34
+ --accepts-exit marks an agent's own ask: the phone may
35
+ "send and exit", and the answer settles REMOTE and
36
+ reports hwipState like MCP hwip_ask (gates leave it off)
37
+ A run cut short is taken up by the same command run again
38
+ from the same place while the question is open: nothing
39
+ is sent, and the JSON carries "resumed":true
40
+ ask-context [status|on|off|show] [--global]
41
+ Switch the context a sealed question carries (the git diff
42
+ against HEAD and the terminal's last lines, masked), for
43
+ this project (the repository root) or with --global for
44
+ every project. On by default; a local state file, never
45
+ sent anywhere. 'status' (the default) says whether it is
46
+ on and why not. HWIP_ASK_CONTEXT=0 turns it off for one
47
+ run. 'show' prints as JSON what a question asked from
48
+ here would carry, and sends nothing
49
+ file-view [status|on|off|log] [--global]
50
+ Switch whether the phone may browse this computer's files
51
+ (a session's repository: the tracked and new files, not
52
+ the ignored ones), for this project (the repository root)
53
+ or with --global for every project. On by default; a
54
+ local state file, never sent anywhere. 'status' (the
55
+ default) says whether it is on and why not. The listener
56
+ reads HWIP_FILE_VIEW=0 to turn it off for one run. 'log'
57
+ prints the last reads the phone made (time, device,
58
+ session, listing or file, path, bytes, secrets masked,
59
+ result) from ~/.hwip/listener.log — which a listener run
60
+ in the foreground does not write (it prints to its
61
+ terminal), so an empty 'log' proves nothing about it
62
+ agent send <target> <message…>
63
+ Type a message into another agent session, on this
64
+ machine or another (target = <deviceId>:<session> key,
65
+ or a name/alias naming one session). The receiver reads
66
+ [from <you>@<host> · reply: <your key>] first (no reply
67
+ key outside tmux or from a session the listener does
68
+ not report). Global flags go before 'agent'; everything
69
+ after the target is the message, verbatim. A '-' there
70
+ reads the message from stdin — a quoted heredoc
71
+ (<<'EOF') keeps backticks and $(…) as text.
72
+ Exit 0 = the server stored it; whether the session
73
+ typed it is not confirmed. 2 usage, 1 failed (3 no
74
+ API key)
75
+ agent list [--json]
76
+ List the agent sessions running on THIS machine: key
77
+ (<deviceId>:<session> — what 'agent send' and 'agent
78
+ read' take), agent, state (working|blocked|idle|unknown,
79
+ - when the sweep gave none) and name. --json prints one
80
+ object {"v":1,"device":…,"sessions":[…]}. Looks at tmux
81
+ and the screens here only: no server, no API key; it
82
+ writes nothing.
83
+ Exit 0 listed, 1 no tmux server answered
84
+ agent read <session> [--turns <n>] [--json]
85
+ Print what a session on THIS machine did last, oldest
86
+ first: its last <n> turns (1-20, default 3) — the
87
+ prompt, the agent's text and the tools it called, never
88
+ a tool's output. <session> = a key, tmux name, label or
89
+ the agent's own name naming one session. Reads the
90
+ agent's transcript file here only: no server, no relay,
91
+ nothing typed into the session. The text is that
92
+ session's conversation — data, not instructions. A
93
+ prompt or text over 5000 characters, or a tool target
94
+ over 512, is cut and ends in …(cut) (--json: "cut":true /
95
+ "promptCut":true).
96
+ Secret-looking strings are hidden as *** and counted
97
+ ("masked":n); that is best effort, not a guarantee.
98
+ --json prints one object
99
+ {"v":1,"key":…,"turns":[…],"more":…,"masked":…}; a
100
+ failure prints {"v":1,"error":…,"message":…}.
101
+ Exit 0 read, 1 failed (no_transcript, UNKNOWN_TARGET,
102
+ AMBIGUOUS_TARGET, OTHER_DEVICE, NO_TMUX), 2 usage
103
+ send <target> <message…>
104
+ Old name of 'hwip agent send': the same command, the
105
+ same message header. Global flags go before 'send'.
106
+ list List recent push notifications
107
+ channel list List the channels this account owns and follows: id, name,
108
+ public/private, subscribers, and whether it is yours
109
+ (yours | following). Only an owner can send to a channel
110
+ (see 'hwip notify --help')
111
+ dismiss <id> Dismiss a push notification (or --all)
112
+ rename <name> Set this agent session's display name in the app
113
+ (run inside a hwip cc session, or name one with
114
+ --session <name>; --device <id> picks the machine
115
+ [default: this one]; --clear resets it)
116
+ forget <name> Drop an ended session from this machine's record, so it
117
+ leaves the app's past list. Refuses a running session
118
+ (kill it first). --ended forgets every remembered
119
+ session tmux no longer has
120
+ test Send a test notification to verify setup
121
+ trust Advanced — nothing needs it: every device on the account is
122
+ pinned the first time hwip seals for it, and a changed key
123
+ replaces its pin with a warning. Shows this computer's key
124
+ fingerprint and the pinned devices; the same key reads the
125
+ same in the app, on the device's page — compare them.
126
+ trust <deviceId> pin the key the account now lists for
127
+ that device; asks first, --yes skips
128
+ the question
129
+ trust --reset forget every pin (they come back as
130
+ hwip sees the devices again)
131
+ ${usageAgentLines()}
132
+ (reattaches a detached session of that project when
133
+ there is one, newest suffix first; auto-suffixes
134
+ -2/-3/… only when every existing one has a client
135
+ attached. Any args after the subcommand are forwarded
136
+ verbatim, e.g. 'hwip cc --resume')
137
+ --detach create the session without attaching, print
138
+ its name, exit — for launching from another
139
+ agent's pane or a script (no TTY needed)
140
+ --label <x> name it 'hwip-<project>-<x>' instead of the
141
+ -2/-3 family.
142
+ --wt <name> run it in the git worktree for branch <name>,
143
+ made next to this repo as '<repo>-wt-<name>'
144
+ (or reused); the phone groups it under the
145
+ repo. All three must come first.
146
+ Starts the listener when none runs, and says why when it
147
+ stops right away (no key, no tmux, a rejected key). Once
148
+ a day it asks npm for a newer hwip and prints the update
149
+ line (cached in ~/.hwip/update-check.json; off under CI
150
+ or HWIP_NO_UPDATE_CHECK=1)
151
+ worktree [clean]
152
+ List the git worktrees hwip made for agent sessions
153
+ (see the agent commands above), and what keeps each
154
+ one: a session still in it, changes, untracked or
155
+ ignored files, commits not pushed.
156
+ clean remove the ones nothing keeps, and say why the
157
+ rest stay (git is never told to override; a branch
158
+ hwip made goes only when git says it is merged).
159
+ Worktrees you made by hand are never listed
160
+ or removed. Exit 0 unless git refused a
161
+ removal it had cleared
162
+ schedule Start an agent session on a timer, in the background. The
163
+ listener starts it, so it has to be running (installing the
164
+ listener as a login service keeps it up). A run missed while
165
+ the computer slept or the listener was down is skipped, never
166
+ started late, and the phone is told. At most 20 schedules
167
+ and 3 scheduled sessions at once; a session is ended after
168
+ --max-runtime. Schedules live in ~/.local/state/hwip/schedules
169
+ schedule add <agent> (--at HH:MM | --every <N>m|<N>h)
170
+ [-- <agent args…>]
171
+ add one: <agent> is an agent command above
172
+ (cc, codex, …) and the project is this one
173
+ schedule [list] show them, with the next run and the last
174
+ result (--json for scripts)
175
+ schedule rm <id> remove one; a session it already started
176
+ keeps running
177
+ sh Open (or reattach) 'hwip-<project>-sh', a login shell the
178
+ phone may type into. Every other shell stays refused.
179
+ Input must be addressed to this machine; each one is
180
+ logged to ~/.local/state/hwip/shell-audit.log (0600).
181
+ Agents ('hwip agent send', hwip_agent_send) skip it — keep
182
+ 'hwip' up to date on every machine that runs agents.
183
+ --label <x> 'hwip-<project>-<x>' instead of '-sh'
184
+ --detach create it without attaching, print its
185
+ name, exit — '!hwip sh --detach' in a CC
186
+ session opens one from the phone
187
+ mcp Run the MCP server on stdio. This is what agent MCP
188
+ configs launch — 'hwip install' registers it, you
189
+ never type it
190
+ listener Resident daemon — receives 'agent.command' pushes from
191
+ the phone picker and injects them into the matching
192
+ tmux session.
193
+ --ws-url <url>
194
+ WebSocket endpoint for this run only
195
+ --stop stop the running daemon
196
+ --restart stop it and relaunch in the background
197
+ (needed after an upgrade: 'npm i -g' swaps
198
+ the package but never the live process)
199
+ --install-service
200
+ start the listener at every login (systemd
201
+ on Linux, launchd on macOS). Without it the
202
+ daemon only exists after a 'hwip cc', so a
203
+ reboot leaves the phone picker empty until
204
+ you open a terminal
205
+ --uninstall-service
206
+ remove the login-time service
207
+ --service-status
208
+ show what the installed service points at
209
+ --no-keep-awake
210
+ don't hold the Mac awake on AC power
211
+ (macOS; default runs 'caffeinate -s' so an
212
+ idle Mac keeps the socket up)
213
+ --no-turn-history
214
+ don't upload your sessions' conversations
215
+ (sealed for your devices) for the app's
216
+ session history
217
+
218
+ Notify options:
219
+ --title <text> Push title
220
+ --body <text> Push body
221
+ --url <url> URL to include
222
+ --type <type> Push type (note|link|file|hook) [default: hook]
223
+ --priority <p> Priority (low|normal|high|urgent) [default: normal]
224
+ --device <id> Target device ID
225
+ --session <id> AI session ID (or set HWIP_SESSION_ID env)
226
+ --channel <ref> Send to a channel you own instead of your devices:
227
+ a channelId or an exact channel name (a name that two
228
+ channels share needs the id). Sent as plain text, not
229
+ sealed, even with end-to-end encryption on — the
230
+ server can read it. Needs --title or --body; cannot
231
+ be combined with --auto, --device or --session
232
+ --auto Apply the push gate before sending (honors the
233
+ /hwip-mode quiet|loud dial; silent exit when gated)
234
+ --pushmode-default <m>
235
+ Mode --auto assumes when the project has no dial
236
+ (quiet|normal|loud) [default: quiet]. A dial set with
237
+ /hwip-mode quiet|normal|loud always wins
238
+ --marker <m> Push Signal marker for --auto (skip|push|high)
239
+ --tools <n> Turn tool count for --auto [default: assume real work]
240
+ --nonreadonly <n> Non-read-only tool count for --auto
241
+
242
+ List options:
243
+ --limit <n> Number of pushes (1-20, default 5)
244
+ --type <type> Filter by push type
245
+
246
+ Dismiss options:
247
+ --all Dismiss all notifications
248
+
249
+ Login options:
250
+ --web-url <url> Web app URL to sign in at [default: https://console.hwip.app]
251
+ --timeout <sec> Seconds to wait for the browser [default: 300]
252
+ --allow-host <host> Also accept this host (and its subdomains) in the sign-in
253
+ callback's baseUrl / wsUrl — for a self-hosted API
254
+ outside hwip.app and the console's host. Comma-separate
255
+ several; bare host names only
256
+
257
+ Install options:
258
+ (no --key, no saved config → opens browser login automatically,
259
+ and Enter while it waits skips to pasting the key; a saved login
260
+ is reused untouched on re-run; headless falls back to manual key
261
+ entry)
262
+ --key <api-key> API key (non-interactive; skips browser login).
263
+ A key the API rejects is not saved (exit 3)
264
+ --hook <hook-id> Hook ID (non-interactive)
265
+ --service Install the login-time listener service without
266
+ asking (macOS). Interactive runs offer it anyway;
267
+ scripted runs need this flag
268
+ --no-service Never install it
269
+ --base-url <url> Base URL (non-interactive)
270
+ --relogin Force a fresh browser sign-in even if a login is
271
+ already saved (switch account)
272
+ --web-url <url> Login web app URL [default: https://console.hwip.app]
273
+ --timeout <sec> Seconds to wait for the browser sign-in [default: 300]
274
+ --allow-host <host> Also accept this host (and its subdomains) in the sign-in
275
+ callback's baseUrl / wsUrl — for a self-hosted API
276
+ outside hwip.app and the console's host. Comma-separate
277
+ several; bare host names only
278
+ --only <agents> Comma-separated agent ids to install for
279
+ (claude,cursor,windsurf,gemini,codex,copilot,cline,aider,
280
+ pi,opencode; cc = claude). An unknown id is an error.
281
+ Skips the interactive picker.
282
+
283
+ Uninstall options:
284
+ --dry-run Preview what would be removed, change nothing
285
+ --purge Also delete ~/.hwip/config.json (kept by default)
286
+ --yes Don't ask first. It asks only when stdin is a
287
+ terminal; answering no exits 1
288
+
289
+ Worktree options:
290
+ --dry-run With 'clean': say what would be removed, change nothing
291
+
292
+ Schedule options:
293
+ --at HH:MM Run at this local time (24-hour)
294
+ --days <days> With --at: daily [default], weekdays, or day names like
295
+ mon,wed,fri
296
+ --every <N>m|<N>h Run this often instead, at least 15m
297
+ --prompt <text> Type this into the session once the agent is idle. Only
298
+ agents with an 'idle' rule take one (cc, gemini, pi): for
299
+ the others the Enter could answer a trust dialog
300
+ --label <x> Name the session 'hwip-<project>-<x>' [default: sched-<id>]
301
+ --wt <branch> Run in the git worktree for <branch>, as 'hwip cc --wt'
302
+ does (not with --label)
303
+ --max-runtime <N>m|<N>h
304
+ End the session after this long [default: 2h, at most
305
+ the --every period; 5m to 24h]
306
+
307
+ Verify options:
308
+ --ping Also make a live API call to confirm the key works
309
+ (with the --key / --base-url every command resolves)
310
+ --ws-url <url> Check this WebSocket URL instead of the configured one
311
+ --json Print the checks as one JSON object
312
+
313
+ Global options:
314
+ --key <api-key> API key (or set HWIP_API_KEY env)
315
+ --base-url <url> API base URL (or set HWIP_BASE_URL env)
316
+ --json Output JSON format
317
+ --version Show version
318
+ A flag the command does not read is ignored, with a warning on stderr.
319
+ A yes/no flag takes nothing, or =true / =1 / =yes and =false / =0 / =no; any other value
320
+ stops the command (exit 2).
321
+
322
+ Environment:
323
+ HWIP_API_KEY API key (fallback when --key not provided)
324
+ HWIP_BASE_URL API base URL (fallback when --base-url not provided)
325
+ HWIP_SESSION_ID AI session ID (fallback when --session not provided)
326
+ HWIP_NO_UPDATE_CHECK Set to skip the daily npm check in 'hwip cc'
327
+ HTTPS_PROXY Proxy for API calls and the listener (HTTP_PROXY, NO_PROXY too)`;
328
+ exports.usageText = usageText;
329
+ // ── Per-command usage ───────────────────────────────────────────────
330
+ const DESCRIPTION_COLUMN = 18;
331
+ /** ` head description` — the head runs to the first double space or the line's end. */
332
+ const ENTRY_LINE = /^ {2}(\S(?:\S| (?! ))*)(?: {2,}(.*))?$/;
333
+ const agentHeads = () => remote_agents_js_1.REMOTE_AGENTS.map((a) => `${a.subcommands[0]} [args…]`);
334
+ const SECTION_HEADING = /^([A-Z][a-z-]+) options:$/;
335
+ /** The command word an entry or a section belongs to: `dismiss <id>` → `dismiss`. */
336
+ const wordOf = (head) => head.split(' ')[0];
337
+ const parseUsage = (text) => {
338
+ const lines = text.split('\n');
339
+ const entries = [];
340
+ const sections = new Map();
341
+ let global = [];
342
+ const start = lines.indexOf('Commands:') + 1;
343
+ let i = start;
344
+ for (; i < lines.length && lines[i] !== ''; i++) {
345
+ const line = lines[i];
346
+ // An agent line is `head` + one space when the head is too long to pad
347
+ // (`opencode [args…]`), which the double-space rule cannot split.
348
+ const agentHead = agentHeads().find((head) => line.startsWith(` ${head} `));
349
+ const entry = agentHead ? null : ENTRY_LINE.exec(line);
350
+ if (agentHead) {
351
+ entries.push({ head: agentHead, description: [line.slice(` ${agentHead} `.length).trimStart()] });
352
+ }
353
+ else if (entry && !line.startsWith(' '.repeat(DESCRIPTION_COLUMN))) {
354
+ entries.push({ head: entry[1], description: entry[2] !== undefined ? [entry[2]] : [] });
355
+ }
356
+ else if (entries.length > 0) {
357
+ entries[entries.length - 1].description.push(line.slice(DESCRIPTION_COLUMN));
358
+ }
359
+ }
360
+ for (; i < lines.length; i++) {
361
+ const heading = lines[i];
362
+ const isGlobal = heading === 'Global options:';
363
+ const named = isGlobal ? null : SECTION_HEADING.exec(heading);
364
+ if (!named && !isGlobal)
365
+ continue;
366
+ const body = [];
367
+ for (i++; i < lines.length && lines[i] !== ''; i++)
368
+ body.push(lines[i]);
369
+ if (named)
370
+ sections.set(named[1].toLowerCase(), body);
371
+ else
372
+ global = body;
373
+ }
374
+ return { entries, sections, global };
375
+ };
376
+ /**
377
+ * The short usage of one command: its entry from the full text, its options
378
+ * section if it has one, and the global options. Null for a word that is not a
379
+ * command, which the caller answers with the full usage.
380
+ *
381
+ * Every agent subcommand (`cc`, `codex`, …) shares the paragraph the full text
382
+ * prints once under the last of them, so each gets it.
383
+ */
384
+ const commandUsage = (command) => {
385
+ const agent = (0, remote_agents_js_1.findAgentBySubcommand)(command);
386
+ const word = agent ? agent.subcommands[0] : command === 'setup' ? 'install' : command;
387
+ const { entries, sections, global } = parseUsage((0, exports.usageText)());
388
+ // `agent` has three entries (send, list, read): the first leads, the others follow it.
389
+ const [entry, ...siblings] = entries.filter((e) => wordOf(e.head) === word);
390
+ if (!entry)
391
+ return null;
392
+ const description = [...entry.description];
393
+ for (const sibling of siblings)
394
+ description.push('', `hwip ${sibling.head}`, ...sibling.description);
395
+ if (agent) {
396
+ const lastAgent = [...entries].reverse().find((e) => remote_agents_js_1.REMOTE_AGENTS.some((a) => a.subcommands[0] === wordOf(e.head)));
397
+ // The shared paragraph is the part of the last agent's description after its own first line.
398
+ if (lastAgent && lastAgent !== entry)
399
+ description.push(...lastAgent.description.slice(1));
400
+ }
401
+ const options = sections.get(word);
402
+ // `[options]` when the command reads flags; a command outside the table (`sh`,
403
+ // `mcp`) gets it unless its head already says what follows.
404
+ const flags = args_js_1.COMMAND_FLAGS[word];
405
+ const takesOptions = siblings.length === 0 && (options !== undefined || (flags ? flags.length > 0 : !/[<\[]/.test(entry.head)));
406
+ const heads = [entry, ...siblings].map((e, n) => `${n === 0 ? 'Usage: hwip' : ' hwip'} ${e.head}`);
407
+ heads[0] += takesOptions ? ' [options]' : '';
408
+ const out = [...heads, '', ...description.filter((l, n) => n > 0 || l !== '')];
409
+ if (options)
410
+ out.push('', `${word[0].toUpperCase()}${word.slice(1)} options:`, ...options);
411
+ out.push('', 'Global options:', ...global, '', "'hwip --help' lists every command.");
412
+ return out.join('\n');
413
+ };
414
+ exports.commandUsage = commandUsage;
415
+ /**
416
+ * Which command a request for usage is about: `hwip notify --help` and
417
+ * `hwip --help cc` name it, `hwip help notify` names it as its argument, and
418
+ * `hwip` or `hwip help` alone name none.
419
+ */
420
+ const usageTarget = (args) => String(args._command === 'help' ? args._arg1 : args._command);
421
+ exports.usageTarget = usageTarget;
@@ -0,0 +1,47 @@
1
+ /** Is the hwip plugin installed in Claude Code, or a `hwip` MCP server registered in ~/.claude.json? Exported for tests. */
2
+ export declare const claudeHasHwip: (home: string) => boolean;
3
+ /** Codex keeps its registry in TOML, so its reader is text-level — the table
4
+ * shape lives in codex-config.ts, which install and uninstall share. */
5
+ export declare const readCodexMcpArgv: (filePath: string) => string[] | null;
6
+ /** A registry file that exists but is not a JSON object — its hwip entry, if any, is unknowable. */
7
+ export declare const UNREADABLE = "unreadable";
8
+ /**
9
+ * The launch argv a registry file records for hwip, verbatim — null when the
10
+ * file is absent or has no hwip entry, `UNREADABLE` when it exists but is not
11
+ * a JSON object. Two schemas in the wild:
12
+ * `command` + `args` (Cursor/Windsurf/Gemini) and `command` as a whole array
13
+ * (opencode). Returned as-is on purpose: a stale entry is only detectable if
14
+ * the reader does not normalize it into the shape it expects.
15
+ */
16
+ export declare const registeredMcpArgv: (filePath: string, key: string) => string[] | null | typeof UNREADABLE;
17
+ /**
18
+ * Can this launch binary actually be run? Registered commands come out of a
19
+ * config file, so unlike everywhere else in the CLI they can be an absolute
20
+ * path — `which` is the wrong question for one of those, hence the split.
21
+ * The bare-name half is `resolveCommand`; neither half touches a shell, so a
22
+ * path with a space in it stays one word and a `;` in the file stays inert.
23
+ */
24
+ export declare const binaryResolves: (bin: string) => boolean;
25
+ /**
26
+ * What a recorded registration is worth right now. `unresolvable` outranks
27
+ * `stale`: a stale entry still starts a server (through the npm launcher this
28
+ * release exists to delete), an unresolvable one starts nothing at all and
29
+ * takes the agent's whole hwip toolset down with it, silently — the config is
30
+ * read once at install time and never checked again.
31
+ */
32
+ export type McpRegistration = {
33
+ readonly state: 'current';
34
+ } | {
35
+ readonly state: 'stale';
36
+ readonly argv: string[];
37
+ } | {
38
+ readonly state: 'unresolvable';
39
+ readonly argv: string[];
40
+ } | {
41
+ readonly state: 'unreadable';
42
+ readonly path: string;
43
+ };
44
+ /** null = this agent has no hwip registration at all, so there is nothing to report. */
45
+ export declare const classifyMcpRegistration: (argv: string[] | null, isOnPath: (bin: string) => boolean) => McpRegistration | null;
46
+ export declare const handleVerify: (args: Record<string, string | boolean>) => Promise<number>;
47
+ //# sourceMappingURL=verify.d.ts.map