waitspin 0.1.5 → 0.1.6
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/README.md +24 -5
- package/dist/cli.js +101 -10
- package/dist/cli.js.map +1 -1
- package/dist/targets/experimental-cli.js +1108 -0
- package/dist/targets/experimental-cli.js.map +1 -0
- package/dist/targets/experimental-runtime.js +343 -0
- package/dist/targets/experimental-runtime.js.map +1 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -46,6 +46,10 @@ waitspin mimocode status
|
|
|
46
46
|
# Or install for OpenCode TUI plugin slot
|
|
47
47
|
waitspin opencode install --api-key PASTE_PUBLISHER_EXTENSION_KEY
|
|
48
48
|
waitspin opencode status
|
|
49
|
+
|
|
50
|
+
# Or install for Grok Code CLI footer
|
|
51
|
+
waitspin grok install --api-key PASTE_PUBLISHER_EXTENSION_KEY
|
|
52
|
+
waitspin grok status
|
|
49
53
|
```
|
|
50
54
|
|
|
51
55
|
## Commands
|
|
@@ -74,15 +78,20 @@ waitspin opencode status
|
|
|
74
78
|
- `waitspin opencode install` — install the OpenCode TUI plugin slot
|
|
75
79
|
- `waitspin opencode status` — inspect managed OpenCode runtime state
|
|
76
80
|
- `waitspin opencode uninstall` — remove managed OpenCode runtime and plugin
|
|
81
|
+
- `waitspin grok install` — install the Grok Code CLI footer surface
|
|
82
|
+
- `waitspin grok status` — inspect managed Grok Code CLI runtime state
|
|
83
|
+
- `waitspin grok uninstall` — restore Grok Code CLI and remove managed state
|
|
77
84
|
|
|
78
85
|
API base: `https://api.waitspin.com`
|
|
79
86
|
|
|
80
|
-
The public package installs
|
|
87
|
+
The public package installs five verified publisher targets: the VS Code
|
|
81
88
|
status-bar fallback, the Claude Code statusline command, the MiMo Code shell
|
|
82
|
-
hook,
|
|
83
|
-
`statusLine.command` path and does not patch Claude
|
|
84
|
-
uses a bash hook that polls the API for sponsored
|
|
85
|
-
TUI `app_bottom` plugin slot.
|
|
89
|
+
hook, the OpenCode TUI plugin slot, and the Grok Code CLI footer. Claude Code
|
|
90
|
+
support uses the official `statusLine.command` path and does not patch Claude
|
|
91
|
+
Code internals. MiMo Code uses a bash hook that polls the API for sponsored
|
|
92
|
+
messages. OpenCode uses its TUI `app_bottom` plugin slot. Grok Code CLI uses a
|
|
93
|
+
managed text-asset footer patch with hash-backed backup/restore and does not
|
|
94
|
+
patch native binaries.
|
|
86
95
|
|
|
87
96
|
`waitspin install --all` is an advanced agent command for installing every
|
|
88
97
|
detected supported target. It keeps explicit target commands as the canonical
|
|
@@ -112,6 +121,7 @@ npx waitspin extension install --target vscode --api-key PASTE_PUBLISHER_EXTENSI
|
|
|
112
121
|
npx waitspin claude-code install --api-key PASTE_PUBLISHER_EXTENSION_KEY --compose-existing
|
|
113
122
|
npx waitspin mimocode install --api-key PASTE_PUBLISHER_EXTENSION_KEY
|
|
114
123
|
npx waitspin opencode install --api-key PASTE_PUBLISHER_EXTENSION_KEY
|
|
124
|
+
npx waitspin grok install --api-key PASTE_PUBLISHER_EXTENSION_KEY
|
|
115
125
|
```
|
|
116
126
|
|
|
117
127
|
- `WAITSPIN_API_KEY` — temporary publisher-extension key for first activation
|
|
@@ -136,6 +146,14 @@ The OpenCode installer writes a managed runtime/state under `~/.waitspin`,
|
|
|
136
146
|
installs a TUI plugin under `~/.config/opencode/plugins`, and adds the managed
|
|
137
147
|
entry to `~/.config/opencode/tui.json` so OpenCode mounts the `app_bottom` slot.
|
|
138
148
|
|
|
149
|
+
The Grok Code CLI installer writes a managed runtime/state under `~/.waitspin`
|
|
150
|
+
and patches the verified OpenTUI footer text asset with a hash-backed backup so
|
|
151
|
+
uninstall can restore the original file.
|
|
152
|
+
|
|
153
|
+
Cline VS Code extension installs are covered by the VS Code fallback target.
|
|
154
|
+
Standalone Cline CLI is not a public install target until Cline exposes an
|
|
155
|
+
official statusline/plugin surface.
|
|
156
|
+
|
|
139
157
|
## Release validation
|
|
140
158
|
|
|
141
159
|
Before advertising the public `npx waitspin` path, release operators should run:
|
|
@@ -147,4 +165,5 @@ npm view waitspin version
|
|
|
147
165
|
npx --yes waitspin --help
|
|
148
166
|
npx --yes waitspin@latest mimocode status
|
|
149
167
|
npx --yes waitspin@latest opencode status
|
|
168
|
+
npx --yes waitspin@latest grok status
|
|
150
169
|
```
|
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ import { constants as fsConstants } from "node:fs";
|
|
|
6
6
|
import { access, chmod, cp, mkdir, readFile, rename, rm, writeFile, } from "node:fs/promises";
|
|
7
7
|
import os from "node:os";
|
|
8
8
|
import path from "node:path";
|
|
9
|
+
import { experimentalAllInstallTargets, experimentalInstallTarget, isExperimentalCliTargetName, runExperimentalCliTargetInstall, runExperimentalCliTargetStatus, runExperimentalCliTargetUninstall, } from "./targets/experimental-cli.js";
|
|
9
10
|
const DEFAULT_BASE_URL = process.env.WAITSPIN_BASE_URL?.trim() || "https://api.waitspin.com";
|
|
10
11
|
const PRODUCTION_API_ORIGIN = "https://api.waitspin.com";
|
|
11
12
|
const REQUEST_TIMEOUT_MS = 30_000;
|
|
@@ -50,11 +51,14 @@ export function usageText() {
|
|
|
50
51
|
" waitspin opencode install [--api-key KEY] [--dry-run]",
|
|
51
52
|
" waitspin opencode status",
|
|
52
53
|
" waitspin opencode uninstall [--dry-run]",
|
|
54
|
+
" waitspin grok install [--api-key KEY] [--dry-run]",
|
|
55
|
+
" waitspin grok status",
|
|
56
|
+
" waitspin grok uninstall [--dry-run]",
|
|
53
57
|
"",
|
|
54
58
|
"Defaults:",
|
|
55
59
|
" API base: https://api.waitspin.com",
|
|
56
60
|
" API key: WAITSPIN_API_KEY env var",
|
|
57
|
-
" Public publisher targets: status-bar-fallback, claude-code, mimocode, opencode",
|
|
61
|
+
" Public publisher targets: status-bar-fallback, claude-code, mimocode, opencode, grok",
|
|
58
62
|
].join("\n") + "\n");
|
|
59
63
|
}
|
|
60
64
|
function usage(exitCode = 1) {
|
|
@@ -95,6 +99,7 @@ function parseArgs(argv) {
|
|
|
95
99
|
key === "allow-dev-extension-assets" ||
|
|
96
100
|
key === "confirm-test-transfer" ||
|
|
97
101
|
key === "compose-existing" ||
|
|
102
|
+
key === "include-experimental" ||
|
|
98
103
|
key === "all") {
|
|
99
104
|
flags.set(key, ["true"]);
|
|
100
105
|
continue;
|
|
@@ -607,6 +612,20 @@ async function registerPublisherInstall(input) {
|
|
|
607
612
|
"For developer-local acceptance only, use an explicit loopback API with --allow-dev-api-base.",
|
|
608
613
|
].join("\n"));
|
|
609
614
|
}
|
|
615
|
+
if (isExperimentalCliTargetName(input.target) &&
|
|
616
|
+
error instanceof WaitSpinCliHttpError &&
|
|
617
|
+
error.status === 400 &&
|
|
618
|
+
/Invalid input|Validation error/.test(error.message)) {
|
|
619
|
+
throw new Error([
|
|
620
|
+
`WaitSpin API rejected target "${input.target}".`,
|
|
621
|
+
"Your local CLI supports this hidden experimental target, but the selected API base does not.",
|
|
622
|
+
"",
|
|
623
|
+
"For production:",
|
|
624
|
+
" deploy the backend target allowlist, then rerun the explicit target install.",
|
|
625
|
+
"",
|
|
626
|
+
"For developer-local acceptance only, use an explicit loopback API with --allow-dev-api-base.",
|
|
627
|
+
].join("\n"));
|
|
628
|
+
}
|
|
610
629
|
throw error;
|
|
611
630
|
}
|
|
612
631
|
if (!body) {
|
|
@@ -2722,8 +2741,20 @@ async function preflightMiMoCode() {
|
|
|
2722
2741
|
async function preflightOpenCode() {
|
|
2723
2742
|
return executableVersion(OPENCODE_BIN_ENV, OPENCODE_DEFAULT_BIN, "OpenCode");
|
|
2724
2743
|
}
|
|
2725
|
-
function
|
|
2726
|
-
return
|
|
2744
|
+
function experimentalCliDeps() {
|
|
2745
|
+
return {
|
|
2746
|
+
booleanFlag,
|
|
2747
|
+
optionalFlag,
|
|
2748
|
+
resolveCredentialedBaseUrl,
|
|
2749
|
+
requireApiKey,
|
|
2750
|
+
registerPublisherInstall,
|
|
2751
|
+
generateInstallId,
|
|
2752
|
+
printJson,
|
|
2753
|
+
};
|
|
2754
|
+
}
|
|
2755
|
+
function allInstallTargets(flags) {
|
|
2756
|
+
const experimentalDeps = experimentalCliDeps();
|
|
2757
|
+
const targets = [
|
|
2727
2758
|
{
|
|
2728
2759
|
target: "vscode",
|
|
2729
2760
|
command: "waitspin extension install --target vscode",
|
|
@@ -2756,7 +2787,12 @@ function allInstallTargets() {
|
|
|
2756
2787
|
install: runOpencodeInstall,
|
|
2757
2788
|
status: () => runOpencodeStatus(),
|
|
2758
2789
|
},
|
|
2790
|
+
experimentalInstallTarget("grok", experimentalDeps),
|
|
2759
2791
|
];
|
|
2792
|
+
if (booleanFlag(flags, "include-experimental")) {
|
|
2793
|
+
targets.push(...experimentalAllInstallTargets(experimentalDeps).filter((target) => target.target !== "grok"));
|
|
2794
|
+
}
|
|
2795
|
+
return targets;
|
|
2760
2796
|
}
|
|
2761
2797
|
function safeErrorMessage(error) {
|
|
2762
2798
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -2773,6 +2809,9 @@ function isNotDetectedError(message) {
|
|
|
2773
2809
|
function isConflictError(message) {
|
|
2774
2810
|
return /statusLine|status line|conflict|override|already has|blocked/i.test(message);
|
|
2775
2811
|
}
|
|
2812
|
+
function isUnsupportedTargetLayoutReason(reason) {
|
|
2813
|
+
return /unsupported_patch_layout|unsupported_native_cli/i.test(reason);
|
|
2814
|
+
}
|
|
2776
2815
|
function objectRecord(value) {
|
|
2777
2816
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
2778
2817
|
? value
|
|
@@ -2782,17 +2821,40 @@ function dryRunConflictReason(result) {
|
|
|
2782
2821
|
const record = objectRecord(result);
|
|
2783
2822
|
if (!record.would_fail)
|
|
2784
2823
|
return null;
|
|
2785
|
-
|
|
2824
|
+
if (typeof record.failure_kind === "string" &&
|
|
2825
|
+
isUnsupportedTargetLayoutReason(record.failure_kind)) {
|
|
2826
|
+
return typeof record.human_message === "string"
|
|
2827
|
+
? record.human_message
|
|
2828
|
+
: record.failure_kind;
|
|
2829
|
+
}
|
|
2830
|
+
const reason = record.settings_blocked_reason ??
|
|
2831
|
+
(record.failure_kind ? null : record.human_message);
|
|
2832
|
+
if (!reason)
|
|
2833
|
+
return null;
|
|
2786
2834
|
return typeof reason === "string" ? reason : "target reported a conflict";
|
|
2787
2835
|
}
|
|
2836
|
+
function dryRunFailureReason(result) {
|
|
2837
|
+
const record = objectRecord(result);
|
|
2838
|
+
if (!record.would_fail)
|
|
2839
|
+
return null;
|
|
2840
|
+
const reason = record.failure_kind ??
|
|
2841
|
+
record.rollback_reason ??
|
|
2842
|
+
record.human_message ??
|
|
2843
|
+
"target dry-run reported failure";
|
|
2844
|
+
return typeof reason === "string" ? reason : "target dry-run reported failure";
|
|
2845
|
+
}
|
|
2788
2846
|
export async function runInstallAll(flags) {
|
|
2789
2847
|
const dryRun = booleanFlag(flags, "dry-run");
|
|
2848
|
+
const includeExperimental = booleanFlag(flags, "include-experimental");
|
|
2849
|
+
if (includeExperimental && !dryRun) {
|
|
2850
|
+
throw new Error("--include-experimental is only available with install --all --dry-run. Use explicit waitspin <target> install commands for hidden experimental targets.");
|
|
2851
|
+
}
|
|
2790
2852
|
const installed = [];
|
|
2791
2853
|
const wouldInstall = [];
|
|
2792
2854
|
const skippedNotDetected = [];
|
|
2793
2855
|
const skippedConflict = [];
|
|
2794
2856
|
const failedRollback = [];
|
|
2795
|
-
for (const target of allInstallTargets()) {
|
|
2857
|
+
for (const target of allInstallTargets(flags)) {
|
|
2796
2858
|
let detail = null;
|
|
2797
2859
|
try {
|
|
2798
2860
|
detail = await target.preflight(flags);
|
|
@@ -2822,6 +2884,17 @@ export async function runInstallAll(flags) {
|
|
|
2822
2884
|
});
|
|
2823
2885
|
continue;
|
|
2824
2886
|
}
|
|
2887
|
+
const failureReason = dryRunFailureReason(result);
|
|
2888
|
+
if (failureReason) {
|
|
2889
|
+
failedRollback.push({
|
|
2890
|
+
target: target.target,
|
|
2891
|
+
command: target.command,
|
|
2892
|
+
reason: failureReason,
|
|
2893
|
+
detail,
|
|
2894
|
+
result,
|
|
2895
|
+
});
|
|
2896
|
+
continue;
|
|
2897
|
+
}
|
|
2825
2898
|
const summary = {
|
|
2826
2899
|
target: target.target,
|
|
2827
2900
|
command: target.command,
|
|
@@ -2839,9 +2912,11 @@ export async function runInstallAll(flags) {
|
|
|
2839
2912
|
const reason = safeErrorMessage(error);
|
|
2840
2913
|
const bucket = isConflictError(reason)
|
|
2841
2914
|
? skippedConflict
|
|
2842
|
-
:
|
|
2843
|
-
?
|
|
2844
|
-
:
|
|
2915
|
+
: isUnsupportedTargetLayoutReason(reason)
|
|
2916
|
+
? skippedConflict
|
|
2917
|
+
: isNotDetectedError(reason)
|
|
2918
|
+
? skippedNotDetected
|
|
2919
|
+
: failedRollback;
|
|
2845
2920
|
bucket.push({
|
|
2846
2921
|
target: target.target,
|
|
2847
2922
|
command: target.command,
|
|
@@ -2855,13 +2930,16 @@ export async function runInstallAll(flags) {
|
|
|
2855
2930
|
command: "install --all",
|
|
2856
2931
|
dry_run: dryRun,
|
|
2857
2932
|
mode: "detected-targets",
|
|
2933
|
+
include_experimental: includeExperimental,
|
|
2858
2934
|
installed,
|
|
2859
2935
|
would_install: wouldInstall,
|
|
2860
2936
|
skipped_not_detected: skippedNotDetected,
|
|
2861
2937
|
skipped_conflict: skippedConflict,
|
|
2862
2938
|
failed_rollback: failedRollback,
|
|
2863
2939
|
next: "check_all_status",
|
|
2864
|
-
next_command:
|
|
2940
|
+
next_command: includeExperimental
|
|
2941
|
+
? "waitspin status --all --include-experimental"
|
|
2942
|
+
: "waitspin status --all",
|
|
2865
2943
|
human_message: "Install-all is an advanced agent command. Explicit target commands remain the canonical debug path.",
|
|
2866
2944
|
});
|
|
2867
2945
|
}
|
|
@@ -2869,7 +2947,7 @@ export async function runStatusAll(flags) {
|
|
|
2869
2947
|
const statuses = [];
|
|
2870
2948
|
const installed = [];
|
|
2871
2949
|
const failedStatus = [];
|
|
2872
|
-
for (const target of allInstallTargets()) {
|
|
2950
|
+
for (const target of allInstallTargets(flags)) {
|
|
2873
2951
|
try {
|
|
2874
2952
|
const result = await capturePrintedJson(() => target.status(flags));
|
|
2875
2953
|
const summary = {
|
|
@@ -2893,6 +2971,7 @@ export async function runStatusAll(flags) {
|
|
|
2893
2971
|
printJson({
|
|
2894
2972
|
ok: failedStatus.length === 0,
|
|
2895
2973
|
command: "status --all",
|
|
2974
|
+
include_experimental: booleanFlag(flags, "include-experimental"),
|
|
2896
2975
|
installed,
|
|
2897
2976
|
statuses,
|
|
2898
2977
|
failed_status: failedStatus,
|
|
@@ -2992,6 +3071,18 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
2992
3071
|
await runOpencodeUninstall(flags);
|
|
2993
3072
|
return;
|
|
2994
3073
|
}
|
|
3074
|
+
if (isExperimentalCliTargetName(command) && positionals[0] === "install") {
|
|
3075
|
+
await runExperimentalCliTargetInstall(command, flags, experimentalCliDeps());
|
|
3076
|
+
return;
|
|
3077
|
+
}
|
|
3078
|
+
if (isExperimentalCliTargetName(command) && positionals[0] === "status") {
|
|
3079
|
+
await runExperimentalCliTargetStatus(command, experimentalCliDeps());
|
|
3080
|
+
return;
|
|
3081
|
+
}
|
|
3082
|
+
if (isExperimentalCliTargetName(command) && positionals[0] === "uninstall") {
|
|
3083
|
+
await runExperimentalCliTargetUninstall(command, flags, experimentalCliDeps());
|
|
3084
|
+
return;
|
|
3085
|
+
}
|
|
2995
3086
|
usage();
|
|
2996
3087
|
}
|
|
2997
3088
|
function isDirectEntrypoint() {
|