@raidiant/notifai 11.7.1 → 12.0.0-beta.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 +57 -0
- package/NOTICE +16 -0
- package/THIRD_PARTY_NOTICES +725 -0
- package/bin/notifai.mjs +11420 -0
- package/data/install.ps1 +318 -0
- package/data/release.json +1 -0
- package/inventory.json +1 -0
- package/npm-adapter-files.json +52 -0
- package/package.json +14 -44
- package/README.md +0 -168
- package/dist/agent-update-notice.d.ts +0 -7
- package/dist/agent-update-notice.js +0 -77
- package/dist/agent-update-notice.js.map +0 -1
- package/dist/atomic-file.d.ts +0 -30
- package/dist/atomic-file.js +0 -148
- package/dist/atomic-file.js.map +0 -1
- package/dist/attendant-update.d.ts +0 -15
- package/dist/attendant-update.js +0 -96
- package/dist/attendant-update.js.map +0 -1
- package/dist/claude-wake.d.ts +0 -108
- package/dist/claude-wake.js +0 -369
- package/dist/claude-wake.js.map +0 -1
- package/dist/cli-bin.d.ts +0 -26
- package/dist/cli-bin.js +0 -220
- package/dist/cli-bin.js.map +0 -1
- package/dist/cli-contract.d.ts +0 -16
- package/dist/cli-contract.js +0 -27
- package/dist/cli-contract.js.map +0 -1
- package/dist/cli-release.d.ts +0 -36
- package/dist/cli-release.js +0 -85
- package/dist/cli-release.js.map +0 -1
- package/dist/client.d.ts +0 -109
- package/dist/client.js +0 -217
- package/dist/client.js.map +0 -1
- package/dist/codex-answer-control.d.ts +0 -14
- package/dist/codex-answer-control.js +0 -41
- package/dist/codex-answer-control.js.map +0 -1
- package/dist/codex-answer-presentation.d.ts +0 -18
- package/dist/codex-answer-presentation.js +0 -113
- package/dist/codex-answer-presentation.js.map +0 -1
- package/dist/codex-input-lifecycle.d.ts +0 -10
- package/dist/codex-input-lifecycle.js +0 -63
- package/dist/codex-input-lifecycle.js.map +0 -1
- package/dist/codex-native-control.d.ts +0 -13
- package/dist/codex-native-control.js +0 -120
- package/dist/codex-native-control.js.map +0 -1
- package/dist/codex-native-turn.d.ts +0 -37
- package/dist/codex-native-turn.js +0 -155
- package/dist/codex-native-turn.js.map +0 -1
- package/dist/codex-question-bindings.d.ts +0 -76
- package/dist/codex-question-bindings.js +0 -151
- package/dist/codex-question-bindings.js.map +0 -1
- package/dist/codex-queue-control.d.ts +0 -21
- package/dist/codex-queue-control.js +0 -59
- package/dist/codex-queue-control.js.map +0 -1
- package/dist/codex-tool-messages.d.ts +0 -7
- package/dist/codex-tool-messages.js +0 -126
- package/dist/codex-tool-messages.js.map +0 -1
- package/dist/codex-wake.d.ts +0 -58
- package/dist/codex-wake.js +0 -135
- package/dist/codex-wake.js.map +0 -1
- package/dist/command-session.d.ts +0 -14
- package/dist/command-session.js +0 -31
- package/dist/command-session.js.map +0 -1
- package/dist/commands-acknowledge.d.ts +0 -13
- package/dist/commands-acknowledge.js +0 -116
- package/dist/commands-acknowledge.js.map +0 -1
- package/dist/commands-agent-sessions.d.ts +0 -6
- package/dist/commands-agent-sessions.js +0 -51
- package/dist/commands-agent-sessions.js.map +0 -1
- package/dist/commands-ask.d.ts +0 -62
- package/dist/commands-ask.js +0 -503
- package/dist/commands-ask.js.map +0 -1
- package/dist/commands-auth.d.ts +0 -76
- package/dist/commands-auth.js +0 -421
- package/dist/commands-auth.js.map +0 -1
- package/dist/commands-close.d.ts +0 -6
- package/dist/commands-close.js +0 -273
- package/dist/commands-close.js.map +0 -1
- package/dist/commands-config.d.ts +0 -31
- package/dist/commands-config.js +0 -272
- package/dist/commands-config.js.map +0 -1
- package/dist/commands-core.d.ts +0 -145
- package/dist/commands-core.js +0 -190
- package/dist/commands-core.js.map +0 -1
- package/dist/commands-devices.d.ts +0 -41
- package/dist/commands-devices.js +0 -144
- package/dist/commands-devices.js.map +0 -1
- package/dist/commands-doctor.d.ts +0 -25
- package/dist/commands-doctor.js +0 -1553
- package/dist/commands-doctor.js.map +0 -1
- package/dist/commands-guidance.d.ts +0 -27
- package/dist/commands-guidance.js +0 -150
- package/dist/commands-guidance.js.map +0 -1
- package/dist/commands-harness-context.d.ts +0 -57
- package/dist/commands-harness-context.js +0 -102
- package/dist/commands-harness-context.js.map +0 -1
- package/dist/commands-hook-attend.d.ts +0 -70
- package/dist/commands-hook-attend.js +0 -655
- package/dist/commands-hook-attend.js.map +0 -1
- package/dist/commands-hook-diagnostics.d.ts +0 -37
- package/dist/commands-hook-diagnostics.js +0 -136
- package/dist/commands-hook-diagnostics.js.map +0 -1
- package/dist/commands-hook-install.d.ts +0 -26
- package/dist/commands-hook-install.js +0 -784
- package/dist/commands-hook-install.js.map +0 -1
- package/dist/commands-hook-run.d.ts +0 -29
- package/dist/commands-hook-run.js +0 -933
- package/dist/commands-hook-run.js.map +0 -1
- package/dist/commands-hook-shape.d.ts +0 -19
- package/dist/commands-hook-shape.js +0 -48
- package/dist/commands-hook-shape.js.map +0 -1
- package/dist/commands-init.d.ts +0 -42
- package/dist/commands-init.js +0 -901
- package/dist/commands-init.js.map +0 -1
- package/dist/commands-io.d.ts +0 -2
- package/dist/commands-io.js +0 -117
- package/dist/commands-io.js.map +0 -1
- package/dist/commands-logs.d.ts +0 -30
- package/dist/commands-logs.js +0 -201
- package/dist/commands-logs.js.map +0 -1
- package/dist/commands-native-acknowledge.d.ts +0 -8
- package/dist/commands-native-acknowledge.js +0 -114
- package/dist/commands-native-acknowledge.js.map +0 -1
- package/dist/commands-project.d.ts +0 -4
- package/dist/commands-project.js +0 -41
- package/dist/commands-project.js.map +0 -1
- package/dist/commands-receive.d.ts +0 -3
- package/dist/commands-receive.js +0 -59
- package/dist/commands-receive.js.map +0 -1
- package/dist/commands-send-support.d.ts +0 -59
- package/dist/commands-send-support.js +0 -258
- package/dist/commands-send-support.js.map +0 -1
- package/dist/commands-send.d.ts +0 -34
- package/dist/commands-send.js +0 -900
- package/dist/commands-send.js.map +0 -1
- package/dist/commands-setup-proof.d.ts +0 -43
- package/dist/commands-setup-proof.js +0 -134
- package/dist/commands-setup-proof.js.map +0 -1
- package/dist/commands-skill.d.ts +0 -21
- package/dist/commands-skill.js +0 -199
- package/dist/commands-skill.js.map +0 -1
- package/dist/commands-sounds.d.ts +0 -12
- package/dist/commands-sounds.js +0 -35
- package/dist/commands-sounds.js.map +0 -1
- package/dist/commands-update-check.d.ts +0 -6
- package/dist/commands-update-check.js +0 -102
- package/dist/commands-update-check.js.map +0 -1
- package/dist/commands-update-resume.d.ts +0 -7
- package/dist/commands-update-resume.js +0 -143
- package/dist/commands-update-resume.js.map +0 -1
- package/dist/commands-update-skill.d.ts +0 -5
- package/dist/commands-update-skill.js +0 -36
- package/dist/commands-update-skill.js.map +0 -1
- package/dist/commands-update.d.ts +0 -11
- package/dist/commands-update.js +0 -286
- package/dist/commands-update.js.map +0 -1
- package/dist/commands.d.ts +0 -26
- package/dist/commands.js +0 -27
- package/dist/commands.js.map +0 -1
- package/dist/config-schema.d.ts +0 -62
- package/dist/config-schema.js +0 -302
- package/dist/config-schema.js.map +0 -1
- package/dist/config.d.ts +0 -181
- package/dist/config.js +0 -357
- package/dist/config.js.map +0 -1
- package/dist/credentials.d.ts +0 -96
- package/dist/credentials.js +0 -342
- package/dist/credentials.js.map +0 -1
- package/dist/file-lock.d.ts +0 -34
- package/dist/file-lock.js +0 -367
- package/dist/file-lock.js.map +0 -1
- package/dist/generated-session-label.d.ts +0 -2
- package/dist/generated-session-label.js +0 -152
- package/dist/generated-session-label.js.map +0 -1
- package/dist/guidance-content.d.ts +0 -53
- package/dist/guidance-content.js +0 -248
- package/dist/guidance-content.js.map +0 -1
- package/dist/guidance-render.d.ts +0 -25
- package/dist/guidance-render.js +0 -47
- package/dist/guidance-render.js.map +0 -1
- package/dist/guidance.d.ts +0 -69
- package/dist/guidance.js +0 -173
- package/dist/guidance.js.map +0 -1
- package/dist/harness-session-title.d.ts +0 -22
- package/dist/harness-session-title.js +0 -74
- package/dist/harness-session-title.js.map +0 -1
- package/dist/harnesses.d.ts +0 -65
- package/dist/harnesses.js +0 -159
- package/dist/harnesses.js.map +0 -1
- package/dist/hermes-attendant.d.ts +0 -38
- package/dist/hermes-attendant.js +0 -337
- package/dist/hermes-attendant.js.map +0 -1
- package/dist/hermes-plugin.d.ts +0 -11
- package/dist/hermes-plugin.js +0 -299
- package/dist/hermes-plugin.js.map +0 -1
- package/dist/hook-acknowledgements.d.ts +0 -70
- package/dist/hook-acknowledgements.js +0 -490
- package/dist/hook-acknowledgements.js.map +0 -1
- package/dist/hook-adapter.d.ts +0 -48
- package/dist/hook-adapter.js +0 -419
- package/dist/hook-adapter.js.map +0 -1
- package/dist/hook-events.d.ts +0 -105
- package/dist/hook-events.js +0 -130
- package/dist/hook-events.js.map +0 -1
- package/dist/hook-gates.d.ts +0 -7
- package/dist/hook-gates.js +0 -20
- package/dist/hook-gates.js.map +0 -1
- package/dist/hook-input.d.ts +0 -10
- package/dist/hook-input.js +0 -64
- package/dist/hook-input.js.map +0 -1
- package/dist/hook-lifecycle.d.ts +0 -112
- package/dist/hook-lifecycle.js +0 -2031
- package/dist/hook-lifecycle.js.map +0 -1
- package/dist/hook-project-sessions.d.ts +0 -28
- package/dist/hook-project-sessions.js +0 -141
- package/dist/hook-project-sessions.js.map +0 -1
- package/dist/hook-question-lock.d.ts +0 -29
- package/dist/hook-question-lock.js +0 -217
- package/dist/hook-question-lock.js.map +0 -1
- package/dist/hook-question-retirement.d.ts +0 -74
- package/dist/hook-question-retirement.js +0 -314
- package/dist/hook-question-retirement.js.map +0 -1
- package/dist/hook-question-state.d.ts +0 -58
- package/dist/hook-question-state.js +0 -239
- package/dist/hook-question-state.js.map +0 -1
- package/dist/hook-session-state.d.ts +0 -127
- package/dist/hook-session-state.js +0 -488
- package/dist/hook-session-state.js.map +0 -1
- package/dist/hook-types.d.ts +0 -476
- package/dist/hook-types.js +0 -4
- package/dist/hook-types.js.map +0 -1
- package/dist/injection-render.d.ts +0 -36
- package/dist/injection-render.js +0 -61
- package/dist/injection-render.js.map +0 -1
- package/dist/install-hooks.d.ts +0 -470
- package/dist/install-hooks.js +0 -1622
- package/dist/install-hooks.js.map +0 -1
- package/dist/integration-health.d.ts +0 -26
- package/dist/integration-health.js +0 -133
- package/dist/integration-health.js.map +0 -1
- package/dist/interactive.d.ts +0 -22
- package/dist/interactive.js +0 -644
- package/dist/interactive.js.map +0 -1
- package/dist/invocation-context.d.ts +0 -47
- package/dist/invocation-context.js +0 -164
- package/dist/invocation-context.js.map +0 -1
- package/dist/local-path.d.ts +0 -7
- package/dist/local-path.js +0 -27
- package/dist/local-path.js.map +0 -1
- package/dist/logging.d.ts +0 -157
- package/dist/logging.js +0 -599
- package/dist/logging.js.map +0 -1
- package/dist/main-run.d.ts +0 -1
- package/dist/main-run.js +0 -42
- package/dist/main-run.js.map +0 -1
- package/dist/main.d.ts +0 -2
- package/dist/main.js +0 -12
- package/dist/main.js.map +0 -1
- package/dist/native-answer-operation.d.ts +0 -70
- package/dist/native-answer-operation.js +0 -247
- package/dist/native-answer-operation.js.map +0 -1
- package/dist/native-skills.d.ts +0 -64
- package/dist/native-skills.js +0 -167
- package/dist/native-skills.js.map +0 -1
- package/dist/node-floor.d.ts +0 -19
- package/dist/node-floor.js +0 -32
- package/dist/node-floor.js.map +0 -1
- package/dist/npm-invocation.d.ts +0 -34
- package/dist/npm-invocation.js +0 -53
- package/dist/npm-invocation.js.map +0 -1
- package/dist/openclaw-continuation-bridge.d.ts +0 -7
- package/dist/openclaw-continuation-bridge.js +0 -64
- package/dist/openclaw-continuation-bridge.js.map +0 -1
- package/dist/openclaw-gateway-readiness.d.ts +0 -1
- package/dist/openclaw-gateway-readiness.js +0 -24
- package/dist/openclaw-gateway-readiness.js.map +0 -1
- package/dist/openclaw-generation.d.ts +0 -21
- package/dist/openclaw-generation.js +0 -115
- package/dist/openclaw-generation.js.map +0 -1
- package/dist/openclaw-message-bridge.d.ts +0 -8
- package/dist/openclaw-message-bridge.js +0 -93
- package/dist/openclaw-message-bridge.js.map +0 -1
- package/dist/openclaw-pending.d.ts +0 -8
- package/dist/openclaw-pending.js +0 -47
- package/dist/openclaw-pending.js.map +0 -1
- package/dist/openclaw-plugin.d.ts +0 -75
- package/dist/openclaw-plugin.js +0 -1353
- package/dist/openclaw-plugin.js.map +0 -1
- package/dist/openclaw-session-access.d.ts +0 -12
- package/dist/openclaw-session-access.js +0 -79
- package/dist/openclaw-session-access.js.map +0 -1
- package/dist/opencode-plugin.d.ts +0 -88
- package/dist/opencode-plugin.js +0 -286
- package/dist/opencode-plugin.js.map +0 -1
- package/dist/orca-session-title.d.ts +0 -11
- package/dist/orca-session-title.js +0 -111
- package/dist/orca-session-title.js.map +0 -1
- package/dist/pack-feedback-slice.d.ts +0 -35
- package/dist/pack-feedback-slice.js +0 -126
- package/dist/pack-feedback-slice.js.map +0 -1
- package/dist/pairing-qr.d.ts +0 -5
- package/dist/pairing-qr.js +0 -24
- package/dist/pairing-qr.js.map +0 -1
- package/dist/pending-pairing.d.ts +0 -38
- package/dist/pending-pairing.js +0 -70
- package/dist/pending-pairing.js.map +0 -1
- package/dist/platform.d.ts +0 -67
- package/dist/platform.js +0 -140
- package/dist/platform.js.map +0 -1
- package/dist/process-identity.d.ts +0 -26
- package/dist/process-identity.js +0 -82
- package/dist/process-identity.js.map +0 -1
- package/dist/program.d.ts +0 -59
- package/dist/program.js +0 -691
- package/dist/program.js.map +0 -1
- package/dist/project-enablement.d.ts +0 -21
- package/dist/project-enablement.js +0 -71
- package/dist/project-enablement.js.map +0 -1
- package/dist/question-settlement-process.d.ts +0 -17
- package/dist/question-settlement-process.js +0 -35
- package/dist/question-settlement-process.js.map +0 -1
- package/dist/question-timing.d.ts +0 -46
- package/dist/question-timing.js +0 -48
- package/dist/question-timing.js.map +0 -1
- package/dist/readiness.d.ts +0 -153
- package/dist/readiness.js +0 -149
- package/dist/readiness.js.map +0 -1
- package/dist/release.d.ts +0 -31
- package/dist/release.js +0 -52
- package/dist/release.js.map +0 -1
- package/dist/send-attempts.d.ts +0 -26
- package/dist/send-attempts.js +0 -139
- package/dist/send-attempts.js.map +0 -1
- package/dist/send.d.ts +0 -115
- package/dist/send.js +0 -421
- package/dist/send.js.map +0 -1
- package/dist/session-activation.d.ts +0 -13
- package/dist/session-activation.js +0 -64
- package/dist/session-activation.js.map +0 -1
- package/dist/session-attendant-probe.d.ts +0 -85
- package/dist/session-attendant-probe.js +0 -173
- package/dist/session-attendant-probe.js.map +0 -1
- package/dist/session-attendant-state.d.ts +0 -70
- package/dist/session-attendant-state.js +0 -256
- package/dist/session-attendant-state.js.map +0 -1
- package/dist/session-attendant.d.ts +0 -143
- package/dist/session-attendant.js +0 -520
- package/dist/session-attendant.js.map +0 -1
- package/dist/session-delivery.d.ts +0 -249
- package/dist/session-delivery.js +0 -576
- package/dist/session-delivery.js.map +0 -1
- package/dist/session-handoff.d.ts +0 -98
- package/dist/session-handoff.js +0 -118
- package/dist/session-handoff.js.map +0 -1
- package/dist/session-input-wakes.d.ts +0 -78
- package/dist/session-input-wakes.js +0 -239
- package/dist/session-input-wakes.js.map +0 -1
- package/dist/session-inputs.d.ts +0 -57
- package/dist/session-inputs.js +0 -434
- package/dist/session-inputs.js.map +0 -1
- package/dist/session-labels.d.ts +0 -56
- package/dist/session-labels.js +0 -396
- package/dist/session-labels.js.map +0 -1
- package/dist/session-message-handoff.d.ts +0 -39
- package/dist/session-message-handoff.js +0 -107
- package/dist/session-message-handoff.js.map +0 -1
- package/dist/setup-destinations.d.ts +0 -23
- package/dist/setup-destinations.js +0 -44
- package/dist/setup-destinations.js.map +0 -1
- package/dist/skill-integrity.d.ts +0 -54
- package/dist/skill-integrity.js +0 -164
- package/dist/skill-integrity.js.map +0 -1
- package/dist/skill-source/manifest.json +0 -40
- package/dist/skill-source/notifai/SKILL.md +0 -350
- package/dist/skill-source/notifai/references/diagnostics.md +0 -36
- package/dist/skill-source/notifai/references/harness-setup.md +0 -384
- package/dist/skill-source/notifai/references/native-questions.md +0 -51
- package/dist/skill-source/notifai/references/notes-and-edits.md +0 -54
- package/dist/skill-source/notifai/references/send-details.md +0 -14
- package/dist/skill-source/notifai/references/updates.md +0 -116
- package/dist/skill-source/notifai/references/writing-examples.md +0 -56
- package/dist/sound-ref.d.ts +0 -23
- package/dist/sound-ref.js +0 -28
- package/dist/sound-ref.js.map +0 -1
- package/dist/ui/banner.d.ts +0 -22
- package/dist/ui/banner.js +0 -87
- package/dist/ui/banner.js.map +0 -1
- package/dist/ui/config-view.d.ts +0 -30
- package/dist/ui/config-view.js +0 -108
- package/dist/ui/config-view.js.map +0 -1
- package/dist/ui/help.d.ts +0 -44
- package/dist/ui/help.js +0 -107
- package/dist/ui/help.js.map +0 -1
- package/dist/ui/theme.d.ts +0 -90
- package/dist/ui/theme.js +0 -244
- package/dist/ui/theme.js.map +0 -1
- package/dist/update-handoff.d.ts +0 -29
- package/dist/update-handoff.js +0 -69
- package/dist/update-handoff.js.map +0 -1
- package/dist/url-policy.d.ts +0 -85
- package/dist/url-policy.js +0 -369
- package/dist/url-policy.js.map +0 -1
- package/dist/version.d.ts +0 -40
- package/dist/version.js +0 -132
- package/dist/version.js.map +0 -1
- package/dist/wake-support.d.ts +0 -40
- package/dist/wake-support.js +0 -95
- package/dist/wake-support.js.map +0 -1
package/data/install.ps1
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
#requires -Version 5.1
|
|
2
|
+
<# First execution trusts the HTTPS release channel. Hash checks detect changed
|
|
3
|
+
downloads; the installed verifier authenticates subsequent updates. This
|
|
4
|
+
script never changes execution policy or requires an installed Node runtime. #>
|
|
5
|
+
[CmdletBinding()]
|
|
6
|
+
param(
|
|
7
|
+
[string]$Version,
|
|
8
|
+
[ValidateSet('stable', 'beta')][string]$Channel,
|
|
9
|
+
[switch]$Json,
|
|
10
|
+
[switch]$NoInit,
|
|
11
|
+
[switch]$NoPath,
|
|
12
|
+
[switch]$MigrateNpm
|
|
13
|
+
)
|
|
14
|
+
Set-StrictMode -Version Latest
|
|
15
|
+
$ErrorActionPreference = 'Stop'
|
|
16
|
+
|
|
17
|
+
function Test-NotifaiVersion([string]$Value) {
|
|
18
|
+
return $Value.Length -le 100 -and $Value -cmatch '^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$'
|
|
19
|
+
}
|
|
20
|
+
function Get-NotifaiHash([string]$File) {
|
|
21
|
+
$stream = [IO.File]::OpenRead($File)
|
|
22
|
+
$sha = [Security.Cryptography.SHA256]::Create()
|
|
23
|
+
try { return ([BitConverter]::ToString($sha.ComputeHash($stream))).Replace('-', '').ToLowerInvariant() }
|
|
24
|
+
finally { $sha.Dispose(); $stream.Dispose() }
|
|
25
|
+
}
|
|
26
|
+
function Get-NotifaiDownload([string]$Url, [string]$Destination, [long]$Limit) {
|
|
27
|
+
$uri = [Uri]$Url
|
|
28
|
+
for ($redirect = 0; $redirect -le 5; $redirect++) {
|
|
29
|
+
if ($uri.Scheme -cne 'https' -or -not $uri.IsDefaultPort -or $uri.UserInfo -or
|
|
30
|
+
$uri.Host -notin @('github.com', 'raw.githubusercontent.com', 'release-assets.githubusercontent.com')) {
|
|
31
|
+
throw 'Release download left its trusted HTTPS origins'
|
|
32
|
+
}
|
|
33
|
+
$request = [Net.HttpWebRequest]::Create($uri)
|
|
34
|
+
$request.AllowAutoRedirect = $false
|
|
35
|
+
$request.Timeout = 30000
|
|
36
|
+
$request.ReadWriteTimeout = 30000
|
|
37
|
+
$request.UserAgent = 'notifai-installer'
|
|
38
|
+
$response = $request.GetResponse()
|
|
39
|
+
try {
|
|
40
|
+
$status = [int]$response.StatusCode
|
|
41
|
+
if ($status -in @(301, 302, 303, 307, 308)) {
|
|
42
|
+
if ($redirect -eq 5 -or -not $response.Headers['Location']) { throw 'Release download has too many redirects' }
|
|
43
|
+
$uri = [Uri]::new($uri, $response.Headers['Location'])
|
|
44
|
+
continue
|
|
45
|
+
}
|
|
46
|
+
if ($status -ne 200 -or $response.ContentLength -gt $Limit) { throw 'Release download was unavailable or too large' }
|
|
47
|
+
$inputStream = $response.GetResponseStream()
|
|
48
|
+
$outputStream = [IO.File]::Open($Destination, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None)
|
|
49
|
+
try {
|
|
50
|
+
$buffer = New-Object byte[] 65536
|
|
51
|
+
[long]$total = 0
|
|
52
|
+
while (($count = $inputStream.Read($buffer, 0, $buffer.Length)) -gt 0) {
|
|
53
|
+
$total += $count
|
|
54
|
+
if ($total -gt $Limit) { throw 'Release download exceeded its size limit' }
|
|
55
|
+
$outputStream.Write($buffer, 0, $count)
|
|
56
|
+
}
|
|
57
|
+
$outputStream.Flush($true)
|
|
58
|
+
} finally { $outputStream.Dispose(); $inputStream.Dispose() }
|
|
59
|
+
return
|
|
60
|
+
} finally { $response.Dispose() }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function Read-NotifaiChannel([string]$File, [string]$SelectedChannel) {
|
|
64
|
+
$lines = [IO.File]::ReadAllLines($File)
|
|
65
|
+
if ($lines.Length -lt 1 -or $lines.Length -gt 1001) { throw 'Invalid channel metadata' }
|
|
66
|
+
$header = $lines[0].Split([char]9)
|
|
67
|
+
if ($header.Length -ne 5 -or $header[0] -cne 'notifai-channel-v1' -or $header[1] -cne $SelectedChannel -or
|
|
68
|
+
$header[2] -cnotmatch '^[1-9][0-9]{0,15}$' -or -not (Test-NotifaiVersion $header[3]) -or $header[4] -cnotmatch '^[a-f0-9]{64}$') {
|
|
69
|
+
throw 'Invalid channel metadata'
|
|
70
|
+
}
|
|
71
|
+
$withdrawn = @()
|
|
72
|
+
for ($i = 1; $i -lt $lines.Length; $i++) {
|
|
73
|
+
$fields = $lines[$i].Split([char]9)
|
|
74
|
+
if ($fields.Length -ne 2 -or $fields[0] -cne 'withdrawn' -or -not (Test-NotifaiVersion $fields[1])) { throw 'Invalid channel withdrawal' }
|
|
75
|
+
$withdrawn += $fields[1]
|
|
76
|
+
}
|
|
77
|
+
if ($header[3] -cin $withdrawn -or ($SelectedChannel -eq 'stable' -and $header[3].Split('+')[0].Contains('-'))) { throw 'Channel recommends an ineligible release' }
|
|
78
|
+
return @{ Version = $header[3]; InventoryHash = $header[4]; Withdrawn = $withdrawn }
|
|
79
|
+
}
|
|
80
|
+
function Read-NotifaiArtifact([string]$File, [string]$SelectedVersion, [string]$Target) {
|
|
81
|
+
$lines = [IO.File]::ReadAllLines($File)
|
|
82
|
+
if ($lines.Length -lt 2 -or $lines.Length -gt 7) { throw 'Invalid release metadata' }
|
|
83
|
+
$header = $lines[0].Split([char]9)
|
|
84
|
+
if ($header.Length -ne 3 -or $header[0] -cne 'notifai-bootstrap-v1' -or $header[1] -cne $SelectedVersion -or $header[2] -cnotmatch '^[a-f0-9]{64}$') {
|
|
85
|
+
throw 'Release metadata identity differs'
|
|
86
|
+
}
|
|
87
|
+
$found = $null
|
|
88
|
+
$seen = @{}
|
|
89
|
+
for ($i = 1; $i -lt $lines.Length; $i++) {
|
|
90
|
+
$fields = $lines[$i].Split([char]9)
|
|
91
|
+
if ($fields.Length -ne 7 -or $fields[0] -cne 'artifact' -or
|
|
92
|
+
$fields[1] -cnotmatch '^bun-(darwin|linux|windows)-(arm64|x64)$' -or $seen.ContainsKey($fields[1]) -or
|
|
93
|
+
$fields[3] -cnotmatch '^[1-9][0-9]{0,8}$' -or [long]$fields[3] -gt 268435456 -or
|
|
94
|
+
$fields[4] -cnotmatch '^[a-f0-9]{64}$' -or $fields[5] -cnotmatch '^[a-f0-9]{64}$' -or $fields[6] -cnotmatch '^[a-f0-9]{64}$') {
|
|
95
|
+
throw 'Invalid release artifact metadata'
|
|
96
|
+
}
|
|
97
|
+
$suffix = if ($fields[1].StartsWith('bun-windows-')) { 'zip' } else { 'tar.gz' }
|
|
98
|
+
if ($fields[2] -cne "notifai-$SelectedVersion-$($fields[1].Substring(4)).$suffix") { throw 'Invalid release artifact filename' }
|
|
99
|
+
$seen[$fields[1]] = $true
|
|
100
|
+
if ($fields[1] -ceq $Target) {
|
|
101
|
+
$found = @{ Filename = $fields[2]; Bytes = [long]$fields[3]; Hash = $fields[4]; LauncherHash = $fields[5]; RuntimeHash = $fields[6]; InventoryHash = $header[2] }
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if ($null -eq $found) { throw 'This release does not support the native Windows architecture' }
|
|
105
|
+
return $found
|
|
106
|
+
}
|
|
107
|
+
function Expand-NotifaiArchive([string]$Archive, [string]$Destination) {
|
|
108
|
+
Add-Type -AssemblyName System.IO.Compression, System.IO.Compression.FileSystem
|
|
109
|
+
$zip = [IO.Compression.ZipFile]::OpenRead($Archive)
|
|
110
|
+
try {
|
|
111
|
+
if ($zip.Entries.Count -lt 2 -or $zip.Entries.Count -gt 130) { throw 'Invalid release archive entry count' }
|
|
112
|
+
$seen = @{}
|
|
113
|
+
[long]$expanded = 0
|
|
114
|
+
foreach ($entry in $zip.Entries) {
|
|
115
|
+
$name = $entry.FullName
|
|
116
|
+
if ($name.Length -gt 240 -or $name.Split('/').Length -gt 8) { throw 'Invalid release archive path' }
|
|
117
|
+
foreach ($part in $name.Split('/')) {
|
|
118
|
+
if ($part -cnotmatch '^[A-Za-z0-9_-][A-Za-z0-9._-]*$' -or $part.EndsWith('.') -or $part -imatch '^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\.|$)') { throw 'Unsafe release archive path' }
|
|
119
|
+
}
|
|
120
|
+
$type = ($entry.ExternalAttributes -shr 16) -band 61440
|
|
121
|
+
if ($type -notin @(0, 32768) -or $seen.ContainsKey($name) -or $entry.Length -gt 536870912) { throw 'Unsafe release archive member' }
|
|
122
|
+
foreach ($prior in $seen.Keys) {
|
|
123
|
+
if ($name.StartsWith("$prior/", [StringComparison]::OrdinalIgnoreCase) -or $prior.StartsWith("$name/", [StringComparison]::OrdinalIgnoreCase)) { throw 'Conflicting release archive paths' }
|
|
124
|
+
}
|
|
125
|
+
$seen[$name] = $true
|
|
126
|
+
$expanded += $entry.Length
|
|
127
|
+
if ($expanded -gt 805306368) { throw 'Expanded release archive exceeds its size limit' }
|
|
128
|
+
}
|
|
129
|
+
if (-not $seen.ContainsKey('notifai.exe') -or -not $seen.ContainsKey('notifai-runtime.exe')) { throw 'Release executables are missing' }
|
|
130
|
+
[void][IO.Directory]::CreateDirectory($Destination)
|
|
131
|
+
foreach ($entry in $zip.Entries) {
|
|
132
|
+
$file = [IO.Path]::Combine($Destination, $entry.FullName.Replace('/', [IO.Path]::DirectorySeparatorChar))
|
|
133
|
+
[void][IO.Directory]::CreateDirectory([IO.Path]::GetDirectoryName($file))
|
|
134
|
+
$inputStream = $entry.Open()
|
|
135
|
+
$outputStream = [IO.File]::Open($file, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None)
|
|
136
|
+
try {
|
|
137
|
+
$buffer = New-Object byte[] 65536
|
|
138
|
+
[long]$total = 0
|
|
139
|
+
while (($count = $inputStream.Read($buffer, 0, $buffer.Length)) -gt 0) {
|
|
140
|
+
$total += $count
|
|
141
|
+
if ($total -gt $entry.Length) { throw 'Release archive member exceeded its declared size' }
|
|
142
|
+
$outputStream.Write($buffer, 0, $count)
|
|
143
|
+
}
|
|
144
|
+
if ($total -ne $entry.Length) { throw 'Release archive member is truncated' }
|
|
145
|
+
$outputStream.Flush($true)
|
|
146
|
+
} finally { $outputStream.Dispose(); $inputStream.Dispose() }
|
|
147
|
+
}
|
|
148
|
+
} finally { $zip.Dispose() }
|
|
149
|
+
}
|
|
150
|
+
function Get-NotifaiWindowsTarget {
|
|
151
|
+
if (-not ('NotifaiBootstrap.Native' -as [type])) {
|
|
152
|
+
Add-Type -TypeDefinition @'
|
|
153
|
+
using System;
|
|
154
|
+
using System.Runtime.InteropServices;
|
|
155
|
+
namespace NotifaiBootstrap {
|
|
156
|
+
public static class Native {
|
|
157
|
+
[DllImport("kernel32.dll", SetLastError=true)]
|
|
158
|
+
[return: MarshalAs(UnmanagedType.Bool)]
|
|
159
|
+
public static extern bool IsWow64Process2(IntPtr process, out ushort processMachine, out ushort nativeMachine);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
'@
|
|
163
|
+
}
|
|
164
|
+
[UInt16]$processMachine = 0
|
|
165
|
+
[UInt16]$nativeMachine = 0
|
|
166
|
+
if (-not [NotifaiBootstrap.Native]::IsWow64Process2([IntPtr](-1), [ref]$processMachine, [ref]$nativeMachine)) { throw 'Cannot establish native Windows architecture' }
|
|
167
|
+
switch ($nativeMachine) {
|
|
168
|
+
34404 { return 'bun-windows-x64' }
|
|
169
|
+
43620 { return 'bun-windows-arm64' }
|
|
170
|
+
default { throw 'This native Windows architecture is not supported' }
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function Get-NotifaiAccessControl([string]$File, [IO.FileAttributes]$Attributes) {
|
|
174
|
+
$info = if (($Attributes -band [IO.FileAttributes]::Directory) -ne 0) { [IO.DirectoryInfo]::new($File) } else { [IO.FileInfo]::new($File) }
|
|
175
|
+
# Keep this bootstrap lookup independent of filesystem/security cmdlet
|
|
176
|
+
# module discovery. Windows PowerShell and PowerShell use different .NET APIs.
|
|
177
|
+
if ($PSVersionTable.PSEdition -eq 'Desktop') { return $info.GetAccessControl() }
|
|
178
|
+
return [IO.FileSystemAclExtensions]::GetAccessControl($info)
|
|
179
|
+
}
|
|
180
|
+
function New-NotifaiPrivateDirectory([string]$Directory) {
|
|
181
|
+
if ([IO.Directory]::Exists($Directory) -or [IO.File]::Exists($Directory)) { throw 'Installer temporary directory already exists' }
|
|
182
|
+
$user = [Security.Principal.WindowsIdentity]::GetCurrent().User
|
|
183
|
+
$security = New-Object Security.AccessControl.DirectorySecurity
|
|
184
|
+
$security.SetOwner($user)
|
|
185
|
+
$security.SetAccessRuleProtection($true, $false)
|
|
186
|
+
foreach ($sid in @($user, [Security.Principal.SecurityIdentifier]::new('S-1-5-18'), [Security.Principal.SecurityIdentifier]::new('S-1-5-32-544'))) {
|
|
187
|
+
$rule = [Security.AccessControl.FileSystemAccessRule]::new($sid, [Security.AccessControl.FileSystemRights]::FullControl,
|
|
188
|
+
[Security.AccessControl.InheritanceFlags]'ContainerInherit, ObjectInherit', [Security.AccessControl.PropagationFlags]::None,
|
|
189
|
+
[Security.AccessControl.AccessControlType]::Allow)
|
|
190
|
+
[void]$security.AddAccessRule($rule)
|
|
191
|
+
}
|
|
192
|
+
$overload = [IO.Directory].GetMethods() | Where-Object { $_.Name -eq 'CreateDirectory' -and $_.GetParameters().Length -eq 2 -and $_.GetParameters()[1].ParameterType -eq [Security.AccessControl.DirectorySecurity] }
|
|
193
|
+
if ($overload) { [void][IO.Directory]::CreateDirectory($Directory, $security) }
|
|
194
|
+
else { [IO.FileSystemAclExtensions]::Create([IO.DirectoryInfo]::new($Directory), $security) }
|
|
195
|
+
$attributes = [IO.File]::GetAttributes($Directory)
|
|
196
|
+
$actual = Get-NotifaiAccessControl $Directory $attributes
|
|
197
|
+
if (($attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0 -or -not $actual.AreAccessRulesProtected -or
|
|
198
|
+
$actual.GetOwner([Security.Principal.SecurityIdentifier]).Value -ne $user.Value) { throw 'Installer temporary directory is not privately owned' }
|
|
199
|
+
foreach ($rule in $actual.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
|
|
200
|
+
if ($rule.AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow -and $rule.IdentityReference.Value -notin @($user.Value, 'S-1-5-18', 'S-1-5-32-544')) { throw 'Installer temporary directory permits another account' }
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
function Invoke-NotifaiCandidate([string]$Launcher, [string[]]$NativeArgs) {
|
|
204
|
+
& $Launcher @NativeArgs
|
|
205
|
+
$script:NotifaiBootstrapExitCode = $LASTEXITCODE
|
|
206
|
+
}
|
|
207
|
+
function Get-NotifaiAccountHome {
|
|
208
|
+
$accountHome = [Environment]::GetFolderPath([Environment+SpecialFolder]::UserProfile)
|
|
209
|
+
if (-not $accountHome -or -not [IO.Path]::IsPathRooted($accountHome)) { throw 'Cannot resolve this account home' }
|
|
210
|
+
foreach ($value in @($env:USERPROFILE, $env:HOME)) {
|
|
211
|
+
# Git Bash's POSIX HOME is not a Windows account relocation.
|
|
212
|
+
if ($value -and $value -match '^(?:[A-Za-z]:[\\/]|\\\\)') {
|
|
213
|
+
if (-not [String]::Equals([IO.Path]::GetFullPath($value).TrimEnd('\', '/'), $accountHome.TrimEnd('\', '/'), [StringComparison]::OrdinalIgnoreCase)) { throw 'HOME or USERPROFILE differs from the OS account home' }
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return $accountHome
|
|
217
|
+
}
|
|
218
|
+
# Read-only inspection of an existing path. npm can inherit a token's default
|
|
219
|
+
# owner. The OS-confirmed profile can belong to Windows itself; this exception
|
|
220
|
+
# must never admit a system-owned npm package or managed installation path.
|
|
221
|
+
function Assert-NotifaiPathAccess([string]$File, [switch]$AllowDefaultOwner, [switch]$RequireProtected, [switch]$AccountHome) {
|
|
222
|
+
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
|
223
|
+
$user = $identity.User.Value
|
|
224
|
+
$attributes = [IO.File]::GetAttributes($File)
|
|
225
|
+
$acl = Get-NotifaiAccessControl $File $attributes
|
|
226
|
+
$owner = $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value
|
|
227
|
+
$defaultOwner = $AllowDefaultOwner -and $identity.Owner.Value -eq 'S-1-5-32-544' -and $owner -eq $identity.Owner.Value
|
|
228
|
+
$profileOwner = $false
|
|
229
|
+
if ($AccountHome) {
|
|
230
|
+
$expectedHome = Get-NotifaiAccountHome
|
|
231
|
+
if (-not [String]::Equals([IO.Path]::GetFullPath($File).TrimEnd('\', '/'), $expectedHome.TrimEnd('\', '/'), [StringComparison]::OrdinalIgnoreCase) -or
|
|
232
|
+
($attributes -band [IO.FileAttributes]::Directory) -eq 0) { throw 'Account home access check requires the exact OS profile directory' }
|
|
233
|
+
$profileOwner = $owner -in @('S-1-5-18', 'S-1-5-32-544')
|
|
234
|
+
}
|
|
235
|
+
if (($attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0 -or
|
|
236
|
+
($owner -ne $user -and -not $defaultOwner -and -not $profileOwner) -or
|
|
237
|
+
($RequireProtected -and -not $acl.AreAccessRulesProtected)) { throw 'Existing path is not privately owned; inspect it before repair' }
|
|
238
|
+
$writes = [int64][Security.AccessControl.FileSystemRights]'Write, Delete, DeleteSubdirectoriesAndFiles, ChangePermissions, TakeOwnership' -bor 0x50000000
|
|
239
|
+
foreach ($rule in $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
|
|
240
|
+
if ($rule.AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow -and
|
|
241
|
+
([int64]$rule.FileSystemRights -band $writes) -ne 0 -and
|
|
242
|
+
$rule.IdentityReference.Value -notin @($user, 'S-1-5-18', 'S-1-5-32-544')) { throw 'Existing path permits another writer; inspect it before repair' }
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function Get-NotifaiInstalledCommand {
|
|
246
|
+
$accountHome = Get-NotifaiAccountHome
|
|
247
|
+
$managed = [IO.Path]::Combine($accountHome, '.notifai')
|
|
248
|
+
$bin = [IO.Path]::Combine($managed, 'bin')
|
|
249
|
+
$command = [IO.Path]::Combine($bin, 'notifai.exe')
|
|
250
|
+
try { [void][IO.File]::GetAttributes($command) }
|
|
251
|
+
catch [IO.FileNotFoundException] { return $null }
|
|
252
|
+
catch [IO.DirectoryNotFoundException] { return $null }
|
|
253
|
+
foreach ($file in @($accountHome, $managed, $bin, $command)) {
|
|
254
|
+
Assert-NotifaiPathAccess $file -AccountHome:($file -eq $accountHome) -RequireProtected:($file -eq $managed -or $file -eq $bin)
|
|
255
|
+
}
|
|
256
|
+
if (-not [IO.File]::Exists($command)) { throw 'Existing launcher is not a regular file; repair it explicitly' }
|
|
257
|
+
return $command
|
|
258
|
+
}
|
|
259
|
+
function Get-NotifaiInstallArguments {
|
|
260
|
+
$nativeArgs = @('install', '--source', 'powershell')
|
|
261
|
+
if ($Channel) { $nativeArgs += @('--channel', $Channel) }
|
|
262
|
+
if ($Version) { $nativeArgs += @('--version', $Version) }
|
|
263
|
+
if ($Json) { $nativeArgs += '--json' }
|
|
264
|
+
if ($NoInit) { $nativeArgs += '--no-init' }
|
|
265
|
+
if ($NoPath) { $nativeArgs += '--no-path' }
|
|
266
|
+
if ($MigrateNpm) { $nativeArgs += '--migrate-npm' }
|
|
267
|
+
return $nativeArgs
|
|
268
|
+
}
|
|
269
|
+
function Invoke-NotifaiBootstrap {
|
|
270
|
+
$selectedChannel = if ($Channel) { $Channel } else { 'stable' }
|
|
271
|
+
if ($Version -and -not (Test-NotifaiVersion $Version)) { throw 'Version must be an exact semantic version' }
|
|
272
|
+
$existing = Get-NotifaiInstalledCommand
|
|
273
|
+
if ($existing) {
|
|
274
|
+
Invoke-NotifaiCandidate $existing (Get-NotifaiInstallArguments)
|
|
275
|
+
return
|
|
276
|
+
}
|
|
277
|
+
if ($selectedChannel -eq 'stable' -and $Version -and $Version.Split('+')[0].Contains('-')) { throw 'A prerelease requires -Channel beta' }
|
|
278
|
+
$target = Get-NotifaiWindowsTarget
|
|
279
|
+
$temporary = [IO.Path]::Combine([IO.Path]::GetTempPath(), "notifai-install-$([Guid]::NewGuid().ToString('N'))")
|
|
280
|
+
New-NotifaiPrivateDirectory $temporary
|
|
281
|
+
try {
|
|
282
|
+
$channelFile = [IO.Path]::Combine($temporary, 'channel.tsv')
|
|
283
|
+
Get-NotifaiDownload "https://raw.githubusercontent.com/Raidiant-io/notifai/release-metadata/$selectedChannel.bootstrap.tsv" $channelFile 262144
|
|
284
|
+
$release = Read-NotifaiChannel $channelFile $selectedChannel
|
|
285
|
+
$selectedVersion = if ($Version) { $Version } else { $release.Version }
|
|
286
|
+
if ($selectedVersion -cin $release.Withdrawn) { throw 'The requested release has been withdrawn' }
|
|
287
|
+
$base = "https://github.com/Raidiant-io/notifai/releases/download/v$selectedVersion"
|
|
288
|
+
$artifactFile = [IO.Path]::Combine($temporary, 'bootstrap.tsv')
|
|
289
|
+
Get-NotifaiDownload "$base/bootstrap.tsv" $artifactFile 262144
|
|
290
|
+
$artifact = Read-NotifaiArtifact $artifactFile $selectedVersion $target
|
|
291
|
+
if ($selectedVersion -ceq $release.Version -and $artifact.InventoryHash -cne $release.InventoryHash) { throw 'Channel and release inventory differ' }
|
|
292
|
+
$inventory = [IO.Path]::Combine($temporary, 'inventory.json')
|
|
293
|
+
Get-NotifaiDownload "$base/inventory.json" $inventory 262144
|
|
294
|
+
if ((Get-NotifaiHash $inventory) -cne $artifact.InventoryHash) { throw 'Release inventory digest differs' }
|
|
295
|
+
$archive = [IO.Path]::Combine($temporary, $artifact.Filename)
|
|
296
|
+
Get-NotifaiDownload "$base/$($artifact.Filename)" $archive $artifact.Bytes
|
|
297
|
+
if ((Get-Item -LiteralPath $archive).Length -ne $artifact.Bytes -or (Get-NotifaiHash $archive) -cne $artifact.Hash) { throw 'Release archive digest or size differs' }
|
|
298
|
+
$extracted = [IO.Path]::Combine($temporary, 'release')
|
|
299
|
+
Expand-NotifaiArchive $archive $extracted
|
|
300
|
+
$launcher = [IO.Path]::Combine($extracted, 'notifai.exe')
|
|
301
|
+
if ((Get-NotifaiHash $launcher) -cne $artifact.LauncherHash -or (Get-NotifaiHash ([IO.Path]::Combine($extracted, 'notifai-runtime.exe'))) -cne $artifact.RuntimeHash) { throw 'Release executable digests differ' }
|
|
302
|
+
$nativeArgs = @(Get-NotifaiInstallArguments) + @('--directory', $extracted, '--inventory', $inventory)
|
|
303
|
+
Invoke-NotifaiCandidate $launcher $nativeArgs
|
|
304
|
+
} finally {
|
|
305
|
+
if ([IO.Directory]::Exists($temporary)) {
|
|
306
|
+
try { [IO.Directory]::Delete($temporary, $true) }
|
|
307
|
+
catch { [Console]::Error.WriteLine("Temporary installer files remain at $temporary; remove them after running commands finish.") }
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if ($MyInvocation.InvocationName -ne '.') {
|
|
312
|
+
try { Invoke-NotifaiBootstrap; exit $script:NotifaiBootstrapExitCode }
|
|
313
|
+
catch {
|
|
314
|
+
if ($Json) { @{ ok = $false; code = 'bootstrap_failed'; message = $_.Exception.Message } | ConvertTo-Json -Compress }
|
|
315
|
+
else { [Console]::Error.WriteLine("Notifai installation failed: $($_.Exception.Message)") }
|
|
316
|
+
exit 1
|
|
317
|
+
}
|
|
318
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":"12.0.0-beta.13","source_revision":"a2af9c45ccf49001f4ccf2401f73685fc4e6c05e"}
|
package/inventory.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"key_id":"notifai-release-2026-10","payload":"eyJzY2hlbWEiOjEsInZlcnNpb24iOiIxMi4wLjAtYmV0YS4xMyIsInNvdXJjZV9yZXZpc2lvbiI6ImEyYWY5YzQ1Y2NmNDkwMDFmNGNjZjI0MDFmNzM2ODVmYzRlNmMwNWUiLCJzdG9yZV9zY2hlbWEiOjEsImxhdW5jaGVyX3NjaGVtYSI6MSwiYXJ0aWZhY3RzIjpbeyJ0YXJnZXQiOiJidW4tZGFyd2luLWFybTY0IiwiZmlsZW5hbWUiOiJub3RpZmFpLTEyLjAuMC1iZXRhLjEzLWRhcndpbi1hcm02NC50YXIuZ3oiLCJieXRlcyI6Mjc3NjkzNDAsInNoYTI1NiI6IjlkMWIwZjcyZmVjNmY2ZDE4YzJlZjEwMWUzNGNlMDI2NGI0ZmEwNzA4Yzg0MzhhZDY5NGJjMWNjZTY1MmMwZGYiLCJydW50aW1lX3NoYTI1NiI6ImIzNDEyNmU1NDRhZTgyNzlkNzI1NjU0NDU3ZjhhZTZlMWIwZjlhOGY5ODVhZWQ2NjVlMjlmNWMyNTI5ZGIzZjYiLCJsYXVuY2hlcl9zaGEyNTYiOiIxYzY0ZTE4NTEwZWY1YTQxYzZhN2I5MWMxODU1ZDgyMjIwNDk1NWM1YzI3NGFhZmZjNThmYjNjMTA4YTY2N2VjIiwibWF0ZXJpYWxzIjpbeyJwYXRoIjoiQlVOLUxJQ0VOU0UubWQiLCJieXRlcyI6NTYxMywic2hhMjU2IjoiYjljYWY1MjcyODY5MWI0MDU3ZTM3MTIzMmMyMjFhMTMyODgzMTk4YmUyZjNkMmRkZjkyYzkwNDA0Yzk4NGIxYSJ9LHsicGF0aCI6IkNPUlJFU1BPTkRJTkctU09VUkNFUy5qc29uIiwiYnl0ZXMiOjIwMjAsInNoYTI1NiI6ImZhNGMzNDQ4MDExNTQ4NzJkNjE3OWVlMmVmNDk5MjNkYzlmODkwOWVmMDFlNTNiODZlOGY1N2M2MjU4MjMyNzQifSx7InBhdGgiOiJMSUNFTlNFLnR4dCIsImJ5dGVzIjoxMTM0Niwic2hhMjU2IjoiOTQ0YzEzZmYwZmU3OTVlMjkxZmQxYzQ5NDczZjk4ZDRmZGYxZjc0NjM4ZTAxZjg4Mjc2OWNkNGNhZTc4YjczZCJ9LHsicGF0aCI6Ik5PVElDRS1QUk9WRU5BTkNFLmpzb24iLCJieXRlcyI6NDUwMjY0LCJzaGEyNTYiOiI1MzRkZDU5ZmQ0YzE1ZGQxMzgyZTgyN2YwYjg1YzE5ZjdjNjk4ZTIzNWY5Mjk5ZWFhMjAyZGI1NDAwODM0Mjg4In0seyJwYXRoIjoiTk9USUNFLnR4dCIsImJ5dGVzIjo2MjYsInNoYTI1NiI6IjFkZmJmNDQ5OGRjMDI2YjIwNTljMGIwYjVlYjVmYTFkODJhZTMzNGU1OGZmMTFlN2MyOTczMzMyN2YyNWM0ZWIifSx7InBhdGgiOiJSRUJVSUxESU5HLm1kIiwiYnl0ZXMiOjM4NDIsInNoYTI1NiI6ImNlNjA1YjVmZGIwMzE5MzM5ZjlmODNmMmZlN2NjY2JjN2U1NzI2ZmRmNDk0ZGE2ZTI4NDMzYmVmODI5ZWIwYmUifSx7InBhdGgiOiJTT1VSQ0UtTk9USUNFUy50eHQiLCJieXRlcyI6OTAxNzc3MSwic2hhMjU2IjoiODk5NzZiZWNjMjU2NTQwZTZkMmU4MDdiNDdhNGUwNWU4ODk5ODJjMDYyMmZjMDQ0MTNhN2JmN2U3N2E3N2UzNyJ9LHsicGF0aCI6IlRISVJELVBBUlRZLU5PVElDRVMudHh0IiwiYnl0ZXMiOjI0OTE0OTYsInNoYTI1NiI6IjExNjQ0N2VmZjc3ODkzNTExNzk3ZWY0NzYwMTFkZWM4MDAyMjRmOTFlMzM0MmUzZDY1NzA3MDg3MTJiNGI3NzIifSx7InBhdGgiOiJsaWNlbnNlcy9ucG0tY21kLXNoaW0udHh0IiwiYnl0ZXMiOjgxMywic2hhMjU2IjoiYWZmZmRmMTIwODExMjI3NDljNGI3MWM1YjFjMTFiYzY1OWQ3OTI0MmQxOWUxOGY1ZThkYmFiMDRhNDVlMzZiYiJ9LHsicGF0aCI6Im5wbS1hZGFwdGVyLWZpbGVzLmpzb24iLCJieXRlcyI6MTUyNCwic2hhMjU2IjoiZjIyNmJiMjNiMjEyYWE4MjQ0NzdlYTY3ZGY0MjQ1ZjQxMjFkOWQ2MTdmYTA4NGVhYWQwZThjYjlhNTIxN2RlYSJ9XX0seyJ0YXJnZXQiOiJidW4tZGFyd2luLXg2NCIsImZpbGVuYW1lIjoibm90aWZhaS0xMi4wLjAtYmV0YS4xMy1kYXJ3aW4teDY0LnRhci5neiIsImJ5dGVzIjozMDAwNzg1Nywic2hhMjU2IjoiODRhNjVhYjUzZjhiZjU5YjNlNmU5N2NhOWZlNDVlNjRlNGE3MzIyZjllOGM3ZmI4YWJkYzc1MmQ5N2ZhZWRmZiIsInJ1bnRpbWVfc2hhMjU2IjoiNTFhMDViYTcwNTliYTJmNGI5NzUxYWZlNTNlNTM1NjgyODdmY2IwNTk4NmFlYzRmYzI3YTA5NTBhMWE0ZGQ0NiIsImxhdW5jaGVyX3NoYTI1NiI6IjRhZTkyNTU3MWIxNzFjYzBkNzExYTQzYTZhYzU5ZGI3NjFiNzBmNzRhNTgyZDVlMjQ3ZjFhOWU4Mjc0ZDk5OWQiLCJtYXRlcmlhbHMiOlt7InBhdGgiOiJCVU4tTElDRU5TRS5tZCIsImJ5dGVzIjo1NjEzLCJzaGEyNTYiOiJiOWNhZjUyNzI4NjkxYjQwNTdlMzcxMjMyYzIyMWExMzI4ODMxOThiZTJmM2QyZGRmOTJjOTA0MDRjOTg0YjFhIn0seyJwYXRoIjoiQ09SUkVTUE9ORElORy1TT1VSQ0VTLmpzb24iLCJieXRlcyI6MjAyMCwic2hhMjU2IjoiZmE0YzM0NDgwMTE1NDg3MmQ2MTc5ZWUyZWY0OTkyM2RjOWY4OTA5ZWYwMWU1M2I4NmU4ZjU3YzYyNTgyMzI3NCJ9LHsicGF0aCI6IkxJQ0VOU0UudHh0IiwiYnl0ZXMiOjExMzQ2LCJzaGEyNTYiOiI5NDRjMTNmZjBmZTc5NWUyOTFmZDFjNDk0NzNmOThkNGZkZjFmNzQ2MzhlMDFmODgyNzY5Y2Q0Y2FlNzhiNzNkIn0seyJwYXRoIjoiTk9USUNFLVBST1ZFTkFOQ0UuanNvbiIsImJ5dGVzIjo0NTAyNjQsInNoYTI1NiI6IjUzNGRkNTlmZDRjMTVkZDEzODJlODI3ZjBiODVjMTlmN2M2OThlMjM1ZjkyOTllYWEyMDJkYjU0MDA4MzQyODgifSx7InBhdGgiOiJOT1RJQ0UudHh0IiwiYnl0ZXMiOjYyNiwic2hhMjU2IjoiMWRmYmY0NDk4ZGMwMjZiMjA1OWMwYjBiNWViNWZhMWQ4MmFlMzM0ZTU4ZmYxMWU3YzI5NzMzMzI3ZjI1YzRlYiJ9LHsicGF0aCI6IlJFQlVJTERJTkcubWQiLCJieXRlcyI6Mzg0Miwic2hhMjU2IjoiY2U2MDViNWZkYjAzMTkzMzlmOWY4M2YyZmU3Y2NjYmM3ZTU3MjZmZGY0OTRkYTZlMjg0MzNiZWY4MjllYjBiZSJ9LHsicGF0aCI6IlNPVVJDRS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjo5MDE3NzcxLCJzaGEyNTYiOiI4OTk3NmJlY2MyNTY1NDBlNmQyZTgwN2I0N2E0ZTA1ZTg4OTk4MmMwNjIyZmMwNDQxM2E3YmY3ZTc3YTc3ZTM3In0seyJwYXRoIjoiVEhJUkQtUEFSVFktTk9USUNFUy50eHQiLCJieXRlcyI6MjQ5MTQ5Niwic2hhMjU2IjoiMTE2NDQ3ZWZmNzc4OTM1MTE3OTdlZjQ3NjAxMWRlYzgwMDIyNGY5MWUzMzQyZTNkNjU3MDcwODcxMmI0Yjc3MiJ9LHsicGF0aCI6ImxpY2Vuc2VzL25wbS1jbWQtc2hpbS50eHQiLCJieXRlcyI6ODEzLCJzaGEyNTYiOiJhZmZmZGYxMjA4MTEyMjc0OWM0YjcxYzViMWMxMWJjNjU5ZDc5MjQyZDE5ZTE4ZjVlOGRiYWIwNGE0NWUzNmJiIn0seyJwYXRoIjoibnBtLWFkYXB0ZXItZmlsZXMuanNvbiIsImJ5dGVzIjoxNTI0LCJzaGEyNTYiOiJmMjI2YmIyM2IyMTJhYTgyNDQ3N2VhNjdkZjQyNDVmNDEyMWQ5ZDYxN2ZhMDg0ZWFhZDBlOGNiOWE1MjE3ZGVhIn1dfSx7InRhcmdldCI6ImJ1bi1saW51eC1hcm02NCIsImZpbGVuYW1lIjoibm90aWZhaS0xMi4wLjAtYmV0YS4xMy1saW51eC1hcm02NC50YXIuZ3oiLCJieXRlcyI6MzkzMTcwNzIsInNoYTI1NiI6IjIzMWM2ZGQzNTI0MWZiNDRmZmUwNDgxYTU2NTEyNTgyODU2YmU1NGMwY2RmZWNiNWVmMTM2YTM2ZjEzMjE4NDAiLCJydW50aW1lX3NoYTI1NiI6IjcyNTAyOTY5MzIwMTA3YmQzZWVmMTJhMTY1MDU2NDI3MTUxOGJhNjI1ZmJiZjhiOWFjNTg5YzEzYzZlNTBhOGUiLCJsYXVuY2hlcl9zaGEyNTYiOiJjMTllMzMyYzgyMWI3MTI4Y2IyNWY2MWU0YWI3ZTBiM2M2MzM0NWYwNGUyYWI1YWI5NWQ0NTFhNGE2ZmJkYzQ1IiwibWF0ZXJpYWxzIjpbeyJwYXRoIjoiQlVOLUxJQ0VOU0UubWQiLCJieXRlcyI6NTYxMywic2hhMjU2IjoiYjljYWY1MjcyODY5MWI0MDU3ZTM3MTIzMmMyMjFhMTMyODgzMTk4YmUyZjNkMmRkZjkyYzkwNDA0Yzk4NGIxYSJ9LHsicGF0aCI6IkNPUlJFU1BPTkRJTkctU09VUkNFUy5qc29uIiwiYnl0ZXMiOjIwMjAsInNoYTI1NiI6ImZhNGMzNDQ4MDExNTQ4NzJkNjE3OWVlMmVmNDk5MjNkYzlmODkwOWVmMDFlNTNiODZlOGY1N2M2MjU4MjMyNzQifSx7InBhdGgiOiJMSUNFTlNFLnR4dCIsImJ5dGVzIjoxMTM0Niwic2hhMjU2IjoiOTQ0YzEzZmYwZmU3OTVlMjkxZmQxYzQ5NDczZjk4ZDRmZGYxZjc0NjM4ZTAxZjg4Mjc2OWNkNGNhZTc4YjczZCJ9LHsicGF0aCI6Ik5PVElDRS1QUk9WRU5BTkNFLmpzb24iLCJieXRlcyI6NDUwMjY0LCJzaGEyNTYiOiI1MzRkZDU5ZmQ0YzE1ZGQxMzgyZTgyN2YwYjg1YzE5ZjdjNjk4ZTIzNWY5Mjk5ZWFhMjAyZGI1NDAwODM0Mjg4In0seyJwYXRoIjoiTk9USUNFLnR4dCIsImJ5dGVzIjo2MjYsInNoYTI1NiI6IjFkZmJmNDQ5OGRjMDI2YjIwNTljMGIwYjVlYjVmYTFkODJhZTMzNGU1OGZmMTFlN2MyOTczMzMyN2YyNWM0ZWIifSx7InBhdGgiOiJSRUJVSUxESU5HLm1kIiwiYnl0ZXMiOjM4NDIsInNoYTI1NiI6ImNlNjA1YjVmZGIwMzE5MzM5ZjlmODNmMmZlN2NjY2JjN2U1NzI2ZmRmNDk0ZGE2ZTI4NDMzYmVmODI5ZWIwYmUifSx7InBhdGgiOiJTT1VSQ0UtTk9USUNFUy50eHQiLCJieXRlcyI6OTAxNzc3MSwic2hhMjU2IjoiODk5NzZiZWNjMjU2NTQwZTZkMmU4MDdiNDdhNGUwNWU4ODk5ODJjMDYyMmZjMDQ0MTNhN2JmN2U3N2E3N2UzNyJ9LHsicGF0aCI6IlRISVJELVBBUlRZLU5PVElDRVMudHh0IiwiYnl0ZXMiOjI0OTE0OTYsInNoYTI1NiI6IjExNjQ0N2VmZjc3ODkzNTExNzk3ZWY0NzYwMTFkZWM4MDAyMjRmOTFlMzM0MmUzZDY1NzA3MDg3MTJiNGI3NzIifSx7InBhdGgiOiJsaWNlbnNlcy9ucG0tY21kLXNoaW0udHh0IiwiYnl0ZXMiOjgxMywic2hhMjU2IjoiYWZmZmRmMTIwODExMjI3NDljNGI3MWM1YjFjMTFiYzY1OWQ3OTI0MmQxOWUxOGY1ZThkYmFiMDRhNDVlMzZiYiJ9LHsicGF0aCI6Im5wbS1hZGFwdGVyLWZpbGVzLmpzb24iLCJieXRlcyI6MTUyNCwic2hhMjU2IjoiZjIyNmJiMjNiMjEyYWE4MjQ0NzdlYTY3ZGY0MjQ1ZjQxMjFkOWQ2MTdmYTA4NGVhYWQwZThjYjlhNTIxN2RlYSJ9XX0seyJ0YXJnZXQiOiJidW4tbGludXgteDY0IiwiZmlsZW5hbWUiOiJub3RpZmFpLTEyLjAuMC1iZXRhLjEzLWxpbnV4LXg2NC50YXIuZ3oiLCJieXRlcyI6Mzg4ODAwNDIsInNoYTI1NiI6IjM4YzNkMjk3YmM3NDVlYjk1ZDg5OTY5ODE4ZGQ1ODc4MmE4ZTBjZjUxN2U0YWE4Njg4MmM4NjI5NjE2NzNlYzQiLCJydW50aW1lX3NoYTI1NiI6ImRjY2Q3NTNkODIyNTFiYmU3ZGIyMmUyNmQ2ZmU4YzFlYzllYjhjYTAyMTE1OGUwOGFhNjU4ODE3NWM3ZjgwYWYiLCJsYXVuY2hlcl9zaGEyNTYiOiJiZGY4ZDQ3ZGY4NTgxYWNlMjliNTc5MDQ1N2NiYzZjMjZkMTJiM2NiMTRjMGRkYWIzMzc5YTcyNzVkOWVhNGIxIiwibWF0ZXJpYWxzIjpbeyJwYXRoIjoiQlVOLUxJQ0VOU0UubWQiLCJieXRlcyI6NTYxMywic2hhMjU2IjoiYjljYWY1MjcyODY5MWI0MDU3ZTM3MTIzMmMyMjFhMTMyODgzMTk4YmUyZjNkMmRkZjkyYzkwNDA0Yzk4NGIxYSJ9LHsicGF0aCI6IkNPUlJFU1BPTkRJTkctU09VUkNFUy5qc29uIiwiYnl0ZXMiOjIwMjAsInNoYTI1NiI6ImZhNGMzNDQ4MDExNTQ4NzJkNjE3OWVlMmVmNDk5MjNkYzlmODkwOWVmMDFlNTNiODZlOGY1N2M2MjU4MjMyNzQifSx7InBhdGgiOiJMSUNFTlNFLnR4dCIsImJ5dGVzIjoxMTM0Niwic2hhMjU2IjoiOTQ0YzEzZmYwZmU3OTVlMjkxZmQxYzQ5NDczZjk4ZDRmZGYxZjc0NjM4ZTAxZjg4Mjc2OWNkNGNhZTc4YjczZCJ9LHsicGF0aCI6Ik5PVElDRS1QUk9WRU5BTkNFLmpzb24iLCJieXRlcyI6NDUwMjY0LCJzaGEyNTYiOiI1MzRkZDU5ZmQ0YzE1ZGQxMzgyZTgyN2YwYjg1YzE5ZjdjNjk4ZTIzNWY5Mjk5ZWFhMjAyZGI1NDAwODM0Mjg4In0seyJwYXRoIjoiTk9USUNFLnR4dCIsImJ5dGVzIjo2MjYsInNoYTI1NiI6IjFkZmJmNDQ5OGRjMDI2YjIwNTljMGIwYjVlYjVmYTFkODJhZTMzNGU1OGZmMTFlN2MyOTczMzMyN2YyNWM0ZWIifSx7InBhdGgiOiJSRUJVSUxESU5HLm1kIiwiYnl0ZXMiOjM4NDIsInNoYTI1NiI6ImNlNjA1YjVmZGIwMzE5MzM5ZjlmODNmMmZlN2NjY2JjN2U1NzI2ZmRmNDk0ZGE2ZTI4NDMzYmVmODI5ZWIwYmUifSx7InBhdGgiOiJTT1VSQ0UtTk9USUNFUy50eHQiLCJieXRlcyI6OTAxNzc3MSwic2hhMjU2IjoiODk5NzZiZWNjMjU2NTQwZTZkMmU4MDdiNDdhNGUwNWU4ODk5ODJjMDYyMmZjMDQ0MTNhN2JmN2U3N2E3N2UzNyJ9LHsicGF0aCI6IlRISVJELVBBUlRZLU5PVElDRVMudHh0IiwiYnl0ZXMiOjI0OTE0OTYsInNoYTI1NiI6IjExNjQ0N2VmZjc3ODkzNTExNzk3ZWY0NzYwMTFkZWM4MDAyMjRmOTFlMzM0MmUzZDY1NzA3MDg3MTJiNGI3NzIifSx7InBhdGgiOiJsaWNlbnNlcy9ucG0tY21kLXNoaW0udHh0IiwiYnl0ZXMiOjgxMywic2hhMjU2IjoiYWZmZmRmMTIwODExMjI3NDljNGI3MWM1YjFjMTFiYzY1OWQ3OTI0MmQxOWUxOGY1ZThkYmFiMDRhNDVlMzZiYiJ9LHsicGF0aCI6Im5wbS1hZGFwdGVyLWZpbGVzLmpzb24iLCJieXRlcyI6MTUyNCwic2hhMjU2IjoiZjIyNmJiMjNiMjEyYWE4MjQ0NzdlYTY3ZGY0MjQ1ZjQxMjFkOWQ2MTdmYTA4NGVhYWQwZThjYjlhNTIxN2RlYSJ9XX0seyJ0YXJnZXQiOiJidW4td2luZG93cy1hcm02NCIsImZpbGVuYW1lIjoibm90aWZhaS0xMi4wLjAtYmV0YS4xMy13aW5kb3dzLWFybTY0LnppcCIsImJ5dGVzIjozODcxMTczNiwic2hhMjU2IjoiMGZiMTU0OTY1NmRlMTFlMjQ3ODUzZGNiZGFhODVkMWYxYTc2ZDI1YWFmMDMzODZkOGFlZWZlMGRjY2Y5ZTk3MCIsInJ1bnRpbWVfc2hhMjU2IjoiZjZjMmEyOWNmMmZhMGUyMzYyYjhiMGU5NTk3ZmM5ZTRlMTFkMmQzMjkxZjEyYzBlMGZjNGE5YzQyYjEwOWM1MCIsImxhdW5jaGVyX3NoYTI1NiI6IjVkMjQ0MTViZjc0NWY1MzhjZmNhMGYxY2NlYzcxNTFjYjdkMGQ0ODgwMGY3NTE5ZTczYzhhNzIzMzE2OTFlNmQiLCJtYXRlcmlhbHMiOlt7InBhdGgiOiJCVU4tTElDRU5TRS5tZCIsImJ5dGVzIjo1NjEzLCJzaGEyNTYiOiJiOWNhZjUyNzI4NjkxYjQwNTdlMzcxMjMyYzIyMWExMzI4ODMxOThiZTJmM2QyZGRmOTJjOTA0MDRjOTg0YjFhIn0seyJwYXRoIjoiQ09SUkVTUE9ORElORy1TT1VSQ0VTLmpzb24iLCJieXRlcyI6MjAyMCwic2hhMjU2IjoiZmE0YzM0NDgwMTE1NDg3MmQ2MTc5ZWUyZWY0OTkyM2RjOWY4OTA5ZWYwMWU1M2I4NmU4ZjU3YzYyNTgyMzI3NCJ9LHsicGF0aCI6IkxJQ0VOU0UudHh0IiwiYnl0ZXMiOjExMzQ2LCJzaGEyNTYiOiI5NDRjMTNmZjBmZTc5NWUyOTFmZDFjNDk0NzNmOThkNGZkZjFmNzQ2MzhlMDFmODgyNzY5Y2Q0Y2FlNzhiNzNkIn0seyJwYXRoIjoiTk9USUNFLVBST1ZFTkFOQ0UuanNvbiIsImJ5dGVzIjo0NTAyNjQsInNoYTI1NiI6IjUzNGRkNTlmZDRjMTVkZDEzODJlODI3ZjBiODVjMTlmN2M2OThlMjM1ZjkyOTllYWEyMDJkYjU0MDA4MzQyODgifSx7InBhdGgiOiJOT1RJQ0UudHh0IiwiYnl0ZXMiOjYyNiwic2hhMjU2IjoiMWRmYmY0NDk4ZGMwMjZiMjA1OWMwYjBiNWViNWZhMWQ4MmFlMzM0ZTU4ZmYxMWU3YzI5NzMzMzI3ZjI1YzRlYiJ9LHsicGF0aCI6IlJFQlVJTERJTkcubWQiLCJieXRlcyI6Mzg0Miwic2hhMjU2IjoiY2U2MDViNWZkYjAzMTkzMzlmOWY4M2YyZmU3Y2NjYmM3ZTU3MjZmZGY0OTRkYTZlMjg0MzNiZWY4MjllYjBiZSJ9LHsicGF0aCI6IlNPVVJDRS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjo5MDE3NzcxLCJzaGEyNTYiOiI4OTk3NmJlY2MyNTY1NDBlNmQyZTgwN2I0N2E0ZTA1ZTg4OTk4MmMwNjIyZmMwNDQxM2E3YmY3ZTc3YTc3ZTM3In0seyJwYXRoIjoiVEhJUkQtUEFSVFktTk9USUNFUy50eHQiLCJieXRlcyI6MjQ5MTQ5Niwic2hhMjU2IjoiMTE2NDQ3ZWZmNzc4OTM1MTE3OTdlZjQ3NjAxMWRlYzgwMDIyNGY5MWUzMzQyZTNkNjU3MDcwODcxMmI0Yjc3MiJ9LHsicGF0aCI6ImxpY2Vuc2VzL25wbS1jbWQtc2hpbS50eHQiLCJieXRlcyI6ODEzLCJzaGEyNTYiOiJhZmZmZGYxMjA4MTEyMjc0OWM0YjcxYzViMWMxMWJjNjU5ZDc5MjQyZDE5ZTE4ZjVlOGRiYWIwNGE0NWUzNmJiIn0seyJwYXRoIjoibnBtLWFkYXB0ZXItZmlsZXMuanNvbiIsImJ5dGVzIjoxNTI0LCJzaGEyNTYiOiJmMjI2YmIyM2IyMTJhYTgyNDQ3N2VhNjdkZjQyNDVmNDEyMWQ5ZDYxN2ZhMDg0ZWFhZDBlOGNiOWE1MjE3ZGVhIn1dfSx7InRhcmdldCI6ImJ1bi13aW5kb3dzLXg2NCIsImZpbGVuYW1lIjoibm90aWZhaS0xMi4wLjAtYmV0YS4xMy13aW5kb3dzLXg2NC56aXAiLCJieXRlcyI6NDE4NTc1MjIsInNoYTI1NiI6IjlhNWY1ZDk2NmIxMGI1YTFkMzUyOTc1Y2FmOWMyZmJhNDE4NGFkMGQ2NTQ3ODg5MzJjNjUwMTAzMWVmNTBlNWYiLCJydW50aW1lX3NoYTI1NiI6IjUxNTBlYzBjYzUzZjk5ODBhYmUwZDg0ZjkxN2Y3YjM1MTFiMDc4YTJhZWIwZjk1OWU3ZjkyMjMzN2MxNGE0YmIiLCJsYXVuY2hlcl9zaGEyNTYiOiI1MDkwYTliYjZlZDRjN2NlMWRmMDBlNDEzMmVhYWI4YmQ4NDhlYWEwNzIyZWY1ZGU3YjdhOTA5MTgxYWJhNzI4IiwibWF0ZXJpYWxzIjpbeyJwYXRoIjoiQlVOLUxJQ0VOU0UubWQiLCJieXRlcyI6NTYxMywic2hhMjU2IjoiYjljYWY1MjcyODY5MWI0MDU3ZTM3MTIzMmMyMjFhMTMyODgzMTk4YmUyZjNkMmRkZjkyYzkwNDA0Yzk4NGIxYSJ9LHsicGF0aCI6IkNPUlJFU1BPTkRJTkctU09VUkNFUy5qc29uIiwiYnl0ZXMiOjIwMjAsInNoYTI1NiI6ImZhNGMzNDQ4MDExNTQ4NzJkNjE3OWVlMmVmNDk5MjNkYzlmODkwOWVmMDFlNTNiODZlOGY1N2M2MjU4MjMyNzQifSx7InBhdGgiOiJMSUNFTlNFLnR4dCIsImJ5dGVzIjoxMTM0Niwic2hhMjU2IjoiOTQ0YzEzZmYwZmU3OTVlMjkxZmQxYzQ5NDczZjk4ZDRmZGYxZjc0NjM4ZTAxZjg4Mjc2OWNkNGNhZTc4YjczZCJ9LHsicGF0aCI6Ik5PVElDRS1QUk9WRU5BTkNFLmpzb24iLCJieXRlcyI6NDUwMjY0LCJzaGEyNTYiOiI1MzRkZDU5ZmQ0YzE1ZGQxMzgyZTgyN2YwYjg1YzE5ZjdjNjk4ZTIzNWY5Mjk5ZWFhMjAyZGI1NDAwODM0Mjg4In0seyJwYXRoIjoiTk9USUNFLnR4dCIsImJ5dGVzIjo2MjYsInNoYTI1NiI6IjFkZmJmNDQ5OGRjMDI2YjIwNTljMGIwYjVlYjVmYTFkODJhZTMzNGU1OGZmMTFlN2MyOTczMzMyN2YyNWM0ZWIifSx7InBhdGgiOiJSRUJVSUxESU5HLm1kIiwiYnl0ZXMiOjM4NDIsInNoYTI1NiI6ImNlNjA1YjVmZGIwMzE5MzM5ZjlmODNmMmZlN2NjY2JjN2U1NzI2ZmRmNDk0ZGE2ZTI4NDMzYmVmODI5ZWIwYmUifSx7InBhdGgiOiJTT1VSQ0UtTk9USUNFUy50eHQiLCJieXRlcyI6OTAxNzc3MSwic2hhMjU2IjoiODk5NzZiZWNjMjU2NTQwZTZkMmU4MDdiNDdhNGUwNWU4ODk5ODJjMDYyMmZjMDQ0MTNhN2JmN2U3N2E3N2UzNyJ9LHsicGF0aCI6IlRISVJELVBBUlRZLU5PVElDRVMudHh0IiwiYnl0ZXMiOjI0OTE0OTYsInNoYTI1NiI6IjExNjQ0N2VmZjc3ODkzNTExNzk3ZWY0NzYwMTFkZWM4MDAyMjRmOTFlMzM0MmUzZDY1NzA3MDg3MTJiNGI3NzIifSx7InBhdGgiOiJsaWNlbnNlcy9ucG0tY21kLXNoaW0udHh0IiwiYnl0ZXMiOjgxMywic2hhMjU2IjoiYWZmZmRmMTIwODExMjI3NDljNGI3MWM1YjFjMTFiYzY1OWQ3OTI0MmQxOWUxOGY1ZThkYmFiMDRhNDVlMzZiYiJ9LHsicGF0aCI6Im5wbS1hZGFwdGVyLWZpbGVzLmpzb24iLCJieXRlcyI6MTUyNCwic2hhMjU2IjoiZjIyNmJiMjNiMjEyYWE4MjQ0NzdlYTY3ZGY0MjQ1ZjQxMjFkOWQ2MTdmYTA4NGVhYWQwZThjYjlhNTIxN2RlYSJ9XX1dfQ==","signature":"P86ZWqty8zl111akeDRKvJEd2/D0ew2lIyGQRcc/myvJWBh+wVMC5GnV4+2613/GZJx7XQPpol/r0HPFSHPpAw=="}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": 1,
|
|
3
|
+
"package": "@raidiant/notifai",
|
|
4
|
+
"adapter_version": "12.0.0-beta.13",
|
|
5
|
+
"native": {
|
|
6
|
+
"version": "12.0.0-beta.13",
|
|
7
|
+
"source_revision": "a2af9c45ccf49001f4ccf2401f73685fc4e6c05e",
|
|
8
|
+
"inventory_url": "https://github.com/Raidiant-io/notifai/releases/download/v12.0.0-beta.13/inventory.json"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
{
|
|
12
|
+
"path": "CHANGELOG.md",
|
|
13
|
+
"bytes": 61777,
|
|
14
|
+
"sha256": "5889710ae0b01c7358360c1fbb84d26181569469f33397a2465a4444f286babf"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"path": "LICENSE",
|
|
18
|
+
"bytes": 11346,
|
|
19
|
+
"sha256": "944c13ff0fe795e291fd1c49473f98d4fdf1f74638e01f882769cd4cae78b73d"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"path": "NOTICE",
|
|
23
|
+
"bytes": 626,
|
|
24
|
+
"sha256": "1dfbf4498dc026b2059c0b0b5eb5fa1d82ae334e58ff11e7c29733327f25c4eb"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"path": "THIRD_PARTY_NOTICES",
|
|
28
|
+
"bytes": 39652,
|
|
29
|
+
"sha256": "4639bc49701f661f67baf3d0408436d2cb80fd0c9799e68b9be3684f5ad69b91"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"path": "bin/notifai.mjs",
|
|
33
|
+
"bytes": 520496,
|
|
34
|
+
"sha256": "94eb5ae58a5ee49e7cd07552806a93d17bf83038c221a477c82c8341a9ae5d04"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"path": "data/install.ps1",
|
|
38
|
+
"bytes": 18811,
|
|
39
|
+
"sha256": "2925b84fb7890110695249d7f651a4ca0878f6ace2e127f44b7b4ad835073c5f"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"path": "data/release.json",
|
|
43
|
+
"bytes": 90,
|
|
44
|
+
"sha256": "a66335b124530acf33fb337a1272fb17e83ac43dc7b462239ec974921379b51d"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"path": "package.json",
|
|
48
|
+
"bytes": 815,
|
|
49
|
+
"sha256": "356ffcb901d42406f254632921de3c0c5af99ce9c47d8bfa4e03df27af0b78da"
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
package/package.json
CHANGED
|
@@ -1,34 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raidiant/notifai",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "12.0.0-beta.13",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Launch the independently managed native Notifai CLI",
|
|
6
6
|
"bin": {
|
|
7
|
-
"notifai": "
|
|
7
|
+
"notifai": "bin/notifai.mjs"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
|
-
"
|
|
10
|
+
"bin",
|
|
11
|
+
"data",
|
|
12
|
+
"package.json",
|
|
13
|
+
"npm-adapter-files.json",
|
|
14
|
+
"inventory.json",
|
|
15
|
+
"LICENSE",
|
|
16
|
+
"NOTICE",
|
|
17
|
+
"THIRD_PARTY_NOTICES",
|
|
11
18
|
"CHANGELOG.md"
|
|
12
19
|
],
|
|
13
|
-
"dependencies": {
|
|
14
|
-
"@clack/prompts": "^1.7.0",
|
|
15
|
-
"@raidiant/notifai-protocol": "8.2.1",
|
|
16
|
-
"commander": "^14.0.0",
|
|
17
|
-
"jsonc-parser": "^3.3.1",
|
|
18
|
-
"picocolors": "^1.1.1",
|
|
19
|
-
"qrcode": "1.5.4",
|
|
20
|
-
"smol-toml": "^1.4.0",
|
|
21
|
-
"ws": "8.21.0"
|
|
22
|
-
},
|
|
23
|
-
"devDependencies": {
|
|
24
|
-
"@types/pngjs": "6.0.5",
|
|
25
|
-
"@types/qrcode": "1.5.6",
|
|
26
|
-
"@types/ws": "8.18.1",
|
|
27
|
-
"jsqr": "1.4.0",
|
|
28
|
-
"pngjs": "7.0.0",
|
|
29
|
-
"typescript": "^5.8.0",
|
|
30
|
-
"vitest": "4.1.11"
|
|
31
|
-
},
|
|
32
20
|
"engines": {
|
|
33
21
|
"node": ">=20.12.0"
|
|
34
22
|
},
|
|
@@ -38,30 +26,12 @@
|
|
|
38
26
|
"bugs": {
|
|
39
27
|
"url": "https://github.com/Raidiant-io/notifai/issues"
|
|
40
28
|
},
|
|
41
|
-
"publishConfig": {
|
|
42
|
-
"access": "public"
|
|
43
|
-
},
|
|
44
29
|
"repository": {
|
|
45
30
|
"type": "git",
|
|
46
31
|
"url": "git+https://github.com/Raidiant-io/notifai.git",
|
|
47
32
|
"directory": "apps/cli"
|
|
48
33
|
},
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"cli",
|
|
52
|
-
"agents",
|
|
53
|
-
"apns",
|
|
54
|
-
"fcm",
|
|
55
|
-
"android",
|
|
56
|
-
"push",
|
|
57
|
-
"ai",
|
|
58
|
-
"claude",
|
|
59
|
-
"codex"
|
|
60
|
-
],
|
|
61
|
-
"scripts": {
|
|
62
|
-
"build": "node ../../scripts/clean-dist.mjs && tsc -p tsconfig.json && node ../../scripts/copy-shipped-skill.mjs && node ../../scripts/chmod-cli-bin.mjs",
|
|
63
|
-
"pretest": "pnpm run build",
|
|
64
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
65
|
-
"test": "node ../../scripts/run-cli-tests.mjs"
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
66
36
|
}
|
|
67
|
-
}
|
|
37
|
+
}
|
package/README.md
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
# notifai
|
|
2
|
-
|
|
3
|
-
Send native phone notifications from agents and local programs.
|
|
4
|
-
|
|
5
|
-
An agent working while you are away has no way to reach you, so it either
|
|
6
|
-
guesses or sits blocked in a terminal nobody is watching. `notifai` gives
|
|
7
|
-
it a way to tell you something finished, and a way to ask you a question
|
|
8
|
-
and get your answer back as a banner on your phone.
|
|
9
|
-
|
|
10
|
-
```sh
|
|
11
|
-
npm install -g @raidiant/notifai
|
|
12
|
-
notifai init
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
The `notifai` command is always a machine-wide install. Setup scope (this
|
|
16
|
-
project vs this machine) does not change that. If you do not want a global
|
|
17
|
-
bin, `npx --yes @raidiant/notifai@<version>` is supported. Pin the version.
|
|
18
|
-
`hooks install` then writes that same pinned npx invocation into the harness
|
|
19
|
-
adapter. This is slower than a real install and is not the default path.
|
|
20
|
-
|
|
21
|
-
Run `notifai doctor` or `notifai update --check --json` to check for a newer
|
|
22
|
-
CLI and inspect release notes, guidance, and session requirements. Enabled
|
|
23
|
-
Projects give root agents a quiet update offer at most once every seven days
|
|
24
|
-
across the machine. A release does not install itself or restart an Agent
|
|
25
|
-
Session automatically. The package includes its changelog.
|
|
26
|
-
|
|
27
|
-
Use `notifai update` for later global updates. It repairs the installation the
|
|
28
|
-
shell actually selects and keeps the stable hook adapter on that same CLI. It
|
|
29
|
-
fails instead of moving the command to a different PATH slot when it cannot
|
|
30
|
-
verify the selected installation or retarget an existing adapter safely.
|
|
31
|
-
|
|
32
|
-
`init` walks the setup one step at a time and tells you the single next
|
|
33
|
-
thing to do. Run it again after each step; it works out what remains.
|
|
34
|
-
|
|
35
|
-
At a human terminal, `init` asks once whether this setup is for this project
|
|
36
|
-
or for every project on this machine. That answer is skill, hooks, and
|
|
37
|
-
config together. Pairing, devices, and credentials stay on this machine
|
|
38
|
-
either way. An unattended caller passes the same choice as a flag:
|
|
39
|
-
`notifai init --setup-scope project` or `notifai init --setup-scope global`.
|
|
40
|
-
`--skills-scope` is an alias of that flag when `--skills` is set. Shared
|
|
41
|
-
project config may live in the repo; personal project preferences live under
|
|
42
|
-
the user config directory and never require a `.gitignore` edit.
|
|
43
|
-
|
|
44
|
-
## Telling you something happened
|
|
45
|
-
|
|
46
|
-
```sh
|
|
47
|
-
notifai send --kind done \
|
|
48
|
-
--title "Deploy finished" \
|
|
49
|
-
--summary "The staging deployment is live." \
|
|
50
|
-
--body "The staging deployment is live and ready for review."
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Write a brief title whose substance is immediately understandable; type lives
|
|
54
|
-
in `--kind`, and Project identity is inferred from the invocation directory.
|
|
55
|
-
Every Notification Request has a purpose-written, one-line plain-text Summary
|
|
56
|
-
for native banners and list views. It is required and limited to 240 Unicode
|
|
57
|
-
characters. Body is optional standalone Markdown for focused detail; when it is
|
|
58
|
-
absent, the focused view shows Summary. Use `--body-file <path|->` for long
|
|
59
|
-
content. Repeat `--image` for an ordered image
|
|
60
|
-
collection (up to eight) and pair each with `--image-alt`. Every attached
|
|
61
|
-
image appears in the gallery; to place one where the words refer to it, write
|
|
62
|
-
Markdown image syntax with its 1-based position, ``.
|
|
63
|
-
A bare `media:1` or a link to it is refused before sending.
|
|
64
|
-
|
|
65
|
-
## Asking you a question
|
|
66
|
-
|
|
67
|
-
```sh
|
|
68
|
-
notifai ask "Deploy the migration to production?" \
|
|
69
|
-
--choice Yes --choice No
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
The agent registers the question and starts background submission immediately;
|
|
73
|
-
it can continue independent work while your answer is outstanding. Registration
|
|
74
|
-
alone does not prove Provider Acceptance. Question Routing keeps the exact
|
|
75
|
-
Agent Session's answer path for the complete answer window. Claude Code on
|
|
76
|
-
macOS/Linux and Codex observe answers out of band; Claude Code on Windows
|
|
77
|
-
returns answers through a held Stop. Codex queues a wake-up, then drains current
|
|
78
|
-
notes and answers together at a supported hook or `notifai receive` boundary.
|
|
79
|
-
Queue success proves wake storage, not presentation.
|
|
80
|
-
|
|
81
|
-
By default submission begins without waiting for the turn to end
|
|
82
|
-
(`ask_grace_seconds = 0`). Set a positive grace period for a terminal-only
|
|
83
|
-
answer window first.
|
|
84
|
-
|
|
85
|
-
When you answer, the agent acknowledges it before it does anything else, so you
|
|
86
|
-
find out your reply landed and what it set in motion — not just that you sent
|
|
87
|
-
it. Answering from your phone and wondering whether anything happened is the
|
|
88
|
-
whole problem this solves.
|
|
89
|
-
|
|
90
|
-
For a harness that cannot resume an idle agent turn, `notifai send --reply`
|
|
91
|
-
owns the complete answer window in the foreground: keep it alive and set
|
|
92
|
-
`--reply-timeout` equal to `--reply-window`. After a timeout, retain the request
|
|
93
|
-
ID and inspect that original with `notifai replies` and `notifai status`; never
|
|
94
|
-
send a duplicate.
|
|
95
|
-
|
|
96
|
-
## Agent harnesses
|
|
97
|
-
|
|
98
|
-
The CLI and managed hook adapters support macOS, Linux, and Windows. iPhone
|
|
99
|
-
and Android Companion Apps are both active: Android is distributed as a
|
|
100
|
-
directly downloadable signed APK (no Google Play listing yet), with a separate
|
|
101
|
-
invitation-only Firebase App Distribution test lane. Native desktop Companion
|
|
102
|
-
Apps are not shipped.
|
|
103
|
-
|
|
104
|
-
```sh
|
|
105
|
-
notifai hooks install
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
Wires lifecycle hooks into every supported harness detected on this
|
|
109
|
-
machine (Claude Code, Codex, Cursor, OpenCode, OpenClaw, Grok). `notifai init` does the
|
|
110
|
-
same and, at a terminal, lets you keep the detected set, pick a subset,
|
|
111
|
-
or add one it did not see. This is what lets an agent's question reach
|
|
112
|
-
your phone without the agent having to cooperate — no question detection,
|
|
113
|
-
no state in a context window that compaction will eat. Grok's managed hooks
|
|
114
|
-
observe lifecycle events and hold Stop through the complete answer window,
|
|
115
|
-
then return the answer to the same Agent Session. They cannot inject activation
|
|
116
|
-
guidance; load the Notifai skill directly. Exact Source Context comes from
|
|
117
|
-
`GROK_SESSION_ID`.
|
|
118
|
-
|
|
119
|
-
Every harness definition calls one stable user-level adapter under the account
|
|
120
|
-
home (`~/.notifai/bin/hook-adapter` on macOS/Linux and the corresponding user
|
|
121
|
-
profile path on Windows). Node, package manager, CLI version, checkout,
|
|
122
|
-
configuration directories, and notification preferences are resolved behind
|
|
123
|
-
it, so upgrades and configuration changes do not rewrite trusted hook
|
|
124
|
-
definitions. Windows invokes its JavaScript adapter through the registered Node
|
|
125
|
-
executable; macOS/Linux retain the POSIX adapter and its stable command bytes.
|
|
126
|
-
Codex SessionStart guidance stays within Codex's built-in inline-context budget,
|
|
127
|
-
so its stable definition does not need an output-limit override that would
|
|
128
|
-
create a different approval identity.
|
|
129
|
-
Claude Code Stop returns immediately into the live inbox route on macOS/Linux;
|
|
130
|
-
on Windows, where upstream exposes no inbox socket, Stop stays open and returns
|
|
131
|
-
the accepted answer through the harness continuation. The first migration may
|
|
132
|
-
require one Codex `/hooks` approval; later repairs keep the same source and
|
|
133
|
-
definition identity.
|
|
134
|
-
Codex's Stop definition declares the full-window timeout explicitly; that
|
|
135
|
-
one-time definition change is why the migration needs approval. Prompt-submit
|
|
136
|
-
and session-end retain fixed short limits.
|
|
137
|
-
|
|
138
|
-
`notifai doctor` compares Codex trust on a best-effort basis against Codex's
|
|
139
|
-
current persisted representation. Notifai never writes that trust store;
|
|
140
|
-
Codex's `/hooks` review is authoritative if the diagnostic and UI disagree.
|
|
141
|
-
|
|
142
|
-
Uninstall removes only the selected harness definition. It intentionally keeps
|
|
143
|
-
the shared adapter because definitions for other harnesses or projects may
|
|
144
|
-
still invoke it and cannot all be discovered from one working directory.
|
|
145
|
-
|
|
146
|
-
## Checking it works
|
|
147
|
-
|
|
148
|
-
```sh
|
|
149
|
-
notifai doctor
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
Reports every part of the setup and names where to start if something is
|
|
153
|
-
wrong. Any `FAIL` line makes the command exit nonzero; informational `--` lines
|
|
154
|
-
do not. `--json` emits the same result with an explicit `exit_code`.
|
|
155
|
-
|
|
156
|
-
## Reference
|
|
157
|
-
|
|
158
|
-
`notifai <command> --help` is the exhaustive and current flag surface.
|
|
159
|
-
Everything useful is possible non-interactively, so an agent never
|
|
160
|
-
reaches a prompt and hangs.
|
|
161
|
-
|
|
162
|
-
Source, issues and the public/private boundary policy:
|
|
163
|
-
<https://github.com/Raidiant-io/notifai>
|
|
164
|
-
|
|
165
|
-
The URL, self-host exception, guidance-authority and non-exfiltration policy is
|
|
166
|
-
documented in [`docs/TRUST.md`](https://github.com/Raidiant-io/notifai/blob/main/docs/TRUST.md).
|
|
167
|
-
|
|
168
|
-
Apache-2.0.
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/** One optional notice per machine-local state directory, across roots and harnesses. */
|
|
2
|
-
export declare function agentUpdateNotice(options: {
|
|
3
|
-
env: NodeJS.ProcessEnv;
|
|
4
|
-
now: number;
|
|
5
|
-
updateCommand: string;
|
|
6
|
-
fetchImpl?: typeof fetch;
|
|
7
|
-
}): Promise<string | undefined>;
|