aegis-desktop 1.0.13 → 1.0.15

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 (96) hide show
  1. package/SOURCE-OFFER.txt +9 -0
  2. package/bin/aegis.js +1 -32
  3. package/lib/account-key.js +1 -56
  4. package/lib/auto.js +1 -430
  5. package/lib/avatar/companion.js +1 -698
  6. package/lib/avatar/cosmetics.js +1 -532
  7. package/lib/avatar/events.js +1 -344
  8. package/lib/avatar/holder-turn.js +1 -350
  9. package/lib/avatar/holders.js +1 -612
  10. package/lib/avatar/identity.js +1 -641
  11. package/lib/avatar/level.js +1 -368
  12. package/lib/avatar/mirror.js +1 -524
  13. package/lib/avatar/persona.js +1 -388
  14. package/lib/avatar/profile.js +1 -977
  15. package/lib/avatar/register.js +1 -307
  16. package/lib/avatar/store.js +1 -472
  17. package/lib/avatar/tiers.js +1 -38
  18. package/lib/avatar/transfer.js +1 -415
  19. package/lib/avatar/turn.js +1 -216
  20. package/lib/avatar/voice.js +1 -328
  21. package/lib/avatar/xp.js +1 -404
  22. package/lib/deep-link.js +1 -120
  23. package/lib/fingerprint.js +2 -347
  24. package/lib/google-connect.js +1 -169
  25. package/lib/local/agents.js +1 -105
  26. package/lib/local/autonomous.js +1 -1045
  27. package/lib/local/claude-pro.js +1 -993
  28. package/lib/local/context.js +1 -95
  29. package/lib/local/engine.js +1 -3228
  30. package/lib/local/entitlement.js +1 -654
  31. package/lib/local/git-scope.js +1 -228
  32. package/lib/local/local.js +1 -2135
  33. package/lib/local/prompt.js +1 -275
  34. package/lib/local/queue.js +1 -560
  35. package/lib/local/session-rounds.js +1 -208
  36. package/lib/local/shell.js +1 -680
  37. package/lib/local/telemetry.js +1 -470
  38. package/lib/local/tools.js +1 -1238
  39. package/lib/local/turn-guard.js +1 -300
  40. package/lib/local/worktree-lock.js +1 -235
  41. package/lib/provider-key-mirror.js +1 -252
  42. package/lib/quick-launcher.js +1 -84
  43. package/lib/settings.js +1 -890
  44. package/lib/sync/memory-queue.js +1 -60
  45. package/lib/sync/persist-gate.js +1 -148
  46. package/lib/sync/sessions.js +1 -106
  47. package/lib/window-state.js +1 -66
  48. package/main.js +3 -4390
  49. package/package.json +3 -5
  50. package/preload.js +3 -628
  51. package/renderer/app.js +1 -6560
  52. package/renderer/avatar/assemble.js +1 -335
  53. package/renderer/avatar/avatar.js +1 -380
  54. package/renderer/avatar/cards.js +1 -141
  55. package/renderer/avatar/hud.js +1 -206
  56. package/renderer/avatar/machine.js +1 -213
  57. package/renderer/avatar/pane.js +1 -439
  58. package/renderer/avatar/parts.js +1 -437
  59. package/renderer/budget.js +1 -168
  60. package/renderer/companion.js +1 -223
  61. package/renderer/diff.js +1 -359
  62. package/renderer/diffview.js +1 -336
  63. package/renderer/fingerprint.js +3 -720
  64. package/renderer/markdown.js +1 -168
  65. package/renderer/provider-toolbar.js +1 -134
  66. package/renderer/providers.js +1 -259
  67. package/renderer/quick.js +1 -191
  68. package/renderer/stream-policy.js +1 -306
  69. package/renderer/transcript-view.js +1 -323
  70. package/renderer/usage.js +1 -1239
  71. package/vendor/aegis.js +1 -2054
  72. package/vendor/attest.js +1 -442
  73. package/vendor/authorship-key.js +1 -410
  74. package/vendor/auto-provision.js +1 -134
  75. package/vendor/brain-catalog.js +1 -268
  76. package/vendor/byok-catalog.js +1 -230
  77. package/vendor/credentials.js +1 -494
  78. package/vendor/device-fingerprint.js +1 -141
  79. package/vendor/drive-connect.js +1 -85
  80. package/vendor/drive-upload.js +1 -174
  81. package/vendor/env-file.js +1 -1273
  82. package/vendor/fingerprint.js +1 -1064
  83. package/vendor/foreign-memory.js +1 -669
  84. package/vendor/google-signin.js +1 -125
  85. package/vendor/hooks.js +1 -430
  86. package/vendor/model-discovery.js +1 -330
  87. package/vendor/platform.js +1 -937
  88. package/vendor/prefs.js +1 -351
  89. package/vendor/presence-constants.js +1 -107
  90. package/vendor/presence.js +1 -438
  91. package/vendor/record-vault.js +3 -1055
  92. package/vendor/session-store.js +1 -548
  93. package/vendor/topup.js +1 -297
  94. package/vendor/touch.js +1 -458
  95. package/vendor/update.js +1 -704
  96. package/vendor/user-models.js +1 -381
@@ -1,208 +1,3 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
2
  // Copyright (C) 2026 Niklas Borneklint — AEGIS Code (aegiscode) / Aegiscloud.
3
- // AEGIS Code (aegiscode) — source: https://github.com/aegisinfo/aegiscode-plugin
4
- // Conveying a modified copy, or running one as a network service, owes the
5
- // corresponding source under this licence (§5/§13) — see LICENSING.md.
6
- 'use strict';
7
-
8
- /**
9
- * hud.js — the level HUD: XP bar, next unlock, and the honest held state.
10
- *
11
- * The HUD is a *renderer*: it draws a projection main handed it and derives
12
- * nothing. That is not a stylistic preference — §1.5 of the plan says a level is
13
- * written by main because "a renderer-held counter is a suggestion, not a fact",
14
- * so `hudModel` has no branch that turns XP into a level. It reads `level`,
15
- * `progress`, `tier` and `held` off the projection, and when there is no
16
- * projection it says exactly that:
17
- *
18
- * known: false, percent: null, readout: "level unknown — …"
19
- *
20
- * The tempting alternative — treat a missing projection as `level 1, 0 XP` —
21
- * would be a fabricated number on a screen about the user's own progress, and on
22
- * a real install (main landed, level 12) it would be a lie, not a default. The
23
- * unknown state costs a line of text and cannot be wrong.
24
- *
25
- * The three honesty rules the tests hold it to:
26
- *
27
- * 1. **Unknown is not zero.** No projection ⇒ no percentage, no bar fill, and
28
- * a readout that says so.
29
- * 2. **Held is labelled.** §1.4: a level never silently regresses while the
30
- * user watches. When `projection.held` is set the HUD says
31
- * `level held · reshuffling` and marks the bar, and the next-unlock line
32
- * says it is waiting for the ledger to settle — because unlocks follow the
33
- * *settled* level, and claiming a unlock the ledger does not support is the
34
- * same class of lie as a level that ticks down unannounced.
35
- * 3. **Every number has a text twin.** The SVG is `aria-hidden`, so the
36
- * readout below it must carry the whole state as a sentence.
37
- *
38
- * Pure (a model) plus one small DOM writer. No timers, no storage.
39
- */
40
-
41
- const pkg = typeof window !== 'undefined' && window.AegisAvatarParts
42
- ? {
43
- parts: window.AegisAvatarParts,
44
- level: window.AegisAvatarLevel || null,
45
- }
46
- : typeof module !== 'undefined' && module.exports
47
- ? {
48
- parts: require('./parts.js'),
49
- level: require('../../lib/avatar/level.js'),
50
- }
51
- : { parts: null, level: null };
52
-
53
- if (!pkg.parts) throw new Error('avatar/hud.js: avatar/parts.js must be loaded first');
54
-
55
- function num(v, fallback) {
56
- return typeof v === 'number' && Number.isFinite(v) ? v : fallback;
57
- }
58
-
59
- /** `Headphones`, `Seasonal set · pack` — a paid cosmetic says so on the tin. */
60
- function unlockText(unlock) {
61
- return unlock.unlocks
62
- .map((u) => (u.paid ? `${u.label} · pack` : u.label))
63
- .join(', ');
64
- }
65
-
66
- /**
67
- * Build the view model.
68
- *
69
- * @param {object} input
70
- * @param {object} [input.persona] validated persona (for the name)
71
- * @param {object} [input.projection] `xp.evaluate()` output, as main reports it
72
- * @param {object} [input.capabilities] `level.capabilities()` output, for the
73
- * cosmetics gate (which packs the pane may offer)
74
- * @param {string} [input.expression] current expression id
75
- * @param {string} [input.expressionLabel] its human label
76
- * @param {string} [input.reason] why there is no projection, shown verbatim
77
- */
78
- function hudModel(input = {}) {
79
- const persona = input.persona && typeof input.persona === 'object' ? input.persona : pkg.parts.defaultPersona();
80
- const name = (persona.identity && persona.identity.name) || 'Aegis';
81
- const projection = input.projection && typeof input.projection === 'object' ? input.projection : null;
82
- const levelNo = projection ? num(projection.level, null) : null;
83
- const known = levelNo !== null;
84
-
85
- const expressionLabel = String(input.expressionLabel || input.expression || 'neutral');
86
- const expressionNote = `expression: ${expressionLabel}`;
87
-
88
- if (!known) {
89
- const reason = String(input.reason || 'main has not published a level yet');
90
- return {
91
- known: false,
92
- name,
93
- level: null,
94
- tier: null,
95
- xpIntoLevel: null,
96
- xpForNext: null,
97
- percent: null,
98
- held: false,
99
- heldNote: '',
100
- nextUnlock: null,
101
- nextUnlockText: '',
102
- unlockNote: '',
103
- expression: input.expression || 'neutral',
104
- expressionLabel,
105
- readout: `${name} · level unknown — ${reason} · ${expressionNote}`,
106
- ariaLive: 'polite',
107
- };
108
- }
109
-
110
- const held = projection.held === true;
111
- const settled = num(projection.settledLevel, levelNo);
112
- const tier = projection.tier || call(() => pkg.level.tierFor(levelNo).name, null) || null;
113
- const xpIntoLevel = num(projection.xpIntoLevel, null);
114
- const xpForNext = num(projection.xpForNext, null);
115
- // The bar shows the projection's own progress — never a number this file
116
- // computed. Clamped only so a malformed projection cannot draw outside the
117
- // track; the held case is labelled in the readout instead of fudged here.
118
- const percent = Math.round(Math.min(1, Math.max(0, num(projection.progress, 0))) * 100);
119
-
120
- // Unlocks follow the settled level, never the held one.
121
- const unlockLevel = held ? settled : levelNo;
122
- let next = null;
123
- try {
124
- next = pkg.level ? pkg.level.nextUnlock(unlockLevel) : null;
125
- } catch {
126
- next = null;
127
- }
128
- const nextUnlockText = next ? `next at level ${next.level}: ${unlockText(next)}` : 'every unlock is yours';
129
-
130
- const parts = [];
131
- parts.push(`${name} · level ${levelNo}`);
132
- if (tier) parts.push(tier);
133
- if (held) parts.push('level held · reshuffling');
134
- if (!held && xpForNext !== null && xpIntoLevel !== null) {
135
- parts.push(`${xpIntoLevel} / ${xpForNext} XP to level ${levelNo + 1}`);
136
- }
137
- parts.push(nextUnlockText);
138
- parts.push(expressionNote);
139
-
140
- return {
141
- known: true,
142
- name,
143
- level: levelNo,
144
- tier,
145
- xpIntoLevel,
146
- xpForNext,
147
- percent,
148
- held,
149
- heldNote: held ? 'level held · reshuffling' : '',
150
- nextUnlock: next,
151
- nextUnlockText,
152
- // The held state makes the unlock line provisional; say so where it is read.
153
- unlockNote: held ? `held — applies after the ledger settles (level ${settled})` : '',
154
- expression: input.expression || 'neutral',
155
- expressionLabel,
156
- readout: parts.join(' · '),
157
- ariaLive: 'polite',
158
- cosmetics: input.capabilities && Array.isArray(input.capabilities.cosmeticsUnlocked)
159
- ? input.capabilities.cosmeticsUnlocked.slice()
160
- : null,
161
- };
162
- }
163
-
164
- function call(fn, fallback) {
165
- try {
166
- return fn();
167
- } catch {
168
- return fallback;
169
- }
170
- }
171
-
172
- /** Write a model into DOM handles. Missing handles are skipped, never thrown on. */
173
- function renderHud(els, model) {
174
- const e = els || {};
175
- const set = (node, value) => {
176
- if (node && typeof value === 'string') node.textContent = value;
177
- };
178
- const width = model.percent === null ? '' : `${model.percent}%`;
179
- if (e.root) {
180
- e.root.setAttribute('data-known', model.known ? 'true' : 'false');
181
- e.root.setAttribute('data-held', model.held ? 'true' : 'false');
182
- }
183
- set(e.level, model.known ? `L${model.level}` : 'L—');
184
- set(e.tier, model.tier || '—');
185
- set(e.readout, model.readout);
186
- set(e.nextUnlock, model.nextUnlockText);
187
- set(e.unlockNote, model.unlockNote);
188
- set(e.expression, model.expressionLabel);
189
- if (e.fill) {
190
- e.fill.style.width = width;
191
- if (e.fill.setAttribute) e.fill.setAttribute('data-held', model.held ? 'true' : 'false');
192
- }
193
- if (e.bar) {
194
- // The bar is decorative: its text twin is the readout, so it is hidden from
195
- // assistive tech rather than announced twice with different words.
196
- e.bar.setAttribute('aria-hidden', 'true');
197
- }
198
- if (e.heldBadge) {
199
- e.heldBadge.textContent = model.heldNote;
200
- e.heldBadge.hidden = !model.held;
201
- }
202
- return model;
203
- }
204
-
205
- const API = Object.freeze({ hudModel, renderHud, unlockText });
206
-
207
- if (typeof module !== 'undefined' && module.exports) module.exports = API;
208
- else if (typeof globalThis !== 'undefined') globalThis.AegisAvatarHud = API;
3
+ "use strict";const pkg="undefined"!=typeof window&&window.AegisAvatarParts?{parts:window.AegisAvatarParts,level:window.AegisAvatarLevel||null}:"undefined"!=typeof module&&module.exports?{parts:require("./parts.js"),level:require("../../lib/avatar/level.js")}:{parts:null,level:null};if(!pkg.parts)throw new Error("avatar/hud.js: avatar/parts.js must be loaded first");function num(e,l){return"number"==typeof e&&Number.isFinite(e)?e:l}function unlockText(e){return e.unlocks.map((e=>e.paid?`${e.label} · pack`:e.label)).join(", ")}function hudModel(e={}){const l=e.persona&&"object"==typeof e.persona?e.persona:pkg.parts.defaultPersona(),t=l.identity&&l.identity.name||"Aegis",n=e.projection&&"object"==typeof e.projection?e.projection:null,o=n?num(n.level,null):null,r=null!==o,u=String(e.expressionLabel||e.expression||"neutral"),s=`expression: ${u}`;if(!r){const l=String(e.reason||"main has not published a level yet");return{known:!1,name:t,level:null,tier:null,xpIntoLevel:null,xpForNext:null,percent:null,held:!1,heldNote:"",nextUnlock:null,nextUnlockText:"",unlockNote:"",expression:e.expression||"neutral",expressionLabel:u,readout:`${t} · level unknown — ${l} · ${s}`,ariaLive:"polite"}}const i=!0===n.held,a=num(n.settledLevel,o),d=n.tier||call((()=>pkg.level.tierFor(o).name),null)||null,p=num(n.xpIntoLevel,null),c=num(n.xpForNext,null),h=Math.round(100*Math.min(1,Math.max(0,num(n.progress,0)))),x=i?a:o;let v=null;try{v=pkg.level?pkg.level.nextUnlock(x):null}catch{v=null}const f=v?`next at level ${v.level}: ${unlockText(v)}`:"every unlock is yours",k=[];return k.push(`${t} · level ${o}`),d&&k.push(d),i&&k.push("level held · reshuffling"),i||null===c||null===p||k.push(`${p} / ${c} XP to level ${o+1}`),k.push(f),k.push(s),{known:!0,name:t,level:o,tier:d,xpIntoLevel:p,xpForNext:c,percent:h,held:i,heldNote:i?"level held · reshuffling":"",nextUnlock:v,nextUnlockText:f,unlockNote:i?`held — applies after the ledger settles (level ${a})`:"",expression:e.expression||"neutral",expressionLabel:u,readout:k.join(" · "),ariaLive:"polite",cosmetics:e.capabilities&&Array.isArray(e.capabilities.cosmeticsUnlocked)?e.capabilities.cosmeticsUnlocked.slice():null}}function call(e,l){try{return e()}catch{return l}}function renderHud(e,l){const t=e||{},n=(e,l)=>{e&&"string"==typeof l&&(e.textContent=l)},o=null===l.percent?"":`${l.percent}%`;return t.root&&(t.root.setAttribute("data-known",l.known?"true":"false"),t.root.setAttribute("data-held",l.held?"true":"false")),n(t.level,l.known?`L${l.level}`:"L—"),n(t.tier,l.tier||"—"),n(t.readout,l.readout),n(t.nextUnlock,l.nextUnlockText),n(t.unlockNote,l.unlockNote),n(t.expression,l.expressionLabel),t.fill&&(t.fill.style.width=o,t.fill.setAttribute&&t.fill.setAttribute("data-held",l.held?"true":"false")),t.bar&&t.bar.setAttribute("aria-hidden","true"),t.heldBadge&&(t.heldBadge.textContent=l.heldNote,t.heldBadge.hidden=!l.held),l}const API=Object.freeze({hudModel:hudModel,renderHud:renderHud,unlockText:unlockText});"undefined"!=typeof module&&module.exports?module.exports=API:"undefined"!=typeof globalThis&&(globalThis.AegisAvatarHud=API);
@@ -1,215 +1,3 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
2
  // Copyright (C) 2026 Niklas Borneklint — AEGIS Code (aegiscode) / Aegiscloud.
3
- // AEGIS Code (aegiscode) — source: https://github.com/aegisinfo/aegiscode-plugin
4
- // Conveying a modified copy, or running one as a network service, owes the
5
- // corresponding source under this licence (§5/§13) — see LICENSING.md.
6
- 'use strict';
7
-
8
- /**
9
- * machine.js — the avatar's face, driven by the engine's real signals.
10
- *
11
- * The state machine itself is NOT re-implemented here. `lib/avatar/events.js`
12
- * is a pure module with no timers and no DOM, and index.html loads that same
13
- * file into the renderer (its UMD tail publishes `AegisAvatarEvents`), so the
14
- * face follows the *exact* table the engine's events are described by — not a
15
- * copy of it that can drift. What this file adds is the only thing the pure
16
- * module deliberately refuses to know: which real renderer event in this app
17
- * means which signal.
18
- *
19
- * The mapping is the interesting part, and it is one table, testable in
20
- * isolation:
21
- *
22
- * send / setBusy(true) → turn.start
23
- * a streamed delta → turn.stream
24
- * setBusy(false) → turn.end {green}
25
- * a tool frame → tool.read | tool.write | tool.run (by NAME)
26
- * the approval card → approval.card / approval.decided
27
- * queue progress → queue.progress
28
- * connection state → sync.error / sync.ok
29
- * typing in the composer → poke
30
- *
31
- * `signalForTool` is deliberately conservative: a tool this table has never
32
- * heard of (a new tool, a commissioned pack, an MCP server's verb) reads as
33
- * `tool.run` — "the agent is doing something" — rather than being mapped to
34
- * `reading`, which would understate what is happening on the user's machine.
35
- * Understating activity on the face of the thing doing it is the wrong way to
36
- * be wrong.
37
- *
38
- * Nothing here throws on an unknown signal: `events.js` made unknown signals
39
- * no-ops precisely so that tomorrow's feature cannot crash the avatar, and the
40
- * wrapper below preserves that.
41
- */
42
-
43
- 'use strict';
44
-
45
- const pkg = typeof window !== 'undefined' && window.AegisAvatarEvents
46
- ? { events: window.AegisAvatarEvents, parts: window.AegisAvatarParts || null }
47
- : typeof module !== 'undefined' && module.exports
48
- ? { events: require('../../lib/avatar/events.js'), parts: require('./parts.js') }
49
- : { events: null, parts: null };
50
-
51
- if (!pkg.events) throw new Error('avatar/machine.js: lib/avatar/events.js must be loaded first');
52
-
53
- /** Tool names → the signal the face shows. Order matters: first match wins. */
54
- const TOOL_SIGNALS = Object.freeze([
55
- Object.freeze({
56
- signal: 'tool.write',
57
- re: /^(write|edit|apply|patch|create|mkdir|append|save|delete|remove|move|rename|memorysave|memory_save)/i,
58
- }),
59
- Object.freeze({
60
- signal: 'tool.read',
61
- re: /^(read|open|list|ls|glob|grep|search|find|cat|stat|memorysearch|memory_search|memorylist|recall)/i,
62
- }),
63
- Object.freeze({
64
- signal: 'tool.run',
65
- re: /^(run|shell|bash|exec|spawn|test|build|npm|node|python|fetch|http|curl|websearch|browser)/i,
66
- }),
67
- ]);
68
-
69
- /** The tool name a frame is about, whichever shape the frame arrived in. */
70
- function toolName(tool) {
71
- if (!tool) return '';
72
- if (typeof tool === 'string') return tool;
73
- return String(tool.name || tool.tool || tool.id || '');
74
- }
75
-
76
- /**
77
- * Which signal a tool call is worth. Unknown verbs are `tool.run` — see header.
78
- * A read frame is the ONLY thing that may say "reading".
79
- */
80
- function signalForTool(tool) {
81
- const name = toolName(tool);
82
- for (const row of TOOL_SIGNALS) if (row.re.test(name)) return row.signal;
83
- return 'tool.run';
84
- }
85
-
86
- /**
87
- * Wrap the shared machine with the app's vocabulary.
88
- *
89
- * @param {object} [opts]
90
- * @param {object} [opts.machine] an `events.createMachine()` instance (tests inject one)
91
- * @param {number} [opts.idleTimeoutMs] silence before `dozing`
92
- * @param {function} [opts.onChange] called with `{ state, expression, label, signal }`
93
- */
94
- function createAvatarSignals(opts = {}) {
95
- const machine = opts.machine || pkg.events.createMachine({
96
- state: opts.state,
97
- now: opts.now,
98
- idleTimeoutMs: opts.idleTimeoutMs,
99
- });
100
- const listeners = new Set();
101
- let lastSent = null;
102
-
103
- function labelFor(expression) {
104
- const table = pkg.parts && pkg.parts.EXPRESSIONS;
105
- return (table && table[expression] && table[expression].label) || expression;
106
- }
107
-
108
- function announce(signal) {
109
- const payload = {
110
- state: machine.state,
111
- expression: machine.expression,
112
- label: labelFor(machine.expression),
113
- signal: signal == null ? null : String(signal),
114
- };
115
- for (const fn of listeners) {
116
- try {
117
- fn(payload);
118
- } catch {
119
- // A listener that throws must not take the turn with it: app.js calls
120
- // this from the chat delta path.
121
- }
122
- }
123
- return payload;
124
- }
125
-
126
- function send(signal, meta) {
127
- lastSent = String(signal);
128
- machine.send(signal, meta);
129
- return announce(signal);
130
- }
131
-
132
- const api = {
133
- machine,
134
- get state() {
135
- return machine.state;
136
- },
137
- get expression() {
138
- return machine.expression;
139
- },
140
- get label() {
141
- return labelFor(machine.expression);
142
- },
143
- get lastSignal() {
144
- return lastSent;
145
- },
146
- signal: send,
147
- /** turn.start / turn.stream / turn.end — the chat path, in order. */
148
- turnStart(meta) {
149
- return send('turn.start', meta);
150
- },
151
- stream() {
152
- return send('turn.stream');
153
- },
154
- turnEnd(meta) {
155
- return send('turn.end', meta);
156
- },
157
- /** A tool frame: the signal is picked from the tool's name. */
158
- tool(tool) {
159
- return send(signalForTool(tool), { tool: toolName(tool) });
160
- },
161
- approvalCard() {
162
- return send('approval.card');
163
- },
164
- approvalDecided() {
165
- return send('approval.decided');
166
- },
167
- /** Queue progress frames; the machine treats them as activity. */
168
- queue() {
169
- return send('queue.progress');
170
- },
171
- syncOk() {
172
- return send('sync.ok');
173
- },
174
- syncError(meta) {
175
- return send('sync.error', meta);
176
- },
177
- poke() {
178
- return send('poke');
179
- },
180
- celebrateDone() {
181
- return send('celebrate.done');
182
- },
183
- reset() {
184
- return send('reset');
185
- },
186
- /** The caller owns the clock — see events.js's "NO TIMERS INSIDE". */
187
- tick(now) {
188
- const out = machine.tick(now);
189
- if (out.changed) announce('idle.timeout');
190
- return out;
191
- },
192
- on(fn) {
193
- listeners.add(fn);
194
- return () => listeners.delete(fn);
195
- },
196
- off(fn) {
197
- return listeners.delete(fn);
198
- },
199
- };
200
- return api;
201
- }
202
-
203
- const API = Object.freeze({
204
- createAvatarSignals,
205
- signalForTool,
206
- toolName,
207
- TOOL_SIGNALS,
208
- STATES: pkg.events.STATES,
209
- SIGNALS: pkg.events.SIGNALS,
210
- EXPRESSIONS: pkg.events.EXPRESSIONS,
211
- expressionFor: pkg.events.expressionFor,
212
- });
213
-
214
- if (typeof module !== 'undefined' && module.exports) module.exports = API;
215
- else if (typeof globalThis !== 'undefined') globalThis.AegisAvatarMachine = API;
3
+ "use strict";const pkg="undefined"!=typeof window&&window.AegisAvatarEvents?{events:window.AegisAvatarEvents,parts:window.AegisAvatarParts||null}:"undefined"!=typeof module&&module.exports?{events:require("../../lib/avatar/events.js"),parts:require("./parts.js")}:{events:null,parts:null};if(!pkg.events)throw new Error("avatar/machine.js: lib/avatar/events.js must be loaded first");const TOOL_SIGNALS=Object.freeze([Object.freeze({signal:"tool.write",re:/^(write|edit|apply|patch|create|mkdir|append|save|delete|remove|move|rename|memorysave|memory_save)/i}),Object.freeze({signal:"tool.read",re:/^(read|open|list|ls|glob|grep|search|find|cat|stat|memorysearch|memory_search|memorylist|recall)/i}),Object.freeze({signal:"tool.run",re:/^(run|shell|bash|exec|spawn|test|build|npm|node|python|fetch|http|curl|websearch|browser)/i})]);function toolName(e){return e?"string"==typeof e?e:String(e.name||e.tool||e.id||""):""}function signalForTool(e){const t=toolName(e);for(const e of TOOL_SIGNALS)if(e.re.test(t))return e.signal;return"tool.run"}function createAvatarSignals(e={}){const t=e.machine||pkg.events.createMachine({state:e.state,now:e.now,idleTimeoutMs:e.idleTimeoutMs}),r=new Set;let n=null;function o(e){const t=pkg.parts&&pkg.parts.EXPRESSIONS;return t&&t[e]&&t[e].label||e}function s(e){const n={state:t.state,expression:t.expression,label:o(t.expression),signal:null==e?null:String(e)};for(const e of r)try{e(n)}catch{}return n}function a(e,r){return n=String(e),t.send(e,r),s(e)}return{machine:t,get state(){return t.state},get expression(){return t.expression},get label(){return o(t.expression)},get lastSignal(){return n},signal:a,turnStart:e=>a("turn.start",e),stream:()=>a("turn.stream"),turnEnd:e=>a("turn.end",e),tool:e=>a(signalForTool(e),{tool:toolName(e)}),approvalCard:()=>a("approval.card"),approvalDecided:()=>a("approval.decided"),queue:()=>a("queue.progress"),syncOk:()=>a("sync.ok"),syncError:e=>a("sync.error",e),poke:()=>a("poke"),celebrateDone:()=>a("celebrate.done"),reset:()=>a("reset"),tick(e){const r=t.tick(e);return r.changed&&s("idle.timeout"),r},on:e=>(r.add(e),()=>r.delete(e)),off:e=>r.delete(e)}}const API=Object.freeze({createAvatarSignals:createAvatarSignals,signalForTool:signalForTool,toolName:toolName,TOOL_SIGNALS:TOOL_SIGNALS,STATES:pkg.events.STATES,SIGNALS:pkg.events.SIGNALS,EXPRESSIONS:pkg.events.EXPRESSIONS,expressionFor:pkg.events.expressionFor});"undefined"!=typeof module&&module.exports?module.exports=API:"undefined"!=typeof globalThis&&(globalThis.AegisAvatarMachine=API);