@aria_asi/cli 0.2.24 → 0.2.26
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/dist/aria-connector/src/connectors/claude-code.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/claude-code.js +37 -3
- package/dist/aria-connector/src/connectors/claude-code.js.map +1 -1
- package/dist/aria-connector/src/connectors/opencode.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/opencode.js +125 -10
- package/dist/aria-connector/src/connectors/opencode.js.map +1 -1
- package/dist/sdk/BUNDLED.json +1 -1
- package/dist/sdk/index.d.ts +34 -0
- package/dist/sdk/index.js +205 -0
- package/dist/sdk/index.js.map +1 -1
- package/hooks/aria-agent-handoff.mjs +62 -1
- package/hooks/aria-architect-fallback.mjs +198 -0
- package/hooks/aria-discovery-record.mjs +101 -0
- package/hooks/aria-outcome-record.mjs +80 -0
- package/hooks/aria-pre-tool-gate.mjs +158 -0
- package/hooks/aria-stop-gate.mjs +103 -1
- package/opencode-plugins/harness-context/index.js +60 -0
- package/opencode-plugins/harness-context/inject-context.mjs +120 -0
- package/opencode-plugins/harness-context/package.json +9 -0
- package/opencode-plugins/harness-role/index.js +77 -0
- package/opencode-plugins/harness-role/package.json +9 -0
- package/package.json +3 -2
- package/src/connectors/claude-code.ts +45 -10
- package/src/connectors/opencode.ts +156 -19
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aria Harness Role Plugin for OpenCode.
|
|
3
|
+
*
|
|
4
|
+
* Resolves the active role profile on session start and injects lane-specific
|
|
5
|
+
* governance rules (intro, continuity, post-action). Default profile is
|
|
6
|
+
* opencode_deepseek_engineer; override with OPENCODE_ARIA_ROLE_PROFILE env.
|
|
7
|
+
*
|
|
8
|
+
* Distribution: installed by `aria connect` (via connectors/opencode.ts) into
|
|
9
|
+
* `~/.opencode/plugins/harness-role/`. The plugin's absolute install path is
|
|
10
|
+
* wired into ~/.opencode/config.json's `plugin` array.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const ROLE_PROFILES = [
|
|
14
|
+
{
|
|
15
|
+
id: 'opencode_deepseek_engineer',
|
|
16
|
+
label: 'DeepSeek Engineer',
|
|
17
|
+
authority: 'full_write',
|
|
18
|
+
destructiveAllowed: false,
|
|
19
|
+
contractRequired: true,
|
|
20
|
+
ruleIntro: 'You are an engineering execution lane. Prefer exact files, commands, state transitions, and verification over explanation.',
|
|
21
|
+
ruleContinuity: 'Continue the active plan. Update issue/task ledger after meaningful state changes. Keep exact files, commands, evidence, and blockers visible.',
|
|
22
|
+
rulePostAction: 'After work, write outcome, verification, deploy state, residual risk, and next action.',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 'opencode_code_reviewer',
|
|
26
|
+
label: 'Code Reviewer',
|
|
27
|
+
authority: 'read_only',
|
|
28
|
+
destructiveAllowed: false,
|
|
29
|
+
contractRequired: true,
|
|
30
|
+
ruleIntro: 'You are a quality gate, not a generic explainer. Prioritize contradictions, missing evidence, regressions, and unverifiable completion claims.',
|
|
31
|
+
ruleContinuity: 'If output is not proven, fail it cleanly and say what evidence or fix is missing.',
|
|
32
|
+
rulePostAction: 'After review, record findings, severity, and specific fix recommendations.',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 'opencode_infra_operator',
|
|
36
|
+
label: 'Infra Operator',
|
|
37
|
+
authority: 'destructive',
|
|
38
|
+
destructiveAllowed: true,
|
|
39
|
+
contractRequired: true,
|
|
40
|
+
ruleIntro: 'You are an infra/execution lane. Prefer exact commands, state transitions, and verification. Never report success from intent alone.',
|
|
41
|
+
ruleContinuity: 'Report only what was executed, observed, changed, or still blocked. Bind every action to a tracked issue.',
|
|
42
|
+
rulePostAction: 'Record deploy state, rollback plan, residual risk, and verification evidence.',
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
function resolveRole() {
|
|
47
|
+
const envRole = (process.env.OPENCODE_ARIA_ROLE_PROFILE || '').trim().toLowerCase();
|
|
48
|
+
if (envRole) {
|
|
49
|
+
const found = ROLE_PROFILES.find(p => p.id === envRole);
|
|
50
|
+
if (found) return found;
|
|
51
|
+
}
|
|
52
|
+
return ROLE_PROFILES.find(p => p.id === 'opencode_deepseek_engineer');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default async function HarnessRolePlugin(ctx) {
|
|
56
|
+
const role = resolveRole();
|
|
57
|
+
const systemBlock = [
|
|
58
|
+
`=== ARIA LANE: ${role.label} ===`,
|
|
59
|
+
`Role: ${role.id} | Authority: ${role.authority} | Contract Required: ${role.contractRequired}`,
|
|
60
|
+
'',
|
|
61
|
+
role.ruleIntro,
|
|
62
|
+
'',
|
|
63
|
+
role.ruleContinuity,
|
|
64
|
+
'',
|
|
65
|
+
role.rulePostAction,
|
|
66
|
+
].join('\n');
|
|
67
|
+
|
|
68
|
+
process.stderr.write(`[harness-role] Active role: ${role.id} (${role.label})\n`);
|
|
69
|
+
process.stderr.write(`[harness-role] Authority: ${role.authority} | Destructive: ${role.destructiveAllowed} | Contract: ${role.contractRequired}\n`);
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
ctx.system?.prepend?.(systemBlock);
|
|
73
|
+
} catch (_) {
|
|
74
|
+
// Silent — different OpenCode versions expose ctx differently.
|
|
75
|
+
}
|
|
76
|
+
return {};
|
|
77
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aria_asi/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.26",
|
|
4
4
|
"description": "Aria Smart CLI — the world's first harness-powered terminal companion",
|
|
5
5
|
"bin": {
|
|
6
6
|
"aria": "./bin/aria.js"
|
|
@@ -37,7 +37,8 @@
|
|
|
37
37
|
"bin",
|
|
38
38
|
"dist",
|
|
39
39
|
"src",
|
|
40
|
-
"hooks"
|
|
40
|
+
"hooks",
|
|
41
|
+
"opencode-plugins"
|
|
41
42
|
],
|
|
42
43
|
"engines": {
|
|
43
44
|
"node": ">=20.0.0"
|
|
@@ -36,6 +36,10 @@ const HOOK_FILES = [
|
|
|
36
36
|
// Pre-text gate — validates state-dependent claims in prose against
|
|
37
37
|
// probe evidence before emission. Closes "WHEN TO LOOK before speaking" gap.
|
|
38
38
|
'aria-pre-text-gate.mjs',
|
|
39
|
+
// Discovery-ledger write primitive (#83) — sub-agents pipe findings here;
|
|
40
|
+
// outcome-record fires on every state-mutating tool PostToolUse.
|
|
41
|
+
'aria-discovery-record.mjs',
|
|
42
|
+
'aria-outcome-record.mjs',
|
|
39
43
|
];
|
|
40
44
|
// Compiled location: <pkg>/dist/aria-connector/src/connectors/claude-code.js
|
|
41
45
|
// (tsc preserves the src/ rooted layout under outDir). From this file:
|
|
@@ -162,15 +166,28 @@ const HOOKS_BLOCK = {
|
|
|
162
166
|
}],
|
|
163
167
|
},
|
|
164
168
|
],
|
|
165
|
-
PostToolUse: [
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
169
|
+
PostToolUse: [
|
|
170
|
+
{
|
|
171
|
+
matcher: 'Agent',
|
|
172
|
+
hooks: [{
|
|
173
|
+
type: 'command',
|
|
174
|
+
command: 'node $HOME/.claude/hooks/aria-agent-ledger-merge.mjs',
|
|
175
|
+
timeout: 8,
|
|
176
|
+
statusMessage: 'Merging sub-agent ledger...',
|
|
177
|
+
}],
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
// Outcome-record: fires on every state-mutating tool to accumulate the
|
|
181
|
+
// outcome ledger (Sonnet H's #76 endpoint). Fire-and-forget — HTTP
|
|
182
|
+
// failures in the hook do not block the tool pipeline.
|
|
183
|
+
matcher: 'Bash|Edit|Write|NotebookEdit',
|
|
184
|
+
hooks: [{
|
|
185
|
+
type: 'command',
|
|
186
|
+
command: 'node $HOME/.claude/hooks/aria-outcome-record.mjs',
|
|
187
|
+
timeout: 3,
|
|
188
|
+
}],
|
|
189
|
+
},
|
|
190
|
+
],
|
|
174
191
|
Stop: [{
|
|
175
192
|
// Stop gate — text-decision boundary. Reflexive replies fail this
|
|
176
193
|
// gate the same way reflexive Bash does. Mirrors PreToolUse
|
|
@@ -307,9 +324,25 @@ function wireHooksBlock(settings: Record<string, unknown>, logs: string[]): void
|
|
|
307
324
|
if (!settings.$schema) {
|
|
308
325
|
settings.$schema = 'https://json.schemastore.org/claude-code-settings.json';
|
|
309
326
|
}
|
|
310
|
-
logs.push(`Wired hooks into settings.json (${mergedEvents} events: SessionStart, UserPromptSubmit, PreToolUse [cognition+memory-gate+Agent-handoff], PostToolUse [Agent-ledger-merge], Stop) — merge-safe, preserves third-party entries`);
|
|
327
|
+
logs.push(`Wired hooks into settings.json (${mergedEvents} events: SessionStart, UserPromptSubmit, PreToolUse [cognition+memory-gate+Agent-handoff], PostToolUse [Agent-ledger-merge + outcome-record], Stop) — merge-safe, preserves third-party entries`);
|
|
311
328
|
}
|
|
312
329
|
|
|
330
|
+
// Layer 2 (#84): hard prefix injected into every Agent dispatch so sub-agents
|
|
331
|
+
// know to load the harness packet before ANY tool call. This text appears in
|
|
332
|
+
// the system-prompt-prefix which Claude Code copies into spawned Agent contexts.
|
|
333
|
+
const ARIA_HARNESS_BINDING_PREFIX = `[ARIA_HARNESS_BINDING — MANDATORY FIRST ACTION]
|
|
334
|
+
Before any tool call, Read the harness packet at: $ARIA_HARNESS_PACKET_PATH
|
|
335
|
+
(path is also in your environment as ARIA_HARNESS_PACKET_PATH variable)
|
|
336
|
+
Cite it in your first cognition block — reference at least one axiom + one frame + one memory class from the packet.
|
|
337
|
+
Without packet-citation in your first cognition block, your output will be rejected by aria-pre-tool-gate.mjs in your sub-process.
|
|
338
|
+
[/ARIA_HARNESS_BINDING]
|
|
339
|
+
|
|
340
|
+
[ARIA_DISCOVERY_RECORDING — when you find a defect, doctrine violation, or notable observation during work]
|
|
341
|
+
Record findings to your session ledger via:
|
|
342
|
+
echo '{"text":"<finding>","kind":"defect|observation|principle","refs":["<file:line>"]}' | node $HOME/.claude/hooks/aria-discovery-record.mjs
|
|
343
|
+
This makes findings visible to the parent session's ledger-merge hook + the auto-fix spawner.
|
|
344
|
+
[/ARIA_DISCOVERY_RECORDING]`;
|
|
345
|
+
|
|
313
346
|
function buildAriaSystemBlock(config: AriaConfig): string {
|
|
314
347
|
const repoList = config.repositories.map((r) => `- ${r.name} (${r.path})`).join('\n');
|
|
315
348
|
const schemaText = Object.entries(config.schemaImages)
|
|
@@ -322,6 +355,8 @@ You are augmented with Aria's cognitive harness. This provides:
|
|
|
322
355
|
- Garden memory: persistent project memory across sessions
|
|
323
356
|
- 8-lens cognition: multi-perspective analysis for every decision
|
|
324
357
|
|
|
358
|
+
${ARIA_HARNESS_BINDING_PREFIX}
|
|
359
|
+
|
|
325
360
|
[SELF-GATE PROTOCOL]
|
|
326
361
|
Before emitting any claim, verify against these hard constraints:
|
|
327
362
|
1. Truth over deception — always.
|
|
@@ -1,8 +1,66 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
existsSync,
|
|
3
|
+
mkdirSync,
|
|
4
|
+
readFileSync,
|
|
5
|
+
writeFileSync,
|
|
6
|
+
copyFileSync,
|
|
7
|
+
readdirSync,
|
|
8
|
+
statSync,
|
|
9
|
+
chmodSync,
|
|
10
|
+
unlinkSync,
|
|
11
|
+
} from 'fs';
|
|
2
12
|
import { homedir } from 'os';
|
|
3
13
|
import * as path from 'path';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
4
15
|
import type { AriaConfig } from '../config.js';
|
|
5
16
|
|
|
17
|
+
// ── Bundled OpenCode plugins ────────────────────────────────────────────────
|
|
18
|
+
//
|
|
19
|
+
// Two plugins ship with the connector:
|
|
20
|
+
// - harness-context: spawns the bundled inject-context.mjs on session start
|
|
21
|
+
// and prepends the resolved harness packet to OpenCode's
|
|
22
|
+
// system prompt. Routes through the canonical SDK at
|
|
23
|
+
// ~/.claude/aria-sdk/.
|
|
24
|
+
// - harness-role: injects the active role profile (default
|
|
25
|
+
// opencode_deepseek_engineer) — intro / continuity /
|
|
26
|
+
// post-action governance rules.
|
|
27
|
+
//
|
|
28
|
+
// Both live at <pkg>/opencode-plugins/<name>/. connectOpenCode copies them
|
|
29
|
+
// into ~/.opencode/plugins/<name>/ and wires the absolute paths into
|
|
30
|
+
// ~/.opencode/config.json's `plugin` (singular, OpenCode v2 schema) array.
|
|
31
|
+
//
|
|
32
|
+
// Compiled location of THIS file (claude-code path applies the same way):
|
|
33
|
+
// <pkg>/dist/aria-connector/src/connectors/opencode.js
|
|
34
|
+
// Plugins ship at <pkg>/opencode-plugins/ → 4 dirs up + 'opencode-plugins'.
|
|
35
|
+
|
|
36
|
+
const PLUGIN_NAMES = ['harness-context', 'harness-role'] as const;
|
|
37
|
+
|
|
38
|
+
function packageOpenCodePluginsDir(): string {
|
|
39
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
40
|
+
return path.resolve(here, '..', '..', '..', '..', 'opencode-plugins');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function copyPluginDir(srcDir: string, dstDir: string, logs: string[]): void {
|
|
44
|
+
if (!existsSync(dstDir)) {
|
|
45
|
+
mkdirSync(dstDir, { recursive: true, mode: 0o755 });
|
|
46
|
+
}
|
|
47
|
+
for (const name of readdirSync(srcDir)) {
|
|
48
|
+
const src = path.join(srcDir, name);
|
|
49
|
+
const stat = statSync(src);
|
|
50
|
+
if (!stat.isFile()) continue;
|
|
51
|
+
const dst = path.join(dstDir, name);
|
|
52
|
+
copyFileSync(src, dst);
|
|
53
|
+
if (name.endsWith('.mjs') || name.endsWith('.js')) {
|
|
54
|
+
try {
|
|
55
|
+
chmodSync(dst, 0o755);
|
|
56
|
+
} catch {
|
|
57
|
+
// chmod failure isn't fatal on filesystems that ignore mode bits.
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
logs.push(`Installed plugin → ${dstDir}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
6
64
|
export async function connectOpenCode(config: AriaConfig): Promise<string[]> {
|
|
7
65
|
const logs: string[] = [];
|
|
8
66
|
const opencodeDir = path.join(homedir(), '.opencode');
|
|
@@ -12,29 +70,91 @@ export async function connectOpenCode(config: AriaConfig): Promise<string[]> {
|
|
|
12
70
|
return logs;
|
|
13
71
|
}
|
|
14
72
|
|
|
73
|
+
// ── Install bundled plugins into ~/.opencode/plugins/<name>/ ──────────────
|
|
74
|
+
const pluginsRoot = path.join(opencodeDir, 'plugins');
|
|
75
|
+
if (!existsSync(pluginsRoot)) {
|
|
76
|
+
mkdirSync(pluginsRoot, { recursive: true, mode: 0o755 });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Remove legacy single-file plugin shadows (~/.opencode/plugins/<name>.js).
|
|
80
|
+
// OpenCode v2 auto-discovers BOTH loose .js files and dir-shaped plugins;
|
|
81
|
+
// when both exist with the same name, behavior is undefined and on at least
|
|
82
|
+
// one machine the loose .js (carrying old hardcoded paths to
|
|
83
|
+
// ~/rei-ai-brain/harness/inject-context.mjs) was winning over the dir
|
|
84
|
+
// install. Idempotent cleanup so re-running connect heals these.
|
|
85
|
+
for (const pluginName of PLUGIN_NAMES) {
|
|
86
|
+
const shadowPath = path.join(pluginsRoot, `${pluginName}.js`);
|
|
87
|
+
if (existsSync(shadowPath)) {
|
|
88
|
+
try {
|
|
89
|
+
unlinkSync(shadowPath);
|
|
90
|
+
logs.push(`Removed legacy single-file plugin shadow: ${shadowPath}`);
|
|
91
|
+
} catch {
|
|
92
|
+
// Permission or fs failure isn't fatal — the install proceeds.
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const bundledDir = packageOpenCodePluginsDir();
|
|
98
|
+
const installedPaths: string[] = [];
|
|
99
|
+
for (const pluginName of PLUGIN_NAMES) {
|
|
100
|
+
const srcDir = path.join(bundledDir, pluginName);
|
|
101
|
+
if (!existsSync(srcDir)) {
|
|
102
|
+
logs.push(`⚠ Bundled plugin missing: ${srcDir} — connector tarball may be incomplete`);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
const dstDir = path.join(pluginsRoot, pluginName);
|
|
106
|
+
copyPluginDir(srcDir, dstDir, logs);
|
|
107
|
+
installedPaths.push(dstDir);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ── Wire ~/.opencode/config.json ──────────────────────────────────────────
|
|
15
111
|
const configPath = path.join(opencodeDir, 'config.json');
|
|
16
112
|
if (existsSync(configPath)) {
|
|
17
113
|
try {
|
|
18
|
-
const opencodeConfig = JSON.parse(
|
|
114
|
+
const opencodeConfig: Record<string, unknown> = JSON.parse(
|
|
115
|
+
readFileSync(configPath, 'utf-8'),
|
|
116
|
+
);
|
|
19
117
|
let modified = false;
|
|
20
118
|
|
|
21
|
-
//
|
|
22
|
-
// That package name was written
|
|
23
|
-
// such npm package exists —
|
|
24
|
-
//
|
|
25
|
-
// non-existent plugin name crashes OpenCode on open. Idempotent
|
|
26
|
-
// cleanup so re-running connect heals broken installs.
|
|
119
|
+
// Heal legacy '@aria/connector' references in the older `plugins`
|
|
120
|
+
// (plural) array. That package name was written by older versions
|
|
121
|
+
// of this connector but no such npm package exists — loading a
|
|
122
|
+
// non-existent plugin crashes OpenCode on open. Idempotent.
|
|
27
123
|
if (Array.isArray(opencodeConfig.plugins)) {
|
|
28
|
-
const before = opencodeConfig.plugins.length;
|
|
29
|
-
opencodeConfig.plugins = opencodeConfig.plugins.filter(
|
|
30
|
-
(p
|
|
124
|
+
const before = (opencodeConfig.plugins as unknown[]).length;
|
|
125
|
+
opencodeConfig.plugins = (opencodeConfig.plugins as unknown[]).filter(
|
|
126
|
+
(p) => p !== '@aria/connector',
|
|
31
127
|
);
|
|
32
|
-
if (opencodeConfig.plugins.length !== before) {
|
|
128
|
+
if ((opencodeConfig.plugins as unknown[]).length !== before) {
|
|
33
129
|
modified = true;
|
|
34
130
|
logs.push('Removed legacy @aria/connector reference from OpenCode plugins (was crashing on open)');
|
|
35
131
|
}
|
|
36
132
|
}
|
|
37
133
|
|
|
134
|
+
// OpenCode v2 schema: `plugin` (singular) array of absolute paths or
|
|
135
|
+
// npm names. We write absolute paths to the locally-installed plugin
|
|
136
|
+
// dirs above, so OpenCode resolves them as Node modules without any
|
|
137
|
+
// network or registry dependency.
|
|
138
|
+
const existingPlugin: unknown[] = Array.isArray(opencodeConfig.plugin)
|
|
139
|
+
? (opencodeConfig.plugin as unknown[]).slice()
|
|
140
|
+
: [];
|
|
141
|
+
const stringSet = new Set(
|
|
142
|
+
existingPlugin.filter((p): p is string => typeof p === 'string'),
|
|
143
|
+
);
|
|
144
|
+
let pluginAdded = false;
|
|
145
|
+
for (const installPath of installedPaths) {
|
|
146
|
+
if (!stringSet.has(installPath)) {
|
|
147
|
+
existingPlugin.push(installPath);
|
|
148
|
+
stringSet.add(installPath);
|
|
149
|
+
pluginAdded = true;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (pluginAdded) {
|
|
153
|
+
opencodeConfig.plugin = existingPlugin;
|
|
154
|
+
modified = true;
|
|
155
|
+
logs.push(`Wired ${installedPaths.length} Aria plugin(s) into OpenCode config.plugin`);
|
|
156
|
+
}
|
|
157
|
+
|
|
38
158
|
if (!opencodeConfig.agentsMdPath) {
|
|
39
159
|
opencodeConfig.agentsMdPath = path.join(homedir(), '.aria', 'AGENTS.md');
|
|
40
160
|
modified = true;
|
|
@@ -51,11 +171,11 @@ export async function connectOpenCode(config: AriaConfig): Promise<string[]> {
|
|
|
51
171
|
}
|
|
52
172
|
}
|
|
53
173
|
|
|
174
|
+
// ── Write the harness AGENTS.md ───────────────────────────────────────────
|
|
54
175
|
const ariaDir = path.join(homedir(), '.aria');
|
|
55
176
|
if (!existsSync(ariaDir)) {
|
|
56
177
|
mkdirSync(ariaDir, { recursive: true });
|
|
57
178
|
}
|
|
58
|
-
|
|
59
179
|
const ariaAgentsPath = path.join(ariaDir, 'AGENTS.md');
|
|
60
180
|
const agentsContent = buildOpenCodeAgentsMd(config);
|
|
61
181
|
writeFileSync(ariaAgentsPath, agentsContent);
|
|
@@ -70,14 +190,31 @@ export async function disconnectOpenCode(): Promise<string[]> {
|
|
|
70
190
|
|
|
71
191
|
if (existsSync(configPath)) {
|
|
72
192
|
try {
|
|
73
|
-
const opencodeConfig = JSON.parse(
|
|
193
|
+
const opencodeConfig: Record<string, unknown> = JSON.parse(
|
|
194
|
+
readFileSync(configPath, 'utf-8'),
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
// Strip any locally-installed Aria plugin paths from `plugin` (singular).
|
|
198
|
+
const pluginsRoot = path.join(homedir(), '.opencode', 'plugins');
|
|
199
|
+
if (Array.isArray(opencodeConfig.plugin)) {
|
|
200
|
+
const before = (opencodeConfig.plugin as unknown[]).length;
|
|
201
|
+
opencodeConfig.plugin = (opencodeConfig.plugin as unknown[]).filter((p) => {
|
|
202
|
+
if (typeof p !== 'string') return true;
|
|
203
|
+
return !PLUGIN_NAMES.some((n) => p === path.join(pluginsRoot, n));
|
|
204
|
+
});
|
|
205
|
+
if ((opencodeConfig.plugin as unknown[]).length !== before) {
|
|
206
|
+
logs.push('Removed Aria plugin paths from OpenCode config.plugin');
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Strip the legacy @aria/connector reference if present.
|
|
74
211
|
if (Array.isArray(opencodeConfig.plugins)) {
|
|
75
|
-
opencodeConfig.plugins = opencodeConfig.plugins.filter(
|
|
76
|
-
(p
|
|
212
|
+
opencodeConfig.plugins = (opencodeConfig.plugins as unknown[]).filter(
|
|
213
|
+
(p) => p !== '@aria/connector',
|
|
77
214
|
);
|
|
78
|
-
writeFileSync(configPath, JSON.stringify(opencodeConfig, null, 2));
|
|
79
|
-
logs.push('Removed @aria/connector from OpenCode plugins');
|
|
80
215
|
}
|
|
216
|
+
|
|
217
|
+
writeFileSync(configPath, JSON.stringify(opencodeConfig, null, 2));
|
|
81
218
|
} catch {
|
|
82
219
|
logs.push('Failed to update OpenCode config');
|
|
83
220
|
}
|
|
@@ -94,7 +231,7 @@ function buildOpenCodeAgentsMd(config: AriaConfig): string {
|
|
|
94
231
|
|
|
95
232
|
return `# Aria Harness — AGENTS.md
|
|
96
233
|
|
|
97
|
-
Automatically injected by @
|
|
234
|
+
Automatically injected by @aria_asi/cli. This file provides Aria's cognitive harness
|
|
98
235
|
to OpenCode sessions.
|
|
99
236
|
|
|
100
237
|
## Connected Repositories
|