@hraness/ghostget 0.18.10 → 0.18.13
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/CHANGELOG.md +28 -0
- package/README.md +38 -7
- package/dist/apple-photos-client.js +3 -1
- package/dist/beeper-client.js +3 -1
- package/dist/client.js +2 -0
- package/dist/{index-95x4d0pk.js → index-maa9hb5z.js} +1 -1
- package/dist/messaging.js +1 -0
- package/dist/omni-client.js +2 -0
- package/dist/whatsapp-client.js +2 -0
- package/package.json +9 -8
- package/skills/ghostget/SKILL.md +29 -14
- package/skills/ghostget/references/install.md +5 -5
- package/src/apple-photos-client.ts +3 -0
- package/src/beeper-client-types.ts +1 -1
- package/src/beeper-client.ts +3 -0
- package/src/cli.ts +22 -14
- package/src/client.ts +3 -0
- package/src/control/menubar-cli.ts +568 -0
- package/src/ghostget.ts +45 -6
- package/src/media/cli.ts +7 -0
- package/src/messaging.ts +2 -0
- package/src/omni-client.ts +3 -0
- package/src/providers/imessage-direct-runtime.ts +28 -2
- package/src/support-profile.ts +7 -0
- package/src/support.ts +3 -9
- package/src/usage.ts +16 -2
- package/src/version.ts +1 -1
- package/src/whatsapp-client.ts +3 -0
package/src/ghostget.ts
CHANGED
|
@@ -839,6 +839,7 @@ async function runCaptureCommand(
|
|
|
839
839
|
output: Output,
|
|
840
840
|
dependencies: GhostgetDependencies,
|
|
841
841
|
signal?: AbortSignal,
|
|
842
|
+
onUsefulResult?: () => void,
|
|
842
843
|
): Promise<number> {
|
|
843
844
|
const resolved = resolveCaptureArgumentsWithAuth(arguments_, environment);
|
|
844
845
|
const unresolvedArguments = [...prefix, ...resolved.arguments];
|
|
@@ -866,16 +867,18 @@ async function runCaptureCommand(
|
|
|
866
867
|
if (persistentPrivateCapture) {
|
|
867
868
|
ensurePrivateStateDirectory(gmailOptions.outputBase, environment);
|
|
868
869
|
}
|
|
869
|
-
|
|
870
|
+
const code = await dependencies.gmailCaptureMain(
|
|
870
871
|
gmailOptions,
|
|
871
872
|
resolved.auth,
|
|
872
873
|
environment,
|
|
873
874
|
output,
|
|
874
875
|
);
|
|
876
|
+
if (code === 0) onUsefulResult?.();
|
|
877
|
+
return code;
|
|
875
878
|
}
|
|
876
879
|
const prepared = prepareCapture(resolved, environment);
|
|
877
880
|
try {
|
|
878
|
-
|
|
881
|
+
const code = await dependencies.clipMain(
|
|
879
882
|
[...prefix, ...prepared.arguments],
|
|
880
883
|
environment,
|
|
881
884
|
output,
|
|
@@ -888,6 +891,8 @@ async function runCaptureCommand(
|
|
|
888
891
|
},
|
|
889
892
|
prepared.runtimeOptions,
|
|
890
893
|
);
|
|
894
|
+
if (code === 0 && (parsed.value.command === "capture" || parsed.value.command === "inspect")) onUsefulResult?.();
|
|
895
|
+
return code;
|
|
891
896
|
} finally {
|
|
892
897
|
prepared.cleanup();
|
|
893
898
|
}
|
|
@@ -1972,6 +1977,7 @@ async function runCommand(
|
|
|
1972
1977
|
output: Output,
|
|
1973
1978
|
dependencies: GhostgetDependencies,
|
|
1974
1979
|
signal?: AbortSignal,
|
|
1980
|
+
onUsefulResult?: () => void,
|
|
1975
1981
|
): Promise<number> {
|
|
1976
1982
|
if (arguments_.command === "help") {
|
|
1977
1983
|
output.stdout(renderGhostgetUsage());
|
|
@@ -2031,6 +2037,7 @@ async function runCommand(
|
|
|
2031
2037
|
output,
|
|
2032
2038
|
dependencies,
|
|
2033
2039
|
signal,
|
|
2040
|
+
onUsefulResult,
|
|
2034
2041
|
);
|
|
2035
2042
|
}
|
|
2036
2043
|
if (arguments_.command === "read") {
|
|
@@ -2041,12 +2048,14 @@ async function runCommand(
|
|
|
2041
2048
|
output,
|
|
2042
2049
|
dependencies,
|
|
2043
2050
|
signal,
|
|
2051
|
+
onUsefulResult,
|
|
2044
2052
|
);
|
|
2045
2053
|
}
|
|
2046
2054
|
if (arguments_.command === "media") {
|
|
2047
2055
|
const media = await dependencies.loadMediaRuntime();
|
|
2048
2056
|
return media.runCli(arguments_.arguments, {
|
|
2049
2057
|
io: output,
|
|
2058
|
+
...(onUsefulResult === undefined ? {} : { onUsefulResult }),
|
|
2050
2059
|
environment,
|
|
2051
2060
|
...(signal === undefined ? {} : { signal }),
|
|
2052
2061
|
});
|
|
@@ -2066,6 +2075,7 @@ async function runCommand(
|
|
|
2066
2075
|
output.stdout(
|
|
2067
2076
|
runtime.encodeApplePhotosContactEvidenceCliOutput(result, arguments_.json),
|
|
2068
2077
|
);
|
|
2078
|
+
onUsefulResult?.();
|
|
2069
2079
|
return 0;
|
|
2070
2080
|
}
|
|
2071
2081
|
if (arguments_.command === "whatsapp-export-message-like-me") {
|
|
@@ -2097,6 +2107,7 @@ async function runCommand(
|
|
|
2097
2107
|
output.stdout(`Manifest SHA-256: ${safe(result.bundle.manifestSha256)}\n`);
|
|
2098
2108
|
output.stdout("Remote history completeness is not claimed. No cloud sync occurred.\n");
|
|
2099
2109
|
}
|
|
2110
|
+
onUsefulResult?.();
|
|
2100
2111
|
return 0;
|
|
2101
2112
|
} finally {
|
|
2102
2113
|
admission.release();
|
|
@@ -2136,6 +2147,7 @@ async function runCommand(
|
|
|
2136
2147
|
...(signal === undefined ? {} : { signal }),
|
|
2137
2148
|
});
|
|
2138
2149
|
output.stdout(runtime.encodeBeeperContactInteractionExportResult(result));
|
|
2150
|
+
onUsefulResult?.();
|
|
2139
2151
|
return 0;
|
|
2140
2152
|
} finally {
|
|
2141
2153
|
admission.release();
|
|
@@ -2184,6 +2196,7 @@ async function runCommand(
|
|
|
2184
2196
|
counts: result.manifest.counts,
|
|
2185
2197
|
});
|
|
2186
2198
|
print(output, summary, arguments_.json);
|
|
2199
|
+
onUsefulResult?.();
|
|
2187
2200
|
return 0;
|
|
2188
2201
|
} finally {
|
|
2189
2202
|
admission.release();
|
|
@@ -2218,6 +2231,7 @@ async function runCommand(
|
|
|
2218
2231
|
environment,
|
|
2219
2232
|
);
|
|
2220
2233
|
output.stdout(exactTerminalJson(receipt));
|
|
2234
|
+
if (arguments_.command === "messaging-context") onUsefulResult?.();
|
|
2221
2235
|
return 0;
|
|
2222
2236
|
}
|
|
2223
2237
|
if (arguments_.command === "doctor") {
|
|
@@ -2259,7 +2273,11 @@ async function runCommand(
|
|
|
2259
2273
|
}
|
|
2260
2274
|
return 0;
|
|
2261
2275
|
}
|
|
2262
|
-
if (arguments_.command === "thread-split")
|
|
2276
|
+
if (arguments_.command === "thread-split") {
|
|
2277
|
+
const code = await runThreadSplit(arguments_, output);
|
|
2278
|
+
if (code === 0) onUsefulResult?.();
|
|
2279
|
+
return code;
|
|
2280
|
+
}
|
|
2263
2281
|
if (arguments_.command === "thread-publish") {
|
|
2264
2282
|
return runThreadPublish(
|
|
2265
2283
|
arguments_,
|
|
@@ -3156,6 +3174,7 @@ async function runCommand(
|
|
|
3156
3174
|
});
|
|
3157
3175
|
if (arguments_.json) output.stdout(exactTerminalJson(value));
|
|
3158
3176
|
else print(output, value, false);
|
|
3177
|
+
if (value.view?.sources.some((source) => source.coverage.state === "observed")) onUsefulResult?.();
|
|
3159
3178
|
return 0;
|
|
3160
3179
|
}
|
|
3161
3180
|
if (arguments_.command === "invoke") {
|
|
@@ -3242,6 +3261,7 @@ async function runCommand(
|
|
|
3242
3261
|
const view = cachedInvocationView(result);
|
|
3243
3262
|
if (arguments_.json) output.stdout(exactTerminalJson(view));
|
|
3244
3263
|
else print(output, view, false);
|
|
3264
|
+
if (result.status === "hit") onUsefulResult?.();
|
|
3245
3265
|
return result.status === "hit" ? 0 : 3;
|
|
3246
3266
|
}
|
|
3247
3267
|
const result = await dependencies.revalidatePreparedCapability(
|
|
@@ -3256,6 +3276,7 @@ async function runCommand(
|
|
|
3256
3276
|
const view = revalidatedInvocationView(result);
|
|
3257
3277
|
if (arguments_.json) output.stdout(exactTerminalJson(view));
|
|
3258
3278
|
else print(output, view, false);
|
|
3279
|
+
if (result.live.receipt.status === "succeeded" || result.live.receipt.status === "submitted") onUsefulResult?.();
|
|
3259
3280
|
return result.live.receipt.status === "succeeded" || result.live.receipt.status === "submitted" ? 0 : result.live.receipt.status === "indeterminate" ? 5 : 3;
|
|
3260
3281
|
}
|
|
3261
3282
|
const stored = createAndSaveInvocationPlan(
|
|
@@ -3325,6 +3346,7 @@ async function runCommand(
|
|
|
3325
3346
|
result.receiptBinding,
|
|
3326
3347
|
environment,
|
|
3327
3348
|
);
|
|
3349
|
+
if (result.receipt.state === "submitted") onUsefulResult?.();
|
|
3328
3350
|
return result.receipt.state === "submitted"
|
|
3329
3351
|
? 0
|
|
3330
3352
|
: result.receipt.state === "indeterminate"
|
|
@@ -3342,6 +3364,7 @@ async function runCommand(
|
|
|
3342
3364
|
...(signal === undefined ? {} : { signal }),
|
|
3343
3365
|
});
|
|
3344
3366
|
print(output, invocationView(result), arguments_.json);
|
|
3367
|
+
if (result.receipt.status === "succeeded" || result.receipt.status === "submitted") onUsefulResult?.();
|
|
3345
3368
|
return result.receipt.status === "succeeded" || result.receipt.status === "submitted" ? 0 : result.receipt.status === "indeterminate" ? 5 : 3;
|
|
3346
3369
|
}
|
|
3347
3370
|
if (arguments_.command === "runs-list") {
|
|
@@ -3483,6 +3506,7 @@ export async function main(
|
|
|
3483
3506
|
output: Output = defaultOutput,
|
|
3484
3507
|
dependencyOverrides: Partial<GhostgetDependencies> = {},
|
|
3485
3508
|
signal?: AbortSignal,
|
|
3509
|
+
onUsefulResult?: () => void,
|
|
3486
3510
|
): Promise<number> {
|
|
3487
3511
|
const parsed = parseGhostgetArguments(rawArguments);
|
|
3488
3512
|
if (!parsed.ok) {
|
|
@@ -3508,13 +3532,19 @@ export async function main(
|
|
|
3508
3532
|
).registry,
|
|
3509
3533
|
};
|
|
3510
3534
|
}
|
|
3511
|
-
|
|
3535
|
+
let usefulResult = false;
|
|
3536
|
+
const code = await runCommand(
|
|
3512
3537
|
parsed.value,
|
|
3513
3538
|
environment,
|
|
3514
3539
|
output,
|
|
3515
3540
|
dependencies,
|
|
3516
3541
|
signal,
|
|
3542
|
+
() => { usefulResult = true; },
|
|
3517
3543
|
);
|
|
3544
|
+
if (code === 0 && usefulResult && signal?.aborted !== true) {
|
|
3545
|
+
try { void Promise.resolve(onUsefulResult?.()).catch(() => undefined); } catch { /* Optional observation cannot alter completed work. */ }
|
|
3546
|
+
}
|
|
3547
|
+
return code;
|
|
3518
3548
|
} catch (error) {
|
|
3519
3549
|
if (error instanceof LinkedDeviceLifecycleIndeterminateError) {
|
|
3520
3550
|
const failure = {
|
|
@@ -3600,6 +3630,7 @@ type GhostgetProcessBoundaryDependencies = {
|
|
|
3600
3630
|
) => () => void;
|
|
3601
3631
|
readonly resendSignal: (signal: NodeJS.Signals) => void;
|
|
3602
3632
|
readonly setExitCode: (code: number) => void;
|
|
3633
|
+
readonly onUsefulResult?: () => void;
|
|
3603
3634
|
};
|
|
3604
3635
|
|
|
3605
3636
|
function subscribeProcessTermination(
|
|
@@ -3631,6 +3662,7 @@ export async function runGhostgetProcess(
|
|
|
3631
3662
|
overrides: Partial<GhostgetProcessBoundaryDependencies> = {},
|
|
3632
3663
|
): Promise<void> {
|
|
3633
3664
|
const dependencies: GhostgetProcessBoundaryDependencies = {
|
|
3665
|
+
...(overrides.onUsefulResult === undefined ? {} : { onUsefulResult: overrides.onUsefulResult }),
|
|
3634
3666
|
rawArguments: overrides.rawArguments ?? process.argv.slice(2),
|
|
3635
3667
|
environment: overrides.environment ?? process.env,
|
|
3636
3668
|
output: overrides.output ?? defaultOutput,
|
|
@@ -3667,18 +3699,25 @@ export async function runGhostgetProcess(
|
|
|
3667
3699
|
);
|
|
3668
3700
|
};
|
|
3669
3701
|
unsubscribeTermination = dependencies.subscribeTermination(terminate);
|
|
3702
|
+
let usefulResult = false;
|
|
3703
|
+
let code: number | undefined;
|
|
3670
3704
|
try {
|
|
3671
|
-
|
|
3705
|
+
code = await dependencies.runMain(
|
|
3672
3706
|
dependencies.rawArguments,
|
|
3673
3707
|
dependencies.environment,
|
|
3674
3708
|
dependencies.output,
|
|
3675
3709
|
{},
|
|
3676
3710
|
controller.signal,
|
|
3677
|
-
|
|
3711
|
+
() => { usefulResult = true; },
|
|
3712
|
+
);
|
|
3713
|
+
dependencies.setExitCode(code);
|
|
3678
3714
|
} finally {
|
|
3679
3715
|
terminationState.cancelFallback?.();
|
|
3680
3716
|
unsubscribeTermination();
|
|
3681
3717
|
}
|
|
3718
|
+
if (code === 0 && usefulResult && !controller.signal.aborted) {
|
|
3719
|
+
try { void Promise.resolve(dependencies.onUsefulResult?.()).catch(() => undefined); } catch { /* Keep the completed command outcome. */ }
|
|
3720
|
+
}
|
|
3682
3721
|
}
|
|
3683
3722
|
|
|
3684
3723
|
if (import.meta.main) {
|
package/src/media/cli.ts
CHANGED
|
@@ -38,6 +38,7 @@ export interface RunCliOptions {
|
|
|
38
38
|
readonly homeDirectory?: string;
|
|
39
39
|
readonly signal?: AbortSignal;
|
|
40
40
|
readonly dependencies?: MediaCliDependencies;
|
|
41
|
+
readonly onUsefulResult?: () => void;
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
const processIo: CliIo = {
|
|
@@ -163,6 +164,10 @@ export async function runCli(argv: readonly string[], options: RunCliOptions = {
|
|
|
163
164
|
const environment = options.environment ?? process.env;
|
|
164
165
|
const homeDirectory = options.homeDirectory ?? homedir();
|
|
165
166
|
const dependencies = options.dependencies ?? defaultDependencies;
|
|
167
|
+
const completed = (): void => {
|
|
168
|
+
if (options.signal?.aborted === true) return;
|
|
169
|
+
try { void Promise.resolve(options.onUsefulResult?.()).catch(() => undefined); } catch { /* Observation cannot change an archive result. */ }
|
|
170
|
+
};
|
|
166
171
|
const parsed = parseArgs(argv);
|
|
167
172
|
if (!parsed.ok) {
|
|
168
173
|
if (parsed.json) writeJson(io, "stderr", { ok: false, error: { code: "USAGE", message: parsed.message } });
|
|
@@ -191,6 +196,7 @@ export async function runCli(argv: readonly string[], options: RunCliOptions = {
|
|
|
191
196
|
if (command.json) writeJson(io, result.ok ? "stdout" : "stderr", { ok: result.ok, verification: result });
|
|
192
197
|
else if (result.ok) io.stdout(`Verified ${sanitizeTerminalText(result.assetKey ?? command.itemDirectory)}: ${String(result.checkedArtifacts)} artifacts\n`);
|
|
193
198
|
else io.stderr(`ghostget media: verification failed\n${result.failures.map((failure) => `- ${redactDiagnostic(failure, { homeDirectory })}`).join("\n")}\n`);
|
|
199
|
+
if (result.ok) completed();
|
|
194
200
|
return result.ok ? 0 : 8;
|
|
195
201
|
}
|
|
196
202
|
if (command.kind === "transcriber-setup") {
|
|
@@ -258,6 +264,7 @@ export async function runCli(argv: readonly string[], options: RunCliOptions = {
|
|
|
258
264
|
});
|
|
259
265
|
if (command.json) writeJson(io, "stdout", captureSummary(result));
|
|
260
266
|
else io.stdout(humanCaptureSummary(result));
|
|
267
|
+
completed();
|
|
261
268
|
return 0;
|
|
262
269
|
} catch (error) {
|
|
263
270
|
const secrets = [
|
package/src/messaging.ts
CHANGED
package/src/omni-client.ts
CHANGED
|
@@ -526,6 +526,8 @@ function snapshotEnvironment(value: unknown): Readonly<Record<string, string>> {
|
|
|
526
526
|
defineEnvironmentValue(result, key, environmentValue);
|
|
527
527
|
}
|
|
528
528
|
}
|
|
529
|
+
// Package-owned SDK children never emit standalone support notices.
|
|
530
|
+
result.GHOSTGET_CLI_DEPTH = "1";
|
|
529
531
|
if (value === undefined) return Object.freeze(result);
|
|
530
532
|
const overrides = record(value, "Ghostget omni client environment");
|
|
531
533
|
for (const [key, environmentValue] of Object.entries(overrides)) {
|
|
@@ -541,6 +543,7 @@ function snapshotEnvironment(value: unknown): Readonly<Record<string, string>> {
|
|
|
541
543
|
defineEnvironmentValue(result, name, environmentValue);
|
|
542
544
|
}
|
|
543
545
|
}
|
|
546
|
+
result.GHOSTGET_CLI_DEPTH = "1";
|
|
544
547
|
return Object.freeze(result);
|
|
545
548
|
}
|
|
546
549
|
|
|
@@ -448,18 +448,38 @@ export async function runImsgRpc(
|
|
|
448
448
|
let timedOut = false;
|
|
449
449
|
let cancelled = false;
|
|
450
450
|
let forceKill: ReturnType<typeof setTimeout> | null = null;
|
|
451
|
+
let groupTerminated: Promise<boolean> | null = null;
|
|
451
452
|
let terminationStarted = false;
|
|
452
453
|
const signalGroup = (signal: "SIGTERM" | "SIGKILL"): void => {
|
|
453
454
|
try {
|
|
454
455
|
process.kill(-child.pid, signal);
|
|
455
456
|
} catch {
|
|
456
|
-
//
|
|
457
|
+
// The bounded group probe below establishes descendant cleanup.
|
|
457
458
|
}
|
|
458
459
|
};
|
|
459
460
|
const terminate = (): void => {
|
|
460
461
|
if (!terminationStarted) {
|
|
461
462
|
terminationStarted = true;
|
|
462
463
|
signalGroup("SIGTERM");
|
|
464
|
+
groupTerminated = (async (): Promise<boolean> => {
|
|
465
|
+
// A joined leader and closed pipes do not prove its descendants exited.
|
|
466
|
+
// Retain the one-second escalation, then bound final group reaping.
|
|
467
|
+
const deadline = performance.now() + 1_500;
|
|
468
|
+
for (;;) {
|
|
469
|
+
try {
|
|
470
|
+
process.kill(-child.pid, 0);
|
|
471
|
+
} catch (error) {
|
|
472
|
+
const code = typeof error === "object" && error !== null
|
|
473
|
+
&& "code" in error ? error.code : undefined;
|
|
474
|
+
if (code === "ESRCH") return true;
|
|
475
|
+
// Allow a transient permission denial to settle within the same
|
|
476
|
+
// bound; it is never proof that the group exited.
|
|
477
|
+
if (code !== "EPERM") return false;
|
|
478
|
+
}
|
|
479
|
+
if (performance.now() >= deadline) return false;
|
|
480
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 20));
|
|
481
|
+
}
|
|
482
|
+
})();
|
|
463
483
|
}
|
|
464
484
|
forceKill ??= setTimeout(() => signalGroup("SIGKILL"), 1_000);
|
|
465
485
|
};
|
|
@@ -509,8 +529,14 @@ export async function runImsgRpc(
|
|
|
509
529
|
});
|
|
510
530
|
} finally {
|
|
511
531
|
clearTimeout(timeout);
|
|
512
|
-
if (forceKill !== null) clearTimeout(forceKill);
|
|
513
532
|
invocation.signal?.removeEventListener("abort", onAbort);
|
|
533
|
+
try {
|
|
534
|
+
if (groupTerminated !== null && !await groupTerminated) {
|
|
535
|
+
throw new ImsgCleanupUnverifiedError();
|
|
536
|
+
}
|
|
537
|
+
} finally {
|
|
538
|
+
if (forceKill !== null) clearTimeout(forceKill);
|
|
539
|
+
}
|
|
514
540
|
}
|
|
515
541
|
}
|
|
516
542
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Public product identity shared by the CLI, menu and static website. */
|
|
2
|
+
export const ghostgetSupportProfile = Object.freeze({
|
|
3
|
+
id: "wrench",
|
|
4
|
+
name: "Ghostget",
|
|
5
|
+
valueProposition: "Support ongoing development of precise web tools for agents.",
|
|
6
|
+
updates: true,
|
|
7
|
+
} as const);
|
package/src/support.ts
CHANGED
|
@@ -2,13 +2,7 @@ import {
|
|
|
2
2
|
maybeShowSupportInvitation,
|
|
3
3
|
runSupportCommand,
|
|
4
4
|
} from "@hraness/support-foundation/node";
|
|
5
|
-
|
|
6
|
-
const profile = {
|
|
7
|
-
id: "wrench",
|
|
8
|
-
name: "Ghostget",
|
|
9
|
-
valueProposition: "Support ongoing development of precise web tools for agents.",
|
|
10
|
-
updates: true,
|
|
11
|
-
} as const;
|
|
5
|
+
import { ghostgetSupportProfile as profile } from "./support-profile";
|
|
12
6
|
|
|
13
7
|
type SupportOutput = {
|
|
14
8
|
readonly stdout: (text: string) => unknown;
|
|
@@ -19,12 +13,12 @@ export async function runGhostgetSupportCommand(
|
|
|
19
13
|
args: readonly string[],
|
|
20
14
|
output: SupportOutput,
|
|
21
15
|
): Promise<number> {
|
|
22
|
-
const result = await runSupportCommand(profile, args);
|
|
16
|
+
const result = await runSupportCommand(profile, args, { command: ["ghostget"] });
|
|
23
17
|
if (result.stdout !== "") output.stdout(result.stdout);
|
|
24
18
|
if (result.stderr !== "") output.stderr(result.stderr);
|
|
25
19
|
return result.exitCode;
|
|
26
20
|
}
|
|
27
21
|
|
|
28
22
|
export async function showGhostgetSupportInvitation(): Promise<void> {
|
|
29
|
-
await maybeShowSupportInvitation(profile, { usefulResult: true });
|
|
23
|
+
await maybeShowSupportInvitation(profile, { usefulResult: true, command: ["ghostget"] });
|
|
30
24
|
}
|
package/src/usage.ts
CHANGED
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
export const ghostgetUsage = `Usage:
|
|
9
9
|
ghostget --version Print the exact Ghostget release version
|
|
10
10
|
ghostget support [--json] View optional product updates and support
|
|
11
|
-
ghostget support
|
|
12
|
-
ghostget support
|
|
11
|
+
ghostget support protocol --json Read the optional agent closeout protocol
|
|
12
|
+
ghostget support offer --json Claim an invitation when due at task closeout
|
|
13
|
+
ghostget support shown <id> Acknowledge human-facing output after presentation
|
|
14
|
+
ghostget support release <id> Cancel an invitation before presentation
|
|
13
15
|
ghostget support dismiss|snooze|enable Set shared invitation preferences
|
|
14
16
|
ghostget support status --json Inspect local invitation preferences
|
|
15
17
|
ghostget init [directory] [--json] Initialize a Markdown vault
|
|
@@ -192,4 +194,16 @@ Omni views:
|
|
|
192
194
|
and Notification entities. 'omni read --cache-only' returns the merged local view
|
|
193
195
|
without provider work. A normal omni read explicitly revalidates each declared
|
|
194
196
|
source; --from-exact-cache rebuilds derivatives from exact snapshots only.
|
|
197
|
+
|
|
198
|
+
Optional updates and support:
|
|
199
|
+
Successful standalone work may write a compact agent discovery notice to stderr,
|
|
200
|
+
including with --json or a PTY; command stdout and exit status stay unchanged.
|
|
201
|
+
Read support protocol --json, then check offer --json once at human task closeout.
|
|
202
|
+
Present persistently before shown <id>; acknowledgement records output, not consent.
|
|
203
|
+
Collapsed progress does not qualify. Final-only hosts omit shown; reservations expire
|
|
204
|
+
after ten minutes without a weekly cooldown, so a later task may offer again.
|
|
205
|
+
A quiet result needs no mention. No signup or payment occurs through these commands.
|
|
206
|
+
HRANESS_SUPPORT_AUDIENCE=agent|human|off selects presentation (default: agent).
|
|
207
|
+
Human presentation requires interactive stderr. Off suppresses due offers too.
|
|
208
|
+
HRANESS_SUPPORT=off disables ambient support; support dismiss opts out locally.
|
|
195
209
|
`;
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Canonical immutable Ghostget package release identity. */
|
|
2
|
-
export const GHOSTGET_VERSION = "0.18.
|
|
2
|
+
export const GHOSTGET_VERSION = "0.18.13" as const;
|
package/src/whatsapp-client.ts
CHANGED
|
@@ -321,6 +321,8 @@ function preparedEnvironment(
|
|
|
321
321
|
for (const [key, value] of Object.entries(process.env)) {
|
|
322
322
|
if (typeof value === "string") environment[key] = value;
|
|
323
323
|
}
|
|
324
|
+
// Package-owned SDK children never emit standalone support notices.
|
|
325
|
+
environment.GHOSTGET_CLI_DEPTH = "1";
|
|
324
326
|
if (additions === undefined) return Object.freeze(environment);
|
|
325
327
|
const source = record(additions, "options.environment");
|
|
326
328
|
for (const [key, value] of Object.entries(source)) {
|
|
@@ -332,6 +334,7 @@ function preparedEnvironment(
|
|
|
332
334
|
return fail("environment value is malformed");
|
|
333
335
|
} else environment[key] = value;
|
|
334
336
|
}
|
|
337
|
+
environment.GHOSTGET_CLI_DEPTH = "1";
|
|
335
338
|
return Object.freeze(environment);
|
|
336
339
|
}
|
|
337
340
|
|