@raidiant/notifai 12.0.0-beta.8 → 12.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -8,23 +8,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8
8
  This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
9
9
  and [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/).
10
10
 
11
- ## [12.0.0-beta.8](https://github.com/Raidiant-io/notifai/compare/v11.8.0...v12.0.0-beta.8) (2026-10-09)
11
+ ## [12.0.0](https://github.com/Raidiant-io/notifai/compare/v11.8.0...v12.0.0) (2026-10-12)
12
12
 
13
- ### Breaking changes
14
13
 
15
- * The existing `@raidiant/notifai` npm package now installs and launches the managed native CLI instead of shipping a separate Node runtime. Existing native installations keep their version and channel until an explicit update.
14
+ ### ⚠ BREAKING CHANGES
15
+
16
+ * **cli:** unify native and npm installation
17
+
18
+ ### Features
19
+
20
+ * **cli:** link a Claude Code picker by its questions, not a copied marker ([#278](https://github.com/Raidiant-io/notifai/issues/278)) ([449a4eb](https://github.com/Raidiant-io/notifai/commit/449a4ebe9de2284b808531675ee9f44f9f6978f1))
21
+ * **cli:** share one sign-in per machine with desktop apps ([#282](https://github.com/Raidiant-io/notifai/issues/282)) ([32863ba](https://github.com/Raidiant-io/notifai/commit/32863ba132261f706726664fd4796134a4d38eb6))
22
+ * **cli:** unify native and npm installation ([2ea7ef7](https://github.com/Raidiant-io/notifai/commit/2ea7ef735b75deee1deda7e08672ad0c757d0d0c))
23
+ * **protocol:** add desktop platforms, the stream provider and the changes feed ([#281](https://github.com/Raidiant-io/notifai/issues/281)) ([4b2bf51](https://github.com/Raidiant-io/notifai/commit/4b2bf51ecf5c120e5fa12141736f0df649f9fea5))
24
+ * **sounds:** add a bundled Update tone ([#289](https://github.com/Raidiant-io/notifai/issues/289)) ([31a7e5d](https://github.com/Raidiant-io/notifai/commit/31a7e5d103b318d7b8b10d1d29bd8c7964172dfe))
16
25
 
17
- ### Improvements
18
26
 
19
- * Batch Windows npm permission verification instead of starting one PowerShell process per package path. Keep signed payload checks and reject unsafe members.
27
+ ### Bug Fixes
20
28
 
21
- * Verify npm-owned Windows directories and account profiles without changing their ACLs, while preserving strict ownership of managed native paths.
29
+ * **auth:** preserve Linux credential authority across sessions ([#285](https://github.com/Raidiant-io/notifai/issues/285)) ([ce1ec66](https://github.com/Raidiant-io/notifai/commit/ce1ec66ea6f6078132b474a5b708107438d9017c))
30
+ * **cli:** link grouped Claude questions across registrations ([#288](https://github.com/Raidiant-io/notifai/issues/288)) ([b2e1bc4](https://github.com/Raidiant-io/notifai/commit/b2e1bc46d68c25dbf7a79bc67f88898d66ec720b))
31
+ * **cli:** preserve activity verification through long Codex turns ([#276](https://github.com/Raidiant-io/notifai/issues/276)) ([151ba68](https://github.com/Raidiant-io/notifai/commit/151ba687effee47ccef65f3800502ea896cd76dc))
32
+ * **cli:** stop reporting an acknowledgement as still required after recording it ([#277](https://github.com/Raidiant-io/notifai/issues/277)) ([0c4b363](https://github.com/Raidiant-io/notifai/commit/0c4b36358c9ff0616732043611aeebdcfd6cf4dd))
22
33
 
23
- * Use the same native runtime and bundled skill through shell, PowerShell, npm, and npx setup.
24
- * Report installation ownership and recovery clearly in doctor, preserve unfinished removal, and make migration from older npm installations explicit.
25
- * Continue interactive setup correctly when installing through a piped shell command.
26
- * Verify npm adapter bytes against the signed native release and coordinate publication across all supported targets.
27
- * Keep long Codex turns readable and link Claude question-picker content to its registered question.
34
+
35
+ ### Dependencies
36
+
37
+ * The following workspace dependencies were updated
38
+ * dependencies
39
+ * @raidiant/notifai-protocol bumped from 8.2.2 to 8.3.0
28
40
 
29
41
  ## [11.8.0](https://github.com/Raidiant-io/notifai/compare/v11.7.1...v11.8.0) (2026-10-08)
30
42
 
package/bin/notifai.mjs CHANGED
@@ -7031,7 +7031,7 @@ var init_zip_reader = __esm({
7031
7031
  });
7032
7032
 
7033
7033
  // apps/cli/npm/main.mjs
7034
- import { readFileSync as readFileSync5, lstatSync as lstatSync5 } from "node:fs";
7034
+ import { readFileSync as readFileSync5, lstatSync as lstatSync6 } from "node:fs";
7035
7035
  import path7 from "node:path";
7036
7036
  import { fileURLToPath as fileURLToPath2 } from "node:url";
7037
7037
 
@@ -7053,6 +7053,13 @@ function isPrerelease(value) {
7053
7053
  return SEMVER.exec(value)?.[4] !== void 0;
7054
7054
  }
7055
7055
 
7056
+ // apps/cli/src/local-continuity.ts
7057
+ function localContinuity(value) {
7058
+ const item = value;
7059
+ if (!item || typeof item.contract !== "string" || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(item.contract)) throw new Error("Invalid local continuity contract");
7060
+ return { contract: item.contract };
7061
+ }
7062
+
7056
7063
  // apps/cli/src/release-distribution.ts
7057
7064
  var RELEASE_TARGETS = [
7058
7065
  "bun-darwin-arm64",
@@ -7111,11 +7118,19 @@ var Distribution = class {
7111
7118
  const publicKey = createPublicKey(key);
7112
7119
  if (publicKey.asymmetricKeyType !== "ed25519" || signature.length !== 64 || !verify(null, releaseSigningMessage(kind, payload), publicKey, signature)) throw new Error("Invalid release signature");
7113
7120
  const value = JSON.parse(payload.toString("utf8"));
7114
- if (!record(value) || value["schema"] !== 1) throw new Error("Unsupported release record schema");
7121
+ if (!record(value) || value["schema"] !== 1 && !(kind === "inventory" && value["schema"] === 2)) {
7122
+ throw new Error("Unsupported release record schema");
7123
+ }
7115
7124
  return value;
7116
7125
  }
7117
7126
  verifyInventory(bytes) {
7118
7127
  const value = this.verifyRecord("inventory", bytes);
7128
+ if (value["schema"] === 2) {
7129
+ const continuity = localContinuity(value["local_continuity"]);
7130
+ value["local_continuity"] = Object.freeze(continuity);
7131
+ } else if (value["local_continuity"] !== void 0) {
7132
+ throw new Error("Historical inventory cannot declare an enforcing continuity contract");
7133
+ }
7119
7134
  if (!version(value["version"]) || typeof value["source_revision"] !== "string" || !/^[a-f0-9]{40}$/.test(value["source_revision"]) || !positive(value["store_schema"]) || !positive(value["launcher_schema"]) || !Array.isArray(value["artifacts"]) || value["artifacts"].length === 0 || value["artifacts"].length > RELEASE_TARGETS.length) {
7120
7135
  throw new Error("Malformed release inventory");
7121
7136
  }
@@ -7260,6 +7275,20 @@ var NPM_ADAPTER_MANIFEST = "npm-adapter-files.json";
7260
7275
  var NPM_ADAPTER_INVENTORY = "inventory.json";
7261
7276
  var NPM_ADAPTER_MAX_METADATA = 256 * 1024;
7262
7277
  var NPM_ADAPTER_MAX_BYTES = 16 * 1024 * 1024;
7278
+ function assertNpmAdapterPackage(value, manifest) {
7279
+ const pkg = value;
7280
+ const bin = pkg?.["bin"];
7281
+ if (!pkg || pkg["name"] !== manifest.package || pkg["version"] !== manifest.adapter_version || !bin || typeof bin !== "object" || Array.isArray(bin) || Object.keys(bin).length !== 1 || bin["notifai"] !== NPM_ADAPTER_BIN || [
7282
+ "scripts",
7283
+ "dependencies",
7284
+ "optionalDependencies",
7285
+ "peerDependencies",
7286
+ "bundleDependencies",
7287
+ "bundledDependencies",
7288
+ "directories",
7289
+ "man"
7290
+ ].some((key) => Object.hasOwn(pkg, key))) throw new Error("Invalid published npm adapter package contract");
7291
+ }
7263
7292
  function npmAdapterInventoryUrl(version2) {
7264
7293
  if (version2.length > 100 || !isSemVer(version2)) throw new Error("Invalid npm adapter version");
7265
7294
  return `https://github.com/Raidiant-io/notifai/releases/download/v${version2}/inventory.json`;
@@ -7353,8 +7382,7 @@ function verifyNpmAdapterArtifact(directory, distribution, checkAccess = npmAdap
7353
7382
  }
7354
7383
  if (expected.size) throw new Error("Npm adapter payload is incomplete");
7355
7384
  const executable = path.join(directory, NPM_ADAPTER_BIN);
7356
- const pkg = JSON.parse(metadata("package.json"));
7357
- if (pkg.name !== manifest.package || pkg.version !== manifest.adapter_version || pkg.bin?.notifai !== NPM_ADAPTER_BIN || pkg.scripts !== void 0 || pkg.dependencies !== void 0) throw new Error("Invalid published npm adapter package contract");
7385
+ assertNpmAdapterPackage(JSON.parse(metadata("package.json")), manifest);
7358
7386
  return { directory, executable, manifest, inventory, signedInventory };
7359
7387
  }
7360
7388
 
@@ -10711,12 +10739,12 @@ function assertCurrentUserOwns(file, owner) {
10711
10739
  var MAX_EXPANDED = 768 * 1024 * 1024;
10712
10740
  var MAX_FILE = 512 * 1024 * 1024;
10713
10741
  var MAX_ENTRIES = 130;
10714
- async function tarEntries(bytes, consume) {
10742
+ async function tarEntries(bytes, consume, maxExpanded = MAX_EXPANDED) {
10715
10743
  const reader = (0, import_tar_stream.extract)();
10716
10744
  let expanded = 0;
10717
10745
  const limit = new Transform({ transform(chunk, _encoding, done) {
10718
10746
  expanded += chunk.length;
10719
- done(expanded > MAX_EXPANDED ? new Error("Archive expanded size exceeds its limit") : null, chunk);
10747
+ done(expanded > maxExpanded ? new Error("Archive expanded size exceeds its limit") : null, chunk);
10720
10748
  } });
10721
10749
  const pumping = pipeline(
10722
10750
  Readable.from([bytes]),
@@ -10888,11 +10916,11 @@ async function acquireNative(release, { distribution, platform, capture = false,
10888
10916
  }
10889
10917
 
10890
10918
  // apps/cli/src/npm-adapter-route.ts
10891
- import { lstatSync as lstatSync3, readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
10919
+ import { lstatSync as lstatSync4, readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
10892
10920
  import path5 from "node:path";
10893
10921
 
10894
10922
  // apps/cli/src/local-path.ts
10895
- import { realpathSync } from "node:fs";
10923
+ import { lstatSync as lstatSync3, readlinkSync, realpathSync } from "node:fs";
10896
10924
  import path4 from "node:path";
10897
10925
  function canonicalPath(file) {
10898
10926
  const absolute = path4.resolve(file);
@@ -11007,7 +11035,7 @@ function inspectNpmAdapterRoute(command, proof, options = {}) {
11007
11035
  const platform = options.platform ?? process.platform, access = options.checkAccess ?? npmAdapterPosixAccess;
11008
11036
  try {
11009
11037
  const candidate = path5.resolve(command), root = path5.resolve(proof.directory);
11010
- if (sameLocalPath(candidate, proof.executable, platform) && !lstatSync3(candidate).isSymbolicLink()) {
11038
+ if (sameLocalPath(candidate, proof.executable, platform) && !lstatSync4(candidate).isSymbolicLink()) {
11011
11039
  access([{ file: candidate, directory: false }]);
11012
11040
  return { kind: "direct", command: candidate, directory: path5.dirname(candidate), global_prefix: null, temporary_bin: null };
11013
11041
  }
@@ -11020,7 +11048,7 @@ function inspectNpmAdapterRoute(command, proof, options = {}) {
11020
11048
  for (const start of [root, route.directory]) {
11021
11049
  let current = start;
11022
11050
  for (let depth = 0; depth < 16; depth++) {
11023
- const stat2 = lstatSync3(current);
11051
+ const stat2 = lstatSync4(current);
11024
11052
  if (!stat2.isDirectory() || stat2.isSymbolicLink()) return null;
11025
11053
  directories.add(current);
11026
11054
  if (sameLocalPath(current, stop, platform)) break;
@@ -11029,7 +11057,7 @@ function inspectNpmAdapterRoute(command, proof, options = {}) {
11029
11057
  current = parent;
11030
11058
  }
11031
11059
  }
11032
- const stat = lstatSync3(candidate);
11060
+ const stat = lstatSync4(candidate);
11033
11061
  if (platform !== "win32") {
11034
11062
  if (!stat.isSymbolicLink() || !process.getuid || stat.uid !== process.getuid() || !sameLocalPath(realpathSync2(candidate), proof.executable, platform)) return null;
11035
11063
  } else {
@@ -11191,7 +11219,7 @@ async function runNpmAdapter(args, { locator, platform, distribution, verify: ve
11191
11219
  import assert3 from "node:assert/strict";
11192
11220
  import { execFileSync, spawn, spawnSync } from "node:child_process";
11193
11221
  import { randomUUID } from "node:crypto";
11194
- import { lstatSync as lstatSync4, mkdtempSync as mkdtempSync2, readFileSync as readFileSync4, readdirSync as readdirSync2 } from "node:fs";
11222
+ import { lstatSync as lstatSync5, mkdtempSync as mkdtempSync2, readFileSync as readFileSync4, readdirSync as readdirSync2 } from "node:fs";
11195
11223
  import os from "node:os";
11196
11224
  import path6 from "node:path";
11197
11225
  import { fileURLToPath } from "node:url";
@@ -11239,13 +11267,13 @@ function windowsPackageAccess(paths, execute = execFileSync) {
11239
11267
  function ownedPosixCommand(home, uid = process.getuid()) {
11240
11268
  const command = path6.join(home, ".notifai/bin/notifai");
11241
11269
  try {
11242
- lstatSync4(command);
11270
+ lstatSync5(command);
11243
11271
  } catch (error) {
11244
11272
  if (error.code === "ENOENT") return null;
11245
11273
  throw error;
11246
11274
  }
11247
11275
  for (const file of [home, path6.join(home, ".notifai"), path6.dirname(command), command]) {
11248
- const stat = lstatSync4(file);
11276
+ const stat = lstatSync5(file);
11249
11277
  assert3.ok(
11250
11278
  !stat.isSymbolicLink() && stat.uid === uid && (stat.mode & 18) === 0 && (file === command ? stat.isFile() && (stat.mode & 64) !== 0 : stat.isDirectory()),
11251
11279
  "Existing installation is not privately owned; inspect it before repair"
@@ -11258,7 +11286,7 @@ function assertAcquisitionReady(home, checkAccess, checkHomeAccess = checkAccess
11258
11286
  for (const directory of [home, root]) {
11259
11287
  let stat;
11260
11288
  try {
11261
- stat = lstatSync4(directory);
11289
+ stat = lstatSync5(directory);
11262
11290
  } catch (error) {
11263
11291
  if (directory === root && error.code === "ENOENT") return;
11264
11292
  throw error;
@@ -11269,7 +11297,7 @@ function assertAcquisitionReady(home, checkAccess, checkHomeAccess = checkAccess
11269
11297
  }
11270
11298
  for (const name of ["uninstall.json", "transaction.json", "install.json", "active.json"]) {
11271
11299
  try {
11272
- lstatSync4(path6.join(root, name));
11300
+ lstatSync5(path6.join(root, name));
11273
11301
  } catch (error) {
11274
11302
  if (error.code === "ENOENT") continue;
11275
11303
  throw error;
@@ -11280,7 +11308,7 @@ function assertAcquisitionReady(home, checkAccess, checkHomeAccess = checkAccess
11280
11308
  const directory = path6.join(root, name);
11281
11309
  let stat;
11282
11310
  try {
11283
- stat = lstatSync4(directory);
11311
+ stat = lstatSync5(directory);
11284
11312
  } catch (error) {
11285
11313
  if (error.code === "ENOENT") continue;
11286
11314
  throw error;
@@ -11355,7 +11383,7 @@ function nativePlatform() {
11355
11383
  checkAccess(paths) {
11356
11384
  if (!windows) {
11357
11385
  for (const { file } of paths) {
11358
- const stat = lstatSync4(file);
11386
+ const stat = lstatSync5(file);
11359
11387
  assert3.ok(stat.uid === process.getuid() && (stat.mode & 18) === 0, "Npm adapter path is not owned by this User");
11360
11388
  }
11361
11389
  return;
@@ -11403,7 +11431,7 @@ function nativePlatform() {
11403
11431
  try {
11404
11432
  const root = path7.resolve(path7.dirname(fileURLToPath2(import.meta.url)), "..");
11405
11433
  const file = path7.join(root, "data/release.json");
11406
- const stat = lstatSync5(file);
11434
+ const stat = lstatSync6(file);
11407
11435
  if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1024) throw new Error("Invalid npm adapter release locator");
11408
11436
  const locator = JSON.parse(readFileSync5(file, "utf8"));
11409
11437
  const platform = nativePlatform(), distribution = new Distribution(RELEASE_PUBLIC_KEYS);
package/data/install.ps1 CHANGED
@@ -9,7 +9,8 @@ param(
9
9
  [switch]$Json,
10
10
  [switch]$NoInit,
11
11
  [switch]$NoPath,
12
- [switch]$MigrateNpm
12
+ [switch]$MigrateNpm,
13
+ [switch]$Upgrade
13
14
  )
14
15
  Set-StrictMode -Version Latest
15
16
  $ErrorActionPreference = 'Stop'
@@ -147,9 +148,38 @@ function Expand-NotifaiArchive([string]$Archive, [string]$Destination) {
147
148
  }
148
149
  } finally { $zip.Dispose() }
149
150
  }
151
+ function Add-NotifaiBootstrapType([string]$Source) {
152
+ if ($PSVersionTable.PSEdition -ne 'Desktop') { Add-Type -TypeDefinition $Source -ErrorAction Stop; return }
153
+ # Framework CodeDom passes csc an ANSI environment block. Keep its temporary
154
+ # paths relative even when the User's profile/TEMP contains non-ANSI text.
155
+ # Only this synchronous compiler invocation changes process-local cwd/env.
156
+ $scratch = [IO.Path]::Combine([IO.Path]::GetTempPath(), 'notifai-compiler-' + [Guid]::NewGuid().ToString('N'))
157
+ New-NotifaiPrivateDirectory $scratch
158
+ $previousDirectory = [Environment]::CurrentDirectory
159
+ $previousTemp = $env:TEMP
160
+ $previousTmp = $env:TMP
161
+ $parameters = [CodeDom.Compiler.CompilerParameters]::new()
162
+ $parameters.GenerateInMemory = $true
163
+ [void]$parameters.ReferencedAssemblies.Add([ComponentModel.Win32Exception].Assembly.Location)
164
+ $parameters.TempFiles = [CodeDom.Compiler.TempFileCollection]::new('.', $false)
165
+ try {
166
+ [Environment]::CurrentDirectory = $scratch
167
+ $env:TEMP = '.'
168
+ $env:TMP = '.'
169
+ Add-Type -TypeDefinition $Source -CompilerParameters $parameters -ErrorAction Stop
170
+ } finally {
171
+ try { $parameters.TempFiles.Dispose() }
172
+ finally {
173
+ [Environment]::CurrentDirectory = $previousDirectory
174
+ $env:TEMP = $previousTemp
175
+ $env:TMP = $previousTmp
176
+ [IO.Directory]::Delete($scratch, $true)
177
+ }
178
+ }
179
+ }
150
180
  function Get-NotifaiWindowsTarget {
151
181
  if (-not ('NotifaiBootstrap.Native' -as [type])) {
152
- Add-Type -TypeDefinition @'
182
+ Add-NotifaiBootstrapType @'
153
183
  using System;
154
184
  using System.Runtime.InteropServices;
155
185
  namespace NotifaiBootstrap {
@@ -215,15 +245,113 @@ function Get-NotifaiAccountHome {
215
245
  }
216
246
  return $accountHome
217
247
  }
248
+ # Read the descriptor and physical location through one non-following handle.
249
+ # Package capabilities restrict a User's access; they do not replace it.
250
+ # Only the registered package owning this current-User npm location is admitted.
251
+ function Get-NotifaiPathSecurity([string]$File, [bool]$Package) {
252
+ if (-not ('NotifaiBootstrap.PathSecurity' -as [type])) {
253
+ Add-NotifaiBootstrapType @'
254
+ using System;
255
+ using System.IO;
256
+ using System.Text;
257
+ using System.ComponentModel;
258
+ using System.Runtime.InteropServices;
259
+ using System.Security.AccessControl;
260
+ using System.Security.Principal;
261
+ using Microsoft.Win32.SafeHandles;
262
+ namespace NotifaiBootstrap {
263
+ public sealed class PathSecurity {
264
+ public RawSecurityDescriptor Descriptor;
265
+ public uint Attributes;
266
+ public string Capability;
267
+ [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
268
+ static extern SafeFileHandle CreateFile(string name, uint access, uint share, IntPtr security, uint disposition, uint flags, IntPtr template);
269
+ [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
270
+ static extern uint GetFinalPathNameByHandle(SafeFileHandle file, StringBuilder path, uint length, uint flags);
271
+ [DllImport("kernel32.dll", SetLastError=true)]
272
+ static extern bool GetFileInformationByHandleEx(SafeFileHandle file, int kind, out TagInfo info, uint size);
273
+ [DllImport("kernel32.dll")]
274
+ static extern uint GetFileType(SafeFileHandle file);
275
+ [StructLayout(LayoutKind.Sequential)] struct TagInfo { public uint Attributes; public uint Tag; }
276
+ [DllImport("advapi32.dll")]
277
+ static extern uint GetSecurityInfo(SafeFileHandle file, int kind, uint information, out IntPtr owner, out IntPtr group, out IntPtr dacl, out IntPtr sacl, out IntPtr descriptor);
278
+ [DllImport("advapi32.dll")]
279
+ static extern uint GetSecurityDescriptorLength(IntPtr descriptor);
280
+ [DllImport("kernel32.dll")]
281
+ static extern IntPtr LocalFree(IntPtr memory);
282
+ [DllImport("advapi32.dll")]
283
+ static extern IntPtr FreeSid(IntPtr sid);
284
+ [DllImport("userenv.dll", CharSet=CharSet.Unicode)]
285
+ static extern int DeriveAppContainerSidFromAppContainerName(string name, out IntPtr sid);
286
+ [DllImport("kernel32.dll", CharSet=CharSet.Unicode)]
287
+ static extern int GetPackagesByPackageFamily(string family, ref uint count, IntPtr names, ref uint size, IntPtr buffer);
288
+ static SafeFileHandle Open(string file, uint access) {
289
+ var handle = CreateFile(file, access, 7, IntPtr.Zero, 3, 0x02200000, IntPtr.Zero);
290
+ if (handle.IsInvalid) { handle.Dispose(); throw new Win32Exception(); }
291
+ return handle;
292
+ }
293
+ static string Physical(SafeFileHandle handle) {
294
+ var path = new StringBuilder(32768);
295
+ uint length = GetFinalPathNameByHandle(handle, path, 32768, 0);
296
+ if (length == 0 || length >= 32768) throw new Win32Exception();
297
+ return path.ToString();
298
+ }
299
+ static string PackageCapability(string physical) {
300
+ string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
301
+ string prefix;
302
+ using (var handle = Open(home, 0x80)) { prefix = Physical(handle).TrimEnd('\\') + @"\AppData\Local\Packages\"; }
303
+ if (!physical.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) return null;
304
+ string relative = physical.Substring(prefix.Length);
305
+ int end = relative.IndexOf('\\');
306
+ if (end <= 0 || end > 255) return null;
307
+ string family = relative.Substring(0, end), tail = relative.Substring(end);
308
+ const string npm = @"\LocalCache\Roaming\npm";
309
+ if (!tail.Equals(npm, StringComparison.OrdinalIgnoreCase) && !tail.StartsWith(npm + @"\", StringComparison.OrdinalIgnoreCase)) return null;
310
+ uint count = 0, size = 0;
311
+ if (GetPackagesByPackageFamily(family, ref count, IntPtr.Zero, ref size, IntPtr.Zero) != 122 || count == 0 || size == 0) return null;
312
+ IntPtr pointer;
313
+ if (DeriveAppContainerSidFromAppContainerName(family, out pointer) != 0) return null;
314
+ try {
315
+ var sid = new SecurityIdentifier(pointer);
316
+ byte[] bytes = new byte[sid.BinaryLength]; sid.GetBinaryForm(bytes, 0);
317
+ if (bytes.Length != 40 || bytes[1] != 8 || BitConverter.ToUInt32(bytes, 8) != 2) return null;
318
+ bytes[8] = 3;
319
+ return new SecurityIdentifier(bytes, 0).Value;
320
+ } finally { FreeSid(pointer); }
321
+ }
322
+ public static PathSecurity Read(string file, bool package) {
323
+ using (var handle = Open(file, 0x20080)) {
324
+ TagInfo info;
325
+ if (GetFileType(handle) != 1 || !GetFileInformationByHandleEx(handle, 9, out info, 8) || (info.Attributes & 0x400) != 0) throw new IOException("Existing path is linked or not a disk object");
326
+ IntPtr owner, group, dacl, sacl, descriptor;
327
+ uint error = GetSecurityInfo(handle, 1, 5, out owner, out group, out dacl, out sacl, out descriptor);
328
+ if (error != 0) throw new Win32Exception((int)error);
329
+ try {
330
+ uint length = GetSecurityDescriptorLength(descriptor);
331
+ if (length == 0 || length > 1024 * 1024) throw new IOException("Invalid path security descriptor");
332
+ byte[] bytes = new byte[length]; Marshal.Copy(descriptor, bytes, 0, bytes.Length);
333
+ return new PathSecurity { Descriptor = new RawSecurityDescriptor(bytes, 0), Attributes = info.Attributes,
334
+ Capability = package ? PackageCapability(Physical(handle)) : null };
335
+ } finally { LocalFree(descriptor); }
336
+ }
337
+ }
338
+ }
339
+ }
340
+ '@
341
+ }
342
+ return [NotifaiBootstrap.PathSecurity]::Read($File, $Package)
343
+ }
218
344
  # Read-only inspection of an existing path. npm can inherit a token's default
219
345
  # owner. The OS-confirmed profile can belong to Windows itself; this exception
220
346
  # must never admit a system-owned npm package or managed installation path.
221
347
  function Assert-NotifaiPathAccess([string]$File, [switch]$AllowDefaultOwner, [switch]$RequireProtected, [switch]$AccountHome) {
222
348
  $identity = [Security.Principal.WindowsIdentity]::GetCurrent()
223
349
  $user = $identity.User.Value
224
- $attributes = [IO.File]::GetAttributes($File)
225
- $acl = Get-NotifaiAccessControl $File $attributes
226
- $owner = $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value
350
+ $security = Get-NotifaiPathSecurity $File $AllowDefaultOwner
351
+ $attributes = [IO.FileAttributes]$security.Attributes
352
+ $acl = $security.Descriptor
353
+ if ($null -eq $acl.Owner -or $null -eq $acl.DiscretionaryAcl) { throw 'Existing path has no owner or discretionary access control' }
354
+ $owner = $acl.Owner.Value
227
355
  $defaultOwner = $AllowDefaultOwner -and $identity.Owner.Value -eq 'S-1-5-32-544' -and $owner -eq $identity.Owner.Value
228
356
  $profileOwner = $false
229
357
  if ($AccountHome) {
@@ -234,12 +362,13 @@ function Assert-NotifaiPathAccess([string]$File, [switch]$AllowDefaultOwner, [sw
234
362
  }
235
363
  if (($attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0 -or
236
364
  ($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' }
365
+ ($RequireProtected -and ($acl.ControlFlags -band [Security.AccessControl.ControlFlags]::DiscretionaryAclProtected) -eq 0)) { throw 'Existing path is not privately owned; inspect it before repair' }
238
366
  $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' }
367
+ foreach ($rule in $acl.DiscretionaryAcl) {
368
+ if ($rule.AceType -eq [Security.AccessControl.AceType]::AccessDenied) { continue }
369
+ if ($rule.AceType -ne [Security.AccessControl.AceType]::AccessAllowed) { throw 'Existing path has unsupported access rules' }
370
+ if (([int64]$rule.AccessMask -band $writes) -ne 0 -and
371
+ $rule.SecurityIdentifier.Value -notin @($user, 'S-1-5-18', 'S-1-5-32-544', $security.Capability)) { throw 'Existing path permits another writer; inspect it before repair' }
243
372
  }
244
373
  }
245
374
  function Get-NotifaiInstalledCommand {
@@ -264,13 +393,15 @@ function Get-NotifaiInstallArguments {
264
393
  if ($NoInit) { $nativeArgs += '--no-init' }
265
394
  if ($NoPath) { $nativeArgs += '--no-path' }
266
395
  if ($MigrateNpm) { $nativeArgs += '--migrate-npm' }
396
+ if ($Upgrade) { $nativeArgs += '--upgrade' }
267
397
  return $nativeArgs
268
398
  }
269
399
  function Invoke-NotifaiBootstrap {
270
400
  $selectedChannel = if ($Channel) { $Channel } else { 'stable' }
271
401
  if ($Version -and -not (Test-NotifaiVersion $Version)) { throw 'Version must be an exact semantic version' }
402
+ if ($Upgrade -and (-not $Version -or -not $Channel -or -not $NoInit -or -not $NoPath)) { throw 'Upgrade requires exact version, channel, no-init and no-path' }
272
403
  $existing = Get-NotifaiInstalledCommand
273
- if ($existing) {
404
+ if ($existing -and -not $Upgrade) {
274
405
  Invoke-NotifaiCandidate $existing (Get-NotifaiInstallArguments)
275
406
  return
276
407
  }
package/data/release.json CHANGED
@@ -1 +1 @@
1
- {"version":"12.0.0-beta.8","source_revision":"c5a855200a3ac8582ea1aa0f5d137040fefdb49e"}
1
+ {"version":"12.0.0","source_revision":"589d4598accb04d83e740868badcae32a3038f28"}
package/inventory.json CHANGED
@@ -1 +1 @@
1
- {"key_id":"notifai-release-2026-10","payload":"eyJzY2hlbWEiOjEsInZlcnNpb24iOiIxMi4wLjAtYmV0YS44Iiwic291cmNlX3JldmlzaW9uIjoiYzVhODU1MjAwYTNhYzg1ODJlYTFhYTBmNWQxMzcwNDBmZWZkYjQ5ZSIsInN0b3JlX3NjaGVtYSI6MSwibGF1bmNoZXJfc2NoZW1hIjoxLCJhcnRpZmFjdHMiOlt7InRhcmdldCI6ImJ1bi1kYXJ3aW4tYXJtNjQiLCJmaWxlbmFtZSI6Im5vdGlmYWktMTIuMC4wLWJldGEuOC1kYXJ3aW4tYXJtNjQudGFyLmd6IiwiYnl0ZXMiOjI3NzY0NDA1LCJzaGEyNTYiOiIxYTczYWFmZGEyMjdjNTIxODAwZjJhN2RlZDM5M2MwYzBhODhkNjkyYTM2NTE4NDY2MzIyZjAxNTM1YmY0MWEzIiwicnVudGltZV9zaGEyNTYiOiI3YzVhOTNkZmJmMTFiZjMzNjZiZjgwYWM1ZjkyZTk4ZDBhNTY4OGFhODk1ODFiOTBjOTY5NDIzYjI5ZDI3NmFlIiwibGF1bmNoZXJfc2hhMjU2IjoiZGVjMmMzMmU1MTFmOWNlYzdlOGQ2OGFjM2Q4M2Q0ZDUzNGY1ODQ0Mjg2OTVkMzA3NjMyNTQ0M2YyMWVlMjEyNiIsIm1hdGVyaWFscyI6W3sicGF0aCI6IkJVTi1MSUNFTlNFLm1kIiwiYnl0ZXMiOjU2MTMsInNoYTI1NiI6ImI5Y2FmNTI3Mjg2OTFiNDA1N2UzNzEyMzJjMjIxYTEzMjg4MzE5OGJlMmYzZDJkZGY5MmM5MDQwNGM5ODRiMWEifSx7InBhdGgiOiJDT1JSRVNQT05ESU5HLVNPVVJDRVMuanNvbiIsImJ5dGVzIjoyMDIwLCJzaGEyNTYiOiJmYTRjMzQ0ODAxMTU0ODcyZDYxNzllZTJlZjQ5OTIzZGM5Zjg5MDllZjAxZTUzYjg2ZThmNTdjNjI1ODIzMjc0In0seyJwYXRoIjoiTElDRU5TRS50eHQiLCJieXRlcyI6MTEzNDYsInNoYTI1NiI6Ijk0NGMxM2ZmMGZlNzk1ZTI5MWZkMWM0OTQ3M2Y5OGQ0ZmRmMWY3NDYzOGUwMWY4ODI3NjljZDRjYWU3OGI3M2QifSx7InBhdGgiOiJOT1RJQ0UtUFJPVkVOQU5DRS5qc29uIiwiYnl0ZXMiOjQ1MDI2NCwic2hhMjU2IjoiNTM0ZGQ1OWZkNGMxNWRkMTM4MmU4MjdmMGI4NWMxOWY3YzY5OGUyMzVmOTI5OWVhYTIwMmRiNTQwMDgzNDI4OCJ9LHsicGF0aCI6Ik5PVElDRS50eHQiLCJieXRlcyI6NjI2LCJzaGEyNTYiOiIxZGZiZjQ0OThkYzAyNmIyMDU5YzBiMGI1ZWI1ZmExZDgyYWUzMzRlNThmZjExZTdjMjk3MzMzMjdmMjVjNGViIn0seyJwYXRoIjoiUkVCVUlMRElORy5tZCIsImJ5dGVzIjozODQyLCJzaGEyNTYiOiJjZTYwNWI1ZmRiMDMxOTMzOWY5ZjgzZjJmZTdjY2NiYzdlNTcyNmZkZjQ5NGRhNmUyODQzM2JlZjgyOWViMGJlIn0seyJwYXRoIjoiU09VUkNFLU5PVElDRVMudHh0IiwiYnl0ZXMiOjkwMTc3NzEsInNoYTI1NiI6Ijg5OTc2YmVjYzI1NjU0MGU2ZDJlODA3YjQ3YTRlMDVlODg5OTgyYzA2MjJmYzA0NDEzYTdiZjdlNzdhNzdlMzcifSx7InBhdGgiOiJUSElSRC1QQVJUWS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjoyNDkxNDk2LCJzaGEyNTYiOiIxMTY0NDdlZmY3Nzg5MzUxMTc5N2VmNDc2MDExZGVjODAwMjI0ZjkxZTMzNDJlM2Q2NTcwNzA4NzEyYjRiNzcyIn0seyJwYXRoIjoibGljZW5zZXMvbnBtLWNtZC1zaGltLnR4dCIsImJ5dGVzIjo4MTMsInNoYTI1NiI6ImFmZmZkZjEyMDgxMTIyNzQ5YzRiNzFjNWIxYzExYmM2NTlkNzkyNDJkMTllMThmNWU4ZGJhYjA0YTQ1ZTM2YmIifSx7InBhdGgiOiJucG0tYWRhcHRlci1maWxlcy5qc29uIiwiYnl0ZXMiOjE1MjEsInNoYTI1NiI6IjEyNTE2N2FiYjk3MTA0Zjc4NmYyNTUwMTAxZWI3MjdkM2ZlMDQyMGZmMjQ2YTJmYjM5ZTNjMzdlMzIzZjgyYjMifV19LHsidGFyZ2V0IjoiYnVuLWRhcndpbi14NjQiLCJmaWxlbmFtZSI6Im5vdGlmYWktMTIuMC4wLWJldGEuOC1kYXJ3aW4teDY0LnRhci5neiIsImJ5dGVzIjozMDAwMTM4MCwic2hhMjU2IjoiODA2MTVmZGY4YTcyYTdiMTc0MjI4OWI3ODljNTI3NmFjZDliMTQ0N2FlNWQxODdlNzQ2MDU1YzYyYzdjNDI1OCIsInJ1bnRpbWVfc2hhMjU2IjoiOGVlMmU0YzUxZWJmZWExMDUzZDU4YzUyODU0NWIwODRkNWYzZjExNTQwYmVkYzNiNDFlMzhmNWFmMzgzNWRlNCIsImxhdW5jaGVyX3NoYTI1NiI6IjE2Y2RhNTNjYmIxMDA3ODkzMDA2ZDE2YzI4N2U3Mzc1NzRkYWQ5ZWU5OTcwNjIxNWNmZWFhOTg0YjE2ZjMyYWIiLCJtYXRlcmlhbHMiOlt7InBhdGgiOiJCVU4tTElDRU5TRS5tZCIsImJ5dGVzIjo1NjEzLCJzaGEyNTYiOiJiOWNhZjUyNzI4NjkxYjQwNTdlMzcxMjMyYzIyMWExMzI4ODMxOThiZTJmM2QyZGRmOTJjOTA0MDRjOTg0YjFhIn0seyJwYXRoIjoiQ09SUkVTUE9ORElORy1TT1VSQ0VTLmpzb24iLCJieXRlcyI6MjAyMCwic2hhMjU2IjoiZmE0YzM0NDgwMTE1NDg3MmQ2MTc5ZWUyZWY0OTkyM2RjOWY4OTA5ZWYwMWU1M2I4NmU4ZjU3YzYyNTgyMzI3NCJ9LHsicGF0aCI6IkxJQ0VOU0UudHh0IiwiYnl0ZXMiOjExMzQ2LCJzaGEyNTYiOiI5NDRjMTNmZjBmZTc5NWUyOTFmZDFjNDk0NzNmOThkNGZkZjFmNzQ2MzhlMDFmODgyNzY5Y2Q0Y2FlNzhiNzNkIn0seyJwYXRoIjoiTk9USUNFLVBST1ZFTkFOQ0UuanNvbiIsImJ5dGVzIjo0NTAyNjQsInNoYTI1NiI6IjUzNGRkNTlmZDRjMTVkZDEzODJlODI3ZjBiODVjMTlmN2M2OThlMjM1ZjkyOTllYWEyMDJkYjU0MDA4MzQyODgifSx7InBhdGgiOiJOT1RJQ0UudHh0IiwiYnl0ZXMiOjYyNiwic2hhMjU2IjoiMWRmYmY0NDk4ZGMwMjZiMjA1OWMwYjBiNWViNWZhMWQ4MmFlMzM0ZTU4ZmYxMWU3YzI5NzMzMzI3ZjI1YzRlYiJ9LHsicGF0aCI6IlJFQlVJTERJTkcubWQiLCJieXRlcyI6Mzg0Miwic2hhMjU2IjoiY2U2MDViNWZkYjAzMTkzMzlmOWY4M2YyZmU3Y2NjYmM3ZTU3MjZmZGY0OTRkYTZlMjg0MzNiZWY4MjllYjBiZSJ9LHsicGF0aCI6IlNPVVJDRS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjo5MDE3NzcxLCJzaGEyNTYiOiI4OTk3NmJlY2MyNTY1NDBlNmQyZTgwN2I0N2E0ZTA1ZTg4OTk4MmMwNjIyZmMwNDQxM2E3YmY3ZTc3YTc3ZTM3In0seyJwYXRoIjoiVEhJUkQtUEFSVFktTk9USUNFUy50eHQiLCJieXRlcyI6MjQ5MTQ5Niwic2hhMjU2IjoiMTE2NDQ3ZWZmNzc4OTM1MTE3OTdlZjQ3NjAxMWRlYzgwMDIyNGY5MWUzMzQyZTNkNjU3MDcwODcxMmI0Yjc3MiJ9LHsicGF0aCI6ImxpY2Vuc2VzL25wbS1jbWQtc2hpbS50eHQiLCJieXRlcyI6ODEzLCJzaGEyNTYiOiJhZmZmZGYxMjA4MTEyMjc0OWM0YjcxYzViMWMxMWJjNjU5ZDc5MjQyZDE5ZTE4ZjVlOGRiYWIwNGE0NWUzNmJiIn0seyJwYXRoIjoibnBtLWFkYXB0ZXItZmlsZXMuanNvbiIsImJ5dGVzIjoxNTIxLCJzaGEyNTYiOiIxMjUxNjdhYmI5NzEwNGY3ODZmMjU1MDEwMWViNzI3ZDNmZTA0MjBmZjI0NmEyZmIzOWUzYzM3ZTMyM2Y4MmIzIn1dfSx7InRhcmdldCI6ImJ1bi1saW51eC1hcm02NCIsImZpbGVuYW1lIjoibm90aWZhaS0xMi4wLjAtYmV0YS44LWxpbnV4LWFybTY0LnRhci5neiIsImJ5dGVzIjozOTMxMjAyNiwic2hhMjU2IjoiZDFmYjdjYTEzYTRjZjQ3ZmU2ZTI2MGExZjZmYWQxMzg2OWY4NjhiYWE2YWY1NzBiZDNlMGU3ODE5MDczNWIxYSIsInJ1bnRpbWVfc2hhMjU2IjoiM2IxM2Y3OTM5MmEyNTFmNjliMmVkMTdmNmY5ZTY4YWY2YmJmZTcxNmQxOTNjY2RhYjg4YWY2M2YxOGZiNDRhYyIsImxhdW5jaGVyX3NoYTI1NiI6ImMxOWUzMzJjODIxYjcxMjhjYjI1ZjYxZTRhYjdlMGIzYzYzMzQ1ZjA0ZTJhYjVhYjk1ZDQ1MWE0YTZmYmRjNDUiLCJtYXRlcmlhbHMiOlt7InBhdGgiOiJCVU4tTElDRU5TRS5tZCIsImJ5dGVzIjo1NjEzLCJzaGEyNTYiOiJiOWNhZjUyNzI4NjkxYjQwNTdlMzcxMjMyYzIyMWExMzI4ODMxOThiZTJmM2QyZGRmOTJjOTA0MDRjOTg0YjFhIn0seyJwYXRoIjoiQ09SUkVTUE9ORElORy1TT1VSQ0VTLmpzb24iLCJieXRlcyI6MjAyMCwic2hhMjU2IjoiZmE0YzM0NDgwMTE1NDg3MmQ2MTc5ZWUyZWY0OTkyM2RjOWY4OTA5ZWYwMWU1M2I4NmU4ZjU3YzYyNTgyMzI3NCJ9LHsicGF0aCI6IkxJQ0VOU0UudHh0IiwiYnl0ZXMiOjExMzQ2LCJzaGEyNTYiOiI5NDRjMTNmZjBmZTc5NWUyOTFmZDFjNDk0NzNmOThkNGZkZjFmNzQ2MzhlMDFmODgyNzY5Y2Q0Y2FlNzhiNzNkIn0seyJwYXRoIjoiTk9USUNFLVBST1ZFTkFOQ0UuanNvbiIsImJ5dGVzIjo0NTAyNjQsInNoYTI1NiI6IjUzNGRkNTlmZDRjMTVkZDEzODJlODI3ZjBiODVjMTlmN2M2OThlMjM1ZjkyOTllYWEyMDJkYjU0MDA4MzQyODgifSx7InBhdGgiOiJOT1RJQ0UudHh0IiwiYnl0ZXMiOjYyNiwic2hhMjU2IjoiMWRmYmY0NDk4ZGMwMjZiMjA1OWMwYjBiNWViNWZhMWQ4MmFlMzM0ZTU4ZmYxMWU3YzI5NzMzMzI3ZjI1YzRlYiJ9LHsicGF0aCI6IlJFQlVJTERJTkcubWQiLCJieXRlcyI6Mzg0Miwic2hhMjU2IjoiY2U2MDViNWZkYjAzMTkzMzlmOWY4M2YyZmU3Y2NjYmM3ZTU3MjZmZGY0OTRkYTZlMjg0MzNiZWY4MjllYjBiZSJ9LHsicGF0aCI6IlNPVVJDRS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjo5MDE3NzcxLCJzaGEyNTYiOiI4OTk3NmJlY2MyNTY1NDBlNmQyZTgwN2I0N2E0ZTA1ZTg4OTk4MmMwNjIyZmMwNDQxM2E3YmY3ZTc3YTc3ZTM3In0seyJwYXRoIjoiVEhJUkQtUEFSVFktTk9USUNFUy50eHQiLCJieXRlcyI6MjQ5MTQ5Niwic2hhMjU2IjoiMTE2NDQ3ZWZmNzc4OTM1MTE3OTdlZjQ3NjAxMWRlYzgwMDIyNGY5MWUzMzQyZTNkNjU3MDcwODcxMmI0Yjc3MiJ9LHsicGF0aCI6ImxpY2Vuc2VzL25wbS1jbWQtc2hpbS50eHQiLCJieXRlcyI6ODEzLCJzaGEyNTYiOiJhZmZmZGYxMjA4MTEyMjc0OWM0YjcxYzViMWMxMWJjNjU5ZDc5MjQyZDE5ZTE4ZjVlOGRiYWIwNGE0NWUzNmJiIn0seyJwYXRoIjoibnBtLWFkYXB0ZXItZmlsZXMuanNvbiIsImJ5dGVzIjoxNTIxLCJzaGEyNTYiOiIxMjUxNjdhYmI5NzEwNGY3ODZmMjU1MDEwMWViNzI3ZDNmZTA0MjBmZjI0NmEyZmIzOWUzYzM3ZTMyM2Y4MmIzIn1dfSx7InRhcmdldCI6ImJ1bi1saW51eC14NjQiLCJmaWxlbmFtZSI6Im5vdGlmYWktMTIuMC4wLWJldGEuOC1saW51eC14NjQudGFyLmd6IiwiYnl0ZXMiOjM4ODc1NDc4LCJzaGEyNTYiOiJmYjUzY2ViY2I3YmFiNjVlYWE1MzI4ZThiODVjYWJkNDhlMjU1NGQwODIwZmM2Nzg5YzQ5YzBiZDg3YzE2ZDNjIiwicnVudGltZV9zaGEyNTYiOiI5ZGY0NTAyZDNiYzE1YTYwNmRmZWVkYWUyMzliYzA1MjZkYTk3NzdlZDY3MGMwNzdkZjcxZTkxNGU4YzNkNjMzIiwibGF1bmNoZXJfc2hhMjU2IjoiYmRmOGQ0N2RmODU4MWFjZTI5YjU3OTA0NTdjYmM2YzI2ZDEyYjNjYjE0YzBkZGFiMzM3OWE3Mjc1ZDllYTRiMSIsIm1hdGVyaWFscyI6W3sicGF0aCI6IkJVTi1MSUNFTlNFLm1kIiwiYnl0ZXMiOjU2MTMsInNoYTI1NiI6ImI5Y2FmNTI3Mjg2OTFiNDA1N2UzNzEyMzJjMjIxYTEzMjg4MzE5OGJlMmYzZDJkZGY5MmM5MDQwNGM5ODRiMWEifSx7InBhdGgiOiJDT1JSRVNQT05ESU5HLVNPVVJDRVMuanNvbiIsImJ5dGVzIjoyMDIwLCJzaGEyNTYiOiJmYTRjMzQ0ODAxMTU0ODcyZDYxNzllZTJlZjQ5OTIzZGM5Zjg5MDllZjAxZTUzYjg2ZThmNTdjNjI1ODIzMjc0In0seyJwYXRoIjoiTElDRU5TRS50eHQiLCJieXRlcyI6MTEzNDYsInNoYTI1NiI6Ijk0NGMxM2ZmMGZlNzk1ZTI5MWZkMWM0OTQ3M2Y5OGQ0ZmRmMWY3NDYzOGUwMWY4ODI3NjljZDRjYWU3OGI3M2QifSx7InBhdGgiOiJOT1RJQ0UtUFJPVkVOQU5DRS5qc29uIiwiYnl0ZXMiOjQ1MDI2NCwic2hhMjU2IjoiNTM0ZGQ1OWZkNGMxNWRkMTM4MmU4MjdmMGI4NWMxOWY3YzY5OGUyMzVmOTI5OWVhYTIwMmRiNTQwMDgzNDI4OCJ9LHsicGF0aCI6Ik5PVElDRS50eHQiLCJieXRlcyI6NjI2LCJzaGEyNTYiOiIxZGZiZjQ0OThkYzAyNmIyMDU5YzBiMGI1ZWI1ZmExZDgyYWUzMzRlNThmZjExZTdjMjk3MzMzMjdmMjVjNGViIn0seyJwYXRoIjoiUkVCVUlMRElORy5tZCIsImJ5dGVzIjozODQyLCJzaGEyNTYiOiJjZTYwNWI1ZmRiMDMxOTMzOWY5ZjgzZjJmZTdjY2NiYzdlNTcyNmZkZjQ5NGRhNmUyODQzM2JlZjgyOWViMGJlIn0seyJwYXRoIjoiU09VUkNFLU5PVElDRVMudHh0IiwiYnl0ZXMiOjkwMTc3NzEsInNoYTI1NiI6Ijg5OTc2YmVjYzI1NjU0MGU2ZDJlODA3YjQ3YTRlMDVlODg5OTgyYzA2MjJmYzA0NDEzYTdiZjdlNzdhNzdlMzcifSx7InBhdGgiOiJUSElSRC1QQVJUWS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjoyNDkxNDk2LCJzaGEyNTYiOiIxMTY0NDdlZmY3Nzg5MzUxMTc5N2VmNDc2MDExZGVjODAwMjI0ZjkxZTMzNDJlM2Q2NTcwNzA4NzEyYjRiNzcyIn0seyJwYXRoIjoibGljZW5zZXMvbnBtLWNtZC1zaGltLnR4dCIsImJ5dGVzIjo4MTMsInNoYTI1NiI6ImFmZmZkZjEyMDgxMTIyNzQ5YzRiNzFjNWIxYzExYmM2NTlkNzkyNDJkMTllMThmNWU4ZGJhYjA0YTQ1ZTM2YmIifSx7InBhdGgiOiJucG0tYWRhcHRlci1maWxlcy5qc29uIiwiYnl0ZXMiOjE1MjEsInNoYTI1NiI6IjEyNTE2N2FiYjk3MTA0Zjc4NmYyNTUwMTAxZWI3MjdkM2ZlMDQyMGZmMjQ2YTJmYjM5ZTNjMzdlMzIzZjgyYjMifV19LHsidGFyZ2V0IjoiYnVuLXdpbmRvd3MtYXJtNjQiLCJmaWxlbmFtZSI6Im5vdGlmYWktMTIuMC4wLWJldGEuOC13aW5kb3dzLWFybTY0LnppcCIsImJ5dGVzIjozODcwNjI0MSwic2hhMjU2IjoiNWI3MDVmMmYxZGQwNmQzYTc1NTU2ZWQ4MTE3Mjc5MjhjNDk0YzU0ZWE4MjU4NjRlMTMwNGQwMGMyZWU4MDRlNSIsInJ1bnRpbWVfc2hhMjU2IjoiYmFiODdhOTBiMDIxNzg4ODJlMjI0NmFhNDE2ZmI4OTFhZjBjMjFhMzhiN2ZhNTJkNzBhZmM4NDI0ZjcyNmIyYiIsImxhdW5jaGVyX3NoYTI1NiI6IjNmMTZkOThkZDAwZmNkYWNlNWY3MmM1YjkzMzEwNTVjMWNlMzQ4OWQ2NzVmYzcyZTc1ODZiMmI1M2UyYTBlNDUiLCJtYXRlcmlhbHMiOlt7InBhdGgiOiJCVU4tTElDRU5TRS5tZCIsImJ5dGVzIjo1NjEzLCJzaGEyNTYiOiJiOWNhZjUyNzI4NjkxYjQwNTdlMzcxMjMyYzIyMWExMzI4ODMxOThiZTJmM2QyZGRmOTJjOTA0MDRjOTg0YjFhIn0seyJwYXRoIjoiQ09SUkVTUE9ORElORy1TT1VSQ0VTLmpzb24iLCJieXRlcyI6MjAyMCwic2hhMjU2IjoiZmE0YzM0NDgwMTE1NDg3MmQ2MTc5ZWUyZWY0OTkyM2RjOWY4OTA5ZWYwMWU1M2I4NmU4ZjU3YzYyNTgyMzI3NCJ9LHsicGF0aCI6IkxJQ0VOU0UudHh0IiwiYnl0ZXMiOjExMzQ2LCJzaGEyNTYiOiI5NDRjMTNmZjBmZTc5NWUyOTFmZDFjNDk0NzNmOThkNGZkZjFmNzQ2MzhlMDFmODgyNzY5Y2Q0Y2FlNzhiNzNkIn0seyJwYXRoIjoiTk9USUNFLVBST1ZFTkFOQ0UuanNvbiIsImJ5dGVzIjo0NTAyNjQsInNoYTI1NiI6IjUzNGRkNTlmZDRjMTVkZDEzODJlODI3ZjBiODVjMTlmN2M2OThlMjM1ZjkyOTllYWEyMDJkYjU0MDA4MzQyODgifSx7InBhdGgiOiJOT1RJQ0UudHh0IiwiYnl0ZXMiOjYyNiwic2hhMjU2IjoiMWRmYmY0NDk4ZGMwMjZiMjA1OWMwYjBiNWViNWZhMWQ4MmFlMzM0ZTU4ZmYxMWU3YzI5NzMzMzI3ZjI1YzRlYiJ9LHsicGF0aCI6IlJFQlVJTERJTkcubWQiLCJieXRlcyI6Mzg0Miwic2hhMjU2IjoiY2U2MDViNWZkYjAzMTkzMzlmOWY4M2YyZmU3Y2NjYmM3ZTU3MjZmZGY0OTRkYTZlMjg0MzNiZWY4MjllYjBiZSJ9LHsicGF0aCI6IlNPVVJDRS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjo5MDE3NzcxLCJzaGEyNTYiOiI4OTk3NmJlY2MyNTY1NDBlNmQyZTgwN2I0N2E0ZTA1ZTg4OTk4MmMwNjIyZmMwNDQxM2E3YmY3ZTc3YTc3ZTM3In0seyJwYXRoIjoiVEhJUkQtUEFSVFktTk9USUNFUy50eHQiLCJieXRlcyI6MjQ5MTQ5Niwic2hhMjU2IjoiMTE2NDQ3ZWZmNzc4OTM1MTE3OTdlZjQ3NjAxMWRlYzgwMDIyNGY5MWUzMzQyZTNkNjU3MDcwODcxMmI0Yjc3MiJ9LHsicGF0aCI6ImxpY2Vuc2VzL25wbS1jbWQtc2hpbS50eHQiLCJieXRlcyI6ODEzLCJzaGEyNTYiOiJhZmZmZGYxMjA4MTEyMjc0OWM0YjcxYzViMWMxMWJjNjU5ZDc5MjQyZDE5ZTE4ZjVlOGRiYWIwNGE0NWUzNmJiIn0seyJwYXRoIjoibnBtLWFkYXB0ZXItZmlsZXMuanNvbiIsImJ5dGVzIjoxNTIxLCJzaGEyNTYiOiIxMjUxNjdhYmI5NzEwNGY3ODZmMjU1MDEwMWViNzI3ZDNmZTA0MjBmZjI0NmEyZmIzOWUzYzM3ZTMyM2Y4MmIzIn1dfSx7InRhcmdldCI6ImJ1bi13aW5kb3dzLXg2NCIsImZpbGVuYW1lIjoibm90aWZhaS0xMi4wLjAtYmV0YS44LXdpbmRvd3MteDY0LnppcCIsImJ5dGVzIjo0MTg1MjAyOSwic2hhMjU2IjoiMjlhYTQ3ZmM4ZjRmNmVhNTQ1YmZjZjllNTI5NDQ3OTE4YTU4ZTk2NjZhZWY4ODEwZDZjY2ExMzhmYzFkZDNlZCIsInJ1bnRpbWVfc2hhMjU2IjoiNmFjMTAxZGY2YTczNmZjNzExYzg4ODk5YzhlNDBiZDMyZGMzZWM2YzBiM2Q0MmZjMjhjOTFhZDVhMTgyN2UyYiIsImxhdW5jaGVyX3NoYTI1NiI6IjcxYzlmMDlkYTZmMDgzMzUzMWE3ZDhkNmNjY2YwNDI3OTcxOTQzMTQ2ZTQ3NDlkYzJkZGNkMGJiODhlYjgwMGYiLCJtYXRlcmlhbHMiOlt7InBhdGgiOiJCVU4tTElDRU5TRS5tZCIsImJ5dGVzIjo1NjEzLCJzaGEyNTYiOiJiOWNhZjUyNzI4NjkxYjQwNTdlMzcxMjMyYzIyMWExMzI4ODMxOThiZTJmM2QyZGRmOTJjOTA0MDRjOTg0YjFhIn0seyJwYXRoIjoiQ09SUkVTUE9ORElORy1TT1VSQ0VTLmpzb24iLCJieXRlcyI6MjAyMCwic2hhMjU2IjoiZmE0YzM0NDgwMTE1NDg3MmQ2MTc5ZWUyZWY0OTkyM2RjOWY4OTA5ZWYwMWU1M2I4NmU4ZjU3YzYyNTgyMzI3NCJ9LHsicGF0aCI6IkxJQ0VOU0UudHh0IiwiYnl0ZXMiOjExMzQ2LCJzaGEyNTYiOiI5NDRjMTNmZjBmZTc5NWUyOTFmZDFjNDk0NzNmOThkNGZkZjFmNzQ2MzhlMDFmODgyNzY5Y2Q0Y2FlNzhiNzNkIn0seyJwYXRoIjoiTk9USUNFLVBST1ZFTkFOQ0UuanNvbiIsImJ5dGVzIjo0NTAyNjQsInNoYTI1NiI6IjUzNGRkNTlmZDRjMTVkZDEzODJlODI3ZjBiODVjMTlmN2M2OThlMjM1ZjkyOTllYWEyMDJkYjU0MDA4MzQyODgifSx7InBhdGgiOiJOT1RJQ0UudHh0IiwiYnl0ZXMiOjYyNiwic2hhMjU2IjoiMWRmYmY0NDk4ZGMwMjZiMjA1OWMwYjBiNWViNWZhMWQ4MmFlMzM0ZTU4ZmYxMWU3YzI5NzMzMzI3ZjI1YzRlYiJ9LHsicGF0aCI6IlJFQlVJTERJTkcubWQiLCJieXRlcyI6Mzg0Miwic2hhMjU2IjoiY2U2MDViNWZkYjAzMTkzMzlmOWY4M2YyZmU3Y2NjYmM3ZTU3MjZmZGY0OTRkYTZlMjg0MzNiZWY4MjllYjBiZSJ9LHsicGF0aCI6IlNPVVJDRS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjo5MDE3NzcxLCJzaGEyNTYiOiI4OTk3NmJlY2MyNTY1NDBlNmQyZTgwN2I0N2E0ZTA1ZTg4OTk4MmMwNjIyZmMwNDQxM2E3YmY3ZTc3YTc3ZTM3In0seyJwYXRoIjoiVEhJUkQtUEFSVFktTk9USUNFUy50eHQiLCJieXRlcyI6MjQ5MTQ5Niwic2hhMjU2IjoiMTE2NDQ3ZWZmNzc4OTM1MTE3OTdlZjQ3NjAxMWRlYzgwMDIyNGY5MWUzMzQyZTNkNjU3MDcwODcxMmI0Yjc3MiJ9LHsicGF0aCI6ImxpY2Vuc2VzL25wbS1jbWQtc2hpbS50eHQiLCJieXRlcyI6ODEzLCJzaGEyNTYiOiJhZmZmZGYxMjA4MTEyMjc0OWM0YjcxYzViMWMxMWJjNjU5ZDc5MjQyZDE5ZTE4ZjVlOGRiYWIwNGE0NWUzNmJiIn0seyJwYXRoIjoibnBtLWFkYXB0ZXItZmlsZXMuanNvbiIsImJ5dGVzIjoxNTIxLCJzaGEyNTYiOiIxMjUxNjdhYmI5NzEwNGY3ODZmMjU1MDEwMWViNzI3ZDNmZTA0MjBmZjI0NmEyZmIzOWUzYzM3ZTMyM2Y4MmIzIn1dfV19","signature":"z0JPO9k27DHv9z11T1CzmRRLjyH7FNLem10hm/MmtMApfo9QgJ2x575rNyOUHf7guNeani7gKT21EHqqe0vEAg=="}
1
+ {"key_id":"notifai-release-2026-10","payload":"eyJzY2hlbWEiOjIsInZlcnNpb24iOiIxMi4wLjAiLCJzb3VyY2VfcmV2aXNpb24iOiI1ODlkNDU5OGFjY2IwNGQ4M2U3NDA4NjhiYWRjYWUzMmEzMDM4ZjI4IiwibG9jYWxfY29udGludWl0eSI6eyJjb250cmFjdCI6Im5vdGlmYWktc2Vzc2lvbi1zdGF0ZS12MiJ9LCJzdG9yZV9zY2hlbWEiOjIsImxhdW5jaGVyX3NjaGVtYSI6MSwiYXJ0aWZhY3RzIjpbeyJ0YXJnZXQiOiJidW4tZGFyd2luLWFybTY0IiwiZmlsZW5hbWUiOiJub3RpZmFpLTEyLjAuMC1kYXJ3aW4tYXJtNjQudGFyLmd6IiwiYnl0ZXMiOjI3ODM0MzUzLCJzaGEyNTYiOiIwZTdmOTY2ZjE1MDI0OTkzMDM3YjUyM2I4M2QxMTQzZDFlYzA3NjAyNGZlMjE0YzUxZTg1ZTFhN2RhMzJmNzEzIiwicnVudGltZV9zaGEyNTYiOiJlMWVlNDkzNjU4Y2M2M2IxZjJlMmJlMWQ2ZGVkNzY0ZjYyNWM2Y2FiYTIzZDBhYTg1MGIwZDg3OGExYTRhOWYwIiwibGF1bmNoZXJfc2hhMjU2IjoiMjE3YjQ1OGU4NGQ0ZmUzNzM2YzkzMDIyN2NlZTY5YjZiYmM2ZDJiNzQzYmI1MDBlZDAwODZiNmQ1ZGMzZjg4ZCIsIm1hdGVyaWFscyI6W3sicGF0aCI6IkJVTi1MSUNFTlNFLm1kIiwiYnl0ZXMiOjU2MTMsInNoYTI1NiI6ImI5Y2FmNTI3Mjg2OTFiNDA1N2UzNzEyMzJjMjIxYTEzMjg4MzE5OGJlMmYzZDJkZGY5MmM5MDQwNGM5ODRiMWEifSx7InBhdGgiOiJDT1JSRVNQT05ESU5HLVNPVVJDRVMuanNvbiIsImJ5dGVzIjoyMDIwLCJzaGEyNTYiOiJmYTRjMzQ0ODAxMTU0ODcyZDYxNzllZTJlZjQ5OTIzZGM5Zjg5MDllZjAxZTUzYjg2ZThmNTdjNjI1ODIzMjc0In0seyJwYXRoIjoiTElDRU5TRS50eHQiLCJieXRlcyI6MTEzNDYsInNoYTI1NiI6Ijk0NGMxM2ZmMGZlNzk1ZTI5MWZkMWM0OTQ3M2Y5OGQ0ZmRmMWY3NDYzOGUwMWY4ODI3NjljZDRjYWU3OGI3M2QifSx7InBhdGgiOiJOT1RJQ0UtUFJPVkVOQU5DRS5qc29uIiwiYnl0ZXMiOjQ1MDI2NCwic2hhMjU2IjoiNTM0ZGQ1OWZkNGMxNWRkMTM4MmU4MjdmMGI4NWMxOWY3YzY5OGUyMzVmOTI5OWVhYTIwMmRiNTQwMDgzNDI4OCJ9LHsicGF0aCI6Ik5PVElDRS50eHQiLCJieXRlcyI6NjI2LCJzaGEyNTYiOiIxZGZiZjQ0OThkYzAyNmIyMDU5YzBiMGI1ZWI1ZmExZDgyYWUzMzRlNThmZjExZTdjMjk3MzMzMjdmMjVjNGViIn0seyJwYXRoIjoiUkVCVUlMRElORy5tZCIsImJ5dGVzIjozODQyLCJzaGEyNTYiOiJjZTYwNWI1ZmRiMDMxOTMzOWY5ZjgzZjJmZTdjY2NiYzdlNTcyNmZkZjQ5NGRhNmUyODQzM2JlZjgyOWViMGJlIn0seyJwYXRoIjoiU09VUkNFLU5PVElDRVMudHh0IiwiYnl0ZXMiOjkwMTc3NzEsInNoYTI1NiI6Ijg5OTc2YmVjYzI1NjU0MGU2ZDJlODA3YjQ3YTRlMDVlODg5OTgyYzA2MjJmYzA0NDEzYTdiZjdlNzdhNzdlMzcifSx7InBhdGgiOiJUSElSRC1QQVJUWS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjoyNDkxNDk2LCJzaGEyNTYiOiIxMTY0NDdlZmY3Nzg5MzUxMTc5N2VmNDc2MDExZGVjODAwMjI0ZjkxZTMzNDJlM2Q2NTcwNzA4NzEyYjRiNzcyIn0seyJwYXRoIjoibGljZW5zZXMvbnBtLWNtZC1zaGltLnR4dCIsImJ5dGVzIjo4MTMsInNoYTI1NiI6ImFmZmZkZjEyMDgxMTIyNzQ5YzRiNzFjNWIxYzExYmM2NTlkNzkyNDJkMTllMThmNWU4ZGJhYjA0YTQ1ZTM2YmIifSx7InBhdGgiOiJucG0tYWRhcHRlci1maWxlcy5qc29uIiwiYnl0ZXMiOjE1MDAsInNoYTI1NiI6IjYzNWI0MjY3OTM1ZTI5ZGM4ODMwYzIwYjE0ZmZkMTE5NGM2NDIwZDYxZWFmMTEyNTc0MzI3NjRhNTg0OTExY2YifV19LHsidGFyZ2V0IjoiYnVuLWRhcndpbi14NjQiLCJmaWxlbmFtZSI6Im5vdGlmYWktMTIuMC4wLWRhcndpbi14NjQudGFyLmd6IiwiYnl0ZXMiOjMwMDczNjEzLCJzaGEyNTYiOiJmMmNkNDdhZTIxYmFhZTIxOGM0N2Y0NDdjZmFjZTM4OTBlMmJmMzFlYTI1YjIxNTc1N2JhYTk3MjJkNGM5NzdjIiwicnVudGltZV9zaGEyNTYiOiIxM2U5MWFkZDQ4OTJlMjQ4OTg1MDExZTdmMWM3OWMwODFmOWJjN2EwNmI0ZTc3YjI5ODhjMjQwOTcyMzg1MTAyIiwibGF1bmNoZXJfc2hhMjU2IjoiNDg1OGY0MmYwNjM5NGM5NmZlODY1OWFhNmMyNmYwZTkzNTgxYjQ3NjhjNTMzZTI1Y2M1MDFhYjViZTVjNDQyZSIsIm1hdGVyaWFscyI6W3sicGF0aCI6IkJVTi1MSUNFTlNFLm1kIiwiYnl0ZXMiOjU2MTMsInNoYTI1NiI6ImI5Y2FmNTI3Mjg2OTFiNDA1N2UzNzEyMzJjMjIxYTEzMjg4MzE5OGJlMmYzZDJkZGY5MmM5MDQwNGM5ODRiMWEifSx7InBhdGgiOiJDT1JSRVNQT05ESU5HLVNPVVJDRVMuanNvbiIsImJ5dGVzIjoyMDIwLCJzaGEyNTYiOiJmYTRjMzQ0ODAxMTU0ODcyZDYxNzllZTJlZjQ5OTIzZGM5Zjg5MDllZjAxZTUzYjg2ZThmNTdjNjI1ODIzMjc0In0seyJwYXRoIjoiTElDRU5TRS50eHQiLCJieXRlcyI6MTEzNDYsInNoYTI1NiI6Ijk0NGMxM2ZmMGZlNzk1ZTI5MWZkMWM0OTQ3M2Y5OGQ0ZmRmMWY3NDYzOGUwMWY4ODI3NjljZDRjYWU3OGI3M2QifSx7InBhdGgiOiJOT1RJQ0UtUFJPVkVOQU5DRS5qc29uIiwiYnl0ZXMiOjQ1MDI2NCwic2hhMjU2IjoiNTM0ZGQ1OWZkNGMxNWRkMTM4MmU4MjdmMGI4NWMxOWY3YzY5OGUyMzVmOTI5OWVhYTIwMmRiNTQwMDgzNDI4OCJ9LHsicGF0aCI6Ik5PVElDRS50eHQiLCJieXRlcyI6NjI2LCJzaGEyNTYiOiIxZGZiZjQ0OThkYzAyNmIyMDU5YzBiMGI1ZWI1ZmExZDgyYWUzMzRlNThmZjExZTdjMjk3MzMzMjdmMjVjNGViIn0seyJwYXRoIjoiUkVCVUlMRElORy5tZCIsImJ5dGVzIjozODQyLCJzaGEyNTYiOiJjZTYwNWI1ZmRiMDMxOTMzOWY5ZjgzZjJmZTdjY2NiYzdlNTcyNmZkZjQ5NGRhNmUyODQzM2JlZjgyOWViMGJlIn0seyJwYXRoIjoiU09VUkNFLU5PVElDRVMudHh0IiwiYnl0ZXMiOjkwMTc3NzEsInNoYTI1NiI6Ijg5OTc2YmVjYzI1NjU0MGU2ZDJlODA3YjQ3YTRlMDVlODg5OTgyYzA2MjJmYzA0NDEzYTdiZjdlNzdhNzdlMzcifSx7InBhdGgiOiJUSElSRC1QQVJUWS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjoyNDkxNDk2LCJzaGEyNTYiOiIxMTY0NDdlZmY3Nzg5MzUxMTc5N2VmNDc2MDExZGVjODAwMjI0ZjkxZTMzNDJlM2Q2NTcwNzA4NzEyYjRiNzcyIn0seyJwYXRoIjoibGljZW5zZXMvbnBtLWNtZC1zaGltLnR4dCIsImJ5dGVzIjo4MTMsInNoYTI1NiI6ImFmZmZkZjEyMDgxMTIyNzQ5YzRiNzFjNWIxYzExYmM2NTlkNzkyNDJkMTllMThmNWU4ZGJhYjA0YTQ1ZTM2YmIifSx7InBhdGgiOiJucG0tYWRhcHRlci1maWxlcy5qc29uIiwiYnl0ZXMiOjE1MDAsInNoYTI1NiI6IjYzNWI0MjY3OTM1ZTI5ZGM4ODMwYzIwYjE0ZmZkMTE5NGM2NDIwZDYxZWFmMTEyNTc0MzI3NjRhNTg0OTExY2YifV19LHsidGFyZ2V0IjoiYnVuLWxpbnV4LWFybTY0IiwiZmlsZW5hbWUiOiJub3RpZmFpLTEyLjAuMC1saW51eC1hcm02NC50YXIuZ3oiLCJieXRlcyI6MzkzNzg5MzIsInNoYTI1NiI6ImJhOTUyZjdlY2RmZTUxYWMwMTE0Nzk3MGY5MDkyZGE5NDE3Y2QyYjA1Y2RiZWNmOTI3OGIzN2YxN2Y3ZjczYmQiLCJydW50aW1lX3NoYTI1NiI6IjkyMmFkMGM4ZWFkOTNiMWQ3ODdhYzQ1NDhjZDU1ZjkyNzkyZjA2YjI3N2U1NGIwYTBmZTMyNmRmNTlmYzM1NGQiLCJsYXVuY2hlcl9zaGEyNTYiOiJmODBmZGJmMzNmYmFhMzkwM2M1NDUyNmYxOTU2YzYxOWYyZjQ3MDFmOTg3MTkwYzViYTJiNGQ1NzRiNDMxMGE0IiwibWF0ZXJpYWxzIjpbeyJwYXRoIjoiQlVOLUxJQ0VOU0UubWQiLCJieXRlcyI6NTYxMywic2hhMjU2IjoiYjljYWY1MjcyODY5MWI0MDU3ZTM3MTIzMmMyMjFhMTMyODgzMTk4YmUyZjNkMmRkZjkyYzkwNDA0Yzk4NGIxYSJ9LHsicGF0aCI6IkNPUlJFU1BPTkRJTkctU09VUkNFUy5qc29uIiwiYnl0ZXMiOjIwMjAsInNoYTI1NiI6ImZhNGMzNDQ4MDExNTQ4NzJkNjE3OWVlMmVmNDk5MjNkYzlmODkwOWVmMDFlNTNiODZlOGY1N2M2MjU4MjMyNzQifSx7InBhdGgiOiJMSUNFTlNFLnR4dCIsImJ5dGVzIjoxMTM0Niwic2hhMjU2IjoiOTQ0YzEzZmYwZmU3OTVlMjkxZmQxYzQ5NDczZjk4ZDRmZGYxZjc0NjM4ZTAxZjg4Mjc2OWNkNGNhZTc4YjczZCJ9LHsicGF0aCI6Ik5PVElDRS1QUk9WRU5BTkNFLmpzb24iLCJieXRlcyI6NDUwMjY0LCJzaGEyNTYiOiI1MzRkZDU5ZmQ0YzE1ZGQxMzgyZTgyN2YwYjg1YzE5ZjdjNjk4ZTIzNWY5Mjk5ZWFhMjAyZGI1NDAwODM0Mjg4In0seyJwYXRoIjoiTk9USUNFLnR4dCIsImJ5dGVzIjo2MjYsInNoYTI1NiI6IjFkZmJmNDQ5OGRjMDI2YjIwNTljMGIwYjVlYjVmYTFkODJhZTMzNGU1OGZmMTFlN2MyOTczMzMyN2YyNWM0ZWIifSx7InBhdGgiOiJSRUJVSUxESU5HLm1kIiwiYnl0ZXMiOjM4NDIsInNoYTI1NiI6ImNlNjA1YjVmZGIwMzE5MzM5ZjlmODNmMmZlN2NjY2JjN2U1NzI2ZmRmNDk0ZGE2ZTI4NDMzYmVmODI5ZWIwYmUifSx7InBhdGgiOiJTT1VSQ0UtTk9USUNFUy50eHQiLCJieXRlcyI6OTAxNzc3MSwic2hhMjU2IjoiODk5NzZiZWNjMjU2NTQwZTZkMmU4MDdiNDdhNGUwNWU4ODk5ODJjMDYyMmZjMDQ0MTNhN2JmN2U3N2E3N2UzNyJ9LHsicGF0aCI6IlRISVJELVBBUlRZLU5PVElDRVMudHh0IiwiYnl0ZXMiOjI0OTE0OTYsInNoYTI1NiI6IjExNjQ0N2VmZjc3ODkzNTExNzk3ZWY0NzYwMTFkZWM4MDAyMjRmOTFlMzM0MmUzZDY1NzA3MDg3MTJiNGI3NzIifSx7InBhdGgiOiJsaWNlbnNlcy9ucG0tY21kLXNoaW0udHh0IiwiYnl0ZXMiOjgxMywic2hhMjU2IjoiYWZmZmRmMTIwODExMjI3NDljNGI3MWM1YjFjMTFiYzY1OWQ3OTI0MmQxOWUxOGY1ZThkYmFiMDRhNDVlMzZiYiJ9LHsicGF0aCI6Im5wbS1hZGFwdGVyLWZpbGVzLmpzb24iLCJieXRlcyI6MTUwMCwic2hhMjU2IjoiNjM1YjQyNjc5MzVlMjlkYzg4MzBjMjBiMTRmZmQxMTk0YzY0MjBkNjFlYWYxMTI1NzQzMjc2NGE1ODQ5MTFjZiJ9XX0seyJ0YXJnZXQiOiJidW4tbGludXgteDY0IiwiZmlsZW5hbWUiOiJub3RpZmFpLTEyLjAuMC1saW51eC14NjQudGFyLmd6IiwiYnl0ZXMiOjM4OTQzNzkzLCJzaGEyNTYiOiIxMmM1M2MyODIzZjlhZGYxNzI5NmZkOWQ2MGZhZmEzOTk4YmIwZWU1YTdiOGZiMTg2OGFiN2I2ZDEwZTNmMTY2IiwicnVudGltZV9zaGEyNTYiOiI2ZGMyOTYxMmVhYThkYWY1NzhhZjI2NWEyODJmN2I3MDJmNmQ0Y2M2ZDcwY2ViYjJlNDFjYzRjNjlmM2RmZGFkIiwibGF1bmNoZXJfc2hhMjU2IjoiOGIxZjA5M2U0NGM2ZmQzOTg0MWUzOWJkZTk3YjI3MTUwNDhkMzk2M2I3MDRmNjJmMmFiZWI1OTAyYzdmYmJlNyIsIm1hdGVyaWFscyI6W3sicGF0aCI6IkJVTi1MSUNFTlNFLm1kIiwiYnl0ZXMiOjU2MTMsInNoYTI1NiI6ImI5Y2FmNTI3Mjg2OTFiNDA1N2UzNzEyMzJjMjIxYTEzMjg4MzE5OGJlMmYzZDJkZGY5MmM5MDQwNGM5ODRiMWEifSx7InBhdGgiOiJDT1JSRVNQT05ESU5HLVNPVVJDRVMuanNvbiIsImJ5dGVzIjoyMDIwLCJzaGEyNTYiOiJmYTRjMzQ0ODAxMTU0ODcyZDYxNzllZTJlZjQ5OTIzZGM5Zjg5MDllZjAxZTUzYjg2ZThmNTdjNjI1ODIzMjc0In0seyJwYXRoIjoiTElDRU5TRS50eHQiLCJieXRlcyI6MTEzNDYsInNoYTI1NiI6Ijk0NGMxM2ZmMGZlNzk1ZTI5MWZkMWM0OTQ3M2Y5OGQ0ZmRmMWY3NDYzOGUwMWY4ODI3NjljZDRjYWU3OGI3M2QifSx7InBhdGgiOiJOT1RJQ0UtUFJPVkVOQU5DRS5qc29uIiwiYnl0ZXMiOjQ1MDI2NCwic2hhMjU2IjoiNTM0ZGQ1OWZkNGMxNWRkMTM4MmU4MjdmMGI4NWMxOWY3YzY5OGUyMzVmOTI5OWVhYTIwMmRiNTQwMDgzNDI4OCJ9LHsicGF0aCI6Ik5PVElDRS50eHQiLCJieXRlcyI6NjI2LCJzaGEyNTYiOiIxZGZiZjQ0OThkYzAyNmIyMDU5YzBiMGI1ZWI1ZmExZDgyYWUzMzRlNThmZjExZTdjMjk3MzMzMjdmMjVjNGViIn0seyJwYXRoIjoiUkVCVUlMRElORy5tZCIsImJ5dGVzIjozODQyLCJzaGEyNTYiOiJjZTYwNWI1ZmRiMDMxOTMzOWY5ZjgzZjJmZTdjY2NiYzdlNTcyNmZkZjQ5NGRhNmUyODQzM2JlZjgyOWViMGJlIn0seyJwYXRoIjoiU09VUkNFLU5PVElDRVMudHh0IiwiYnl0ZXMiOjkwMTc3NzEsInNoYTI1NiI6Ijg5OTc2YmVjYzI1NjU0MGU2ZDJlODA3YjQ3YTRlMDVlODg5OTgyYzA2MjJmYzA0NDEzYTdiZjdlNzdhNzdlMzcifSx7InBhdGgiOiJUSElSRC1QQVJUWS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjoyNDkxNDk2LCJzaGEyNTYiOiIxMTY0NDdlZmY3Nzg5MzUxMTc5N2VmNDc2MDExZGVjODAwMjI0ZjkxZTMzNDJlM2Q2NTcwNzA4NzEyYjRiNzcyIn0seyJwYXRoIjoibGljZW5zZXMvbnBtLWNtZC1zaGltLnR4dCIsImJ5dGVzIjo4MTMsInNoYTI1NiI6ImFmZmZkZjEyMDgxMTIyNzQ5YzRiNzFjNWIxYzExYmM2NTlkNzkyNDJkMTllMThmNWU4ZGJhYjA0YTQ1ZTM2YmIifSx7InBhdGgiOiJucG0tYWRhcHRlci1maWxlcy5qc29uIiwiYnl0ZXMiOjE1MDAsInNoYTI1NiI6IjYzNWI0MjY3OTM1ZTI5ZGM4ODMwYzIwYjE0ZmZkMTE5NGM2NDIwZDYxZWFmMTEyNTc0MzI3NjRhNTg0OTExY2YifV19LHsidGFyZ2V0IjoiYnVuLXdpbmRvd3MtYXJtNjQiLCJmaWxlbmFtZSI6Im5vdGlmYWktMTIuMC4wLXdpbmRvd3MtYXJtNjQuemlwIiwiYnl0ZXMiOjM4Nzc2MDA3LCJzaGEyNTYiOiI5YWIzMmI0Y2ZlNTM4OWZmZTcxYjZmY2M1YmY3MjNkNzVjMGM2ZGU3OTQwNGZiYWE1NmJiZWQwMDEyOTk5NWY2IiwicnVudGltZV9zaGEyNTYiOiI1YTRmM2I5OTYxZmEwY2ViMjVhZDhhY2E2MGQ3NWVhOTc1YjAyZmQyZThmMDExZTUyY2QzNWE3ZDA4NDNmYjhkIiwibGF1bmNoZXJfc2hhMjU2IjoiNzBjMGJiMjAxYzlkY2RiYTYwNWQwOWI2MGE1YjQ5ZjcxOWQ1YTg1MDRjMDZhYzViNjNjNDNlNzFiMzYzMjM3ZiIsIm1hdGVyaWFscyI6W3sicGF0aCI6IkJVTi1MSUNFTlNFLm1kIiwiYnl0ZXMiOjU2MTMsInNoYTI1NiI6ImI5Y2FmNTI3Mjg2OTFiNDA1N2UzNzEyMzJjMjIxYTEzMjg4MzE5OGJlMmYzZDJkZGY5MmM5MDQwNGM5ODRiMWEifSx7InBhdGgiOiJDT1JSRVNQT05ESU5HLVNPVVJDRVMuanNvbiIsImJ5dGVzIjoyMDIwLCJzaGEyNTYiOiJmYTRjMzQ0ODAxMTU0ODcyZDYxNzllZTJlZjQ5OTIzZGM5Zjg5MDllZjAxZTUzYjg2ZThmNTdjNjI1ODIzMjc0In0seyJwYXRoIjoiTElDRU5TRS50eHQiLCJieXRlcyI6MTEzNDYsInNoYTI1NiI6Ijk0NGMxM2ZmMGZlNzk1ZTI5MWZkMWM0OTQ3M2Y5OGQ0ZmRmMWY3NDYzOGUwMWY4ODI3NjljZDRjYWU3OGI3M2QifSx7InBhdGgiOiJOT1RJQ0UtUFJPVkVOQU5DRS5qc29uIiwiYnl0ZXMiOjQ1MDI2NCwic2hhMjU2IjoiNTM0ZGQ1OWZkNGMxNWRkMTM4MmU4MjdmMGI4NWMxOWY3YzY5OGUyMzVmOTI5OWVhYTIwMmRiNTQwMDgzNDI4OCJ9LHsicGF0aCI6Ik5PVElDRS50eHQiLCJieXRlcyI6NjI2LCJzaGEyNTYiOiIxZGZiZjQ0OThkYzAyNmIyMDU5YzBiMGI1ZWI1ZmExZDgyYWUzMzRlNThmZjExZTdjMjk3MzMzMjdmMjVjNGViIn0seyJwYXRoIjoiUkVCVUlMRElORy5tZCIsImJ5dGVzIjozODQyLCJzaGEyNTYiOiJjZTYwNWI1ZmRiMDMxOTMzOWY5ZjgzZjJmZTdjY2NiYzdlNTcyNmZkZjQ5NGRhNmUyODQzM2JlZjgyOWViMGJlIn0seyJwYXRoIjoiU09VUkNFLU5PVElDRVMudHh0IiwiYnl0ZXMiOjkwMTc3NzEsInNoYTI1NiI6Ijg5OTc2YmVjYzI1NjU0MGU2ZDJlODA3YjQ3YTRlMDVlODg5OTgyYzA2MjJmYzA0NDEzYTdiZjdlNzdhNzdlMzcifSx7InBhdGgiOiJUSElSRC1QQVJUWS1OT1RJQ0VTLnR4dCIsImJ5dGVzIjoyNDkxNDk2LCJzaGEyNTYiOiIxMTY0NDdlZmY3Nzg5MzUxMTc5N2VmNDc2MDExZGVjODAwMjI0ZjkxZTMzNDJlM2Q2NTcwNzA4NzEyYjRiNzcyIn0seyJwYXRoIjoibGljZW5zZXMvbnBtLWNtZC1zaGltLnR4dCIsImJ5dGVzIjo4MTMsInNoYTI1NiI6ImFmZmZkZjEyMDgxMTIyNzQ5YzRiNzFjNWIxYzExYmM2NTlkNzkyNDJkMTllMThmNWU4ZGJhYjA0YTQ1ZTM2YmIifSx7InBhdGgiOiJucG0tYWRhcHRlci1maWxlcy5qc29uIiwiYnl0ZXMiOjE1MDAsInNoYTI1NiI6IjYzNWI0MjY3OTM1ZTI5ZGM4ODMwYzIwYjE0ZmZkMTE5NGM2NDIwZDYxZWFmMTEyNTc0MzI3NjRhNTg0OTExY2YifV19LHsidGFyZ2V0IjoiYnVuLXdpbmRvd3MteDY0IiwiZmlsZW5hbWUiOiJub3RpZmFpLTEyLjAuMC13aW5kb3dzLXg2NC56aXAiLCJieXRlcyI6NDE5MjIyNjIsInNoYTI1NiI6ImRiMjQ4NTU5YjRhNTY0NDQxZjkxNDlkYTc5YzNhNzRlZDU5ODRjZjc1ZDJhOWJjYjk3MTUzNjllYWYzZjQ4NDEiLCJydW50aW1lX3NoYTI1NiI6IjE2ZThiMTdlMDFmYzUxNTYwY2Q4MjU4MWY0MjQ1ZjdhMDM5OGE1MTc5MTZlZmMxMjM2NDViYTFmOTMyN2FjMGMiLCJsYXVuY2hlcl9zaGEyNTYiOiIzN2NlYzMwM2NlZmEzMWE2N2ViOTRhMzMwNjE4ZTBkYTFiNDIyZTcxZWI1ZGM5OTY1NWZiMmIyNzBlYWI5NWFkIiwibWF0ZXJpYWxzIjpbeyJwYXRoIjoiQlVOLUxJQ0VOU0UubWQiLCJieXRlcyI6NTYxMywic2hhMjU2IjoiYjljYWY1MjcyODY5MWI0MDU3ZTM3MTIzMmMyMjFhMTMyODgzMTk4YmUyZjNkMmRkZjkyYzkwNDA0Yzk4NGIxYSJ9LHsicGF0aCI6IkNPUlJFU1BPTkRJTkctU09VUkNFUy5qc29uIiwiYnl0ZXMiOjIwMjAsInNoYTI1NiI6ImZhNGMzNDQ4MDExNTQ4NzJkNjE3OWVlMmVmNDk5MjNkYzlmODkwOWVmMDFlNTNiODZlOGY1N2M2MjU4MjMyNzQifSx7InBhdGgiOiJMSUNFTlNFLnR4dCIsImJ5dGVzIjoxMTM0Niwic2hhMjU2IjoiOTQ0YzEzZmYwZmU3OTVlMjkxZmQxYzQ5NDczZjk4ZDRmZGYxZjc0NjM4ZTAxZjg4Mjc2OWNkNGNhZTc4YjczZCJ9LHsicGF0aCI6Ik5PVElDRS1QUk9WRU5BTkNFLmpzb24iLCJieXRlcyI6NDUwMjY0LCJzaGEyNTYiOiI1MzRkZDU5ZmQ0YzE1ZGQxMzgyZTgyN2YwYjg1YzE5ZjdjNjk4ZTIzNWY5Mjk5ZWFhMjAyZGI1NDAwODM0Mjg4In0seyJwYXRoIjoiTk9USUNFLnR4dCIsImJ5dGVzIjo2MjYsInNoYTI1NiI6IjFkZmJmNDQ5OGRjMDI2YjIwNTljMGIwYjVlYjVmYTFkODJhZTMzNGU1OGZmMTFlN2MyOTczMzMyN2YyNWM0ZWIifSx7InBhdGgiOiJSRUJVSUxESU5HLm1kIiwiYnl0ZXMiOjM4NDIsInNoYTI1NiI6ImNlNjA1YjVmZGIwMzE5MzM5ZjlmODNmMmZlN2NjY2JjN2U1NzI2ZmRmNDk0ZGE2ZTI4NDMzYmVmODI5ZWIwYmUifSx7InBhdGgiOiJTT1VSQ0UtTk9USUNFUy50eHQiLCJieXRlcyI6OTAxNzc3MSwic2hhMjU2IjoiODk5NzZiZWNjMjU2NTQwZTZkMmU4MDdiNDdhNGUwNWU4ODk5ODJjMDYyMmZjMDQ0MTNhN2JmN2U3N2E3N2UzNyJ9LHsicGF0aCI6IlRISVJELVBBUlRZLU5PVElDRVMudHh0IiwiYnl0ZXMiOjI0OTE0OTYsInNoYTI1NiI6IjExNjQ0N2VmZjc3ODkzNTExNzk3ZWY0NzYwMTFkZWM4MDAyMjRmOTFlMzM0MmUzZDY1NzA3MDg3MTJiNGI3NzIifSx7InBhdGgiOiJsaWNlbnNlcy9ucG0tY21kLXNoaW0udHh0IiwiYnl0ZXMiOjgxMywic2hhMjU2IjoiYWZmZmRmMTIwODExMjI3NDljNGI3MWM1YjFjMTFiYzY1OWQ3OTI0MmQxOWUxOGY1ZThkYmFiMDRhNDVlMzZiYiJ9LHsicGF0aCI6Im5wbS1hZGFwdGVyLWZpbGVzLmpzb24iLCJieXRlcyI6MTUwMCwic2hhMjU2IjoiNjM1YjQyNjc5MzVlMjlkYzg4MzBjMjBiMTRmZmQxMTk0YzY0MjBkNjFlYWYxMTI1NzQzMjc2NGE1ODQ5MTFjZiJ9XX1dfQ==","signature":"AhZTM63Se5CnP2qeVMCEYyHnHSVMiKmkXVDVUCVBOgEOntT596bL696RipGFIZHUK5JAD6TNMSBQToDqftkxAA=="}
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "schema": 1,
3
3
  "package": "@raidiant/notifai",
4
- "adapter_version": "12.0.0-beta.8",
4
+ "adapter_version": "12.0.0",
5
5
  "native": {
6
- "version": "12.0.0-beta.8",
7
- "source_revision": "c5a855200a3ac8582ea1aa0f5d137040fefdb49e",
8
- "inventory_url": "https://github.com/Raidiant-io/notifai/releases/download/v12.0.0-beta.8/inventory.json"
6
+ "version": "12.0.0",
7
+ "source_revision": "589d4598accb04d83e740868badcae32a3038f28",
8
+ "inventory_url": "https://github.com/Raidiant-io/notifai/releases/download/v12.0.0/inventory.json"
9
9
  },
10
10
  "files": [
11
11
  {
12
12
  "path": "CHANGELOG.md",
13
- "bytes": 61212,
14
- "sha256": "672f186f9587588bc48a25376ab127bfe7a447f5bb8eeaa9105db39df5482d33"
13
+ "bytes": 62276,
14
+ "sha256": "1a7f2dbdab467c6db132fad3dd62e88647f8d19291f7577ee7ceb403c95a69d7"
15
15
  },
16
16
  {
17
17
  "path": "LICENSE",
@@ -30,23 +30,23 @@
30
30
  },
31
31
  {
32
32
  "path": "bin/notifai.mjs",
33
- "bytes": 520496,
34
- "sha256": "94eb5ae58a5ee49e7cd07552806a93d17bf83038c221a477c82c8341a9ae5d04"
33
+ "bytes": 521624,
34
+ "sha256": "ef90a76ffa8081d21f7e496f904e20aed391c99be78e06382137dfe19eaddf49"
35
35
  },
36
36
  {
37
37
  "path": "data/install.ps1",
38
- "bytes": 18811,
39
- "sha256": "2925b84fb7890110695249d7f651a4ca0878f6ace2e127f44b7b4ad835073c5f"
38
+ "bytes": 26228,
39
+ "sha256": "e111259532c11e1e822356d34b0b30059db17b59e6b69ce3af74e491ee3cbc5a"
40
40
  },
41
41
  {
42
42
  "path": "data/release.json",
43
- "bytes": 89,
44
- "sha256": "695cd73ec1247c116187a246abce22af19f9d74f46b1ff21f8a1e025c0b62102"
43
+ "bytes": 82,
44
+ "sha256": "4e070f976fbe30a96ae78e48faec259c7c0119fea3eccd6a63e5582a04442c84"
45
45
  },
46
46
  {
47
47
  "path": "package.json",
48
- "bytes": 814,
49
- "sha256": "2e2d580218039b18927feb4872804f64f056abcb99c65c444797bdbcb2a1328f"
48
+ "bytes": 807,
49
+ "sha256": "81a9d0c23154484501ad1b7f47325ae636d6e219768b2156ef195a035e6408eb"
50
50
  }
51
51
  ]
52
52
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raidiant/notifai",
3
- "version": "12.0.0-beta.8",
3
+ "version": "12.0.0",
4
4
  "type": "module",
5
5
  "description": "Launch the independently managed native Notifai CLI",
6
6
  "bin": {