aiden-runtime 4.1.5 → 4.5.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.
Files changed (163) hide show
  1. package/README.md +250 -847
  2. package/dist/api/server.js +32 -5
  3. package/dist/cli/v4/aidenCLI.js +351 -53
  4. package/dist/cli/v4/callbacks.js +170 -0
  5. package/dist/cli/v4/chatSession.js +138 -3
  6. package/dist/cli/v4/commands/_runtimeToggleHelpers.js +92 -0
  7. package/dist/cli/v4/commands/browserDepth.js +45 -0
  8. package/dist/cli/v4/commands/cron.js +264 -0
  9. package/dist/cli/v4/commands/daemon.js +541 -0
  10. package/dist/cli/v4/commands/daemonStatus.js +253 -0
  11. package/dist/cli/v4/commands/help.js +7 -0
  12. package/dist/cli/v4/commands/index.js +20 -1
  13. package/dist/cli/v4/commands/runs.js +203 -0
  14. package/dist/cli/v4/commands/sandbox.js +48 -0
  15. package/dist/cli/v4/commands/suggestions.js +68 -0
  16. package/dist/cli/v4/commands/tce.js +41 -0
  17. package/dist/cli/v4/commands/trigger.js +378 -0
  18. package/dist/cli/v4/commands/update.js +95 -3
  19. package/dist/cli/v4/daemonAgentBuilder.js +142 -0
  20. package/dist/cli/v4/defaultSoul.js +1 -1
  21. package/dist/cli/v4/display/capabilityCard.js +26 -0
  22. package/dist/cli/v4/display.js +18 -8
  23. package/dist/cli/v4/replyRenderer.js +31 -23
  24. package/dist/cli/v4/updateBootPrompt.js +170 -0
  25. package/dist/core/playwrightBridge.js +129 -0
  26. package/dist/core/v4/aidenAgent.js +308 -4
  27. package/dist/core/v4/browserState.js +436 -0
  28. package/dist/core/v4/checkpoint.js +79 -0
  29. package/dist/core/v4/daemon/bootstrap.js +604 -0
  30. package/dist/core/v4/daemon/cleanShutdown.js +154 -0
  31. package/dist/core/v4/daemon/cron/cronBridge.js +126 -0
  32. package/dist/core/v4/daemon/cron/cronEmitter.js +173 -0
  33. package/dist/core/v4/daemon/cron/migration.js +199 -0
  34. package/dist/core/v4/daemon/cron/misfirePolicy.js +115 -0
  35. package/dist/core/v4/daemon/daemonConfig.js +90 -0
  36. package/dist/core/v4/daemon/db/connection.js +106 -0
  37. package/dist/core/v4/daemon/db/migrations.js +296 -0
  38. package/dist/core/v4/daemon/db/schema/v1.spec.js +18 -0
  39. package/dist/core/v4/daemon/dispatcher/agentRunner.js +98 -0
  40. package/dist/core/v4/daemon/dispatcher/budgetGate.js +127 -0
  41. package/dist/core/v4/daemon/dispatcher/daemonApproval.js +113 -0
  42. package/dist/core/v4/daemon/dispatcher/dailyBudgetTracker.js +120 -0
  43. package/dist/core/v4/daemon/dispatcher/dispatcher.js +389 -0
  44. package/dist/core/v4/daemon/dispatcher/fireRateLimiter.js +113 -0
  45. package/dist/core/v4/daemon/dispatcher/index.js +53 -0
  46. package/dist/core/v4/daemon/dispatcher/promptTemplate.js +95 -0
  47. package/dist/core/v4/daemon/dispatcher/realAgentRunner.js +356 -0
  48. package/dist/core/v4/daemon/dispatcher/resolveModel.js +93 -0
  49. package/dist/core/v4/daemon/dispatcher/sessionId.js +93 -0
  50. package/dist/core/v4/daemon/drain.js +156 -0
  51. package/dist/core/v4/daemon/eventLoopLag.js +73 -0
  52. package/dist/core/v4/daemon/health.js +159 -0
  53. package/dist/core/v4/daemon/idempotencyStore.js +204 -0
  54. package/dist/core/v4/daemon/index.js +179 -0
  55. package/dist/core/v4/daemon/instanceTracker.js +99 -0
  56. package/dist/core/v4/daemon/resourceRegistry.js +150 -0
  57. package/dist/core/v4/daemon/restartCode.js +32 -0
  58. package/dist/core/v4/daemon/restartFailureCounter.js +77 -0
  59. package/dist/core/v4/daemon/runStore.js +114 -0
  60. package/dist/core/v4/daemon/runtimeLock.js +167 -0
  61. package/dist/core/v4/daemon/signals.js +50 -0
  62. package/dist/core/v4/daemon/supervisor.js +272 -0
  63. package/dist/core/v4/daemon/triggerBus.js +279 -0
  64. package/dist/core/v4/daemon/triggers/email/allowlist.js +70 -0
  65. package/dist/core/v4/daemon/triggers/email/automatedSender.js +78 -0
  66. package/dist/core/v4/daemon/triggers/email/bodyExtractor.js +0 -0
  67. package/dist/core/v4/daemon/triggers/email/emailSeenStore.js +99 -0
  68. package/dist/core/v4/daemon/triggers/email/emailSpec.js +107 -0
  69. package/dist/core/v4/daemon/triggers/email/imapConnection.js +211 -0
  70. package/dist/core/v4/daemon/triggers/email/index.js +332 -0
  71. package/dist/core/v4/daemon/triggers/email/seenUids.js +60 -0
  72. package/dist/core/v4/daemon/triggers/fileObservationsStore.js +93 -0
  73. package/dist/core/v4/daemon/triggers/fileWatcher.js +253 -0
  74. package/dist/core/v4/daemon/triggers/fileWatcherSpec.js +88 -0
  75. package/dist/core/v4/daemon/triggers/fsIdentity.js +42 -0
  76. package/dist/core/v4/daemon/triggers/globMatcher.js +100 -0
  77. package/dist/core/v4/daemon/triggers/reconcile.js +206 -0
  78. package/dist/core/v4/daemon/triggers/settleStat.js +81 -0
  79. package/dist/core/v4/daemon/triggers/webhook.js +376 -0
  80. package/dist/core/v4/daemon/triggers/webhookDeliveriesStore.js +109 -0
  81. package/dist/core/v4/daemon/triggers/webhookIdempotency.js +72 -0
  82. package/dist/core/v4/daemon/triggers/webhookRateLimit.js +56 -0
  83. package/dist/core/v4/daemon/triggers/webhookSpec.js +76 -0
  84. package/dist/core/v4/daemon/triggers/webhookVerifier.js +128 -0
  85. package/dist/core/v4/daemon/types.js +15 -0
  86. package/dist/core/v4/dockerSession.js +461 -0
  87. package/dist/core/v4/dryRun.js +117 -0
  88. package/dist/core/v4/failureClassifier.js +779 -0
  89. package/dist/core/v4/recoveryReport.js +449 -0
  90. package/dist/core/v4/runtimeToggles.js +187 -0
  91. package/dist/core/v4/sandboxConfig.js +285 -0
  92. package/dist/core/v4/sandboxFs.js +316 -0
  93. package/dist/core/v4/suggestionCatalog.js +41 -0
  94. package/dist/core/v4/suggestionEngine.js +210 -0
  95. package/dist/core/v4/toolRegistry.js +18 -0
  96. package/dist/core/v4/turnState.js +587 -0
  97. package/dist/core/v4/update/checkUpdate.js +63 -3
  98. package/dist/core/v4/update/installMethodDetect.js +115 -0
  99. package/dist/core/v4/update/registryClient.js +121 -0
  100. package/dist/core/v4/update/skipState.js +75 -0
  101. package/dist/core/v4/verifier.js +448 -0
  102. package/dist/core/version.js +1 -1
  103. package/dist/tools/v4/browser/_observer.js +224 -0
  104. package/dist/tools/v4/browser/browserBlocker.js +396 -0
  105. package/dist/tools/v4/browser/browserClick.js +18 -1
  106. package/dist/tools/v4/browser/browserClose.js +18 -1
  107. package/dist/tools/v4/browser/browserExtract.js +5 -1
  108. package/dist/tools/v4/browser/browserFill.js +17 -1
  109. package/dist/tools/v4/browser/browserGetUrl.js +5 -1
  110. package/dist/tools/v4/browser/browserNavigate.js +16 -1
  111. package/dist/tools/v4/browser/browserScreenshot.js +5 -1
  112. package/dist/tools/v4/browser/browserScroll.js +18 -1
  113. package/dist/tools/v4/browser/browserType.js +17 -1
  114. package/dist/tools/v4/browser/captchaCheck.js +5 -1
  115. package/dist/tools/v4/executeCode.js +1 -0
  116. package/dist/tools/v4/files/fileCopy.js +56 -2
  117. package/dist/tools/v4/files/fileDelete.js +38 -1
  118. package/dist/tools/v4/files/fileList.js +12 -1
  119. package/dist/tools/v4/files/fileMove.js +59 -2
  120. package/dist/tools/v4/files/filePatch.js +43 -1
  121. package/dist/tools/v4/files/fileRead.js +12 -1
  122. package/dist/tools/v4/files/fileWrite.js +41 -1
  123. package/dist/tools/v4/index.js +71 -58
  124. package/dist/tools/v4/memory/memoryAdd.js +14 -0
  125. package/dist/tools/v4/memory/memoryRemove.js +14 -0
  126. package/dist/tools/v4/memory/memoryReplace.js +15 -0
  127. package/dist/tools/v4/memory/sessionSummary.js +12 -0
  128. package/dist/tools/v4/process/processKill.js +19 -0
  129. package/dist/tools/v4/process/processList.js +1 -0
  130. package/dist/tools/v4/process/processLogRead.js +1 -0
  131. package/dist/tools/v4/process/processSpawn.js +13 -0
  132. package/dist/tools/v4/process/processWait.js +1 -0
  133. package/dist/tools/v4/sessions/recallSession.js +1 -0
  134. package/dist/tools/v4/sessions/sessionList.js +1 -0
  135. package/dist/tools/v4/sessions/sessionSearch.js +1 -0
  136. package/dist/tools/v4/skills/lookupToolSchema.js +2 -0
  137. package/dist/tools/v4/skills/skillManage.js +13 -0
  138. package/dist/tools/v4/skills/skillView.js +1 -0
  139. package/dist/tools/v4/skills/skillsList.js +1 -0
  140. package/dist/tools/v4/subagent/subagentFanout.js +1 -0
  141. package/dist/tools/v4/system/aidenSelfUpdate.js +16 -0
  142. package/dist/tools/v4/system/appClose.js +13 -0
  143. package/dist/tools/v4/system/appInput.js +13 -0
  144. package/dist/tools/v4/system/appLaunch.js +13 -0
  145. package/dist/tools/v4/system/clipboardRead.js +1 -0
  146. package/dist/tools/v4/system/clipboardWrite.js +14 -0
  147. package/dist/tools/v4/system/mediaKey.js +12 -0
  148. package/dist/tools/v4/system/mediaSessions.js +1 -0
  149. package/dist/tools/v4/system/mediaTransport.js +13 -0
  150. package/dist/tools/v4/system/naturalEvents.js +1 -0
  151. package/dist/tools/v4/system/nowPlaying.js +1 -0
  152. package/dist/tools/v4/system/osProcessList.js +1 -0
  153. package/dist/tools/v4/system/screenshot.js +1 -0
  154. package/dist/tools/v4/system/systemInfo.js +1 -0
  155. package/dist/tools/v4/system/volumeSet.js +17 -0
  156. package/dist/tools/v4/terminal/shellExec.js +81 -9
  157. package/dist/tools/v4/web/deepResearch.js +1 -0
  158. package/dist/tools/v4/web/openUrl.js +1 -0
  159. package/dist/tools/v4/web/webFetch.js +1 -0
  160. package/dist/tools/v4/web/webPage.js +1 -0
  161. package/dist/tools/v4/web/webSearch.js +1 -0
  162. package/dist/tools/v4/web/youtubeSearch.js +1 -0
  163. package/package.json +7 -1
@@ -38,12 +38,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
38
38
  };
39
39
  Object.defineProperty(exports, "__esModule", { value: true });
40
40
  exports.compareVersions = compareVersions;
41
+ exports.updateCacheFile = updateCacheFile;
41
42
  exports.checkForUpdate = checkForUpdate;
42
43
  exports.formatUpdateLine = formatUpdateLine;
43
44
  const node_fs_1 = require("node:fs");
44
45
  const node_path_1 = __importDefault(require("node:path"));
45
46
  const REGISTRY_URL = 'https://registry.npmjs.org/aiden-runtime/latest';
46
- const CACHE_TTL_MS = 6 * 60 * 60 * 1000; // 6 h
47
+ // v4.5 update system TTL bumped 6h 24h per spec. The old 6h
48
+ // supported the firstRun loud-warn UX; the new interactive boot
49
+ // prompt makes the prompt itself the prominent surface, so we can
50
+ // relax the refresh cadence.
51
+ const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
47
52
  const REGISTRY_TIMEOUT_MS = 4000;
48
53
  /** Cache file path. Co-located with other Aiden home dotfiles. */
49
54
  function defaultCacheFile(paths) {
@@ -109,6 +114,28 @@ async function writeCache(file, cache) {
109
114
  /* swallow — cache write is best-effort */
110
115
  }
111
116
  }
117
+ /**
118
+ * v4.5 update system — public cache writer for the skip-state +
119
+ * release-notes machinery. `mutate` receives the current cache
120
+ * (or a fresh empty shell when none exists) and returns the new
121
+ * cache content; this function persists. Used by:
122
+ *
123
+ * - `/update skip <v>` slash command (writes skippedVersion)
124
+ * - boot prompt path (writes skippedVersion on 'n')
125
+ * - registry probe path (writes releaseNotes / releaseUrl)
126
+ *
127
+ * Never throws — best-effort I/O.
128
+ */
129
+ async function updateCacheFile(paths, mutate) {
130
+ const file = defaultCacheFile(paths);
131
+ const current = (await readCache(file)) ?? {
132
+ ts: 0,
133
+ latest: null,
134
+ installed: '',
135
+ };
136
+ const next = mutate(current);
137
+ await writeCache(file, next);
138
+ }
112
139
  /** Default fetch wrapper with a 4-second AbortController timeout. */
113
140
  async function defaultFetch(url) {
114
141
  const controller = new AbortController();
@@ -152,6 +179,7 @@ async function checkForUpdate(opts) {
152
179
  updateAvailable: false,
153
180
  fromCache: false,
154
181
  firstRun: false,
182
+ skipped: false,
155
183
  };
156
184
  }
157
185
  const cacheFile = opts.cacheFile ?? defaultCacheFile(opts.paths);
@@ -161,12 +189,22 @@ async function checkForUpdate(opts) {
161
189
  const firstRun = cached === null;
162
190
  if (cached && now - cached.ts < ttl && cached.installed === installed) {
163
191
  const updateAvailable = cached.latest !== null && safeCompare(cached.latest, installed) > 0;
192
+ // v4.5 — surface skip-state lazily so the boot prompt can decide
193
+ // whether to render the box at all. The compare is cheap; we
194
+ // avoid pulling skipState.ts module-level to keep this file's
195
+ // dep graph minimal.
196
+ const skipped = typeof cached.skippedVersion === 'string' &&
197
+ cached.latest !== null &&
198
+ safeCompare(cached.skippedVersion, cached.latest) >= 0;
164
199
  return {
165
200
  installed,
166
201
  latest: cached.latest,
167
202
  updateAvailable,
168
203
  fromCache: true,
169
204
  firstRun: false,
205
+ releaseNotes: cached.releaseNotes,
206
+ releaseUrl: cached.releaseUrl,
207
+ skipped,
170
208
  };
171
209
  }
172
210
  let latest = null;
@@ -178,9 +216,31 @@ async function checkForUpdate(opts) {
178
216
  catch {
179
217
  latest = null;
180
218
  }
181
- await writeCache(cacheFile, { ts: now, latest, installed });
219
+ // v4.5 preserve skippedVersion + release-notes across cache
220
+ // refreshes. The fresh probe overwrites the {ts, latest, installed}
221
+ // triple; everything else carries forward from the prior cache.
222
+ await writeCache(cacheFile, {
223
+ ts: now,
224
+ latest,
225
+ installed,
226
+ releaseNotes: cached?.releaseNotes,
227
+ releaseUrl: cached?.releaseUrl,
228
+ skippedVersion: cached?.skippedVersion,
229
+ });
182
230
  const updateAvailable = latest !== null && safeCompare(latest, installed) > 0;
183
- return { installed, latest, updateAvailable, fromCache: false, firstRun };
231
+ const skipped = typeof cached?.skippedVersion === 'string' &&
232
+ latest !== null &&
233
+ safeCompare(cached.skippedVersion, latest) >= 0;
234
+ return {
235
+ installed,
236
+ latest,
237
+ updateAvailable,
238
+ fromCache: false,
239
+ firstRun,
240
+ releaseNotes: cached?.releaseNotes,
241
+ releaseUrl: cached?.releaseUrl,
242
+ skipped,
243
+ };
184
244
  }
185
245
  /** Wrap `compareVersions` so unparseable strings don't blow up the boot path. */
186
246
  function safeCompare(a, b) {
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 Shiva Deore (Taracod).
4
+ * Licensed under AGPL-3.0. See LICENSE for details.
5
+ *
6
+ * Aiden — local-first agent.
7
+ */
8
+ /**
9
+ * core/v4/update/installMethodDetect.ts — v4.5 update system.
10
+ *
11
+ * Identify how the user installed Aiden so the update path can do
12
+ * the right thing without false promises:
13
+ *
14
+ * npm-global — `npm install -g aiden-runtime`
15
+ * → run `npm install -g aiden-runtime@<v>`
16
+ * npm-local — local install in a project's node_modules
17
+ * → run `npm install aiden-runtime@<v>` in that
18
+ * project (printed to user; we don't dispatch
19
+ * a project-local install from the global path)
20
+ * npx — running via `npx aiden-runtime`
21
+ * → tell user to re-run with the new version pinned
22
+ * standalone-binary — packaged binary (aiden-releases artefact)
23
+ * → point at the GitHub releases page
24
+ * unknown — fallback: print the install command verbatim
25
+ *
26
+ * Pure detection logic — no I/O, no spawning. Caller dispatches.
27
+ */
28
+ var __importDefault = (this && this.__importDefault) || function (mod) {
29
+ return (mod && mod.__esModule) ? mod : { "default": mod };
30
+ };
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.detectInstallMethod = detectInstallMethod;
33
+ const node_path_1 = __importDefault(require("node:path"));
34
+ const NPX_CACHE_HINT = /[/\\]_npx[/\\]/;
35
+ const NPM_GLOBAL_HINTS = [
36
+ /[/\\]npm[/\\]node_modules[/\\]aiden-runtime\b/,
37
+ /[/\\]npm-global[/\\]/,
38
+ /[/\\]\.nvm[/\\]versions[/\\]node[/\\][^/\\]+[/\\]lib[/\\]node_modules\b/,
39
+ /Program Files[/\\]nodejs[/\\]node_modules[/\\]aiden-runtime\b/i,
40
+ ];
41
+ function inferDirs(input) {
42
+ return {
43
+ execPath: input.execPath ?? process.execPath,
44
+ moduleDir: input.moduleDir ?? (typeof __dirname === 'string' ? __dirname : ''),
45
+ argvScript: input.argvScript ?? (process.argv[1] ?? ''),
46
+ };
47
+ }
48
+ /**
49
+ * Pure detection. Order matters — npx and standalone-binary are
50
+ * checked first because they have distinctive path markers; npm
51
+ * variants are detected by their node_modules location.
52
+ */
53
+ function detectInstallMethod(input = {}) {
54
+ const { moduleDir, argvScript } = inferDirs(input);
55
+ const platform = input.platform ?? process.platform;
56
+ const env = input.env ?? process.env;
57
+ void platform;
58
+ // npx — running from npm's npx cache directory.
59
+ if (NPX_CACHE_HINT.test(moduleDir) || NPX_CACHE_HINT.test(argvScript)) {
60
+ return {
61
+ method: 'npx',
62
+ inProcessInstallSupported: false,
63
+ description: 'running via npx (no installed copy to update)',
64
+ updateCommand: (v) => `npx aiden-runtime@${v} # re-run the CLI with the pinned version`,
65
+ };
66
+ }
67
+ // Standalone binary — env var set by the release scripts when
68
+ // packaging via pkg / nexe / similar. Future-proof; no current
69
+ // releases set it, so we don't accidentally classify a normal
70
+ // node install as standalone.
71
+ if (env.AIDEN_STANDALONE_BINARY === '1') {
72
+ return {
73
+ method: 'standalone-binary',
74
+ inProcessInstallSupported: false,
75
+ description: 'standalone binary install (not from npm)',
76
+ updateCommand: (_v) => 'Download the latest release from https://github.com/taracodlabs/aiden/releases',
77
+ };
78
+ }
79
+ // npm-global — moduleDir / argvScript live under a global
80
+ // node_modules path.
81
+ const haystack = `${moduleDir} ${argvScript}`;
82
+ if (NPM_GLOBAL_HINTS.some((rx) => rx.test(haystack))) {
83
+ return {
84
+ method: 'npm-global',
85
+ inProcessInstallSupported: true,
86
+ description: 'global npm install (aiden-runtime)',
87
+ updateCommand: (v) => `npm install -g aiden-runtime@${v}`,
88
+ };
89
+ }
90
+ // npm-local — `node_modules/aiden-runtime/` somewhere in the
91
+ // moduleDir's ancestry but NOT under npm/global paths above.
92
+ if (/[/\\]node_modules[/\\]aiden-runtime\b/.test(moduleDir) ||
93
+ /[/\\]node_modules[/\\]aiden-runtime\b/.test(argvScript)) {
94
+ // Walk up to find the project root (parent of `node_modules`).
95
+ const idx = moduleDir.search(/[/\\]node_modules[/\\]aiden-runtime\b/);
96
+ const projectRoot = idx >= 0 ? moduleDir.slice(0, idx) : '<project>';
97
+ return {
98
+ method: 'npm-local',
99
+ inProcessInstallSupported: false,
100
+ description: `local npm install in project (${node_path_1.default.basename(projectRoot)})`,
101
+ updateCommand: (v) => `cd ${projectRoot} && npm install aiden-runtime@${v}`,
102
+ };
103
+ }
104
+ // Unknown — fallback to the verbatim global-install command. The
105
+ // user sees it; we don't spawn. Most accurate default for a
106
+ // fresh `npx tsx cli/v4/aidenCLI.ts` dev-mode invocation, which
107
+ // is also the path the maintainer (and many CI environments)
108
+ // use day-to-day.
109
+ return {
110
+ method: 'unknown',
111
+ inProcessInstallSupported: false,
112
+ description: 'install method not detected (running from source?)',
113
+ updateCommand: (v) => `npm install -g aiden-runtime@${v} # if installed via npm, otherwise see docs`,
114
+ };
115
+ }
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 Shiva Deore (Taracod).
4
+ * Licensed under AGPL-3.0. See LICENSE for details.
5
+ *
6
+ * Aiden — local-first agent.
7
+ */
8
+ /**
9
+ * core/v4/update/registryClient.ts — v4.5 update system.
10
+ *
11
+ * Q-U1(c) two-source strategy:
12
+ *
13
+ * 1. npm registry — `registry.npmjs.org/aiden-runtime/latest` →
14
+ * `{ version, dist.tarball, _id, ... }`. No auth, fast, the
15
+ * authoritative source for "what's the newest published version".
16
+ *
17
+ * 2. GitHub releases — `api.github.com/repos/taracodlabs/aiden/
18
+ * releases/latest` → rich markdown body for the user-facing
19
+ * "What's new" line. Optional; falls through gracefully when
20
+ * anonymous-rate-limited or the repo doesn't mirror npm tags.
21
+ *
22
+ * Both fetches share a 4-second timeout per request. Network failure
23
+ * on either side returns null rather than throwing — the boot prompt
24
+ * just won't include release-notes context when we couldn't fetch it.
25
+ */
26
+ Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.fetchUpdateInfo = fetchUpdateInfo;
28
+ exports.firstLineOf = firstLineOf;
29
+ const NPM_REGISTRY_URL = 'https://registry.npmjs.org/aiden-runtime/latest';
30
+ const GITHUB_RELEASES_URL = 'https://api.github.com/repos/taracodlabs/aiden/releases/latest';
31
+ const REGISTRY_TIMEOUT_MS = 4000;
32
+ /**
33
+ * Probe both sources in parallel. Returns whatever succeeded; either
34
+ * (or both) may be null on network failure.
35
+ */
36
+ async function fetchUpdateInfo(opts = {}) {
37
+ const npmFetch = opts.npmFetch ?? (() => defaultNpmFetch(opts.timeoutMs));
38
+ const githubFetch = opts.githubFetch ?? (() => defaultGithubFetch(opts.timeoutMs));
39
+ const [probe, notes] = await Promise.all([
40
+ npmFetch().catch(() => null),
41
+ githubFetch().catch(() => null),
42
+ ]);
43
+ return { probe, notes };
44
+ }
45
+ // ── Default fetchers ──────────────────────────────────────────────────────
46
+ async function defaultNpmFetch(timeoutMs = REGISTRY_TIMEOUT_MS) {
47
+ const controller = new AbortController();
48
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
49
+ try {
50
+ const res = await fetch(NPM_REGISTRY_URL, {
51
+ headers: {
52
+ Accept: 'application/json',
53
+ 'User-Agent': 'aiden-runtime update check',
54
+ },
55
+ signal: controller.signal,
56
+ });
57
+ if (!res.ok)
58
+ return null;
59
+ const json = (await res.json());
60
+ if (typeof json.version !== 'string')
61
+ return null;
62
+ return {
63
+ version: json.version,
64
+ tarballUrl: typeof json.dist?.tarball === 'string' ? json.dist.tarball : undefined,
65
+ };
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ finally {
71
+ clearTimeout(timer);
72
+ }
73
+ }
74
+ async function defaultGithubFetch(timeoutMs = REGISTRY_TIMEOUT_MS) {
75
+ const controller = new AbortController();
76
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
77
+ try {
78
+ const res = await fetch(GITHUB_RELEASES_URL, {
79
+ headers: {
80
+ Accept: 'application/vnd.github+json',
81
+ 'User-Agent': 'aiden-runtime update check',
82
+ },
83
+ signal: controller.signal,
84
+ });
85
+ // 404 = repo doesn't expose releases yet; 403 = anonymous rate limit.
86
+ // Both → null + boot proceeds without notes.
87
+ if (!res.ok)
88
+ return null;
89
+ const json = (await res.json());
90
+ if (typeof json.tag_name !== 'string')
91
+ return null;
92
+ const body = typeof json.body === 'string' ? json.body : '';
93
+ return {
94
+ tag: json.tag_name,
95
+ url: typeof json.html_url === 'string' ? json.html_url : '',
96
+ blurb: firstLineOf(body, 120),
97
+ };
98
+ }
99
+ catch {
100
+ return null;
101
+ }
102
+ finally {
103
+ clearTimeout(timer);
104
+ }
105
+ }
106
+ /** First non-blank line of a multi-line string, truncated to maxChars. */
107
+ function firstLineOf(text, maxChars) {
108
+ if (typeof text !== 'string' || text.length === 0)
109
+ return '';
110
+ for (const raw of text.split(/\r?\n/)) {
111
+ const line = raw.trim();
112
+ // Skip markdown heading lines (`## What's new` etc.) so the blurb
113
+ // is actually descriptive prose, not a section heading.
114
+ if (line.length === 0 || line.startsWith('#'))
115
+ continue;
116
+ if (line.length <= maxChars)
117
+ return line;
118
+ return line.slice(0, maxChars - 1) + '…';
119
+ }
120
+ return '';
121
+ }
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 Shiva Deore (Taracod).
4
+ * Licensed under AGPL-3.0. See LICENSE for details.
5
+ *
6
+ * Aiden — local-first agent.
7
+ */
8
+ /**
9
+ * core/v4/update/skipState.ts — v4.5 update system.
10
+ *
11
+ * Persistent "user said no thanks to this update" memory. Q-U7(b)
12
+ * semantics: a single `skippedVersion` slot meaning "stop nagging
13
+ * about THIS version; resume when something newer ships."
14
+ *
15
+ * Store: 4.5.1 → prompt for 4.5.1 suppressed
16
+ * prompt for 4.5.2 fires (4.5.2 > 4.5.1)
17
+ *
18
+ * Per-version-list (skip multiple specific versions) is v4.6
19
+ * polish if real usage shows people want it.
20
+ *
21
+ * Storage: piggyback on the existing `.update_check.json` cache so
22
+ * we don't add a second dotfile. The cache file already lives at
23
+ * `<aiden-home>/.update_check.json` (created by checkUpdate.ts).
24
+ *
25
+ * Pure module — every function takes the cache content as input
26
+ * and returns the new content. The actual disk read/write stays
27
+ * inside checkUpdate.ts to keep one source of truth for the cache
28
+ * lifecycle.
29
+ */
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.isVersionSkipped = isVersionSkipped;
32
+ exports.applySkip = applySkip;
33
+ exports.clearSkip = clearSkip;
34
+ const checkUpdate_1 = require("./checkUpdate");
35
+ /**
36
+ * Is `latest` suppressed by the user's prior skip choice?
37
+ *
38
+ * skip empty → never suppress
39
+ * skip = latest → suppress
40
+ * skip < latest → don't suppress (newer version available)
41
+ * skip > latest → suppress (defensive — user already passed
42
+ * this version; treat as still-skipped)
43
+ *
44
+ * Returns false when either input is empty/unparseable — never
45
+ * silently swallow a "should-have-prompted".
46
+ */
47
+ function isVersionSkipped(skippedVersion, latest) {
48
+ if (!skippedVersion || !latest)
49
+ return false;
50
+ try {
51
+ const cmp = (0, checkUpdate_1.compareVersions)(skippedVersion, latest);
52
+ return cmp >= 0;
53
+ }
54
+ catch {
55
+ // Unparseable version on either side → fail safe to "not skipped"
56
+ // so the user gets the prompt rather than silent suppression.
57
+ return false;
58
+ }
59
+ }
60
+ /**
61
+ * Update the cache content with a fresh skipped version. Pure —
62
+ * caller persists.
63
+ */
64
+ function applySkip(cache, version) {
65
+ return { ...cache, skippedVersion: version };
66
+ }
67
+ /**
68
+ * Clear the skipped-version slot — user typed `/update auto on` or
69
+ * explicitly opted back in. Pure.
70
+ */
71
+ function clearSkip(cache) {
72
+ const next = { ...cache };
73
+ delete next.skippedVersion;
74
+ return next;
75
+ }