aiden-runtime 4.8.1 → 4.9.1
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/README.md +88 -1
- package/dist/cli/v4/aidenCLI.js +37 -6
- package/dist/cli/v4/chatSession.js +53 -13
- package/dist/cli/v4/commands/daemon.js +53 -3
- package/dist/cli/v4/commands/daemonDoctor.js +212 -0
- package/dist/cli/v4/commands/daemonStatus.js +45 -26
- package/dist/cli/v4/commands/help.js +5 -0
- package/dist/cli/v4/commands/hooks.js +466 -0
- package/dist/cli/v4/commands/hooksSlash.js +33 -0
- package/dist/cli/v4/commands/index.js +13 -1
- package/dist/cli/v4/commands/mcp.js +89 -1
- package/dist/cli/v4/commands/mcpClientInstall.js +359 -0
- package/dist/cli/v4/commands/memory.js +707 -0
- package/dist/cli/v4/commands/memorySlash.js +38 -0
- package/dist/cli/v4/commands/recovery.js +1 -1
- package/dist/cli/v4/commands/skin.js +7 -0
- package/dist/cli/v4/commands/theme.js +217 -0
- package/dist/cli/v4/commands/trigger.js +1 -1
- package/dist/cli/v4/design/tokens.js +52 -4
- package/dist/cli/v4/display.js +39 -26
- package/dist/cli/v4/replyRenderer.js +6 -5
- package/dist/cli/v4/skinEngine.js +67 -0
- package/dist/cli/v4/ui/progressBar.js +179 -0
- package/dist/cli/v4/util/closestAction.js +48 -0
- package/dist/core/v4/aidenAgent.js +45 -2
- package/dist/core/v4/daemon/api/runs.js +131 -0
- package/dist/core/v4/daemon/bootstrap.js +368 -13
- package/dist/core/v4/daemon/db/migrations.js +169 -0
- package/dist/core/v4/daemon/idempotency/runIdempotencyStore.js +128 -0
- package/dist/core/v4/daemon/incarnationStore.js +47 -0
- package/dist/core/v4/daemon/runs/attemptStore.js +67 -0
- package/dist/core/v4/daemon/runs/reclaim.js +88 -0
- package/dist/core/v4/daemon/runs/retryPolicy.js +73 -0
- package/dist/core/v4/daemon/runs/runWithRetry.js +80 -0
- package/dist/core/v4/daemon/runs/stuckAttemptWatchdog.js +72 -0
- package/dist/core/v4/daemon/spans/spanHelpers.js +272 -0
- package/dist/core/v4/daemon/spans/spanStore.js +113 -0
- package/dist/core/v4/daemon/triggerBus.js +50 -19
- package/dist/core/v4/hooks/auditQuery.js +67 -0
- package/dist/core/v4/hooks/dispatcher.js +286 -0
- package/dist/core/v4/hooks/index.js +46 -0
- package/dist/core/v4/hooks/lifecycle.js +27 -0
- package/dist/core/v4/hooks/manifest.js +142 -0
- package/dist/core/v4/hooks/registry.js +149 -0
- package/dist/core/v4/hooks/runtime/subprocessRunner.js +188 -0
- package/dist/core/v4/hooks/toolHookGate.js +76 -0
- package/dist/core/v4/hooks/trust.js +14 -0
- package/dist/core/v4/identity/contextManager.js +83 -0
- package/dist/core/v4/identity/daemonId.js +85 -0
- package/dist/core/v4/identity/enforcement.js +103 -0
- package/dist/core/v4/identity/executionContext.js +153 -0
- package/dist/core/v4/identity/hookExecution.js +62 -0
- package/dist/core/v4/identity/httpContext.js +68 -0
- package/dist/core/v4/identity/ids.js +185 -0
- package/dist/core/v4/identity/index.js +60 -0
- package/dist/core/v4/identity/subprocessContext.js +98 -0
- package/dist/core/v4/identity/traceparent.js +114 -0
- package/dist/core/v4/logger/index.js +3 -1
- package/dist/core/v4/logger/logger.js +28 -1
- package/dist/core/v4/logger/redact.js +149 -0
- package/dist/core/v4/logger/sinks/fileSink.js +13 -0
- package/dist/core/v4/logger/sinks/stdSink.js +19 -1
- package/dist/core/v4/mcp/install/backup.js +78 -0
- package/dist/core/v4/mcp/install/clientPaths.js +90 -0
- package/dist/core/v4/mcp/install/clients.js +203 -0
- package/dist/core/v4/mcp/install/healthCheck.js +83 -0
- package/dist/core/v4/mcp/install/jsoncMerge.js +174 -0
- package/dist/core/v4/mcp/install/profiles.js +109 -0
- package/dist/core/v4/mcp/install/wslDetect.js +62 -0
- package/dist/core/v4/memory/namespaceRegistry.js +117 -0
- package/dist/core/v4/memory/projectRoot.js +76 -0
- package/dist/core/v4/memory/reviewer/index.js +162 -0
- package/dist/core/v4/memory/reviewer/pendingStore.js +136 -0
- package/dist/core/v4/memory/reviewer/prompt.js +105 -0
- package/dist/core/v4/memory/reviewer/skipRules.js +92 -0
- package/dist/core/v4/memoryManager.js +57 -10
- package/dist/core/v4/paths.js +2 -0
- package/dist/core/v4/subagent/spawnSubAgent.js +20 -7
- package/dist/core/v4/theme/bundledThemes.js +106 -0
- package/dist/core/v4/theme/themeLoader.js +160 -0
- package/dist/core/v4/theme/themeRegistry.js +97 -0
- package/dist/core/v4/theme/themeWatcher.js +95 -0
- package/dist/core/v4/toolRegistry.js +71 -8
- package/dist/core/v4/update/depWarningFilter.js +76 -0
- package/dist/core/v4/update/executeInstall.js +41 -35
- package/dist/core/v4/update/platformInstructions.js +128 -0
- package/dist/moat/approvalEngine.js +4 -0
- package/dist/moat/memoryGuard.js +8 -1
- package/dist/providers/v4/anthropicAdapter.js +10 -4
- package/dist/tools/v4/backends/local.js +19 -2
- package/dist/tools/v4/sessions/recallSession.js +6 -1
- package/package.json +3 -1
- package/plugins/aiden-plugin-chatgpt-plus/index.js +10 -1
- package/themes/default.yaml +52 -0
- package/themes/dracula.yaml +32 -0
- package/themes/light.yaml +32 -0
- package/themes/monochrome.yaml +31 -0
- package/themes/tokyo-night.yaml +32 -0
- package/dist/core/pluginSystem.js +0 -121
- package/dist/tools/v4/ui/_uiSmokeTool.js +0 -60
|
@@ -86,7 +86,10 @@ exports.recallSessionTool = {
|
|
|
86
86
|
error: 'recall_session requires resolved aiden paths',
|
|
87
87
|
};
|
|
88
88
|
}
|
|
89
|
-
|
|
89
|
+
// v4.9.0 Slice 9 — paths hygiene: use centralised distillationsDir
|
|
90
|
+
// when present (added in Slice 9); fall back to the legacy ad-hoc
|
|
91
|
+
// reconstruction so externally-mocked `ctx.paths` objects keep working.
|
|
92
|
+
const dir = ctx.paths.distillationsDir ?? node_path_1.default.join(ctx.paths.root, 'distillations');
|
|
90
93
|
// Read everything off disk first. Each failure (malformed JSON,
|
|
91
94
|
// EACCES on individual files) is skipped silently; the diagnostic
|
|
92
95
|
// for "files exist but couldn't be read" is the gap between
|
|
@@ -169,6 +172,8 @@ exports.recallSessionTool = {
|
|
|
169
172
|
// register recall_session with the slice3 SubsystemHealthRegistry
|
|
170
173
|
// pass this helper to the tracker so they get health snapshots without
|
|
171
174
|
// hard-coding the path in two places.
|
|
175
|
+
// v4.9.0 Slice 9 — kept for back-compat; mirrors `paths.distillationsDir`
|
|
176
|
+
// without requiring the full AidenPaths object.
|
|
172
177
|
function getDistillationsDir(rootDir) {
|
|
173
178
|
return node_path_1.default.join(rootDir, 'distillations');
|
|
174
179
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiden-runtime",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.9.1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"dist/",
|
|
44
44
|
"config/",
|
|
45
45
|
"skills/",
|
|
46
|
+
"themes/",
|
|
46
47
|
"plugins/aiden-plugin-cdp-browser/",
|
|
47
48
|
"plugins/aiden-plugin-claude-pro/",
|
|
48
49
|
"plugins/aiden-plugin-chatgpt-plus/",
|
|
@@ -256,6 +257,7 @@
|
|
|
256
257
|
"imap-simple": "^5.1.0",
|
|
257
258
|
"js-tiktoken": "^1.0.21",
|
|
258
259
|
"js-yaml": "^4.1.1",
|
|
260
|
+
"jsonc-parser": "^3.3.1",
|
|
259
261
|
"kleur": "^4.1.5",
|
|
260
262
|
"lru-cache": "^10.0.0",
|
|
261
263
|
"mailparser": "^3.9.8",
|
|
@@ -37,7 +37,16 @@ const CHATGPT_PLUS = {
|
|
|
37
37
|
displayName: 'ChatGPT Plus',
|
|
38
38
|
description:
|
|
39
39
|
'Sign in with your ChatGPT Plus subscription. Uses your existing ChatGPT login — no API key needed. Inference is routed through the Codex Responses API.',
|
|
40
|
-
defaultModels:
|
|
40
|
+
// v4.9.0 — `defaultModels[0]` is what `setupWizard.ts:810` picks
|
|
41
|
+
// as a new ChatGPT-Plus user's first model. The Codex OAuth backend
|
|
42
|
+
// rejects `gpt-5` outright with a 400 ("not supported when using
|
|
43
|
+
// Codex with a ChatGPT account") for new accounts; `gpt-5.5` is the
|
|
44
|
+
// first non-codex slug in the registry's modelIds and works
|
|
45
|
+
// reliably. `gpt-5` stays in the array so users who specifically
|
|
46
|
+
// want it can still see it in /model. `gpt-5-mini` was removed —
|
|
47
|
+
// it's a direct OpenAI API name and is NOT valid on the Codex OAuth
|
|
48
|
+
// endpoint (see providers/v4/registry.ts:117–119).
|
|
49
|
+
defaultModels: ['gpt-5.5', 'gpt-5'],
|
|
41
50
|
|
|
42
51
|
clientId: 'app_EMoamEEZ73f0CkXaXp7hrann',
|
|
43
52
|
issuer: 'https://auth.openai.com',
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Aiden Theme — Default
|
|
2
|
+
# This is the bundled default theme. To customise, copy this file to
|
|
3
|
+
# ~/.aiden/theme.yaml and edit any field. Aiden hot-reloads on save.
|
|
4
|
+
# Bad values warn + fall back per-field; the theme system never crashes
|
|
5
|
+
# Aiden on a typo. Slash commands: /theme reload, /theme reset, /theme edit.
|
|
6
|
+
|
|
7
|
+
name: "default"
|
|
8
|
+
description: "Aiden's signature brand-orange theme on a dark terminal."
|
|
9
|
+
|
|
10
|
+
# ── Colors — hex strings ───────────────────────────────────────────────
|
|
11
|
+
colors:
|
|
12
|
+
brand:
|
|
13
|
+
primary: "#FF6B35" # signature brand orange
|
|
14
|
+
muted: "#7a3119" # 30%-luma brand for borders + dim brand surfaces
|
|
15
|
+
content:
|
|
16
|
+
primary: "#e8ebf0" # brightest text — replies, headings on dark bg
|
|
17
|
+
secondary: "#b8a89a" # warm muted — gutter, secondary detail
|
|
18
|
+
tertiary: "#6a6a6a" # captions, deprecated rows, dim status
|
|
19
|
+
semantic:
|
|
20
|
+
success: "#7fc28b"
|
|
21
|
+
warn: "#e0a040"
|
|
22
|
+
error: "#e05a5a"
|
|
23
|
+
info: "#7da7c7"
|
|
24
|
+
metrics:
|
|
25
|
+
model: "#9cdcfe" # status bar — model name (cyan)
|
|
26
|
+
tokens: "#e0a040" # status bar — token ratio (amber)
|
|
27
|
+
turnCount: "#a48be0" # status bar — turn counter (purple)
|
|
28
|
+
timer: "#7fc28b" # status bar — per-turn elapsed (teal/green)
|
|
29
|
+
surface:
|
|
30
|
+
bg: "#0d0e10"
|
|
31
|
+
elevated: "#16181b"
|
|
32
|
+
border: "#2a2a2a"
|
|
33
|
+
divider: "#3a3a3a"
|
|
34
|
+
|
|
35
|
+
# ── Glyphs ─────────────────────────────────────────────────────────────
|
|
36
|
+
glyphs:
|
|
37
|
+
panel:
|
|
38
|
+
bar: "│" # left-edge bar on /help, approval, Aiden reply chrome
|
|
39
|
+
trail:
|
|
40
|
+
gutter: "┊" # tool-trail row gutter
|
|
41
|
+
status:
|
|
42
|
+
triangle: "▲" # user-prompt prefix + brand mark
|
|
43
|
+
dot: "●"
|
|
44
|
+
dotOpen: "○"
|
|
45
|
+
sep: "│" # status footer column separator
|
|
46
|
+
timer: "⌛"
|
|
47
|
+
bar:
|
|
48
|
+
filled: "●" # context-bar filled cell
|
|
49
|
+
empty: "○" # context-bar empty cell
|
|
50
|
+
shimmer:
|
|
51
|
+
block: "█" # activity-indicator sliding block
|
|
52
|
+
track: "─" # activity-indicator track
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Aiden Theme — Dracula
|
|
2
|
+
# Palette inspired by the public Dracula theme by Zeno Rocha
|
|
3
|
+
# (draculatheme.com). High-contrast dark with vivid accents, widely
|
|
4
|
+
# re-implemented across editors and terminals. Hex values are the
|
|
5
|
+
# public palette. Glyphs unchanged from default.
|
|
6
|
+
|
|
7
|
+
name: "dracula"
|
|
8
|
+
description: "Inspired by Dracula (draculatheme.com). High-contrast dark with vivid accents."
|
|
9
|
+
|
|
10
|
+
colors:
|
|
11
|
+
brand:
|
|
12
|
+
primary: "#FF79C6"
|
|
13
|
+
muted: "#BD7AA3"
|
|
14
|
+
content:
|
|
15
|
+
primary: "#F8F8F2"
|
|
16
|
+
secondary: "#BFBFBF"
|
|
17
|
+
tertiary: "#6272A4"
|
|
18
|
+
semantic:
|
|
19
|
+
success: "#50FA7B"
|
|
20
|
+
warn: "#F1FA8C"
|
|
21
|
+
error: "#FF5555"
|
|
22
|
+
info: "#8BE9FD"
|
|
23
|
+
metrics:
|
|
24
|
+
model: "#8BE9FD"
|
|
25
|
+
tokens: "#F1FA8C"
|
|
26
|
+
timer: "#8BE9FD"
|
|
27
|
+
turnCount: "#BD93F9"
|
|
28
|
+
surface:
|
|
29
|
+
bg: "#282A36"
|
|
30
|
+
elevated: "#21222C"
|
|
31
|
+
border: "#44475A"
|
|
32
|
+
divider: "#1E1F29"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Aiden Theme — Light
|
|
2
|
+
# Dark text on light terminal background. Brand orange retained as the
|
|
3
|
+
# single warm accent. For users on light-theme terminals (Apple Terminal
|
|
4
|
+
# default profile, Windows Terminal Light, light VS Code integrated, etc.).
|
|
5
|
+
# Glyphs unchanged from default.
|
|
6
|
+
|
|
7
|
+
name: "light"
|
|
8
|
+
description: "Light terminal. Dark text on light background. Brand orange accent."
|
|
9
|
+
|
|
10
|
+
colors:
|
|
11
|
+
brand:
|
|
12
|
+
primary: "#D9531E"
|
|
13
|
+
muted: "#A03D0E"
|
|
14
|
+
content:
|
|
15
|
+
primary: "#1A1A1A"
|
|
16
|
+
secondary: "#555555"
|
|
17
|
+
tertiary: "#888888"
|
|
18
|
+
semantic:
|
|
19
|
+
success: "#2E8B2E"
|
|
20
|
+
warn: "#B8860B"
|
|
21
|
+
error: "#C8202C"
|
|
22
|
+
info: "#1F5FA8"
|
|
23
|
+
metrics:
|
|
24
|
+
model: "#1F5FA8"
|
|
25
|
+
tokens: "#B8860B"
|
|
26
|
+
timer: "#1F5FA8"
|
|
27
|
+
turnCount: "#7B3FBF"
|
|
28
|
+
surface:
|
|
29
|
+
bg: "#F8F8F8"
|
|
30
|
+
elevated: "#EFEFEF"
|
|
31
|
+
border: "#D0D0D0"
|
|
32
|
+
divider: "#E5E5E5"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Aiden Theme — Monochrome
|
|
2
|
+
# Pure greyscale. Two semantic accents (error red + success green) are
|
|
3
|
+
# retained for readability of state signals. Everything else greyscale.
|
|
4
|
+
# Glyphs unchanged from default — themes change colors, not shapes.
|
|
5
|
+
|
|
6
|
+
name: "monochrome"
|
|
7
|
+
description: "Pure greyscale. Semantic accents retained for error/success readability."
|
|
8
|
+
|
|
9
|
+
colors:
|
|
10
|
+
brand:
|
|
11
|
+
primary: "#C8CCD4"
|
|
12
|
+
muted: "#888888"
|
|
13
|
+
content:
|
|
14
|
+
primary: "#C8CCD4"
|
|
15
|
+
secondary: "#888888"
|
|
16
|
+
tertiary: "#555555"
|
|
17
|
+
semantic:
|
|
18
|
+
success: "#7DC97D"
|
|
19
|
+
warn: "#999999"
|
|
20
|
+
error: "#D97777"
|
|
21
|
+
info: "#AAAAAA"
|
|
22
|
+
metrics:
|
|
23
|
+
model: "#AAAAAA"
|
|
24
|
+
tokens: "#AAAAAA"
|
|
25
|
+
timer: "#888888"
|
|
26
|
+
turnCount: "#BBBBBB"
|
|
27
|
+
surface:
|
|
28
|
+
bg: "#0A0A0A"
|
|
29
|
+
elevated: "#1A1A1A"
|
|
30
|
+
border: "#444444"
|
|
31
|
+
divider: "#3A3A3A"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Aiden Theme — Tokyo Night
|
|
2
|
+
# Palette inspired by the public Tokyo Night theme by Folke Lemaitre
|
|
3
|
+
# (folke/tokyonight.nvim). Cool nocturnal palette widely re-implemented
|
|
4
|
+
# across editors and terminals. Hex values are the public palette.
|
|
5
|
+
# Glyphs unchanged from default.
|
|
6
|
+
|
|
7
|
+
name: "tokyo-night"
|
|
8
|
+
description: "Inspired by Tokyo Night (folke/tokyonight.nvim). Cool nocturnal palette."
|
|
9
|
+
|
|
10
|
+
colors:
|
|
11
|
+
brand:
|
|
12
|
+
primary: "#7AA2F7"
|
|
13
|
+
muted: "#3D59A1"
|
|
14
|
+
content:
|
|
15
|
+
primary: "#C0CAF5"
|
|
16
|
+
secondary: "#9AA5CE"
|
|
17
|
+
tertiary: "#565F89"
|
|
18
|
+
semantic:
|
|
19
|
+
success: "#9ECE6A"
|
|
20
|
+
warn: "#E0AF68"
|
|
21
|
+
error: "#F7768E"
|
|
22
|
+
info: "#7DCFFF"
|
|
23
|
+
metrics:
|
|
24
|
+
model: "#7DCFFF"
|
|
25
|
+
tokens: "#E0AF68"
|
|
26
|
+
timer: "#7DCFFF"
|
|
27
|
+
turnCount: "#BB9AF7"
|
|
28
|
+
surface:
|
|
29
|
+
bg: "#1A1B26"
|
|
30
|
+
elevated: "#24283B"
|
|
31
|
+
border: "#3B4261"
|
|
32
|
+
divider: "#1F2335"
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// ============================================================
|
|
3
|
-
// DevOS — Autonomous AI Execution System
|
|
4
|
-
// Copyright (c) 2026 Shiva Deore. All rights reserved.
|
|
5
|
-
// ============================================================
|
|
6
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
-
};
|
|
9
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.pluginManager = void 0;
|
|
11
|
-
// core/pluginSystem.ts — Plugin system foundation.
|
|
12
|
-
// Allows community extensions without modifying core code.
|
|
13
|
-
// Scans workspace/plugins/*/plugin.json, loads entry files,
|
|
14
|
-
// and calls onLoad(ctx) with a sandboxed PluginContext.
|
|
15
|
-
const fs_1 = __importDefault(require("fs"));
|
|
16
|
-
const path_1 = __importDefault(require("path"));
|
|
17
|
-
const toolRegistry_1 = require("./toolRegistry");
|
|
18
|
-
const hooks_1 = require("./hooks");
|
|
19
|
-
const PLUGINS_DIR = path_1.default.join(process.cwd(), 'workspace', 'plugins');
|
|
20
|
-
// ── PluginManager ──────────────────────────────────────────────
|
|
21
|
-
class PluginManager {
|
|
22
|
-
constructor() {
|
|
23
|
-
this.loaded = [];
|
|
24
|
-
}
|
|
25
|
-
// ── Load all plugins from workspace/plugins/ ───────────────
|
|
26
|
-
async loadAll() {
|
|
27
|
-
if (!fs_1.default.existsSync(PLUGINS_DIR)) {
|
|
28
|
-
console.log('[Plugins] No plugins directory found — skipping');
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
const dirs = fs_1.default.readdirSync(PLUGINS_DIR, { withFileTypes: true })
|
|
32
|
-
.filter(d => d.isDirectory())
|
|
33
|
-
.map(d => path_1.default.join(PLUGINS_DIR, d.name));
|
|
34
|
-
for (const dir of dirs) {
|
|
35
|
-
try {
|
|
36
|
-
await this.loadPlugin(dir);
|
|
37
|
-
}
|
|
38
|
-
catch (e) {
|
|
39
|
-
console.error(`[Plugins] Failed to load plugin at ${path_1.default.basename(dir)}:`, e.message);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
console.log(`[Plugins] ${this.loaded.length} plugin(s) active`);
|
|
43
|
-
}
|
|
44
|
-
// ── Load a single plugin directory ────────────────────────
|
|
45
|
-
async loadPlugin(dir) {
|
|
46
|
-
const manifestPath = path_1.default.join(dir, 'plugin.json');
|
|
47
|
-
if (!fs_1.default.existsSync(manifestPath)) {
|
|
48
|
-
console.warn(`[Plugins] No plugin.json in ${path_1.default.basename(dir)} — skipping`);
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
let manifest;
|
|
52
|
-
try {
|
|
53
|
-
manifest = JSON.parse(fs_1.default.readFileSync(manifestPath, 'utf-8'));
|
|
54
|
-
}
|
|
55
|
-
catch (e) {
|
|
56
|
-
throw new Error(`Invalid plugin.json: ${e.message}`);
|
|
57
|
-
}
|
|
58
|
-
if (!manifest.name || !manifest.version || !manifest.entry) {
|
|
59
|
-
throw new Error('plugin.json missing required fields: name, version, entry');
|
|
60
|
-
}
|
|
61
|
-
// ── Security: entry must not escape plugin directory ───────
|
|
62
|
-
const entryPath = path_1.default.resolve(dir, manifest.entry);
|
|
63
|
-
const resolvedBase = path_1.default.resolve(dir);
|
|
64
|
-
if (!entryPath.startsWith(resolvedBase + path_1.default.sep) && entryPath !== resolvedBase) {
|
|
65
|
-
throw new Error(`Security: entry path escapes plugin directory: ${manifest.entry}`);
|
|
66
|
-
}
|
|
67
|
-
if (!fs_1.default.existsSync(entryPath)) {
|
|
68
|
-
throw new Error(`Entry file not found: ${manifest.entry}`);
|
|
69
|
-
}
|
|
70
|
-
// ── Load the plugin module ─────────────────────────────────
|
|
71
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
72
|
-
const mod = require(entryPath);
|
|
73
|
-
const plugin = mod.default ?? mod;
|
|
74
|
-
if (typeof plugin?.onLoad !== 'function') {
|
|
75
|
-
throw new Error(`Plugin "${manifest.name}" must export an object with an onLoad() function`);
|
|
76
|
-
}
|
|
77
|
-
// ── Build sandboxed context ────────────────────────────────
|
|
78
|
-
const ctx = {
|
|
79
|
-
registerTool: (def) => {
|
|
80
|
-
(0, toolRegistry_1.registerExternalTool)(def.name, def.execute, manifest.name);
|
|
81
|
-
},
|
|
82
|
-
registerHook: (event, handler) => {
|
|
83
|
-
(0, hooks_1.registerExternalHook)(event, handler, manifest.name);
|
|
84
|
-
},
|
|
85
|
-
log: (msg) => {
|
|
86
|
-
console.log(`[Plugin:${manifest.name}] ${msg}`);
|
|
87
|
-
},
|
|
88
|
-
};
|
|
89
|
-
await plugin.onLoad(ctx);
|
|
90
|
-
this.loaded.push({ manifest, dir, active: true, plugin });
|
|
91
|
-
console.log(`[Plugins] Loaded "${manifest.name}" v${manifest.version}${manifest.author ? ` by ${manifest.author}` : ''}`);
|
|
92
|
-
}
|
|
93
|
-
// ── List loaded plugins ────────────────────────────────────
|
|
94
|
-
list() {
|
|
95
|
-
return this.loaded.map(r => ({
|
|
96
|
-
name: r.manifest.name,
|
|
97
|
-
version: r.manifest.version,
|
|
98
|
-
description: r.manifest.description,
|
|
99
|
-
author: r.manifest.author,
|
|
100
|
-
active: r.active,
|
|
101
|
-
}));
|
|
102
|
-
}
|
|
103
|
-
// ── Unload all plugins ─────────────────────────────────────
|
|
104
|
-
async unloadAll() {
|
|
105
|
-
for (const record of this.loaded) {
|
|
106
|
-
try {
|
|
107
|
-
if (record.plugin?.onUnload) {
|
|
108
|
-
await record.plugin.onUnload();
|
|
109
|
-
}
|
|
110
|
-
record.active = false;
|
|
111
|
-
}
|
|
112
|
-
catch (e) {
|
|
113
|
-
console.error(`[Plugins] onUnload error for "${record.manifest.name}":`, e.message);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
console.log(`[Plugins] Unloaded ${this.loaded.length} plugin(s)`);
|
|
117
|
-
this.loaded = [];
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
// ── Singleton ──────────────────────────────────────────────────
|
|
121
|
-
exports.pluginManager = new PluginManager();
|
|
@@ -1,60 +0,0 @@
|
|
|
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
|
-
* tools/v4/ui/_uiSmokeTool.ts — v4.7 Slice 1 smoke harness.
|
|
10
|
-
*
|
|
11
|
-
* Internal tool used ONLY to verify the uiOnly dispatch seam from
|
|
12
|
-
* Slice 1 (ToolHandler.uiOnly + resolveUiOnly + onUiEvent +
|
|
13
|
-
* Display.renderUiEvent). NOT for end-user LLM workflows.
|
|
14
|
-
*
|
|
15
|
-
* Registered behind `AIDEN_UI_SMOKE=1` env flag in
|
|
16
|
-
* `tools/v4/index.ts::registerAllTools`. Will be deleted once
|
|
17
|
-
* Slice 2 lands the real ui_task_update / ui_task_done tools.
|
|
18
|
-
*
|
|
19
|
-
* When invoked, the agent's dispatch loop:
|
|
20
|
-
* - resolves uiOnly=true via the resolveUiOnly closure
|
|
21
|
-
* - fires runOptions.onUiEvent('_ui_smoke', args)
|
|
22
|
-
* - SKIPS execute() entirely
|
|
23
|
-
* - SKIPS turnToolMessages push + toolCallCount increment + verifier
|
|
24
|
-
*
|
|
25
|
-
* The handler's `execute` MUST never be called by the dispatch path
|
|
26
|
-
* when uiOnly is honoured. Throws if reached — that throw is a
|
|
27
|
-
* regression alarm.
|
|
28
|
-
*/
|
|
29
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
-
exports.uiSmokeTool = void 0;
|
|
31
|
-
exports.uiSmokeTool = {
|
|
32
|
-
schema: {
|
|
33
|
-
name: '_ui_smoke',
|
|
34
|
-
description: 'Internal smoke-test tool for the v4.7 uiOnly dispatch path. ' +
|
|
35
|
-
'Renders a single debug line through the UI event seam. ' +
|
|
36
|
-
'Does NOT round-trip back to the model. Only available when ' +
|
|
37
|
-
'AIDEN_UI_SMOKE=1.',
|
|
38
|
-
inputSchema: {
|
|
39
|
-
type: 'object',
|
|
40
|
-
properties: {
|
|
41
|
-
message: {
|
|
42
|
-
type: 'string',
|
|
43
|
-
description: 'Free-text payload echoed in the rendered debug line.',
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
required: ['message'],
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
category: 'read',
|
|
50
|
-
mutates: false,
|
|
51
|
-
uiOnly: true,
|
|
52
|
-
execute() {
|
|
53
|
-
// Defensive — if `resolveUiOnly` is wired correctly, the
|
|
54
|
-
// dispatch loop short-circuits BEFORE reaching this body. A
|
|
55
|
-
// call here means the resolver returned false/undefined and
|
|
56
|
-
// the seam regressed. Throwing surfaces the regression at
|
|
57
|
-
// smoke time instead of silently behaving like a regular tool.
|
|
58
|
-
throw new Error('_ui_smoke.execute() should never be called — uiOnly dispatch path regressed');
|
|
59
|
-
},
|
|
60
|
-
};
|