@hwip/cli 0.0.1 → 0.1.1
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.
- package/LICENSE +190 -0
- package/NOTICE +11 -0
- package/README.md +1983 -0
- package/dist/agent-list.d.ts +76 -0
- package/dist/agent-list.js +102 -0
- package/dist/agent-read.d.ts +105 -0
- package/dist/agent-read.js +309 -0
- package/dist/agent-rules-fetch.d.ts +51 -0
- package/dist/agent-rules-fetch.js +275 -0
- package/dist/agent-rules.default.d.ts +30 -0
- package/dist/agent-rules.default.js +305 -0
- package/dist/agent-session.d.ts +23 -0
- package/dist/agent-session.js +44 -0
- package/dist/agent-state.d.ts +84 -0
- package/dist/agent-state.js +188 -0
- package/dist/agent-target.d.ts +60 -0
- package/dist/agent-target.js +81 -0
- package/dist/agents.d.ts +31 -0
- package/dist/agents.js +75 -0
- package/dist/api.d.ts +28 -0
- package/dist/api.js +76 -0
- package/dist/args.d.ts +74 -0
- package/dist/args.js +254 -0
- package/dist/ask-context-attach.d.ts +73 -0
- package/dist/ask-context-attach.js +151 -0
- package/dist/ask-context-screen.d.ts +21 -0
- package/dist/ask-context-screen.js +49 -0
- package/dist/ask-context-switch.d.ts +31 -0
- package/dist/ask-context-switch.js +74 -0
- package/dist/ask-context.d.ts +84 -0
- package/dist/ask-context.js +172 -0
- package/dist/ask-pending.d.ts +47 -0
- package/dist/ask-pending.js +221 -0
- package/dist/ask-seal.d.ts +120 -0
- package/dist/ask-seal.js +179 -0
- package/dist/ask.d.ts +107 -0
- package/dist/ask.js +551 -0
- package/dist/blocked-prompt-seal.d.ts +39 -0
- package/dist/blocked-prompt-seal.js +92 -0
- package/dist/blocked-prompt.d.ts +62 -0
- package/dist/blocked-prompt.js +518 -0
- package/dist/channel.d.ts +67 -0
- package/dist/channel.js +136 -0
- package/dist/check-update.d.ts +28 -0
- package/dist/check-update.js +153 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +813 -0
- package/dist/codex-config.d.ts +24 -0
- package/dist/codex-config.js +169 -0
- package/dist/codex-transcript.d.ts +59 -0
- package/dist/codex-transcript.js +373 -0
- package/dist/command-refusal.d.ts +56 -0
- package/dist/command-refusal.js +127 -0
- package/dist/command-scan.d.ts +46 -0
- package/dist/command-scan.js +154 -0
- package/dist/command-seal.d.ts +57 -0
- package/dist/command-seal.js +88 -0
- package/dist/command-seq.d.ts +30 -0
- package/dist/command-seq.js +150 -0
- package/dist/config.d.ts +156 -0
- package/dist/config.js +392 -0
- package/dist/core-sections.d.ts +18 -0
- package/dist/core-sections.js +28 -0
- package/dist/crypto.d.ts +278 -0
- package/dist/crypto.js +698 -0
- package/dist/desktop-notify.d.ts +33 -0
- package/dist/desktop-notify.js +49 -0
- package/dist/device-directory.d.ts +36 -0
- package/dist/device-directory.js +97 -0
- package/dist/device-presence.d.ts +17 -0
- package/dist/device-presence.js +62 -0
- package/dist/downloads.d.ts +29 -0
- package/dist/downloads.js +106 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.js +28 -0
- package/dist/file-crypto.d.ts +94 -0
- package/dist/file-crypto.js +278 -0
- package/dist/file-view-budget.d.ts +15 -0
- package/dist/file-view-budget.js +34 -0
- package/dist/file-view-switch.d.ts +28 -0
- package/dist/file-view-switch.js +122 -0
- package/dist/file-view.d.ts +108 -0
- package/dist/file-view.js +327 -0
- package/dist/gate.d.ts +141 -0
- package/dist/gate.js +336 -0
- package/dist/gemini-transcript.d.ts +32 -0
- package/dist/gemini-transcript.js +189 -0
- package/dist/http-failure.d.ts +98 -0
- package/dist/http-failure.js +349 -0
- package/dist/hwip-core.generated.d.ts +7 -0
- package/dist/hwip-core.generated.js +14 -0
- package/dist/hwip-hook.d.ts +77 -0
- package/dist/hwip-hook.js +340 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +14 -0
- package/dist/input-sequencer.d.ts +65 -0
- package/dist/input-sequencer.js +142 -0
- package/dist/insecure-url.d.ts +16 -0
- package/dist/insecure-url.js +76 -0
- package/dist/installer.d.ts +96 -0
- package/dist/installer.js +850 -0
- package/dist/inventory-offload.d.ts +49 -0
- package/dist/inventory-offload.js +209 -0
- package/dist/inventory-worker.d.ts +2 -0
- package/dist/inventory-worker.js +27 -0
- package/dist/jsonc-doc.d.ts +106 -0
- package/dist/jsonc-doc.js +354 -0
- package/dist/keep-awake.d.ts +32 -0
- package/dist/keep-awake.js +46 -0
- package/dist/key-changes.d.ts +48 -0
- package/dist/key-changes.js +140 -0
- package/dist/lan-auth.d.ts +140 -0
- package/dist/lan-auth.js +217 -0
- package/dist/lan-endpoint.d.ts +41 -0
- package/dist/lan-endpoint.js +115 -0
- package/dist/lan-receiver.d.ts +122 -0
- package/dist/lan-receiver.js +510 -0
- package/dist/lan-sender.d.ts +76 -0
- package/dist/lan-sender.js +184 -0
- package/dist/lan-transfer.d.ts +36 -0
- package/dist/lan-transfer.js +54 -0
- package/dist/listener-device-id.d.ts +20 -0
- package/dist/listener-device-id.js +133 -0
- package/dist/listener-log.d.ts +4 -0
- package/dist/listener-log.js +23 -0
- package/dist/listener-process.d.ts +200 -0
- package/dist/listener-process.js +470 -0
- package/dist/listener-service.d.ts +225 -0
- package/dist/listener-service.js +682 -0
- package/dist/listener-worktree-cleanup.d.ts +27 -0
- package/dist/listener-worktree-cleanup.js +62 -0
- package/dist/listener.d.ts +1325 -0
- package/dist/listener.js +5681 -0
- package/dist/login-address.d.ts +25 -0
- package/dist/login-address.js +97 -0
- package/dist/login-page.d.ts +29 -0
- package/dist/login-page.js +93 -0
- package/dist/login.d.ts +98 -0
- package/dist/login.js +388 -0
- package/dist/mcp-command.d.ts +45 -0
- package/dist/mcp-command.js +50 -0
- package/dist/mcp.d.ts +19 -0
- package/dist/mcp.js +29 -0
- package/dist/node-support.d.ts +19 -0
- package/dist/node-support.js +38 -0
- package/dist/notify-failure.d.ts +57 -0
- package/dist/notify-failure.js +150 -0
- package/dist/opencode-transcript.d.ts +139 -0
- package/dist/opencode-transcript.js +390 -0
- package/dist/optional-features.d.ts +6 -0
- package/dist/optional-features.js +19 -0
- package/dist/pane-fit.d.ts +40 -0
- package/dist/pane-fit.js +119 -0
- package/dist/peer-key.d.ts +33 -0
- package/dist/peer-key.js +34 -0
- package/dist/pi-transcript.d.ts +26 -0
- package/dist/pi-transcript.js +255 -0
- package/dist/presence.d.ts +14 -0
- package/dist/presence.js +124 -0
- package/dist/private-files.d.ts +51 -0
- package/dist/private-files.js +218 -0
- package/dist/project-switch.d.ts +19 -0
- package/dist/project-switch.js +60 -0
- package/dist/redact.d.ts +10 -0
- package/dist/redact.js +21 -0
- package/dist/remote-agents.d.ts +410 -0
- package/dist/remote-agents.js +1218 -0
- package/dist/remote-hook.d.ts +12 -0
- package/dist/remote-hook.js +196 -0
- package/dist/replace-file.d.ts +50 -0
- package/dist/replace-file.js +328 -0
- package/dist/schedule-command.d.ts +35 -0
- package/dist/schedule-command.js +260 -0
- package/dist/schedule-launch.d.ts +15 -0
- package/dist/schedule-launch.js +24 -0
- package/dist/schedule-ready.d.ts +44 -0
- package/dist/schedule-ready.js +71 -0
- package/dist/schedule-remote.d.ts +77 -0
- package/dist/schedule-remote.js +167 -0
- package/dist/schedule-runner.d.ts +89 -0
- package/dist/schedule-runner.js +452 -0
- package/dist/schedule.d.ts +149 -0
- package/dist/schedule.js +428 -0
- package/dist/secret-mask.d.ts +29 -0
- package/dist/secret-mask.js +245 -0
- package/dist/self-register.d.ts +45 -0
- package/dist/self-register.js +67 -0
- package/dist/send.d.ts +56 -0
- package/dist/send.js +104 -0
- package/dist/session-diff.d.ts +161 -0
- package/dist/session-diff.js +445 -0
- package/dist/session-registry.d.ts +143 -0
- package/dist/session-registry.js +216 -0
- package/dist/sessions-report.d.ts +59 -0
- package/dist/sessions-report.js +99 -0
- package/dist/shell-audit.d.ts +34 -0
- package/dist/shell-audit.js +47 -0
- package/dist/subagent-transcripts.d.ts +167 -0
- package/dist/subagent-transcripts.js +437 -0
- package/dist/subscriber-trust.d.ts +128 -0
- package/dist/subscriber-trust.js +397 -0
- package/dist/templates.d.ts +105 -0
- package/dist/templates.js +871 -0
- package/dist/tmux-install.d.ts +44 -0
- package/dist/tmux-install.js +65 -0
- package/dist/tmux-liveness.d.ts +45 -0
- package/dist/tmux-liveness.js +71 -0
- package/dist/tmux-pane.d.ts +55 -0
- package/dist/tmux-pane.js +126 -0
- package/dist/tmux-socket.d.ts +20 -0
- package/dist/tmux-socket.js +292 -0
- package/dist/todo-fold.d.ts +31 -0
- package/dist/todo-fold.js +102 -0
- package/dist/transcript-tail.d.ts +312 -0
- package/dist/transcript-tail.js +718 -0
- package/dist/trust-command.d.ts +49 -0
- package/dist/trust-command.js +200 -0
- package/dist/trust-lock.d.ts +26 -0
- package/dist/trust-lock.js +94 -0
- package/dist/trust-pins.d.ts +37 -0
- package/dist/trust-pins.js +82 -0
- package/dist/turn-recorder-wire.d.ts +70 -0
- package/dist/turn-recorder-wire.js +165 -0
- package/dist/turn-recorder.d.ts +190 -0
- package/dist/turn-recorder.js +695 -0
- package/dist/turn-ring.d.ts +93 -0
- package/dist/turn-ring.js +418 -0
- package/dist/turn-watch.d.ts +177 -0
- package/dist/turn-watch.js +630 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.js +2 -0
- package/dist/uninstall.d.ts +55 -0
- package/dist/uninstall.js +507 -0
- package/dist/usage.d.ts +17 -0
- package/dist/usage.js +421 -0
- package/dist/verify.d.ts +47 -0
- package/dist/verify.js +396 -0
- package/dist/worktree.d.ts +144 -0
- package/dist/worktree.js +310 -0
- package/dist/wrapper.d.ts +254 -0
- package/dist/wrapper.js +704 -0
- package/dist/ws-url.d.ts +109 -0
- package/dist/ws-url.js +202 -0
- package/package.json +78 -10
- 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;
|
package/dist/verify.d.ts
ADDED
|
@@ -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
|