@rnbsolucoes/axion-code 0.1.3 → 0.1.6

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 CHANGED
@@ -19,7 +19,9 @@ This MVP follows the PREVC-P documentation package in `.context/`:
19
19
  - Axion Desktop fallback provider presets, including OpenAI-compatible and Anthropic-compatible endpoints;
20
20
  - shared Axion Desktop/CLI provider, model and permission stores under `%USERPROFILE%\.axion`;
21
21
  - Pi Agent assets in inspect/import-only mode;
22
- - MCP probe/list/read-only posture.
22
+ - native dotcontext and MCP management posture;
23
+ - plan-scoped PREVC + A learning consolidation through `/learn`;
24
+ - shared plugin and native isolated subagent catalogs.
23
25
 
24
26
  ## MVP Commands
25
27
 
@@ -29,6 +31,8 @@ axion-code ask "Explique este projeto"
29
31
  axion-code ask --provider openrouter --model google/gemini-2.5-flash-lite "Responda em uma linha"
30
32
  axion-code run --json
31
33
  axion-code doctor --json
34
+ axion-code init --json
35
+ axion-code init --project --json
32
36
  axion-code session list --json
33
37
  axion-code provider list --json
34
38
  axion-code provider profile init
@@ -45,6 +49,15 @@ axion-code graphics doctor
45
49
  axion-code graphics logo
46
50
  axion-code graphics logo --mode sixel --width 180
47
51
  axion-code mcp list --json
52
+ axion-code mcp add sample --command node --arg server.js
53
+ axion-code mcp enable sample
54
+ axion-code mcp disable sample
55
+ axion-code mcp remove sample
56
+ axion-code mcp import .\mcp-servers.json
57
+ axion-code plugins list --json
58
+ axion-code agents list --json
59
+ axion-code agents run bug-hunter "review this login flow"
60
+ axion-code learn --json
48
61
  axion-code package inspect <path>
49
62
  ```
50
63
 
@@ -142,33 +155,115 @@ Without npm:
142
155
  go build -o "$env:LOCALAPPDATA\AxionCode\bin\axion-code.exe" ./cmd/axion-code
143
156
  ```
144
157
 
145
- Provider and model configuration is shared with Axion Desktop:
158
+ Provider catalog/configuration is shared with Axion Desktop, while the active
159
+ Axion Code selection is isolated:
146
160
 
147
161
  ```text
148
162
  %USERPROFILE%\.axion\harness\providers.json
149
- %USERPROFILE%\.axion\harness\active_profile
163
+ %USERPROFILE%\.axion\harness\active_profile # Axion Desktop active profile
164
+ %USERPROFILE%\.axion\harness\active_profile_cli # Axion Code active profile
165
+ %USERPROFILE%\.axion\harness\selection_cli.json # Axion Code active model/params
150
166
  %USERPROFILE%\.axion\axion-mode.json
151
167
  %USERPROFILE%\.axion\sessions\axion.db
168
+ %USERPROFILE%\.axion\mcp-servers.json
169
+ %USERPROFILE%\.axion\plugins.json
170
+ %USERPROFILE%\.axion\sub-agents.json
152
171
  ```
153
172
 
154
173
  OpenRouter uses `OPENROUTER_API_KEY` from the environment or a `secret:<NAME>` reference stored in `C:\Israel\Pesoal\secrets.env` (override for tests: `AXION_SECRETS_ENV`). Provider profile config stores only references, never the key value.
155
174
 
156
- For test/dev isolation, set `AXION_HOME` to a temporary folder. In normal use, leave it unset so Desktop and CLI remain two surfaces of the same Axion harness.
175
+ For test/dev isolation, set `AXION_HOME` to a temporary folder. In normal use,
176
+ leave it unset so Desktop and CLI share the same provider catalog while keeping
177
+ their active provider/model selections independent.
178
+
179
+ ## Project Bootstrap
180
+
181
+ `axion-code init --json` bootstraps the shared user-level Axion home used by
182
+ Axion Desktop and Axion Code. It creates missing files under
183
+ `%USERPROFILE%\.axion` without overwriting Desktop-owned provider/model state.
184
+
185
+ `axion-code init --project --json` bootstraps the current workspace. The same
186
+ operation is available inside the TUI with `/init`. It creates only missing
187
+ project scaffolding:
188
+
189
+ ```text
190
+ .brv/ local operational memory and PREVC + A learning buffers
191
+ .context/ workflow, plans, tasks, context snapshots and PREVC evidence
192
+ .docs/ project documents, specs, reports and handoff material
193
+ AGENTS.md project-scoped instructions
194
+ CLAUDE.md Claude-compatible project instructions
195
+ .gitignore ignored local runtime, secrets, cache and build-output patterns
196
+ ```
197
+
198
+ If a legacy `docs/` directory exists and `.docs/` does not, project bootstrap
199
+ renames `docs/` to `.docs/`. If both exist, Axion Code leaves both untouched and
200
+ does not attempt an automatic merge.
201
+
202
+ Instruction layering is explicit: shared `%USERPROFILE%\.axion\AGENTS.md`
203
+ contains global Axion Code agent rules, while the workspace root `AGENTS.md`
204
+ contains project-specific rules. Provider runtime prompts read both layers when
205
+ present, plus `CLAUDE.md` as a compatibility surface.
157
206
 
158
207
  The interactive TUI supports:
159
208
 
160
209
  ```text
161
210
  / inline slash palette
211
+ /init
162
212
  /provider
163
213
  /provider set <profile-id>
164
214
  /model
165
215
  /permission
216
+ /mcp
217
+ /learn
218
+ /plugins
219
+ /agents
220
+ /agents run <id> <prompt>
166
221
  ```
167
222
 
168
223
  Slash palette behavior: `↑/↓` selects, `Tab` completes the selected command, `Enter` executes the selected command, `Esc` closes active menus/wizards.
169
224
 
170
225
  `/model` pulls the active provider's `/models` endpoint when credentials are configured. Reasoning and fast-mode steps appear only when the selected model metadata exposes those parameters.
171
226
 
227
+ `/learn` consolidates plan-scoped learning from `.brv/plans/<plan-id>` and `.context/learning-candidates*.md`, filters low-signal material, deduplicates by content hash/summary and promotes relevant notes into native dotcontext at `<workspace>/.axion/context`.
228
+
229
+ When the active plan comes from `.context/plans/*.md`, `/task add`, `/task done`
230
+ and `/task progress` update the Markdown plan file directly. Axion Code rewrites
231
+ only the target task line marker/progress and keeps the rest of the document
232
+ unchanged.
233
+
234
+ `/mcp` opens an inline MCP list. Enabled servers can be disabled, disabled servers can be enabled, and non-native servers can be uninstalled while preserving valid `mcp-servers.json` formatting.
235
+
236
+ `/agents` lists the native isolated subagents. `/agents run <id> <prompt>` calls one with an isolated prompt while inheriting the active provider/model from the main agent. The subagent returns findings/action feedback instead of joining the main context by default.
237
+
238
+ ## MCP, Plugins And Subagents
239
+
240
+ MCP import files use the same JSON array shape as `%USERPROFILE%\.axion\mcp-servers.json`:
241
+
242
+ ```json
243
+ [
244
+ {
245
+ "id": "context7",
246
+ "name": "Context7",
247
+ "transport": "stdio",
248
+ "command": "npx",
249
+ "args": ["-y", "@upstash/context7-mcp"],
250
+ "enabled": false,
251
+ "read_only": true
252
+ }
253
+ ]
254
+ ```
255
+
256
+ `axion mcp import <file.json>` merges by `id`, preserves `native` protection for built-ins, writes formatted JSON, and rejects entries without `id` or without the required `command`/`url` for the selected transport. Native MCPs such as `dotcontext` cannot be removed, only disabled.
257
+
258
+ Plugins are read from the same shared Axion Desktop file, `%USERPROFILE%\.axion\plugins.json`. The CLI can list, enable, disable and remove plugin records, but executable plugin installation remains intentionally gated for the next trust-policy cycle.
259
+
260
+ Subagents are stored in `%USERPROFILE%\.axion\sub-agents.json`. The initial catalog has 15 native entries:
261
+
262
+ - Programming: `code-reviewer`, `bug-hunter`, `security-reviewer`, `performance-reviewer`, `frontend-ux-reviewer`.
263
+ - Professional: `product-strategist`, `business-analyst`, `financial-analyst`, `legal-policy-reviewer`, `marketing-strategist`, `sales-ops-analyst`, `customer-success-advisor`, `data-analyst`, `operations-advisor`, `hr-talent-advisor`.
264
+
265
+ Execution contract: subagents inherit the active provider/model, receive an isolated prompt containing only their role and the requested task, do not access the main hidden context unless explicitly included in the prompt, and return findings/evidence/actions back to the main timeline.
266
+
172
267
  Provider menu actions:
173
268
 
174
269
  ```text
@@ -204,4 +299,5 @@ This is a functional direction MVP, not the full harness:
204
299
  - initial chat splash shows the Axion logo and system name until the first interaction;
205
300
  - no tool execution yet;
206
301
  - no executable Pi RPC bridge yet;
207
- - no MCP transport execution yet.
302
+ - no MCP transport execution yet;
303
+ - native subagent execution is prompt-isolated and provider/model-inherited; richer multi-subagent orchestration, streaming and budget telemetry remain next-cycle items.
package/npm/bin/axion.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawnSync } from "node:child_process";
3
- import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
4
4
  import https from "node:https";
5
5
  import { dirname, join, resolve } from "node:path";
6
6
  import { fileURLToPath } from "node:url";
@@ -42,15 +42,49 @@ function sourceAvailable() {
42
42
  return existsSync(join(root, "go.mod")) && existsSync(join(root, "cmd", "axion-code"));
43
43
  }
44
44
 
45
+ function sleep(ms) {
46
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
47
+ }
48
+
49
+ function markerMatches(expectedMarker) {
50
+ try {
51
+ return existsSync(exePath) && readFileSync(markerPath, "utf8").trim() === expectedMarker;
52
+ } catch {
53
+ return false;
54
+ }
55
+ }
56
+
57
+ function copyPackagedBinaryWithRetry(expectedMarker) {
58
+ for (let attempt = 0; attempt < 8; attempt += 1) {
59
+ try {
60
+ copyFileSync(packagedExePath, exePath);
61
+ return;
62
+ } catch (error) {
63
+ const retryable = error && (error.code === "EBUSY" || error.code === "EPERM");
64
+ if (!retryable) {
65
+ throw error;
66
+ }
67
+ if (markerMatches(expectedMarker)) {
68
+ return;
69
+ }
70
+ if (attempt === 7) {
71
+ throw error;
72
+ }
73
+ sleep(75 * (attempt + 1));
74
+ }
75
+ }
76
+ }
77
+
45
78
  function installPackagedBinary() {
46
79
  if (!existsSync(packagedExePath)) {
47
80
  return false;
48
81
  }
49
- copyFileSync(packagedExePath, exePath);
82
+ const marker = packagedBinaryMarker();
83
+ copyPackagedBinaryWithRetry(marker);
50
84
  if (!isWindows) {
51
85
  chmodSync(exePath, 0o755);
52
86
  }
53
- writeFileSync(markerPath, `${packageJSON.version}\n`, "utf8");
87
+ writeFileSync(markerPath, `${marker}\n`, "utf8");
54
88
  return true;
55
89
  }
56
90
 
@@ -64,13 +98,14 @@ function buildFromSource() {
64
98
  if (result.status !== 0) {
65
99
  return false;
66
100
  }
67
- writeFileSync(markerPath, `${packageJSON.version}\n`, "utf8");
101
+ writeFileSync(markerPath, `${sourceBinaryMarker()}\n`, "utf8");
68
102
  return true;
69
103
  }
70
104
 
71
105
  function ensureBinary() {
72
106
  const marker = existsSync(markerPath) ? readFileSync(markerPath, "utf8").trim() : "";
73
- if (existsSync(exePath) && marker === packageJSON.version) {
107
+ const desiredMarker = existsSync(packagedExePath) ? packagedBinaryMarker() : sourceBinaryMarker();
108
+ if (existsSync(exePath) && marker === desiredMarker) {
74
109
  return;
75
110
  }
76
111
  mkdirSync(binDir, { recursive: true });
@@ -88,6 +123,19 @@ function ensureBinary() {
88
123
  process.exit(1);
89
124
  }
90
125
 
126
+ function packagedBinaryMarker() {
127
+ try {
128
+ const stat = statSync(packagedExePath);
129
+ return `${packageJSON.version}|${platformKey}|pkg|${stat.size}|${Math.trunc(stat.mtimeMs)}`;
130
+ } catch {
131
+ return `${packageJSON.version}|${platformKey}|pkg`;
132
+ }
133
+ }
134
+
135
+ function sourceBinaryMarker() {
136
+ return `${packageJSON.version}|${platformKey}|source`;
137
+ }
138
+
91
139
  function semverParts(value) {
92
140
  return String(value || "")
93
141
  .trim()
@@ -183,7 +231,12 @@ async function fetchLatestPackage() {
183
231
  async function readUpdateInfo({ force = false } = {}) {
184
232
  const cached = readJSON(updateCachePath);
185
233
  const now = Date.now();
186
- if (!force && cached?.latestVersion && now - Number(cached.checkedAt || 0) < updateCacheTTL) {
234
+ if (
235
+ !force &&
236
+ cached?.latestVersion &&
237
+ compareVersions(cached.latestVersion, packageJSON.version) >= 0 &&
238
+ now - Number(cached.checkedAt || 0) < updateCacheTTL
239
+ ) {
187
240
  return {
188
241
  currentVersion: packageJSON.version,
189
242
  latestVersion: cached.latestVersion,
@@ -209,13 +262,17 @@ async function readUpdateInfo({ force = false } = {}) {
209
262
  }
210
263
  return info;
211
264
  } catch (error) {
265
+ const usableCachedVersion =
266
+ cached?.latestVersion && compareVersions(cached.latestVersion, packageJSON.version) >= 0
267
+ ? cached.latestVersion
268
+ : "";
212
269
  return {
213
270
  currentVersion: packageJSON.version,
214
- latestVersion: cached?.latestVersion || "",
215
- updateAvailable: cached?.latestVersion ? compareVersions(cached.latestVersion, packageJSON.version) > 0 : false,
271
+ latestVersion: usableCachedVersion,
272
+ updateAvailable: usableCachedVersion ? compareVersions(usableCachedVersion, packageJSON.version) > 0 : false,
216
273
  source: cached?.source || updateSource,
217
274
  checkedAt: cached?.checkedAt || 0,
218
- fromCache: Boolean(cached?.latestVersion),
275
+ fromCache: Boolean(usableCachedVersion),
219
276
  error: error.message
220
277
  };
221
278
  }
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rnbsolucoes/axion-code",
3
- "version": "0.1.3",
3
+ "version": "0.1.6",
4
4
  "description": "Axion Code CLI harness for the Axion ecosystem.",
5
5
  "type": "module",
6
6
  "repository": {