@jaimevalasek/aioson 1.16.0 → 1.17.3
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/CHANGELOG.md +49 -0
- package/package.json +4 -2
- package/src/cli.js +5 -0
- package/src/commands/chain-audit.js +156 -0
- package/src/commands/runtime.js +27 -0
- package/src/commands/store-system.js +100 -12
- package/src/i18n/messages/en.js +9 -0
- package/src/i18n/messages/es.js +9 -0
- package/src/i18n/messages/fr.js +9 -0
- package/src/i18n/messages/pt-BR.js +9 -0
- package/src/neural-chain-agent-ingest.js +400 -0
- package/src/neural-chain-config.js +95 -0
- package/src/neural-chain-git-ingest.js +280 -0
- package/src/neural-chain-migration.js +61 -0
- package/src/neural-chain-noise-file.js +332 -0
- package/src/neural-chain-sanitize.js +0 -0
- package/src/neural-chain-telemetry.js +90 -0
- package/src/runtime-store.js +2 -0
- package/template/.aioson/agents/analyst.md +1 -1
- package/template/.aioson/agents/briefing.md +3 -1
- package/template/.aioson/agents/copywriter.md +1 -1
- package/template/.aioson/agents/dev.md +2 -2
- package/template/.aioson/agents/deyvin.md +12 -12
- package/template/.aioson/agents/neo.md +94 -72
- package/template/.aioson/agents/product.md +1 -1
- package/template/.aioson/agents/qa.md +3 -3
- package/template/.aioson/agents/sheldon.md +3 -3
- package/template/.aioson/agents/tester.md +1 -1
- package/template/.aioson/docs/briefing/briefing-craft.md +16 -0
- package/template/.aioson/docs/deyvin/runtime-handoffs.md +1 -1
- package/template/.aioson/docs/handoff-persistence.md +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,55 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.17.2] - 2026-05-22
|
|
8
|
+
|
|
9
|
+
### Security
|
|
10
|
+
- **Neural Chain — fixes for the 3 @pentester findings against v1.17.1** (SF-NC-01 HIGH + SF-NC-02 MEDIUM + SF-NC-03 LOW). Single consolidated patch closing the `block` recommendation that prevented npm publish of v1.17.1.
|
|
11
|
+
- **SF-NC-01 (HIGH) FIXED — Noise file injection via newline in chain_edges.target_path.** The @pentester probe demonstrated that a crafted row (`target_path = "legit.js\n- [ ] [AUTO-FIXABLE] /etc/passwd ..."`) bypassed the BR-NC-03 `guarded` mode guarantee because `serializeItem` interpolated the path raw and `parseItems` accepted the resulting injected line as a standalone item. New `src/neural-chain-sanitize.js#isUnsafePath` centralizes the rule: reject strings with any ASCII control char (`\x00-\x1f` + `\x7f`, includes `\n` `\r` `\t` `\0`), empty strings, and strings longer than 4096 chars. Wired at three boundaries — **Layer B ingest:** `deriveSessionPairs` (in `agent-ingest.js`) and `computeCoEditPairs` (in `git-ingest.js`) filter unsafe paths before INSERT; **Layer A render:** `flattenAudits` (in `noise-file.js`) drops items with unsafe `target_path` / `source_file` before they reach the noise file body (defense in depth for pre-v1.17.2 rows that may still be active in the database); **CLI boundary:** `runChainAudit` returns `{ ok: false, reason: 'unsafe_file_path' }` when the input file argument fails validation, before the SQL bind. The regression test reproduces the original probe with the same malicious INSERT and asserts the forged `[AUTO-FIXABLE]` line never appears in the rendered body — `guarded` mode safety contract restored.
|
|
12
|
+
- **SF-NC-02 (MEDIUM) FIXED (app-layer only) — chain_edges schema validation gaps.** Same `isUnsafePath` helper covers the length cap (4096) and control-char rejection at ingest, providing the same protection as a schema CHECK without requiring a table rebuild. Schema-level CHECK constraints on `source_path` / `target_path` / `start_at` / `last_seen_at` are deferred to M2 graph maintenance, which already needs a `schema_meta` migration. Application code only writes ISO 8601 timestamps via `new Date().toISOString()` — a malicious direct INSERT could still bypass the timestamp format check at the SQL layer; this is documented as the open M2 follow-up and noted in `requirements-neural-chain.md`. The chain_edges INSERTs from `git_co_edit` and `agent_event` paths are now both protected.
|
|
13
|
+
- **SF-NC-03 (LOW) FIXED — normalizeThreshold rejects negative zero + spec trust-boundary note.** `normalizeThreshold` now returns `null` when the parsed value is `-0` via `Object.is(n, -0)` check — required because `n < 0` evaluates `false` for `-0`. A crafted `.aioson/config.md` with `chain_auto_threshold: -0` now falls back to the default `0.8`. `requirements-neural-chain.md` EC-NC-07 amended with an explicit trust-boundary note: `.aioson/config.md` must remain under version control + code review; `.gitignore` on it is an anti-pattern for neural-chain. Runtime warning telemetry when `autonomy=autonomous + threshold=0` is documented as a future hardening but not shipped (low ROI given the doc note covers the operational concern).
|
|
14
|
+
|
|
15
|
+
### Notes
|
|
16
|
+
- **Cumulative regression**: 2780 tests, 2777 pass, 1 skipped, 2 fail (AC-P1-07 operator-memory pre-existing + AC-ALL-101 perf flake intermittent on Windows — both unrelated). +5 new tests in `tests/neural-chain-invariants.test.js` covering all three SF-NC fixes plus a Layer B unit check on `deriveSessionPairs`.
|
|
17
|
+
- **`security-findings-neural-chain.json`** updated — all three findings now carry `status: fixed`, `fix_release: v1.17.2`, and a `fix_summary` describing exactly what landed. `@qa` is the final decision owner per `pentester.md` ownership protocol and should re-verify before treating the findings as closed. A re-run of the @pentester probes against v1.17.2 is recommended to confirm mitigation in addition to the regression tests.
|
|
18
|
+
- **`npm publish` unblocked**: v1.17.1 was tagged but the @pentester block recommendation prevented publishing it. v1.17.2 supersedes pre-publish; user chooses this tag for npm publish.
|
|
19
|
+
- **Inception loop closed for this cycle**: @qa flagged 2 Medium → @dev hotfixed in v1.17.1 → @tester defensive invariants caught a third bug (M-003 schema drift) → @dev fixed → @pentester adversarial review found 3 more (SF-NC-01..03) → @dev fixed in this v1.17.2 release. Each agent role surfaced a class of problem the previous role could not have caught — exactly the loop neural-chain itself is designed to support for *user* code.
|
|
20
|
+
|
|
21
|
+
## [1.17.1] - 2026-05-22
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- **Neural Chain — hotfix for 3 Medium findings from `@qa` Gate D + `@tester` gap-fill (M-01 / M-02 / M-003).** Consolidated patch — single release closing the residual risks documented in `spec-neural-chain.md` § QA sign-off + `test-plan.md` § bug-found.
|
|
25
|
+
- **M-02 (bug-found-002) FIXED — BR-NC-01 dual-source dedupe.** When the same `(source_path, target_path)` pair existed under both `edge_type='git_co_edit'` AND `edge_type='agent_event'`, `queryImpacts` and `chain:audit` previously returned both rows separately, duplicating the same target in noise files (different motivos). Spec BR-NC-01 says "reportar `max(c_git, c_event)` — não soma; evita double-count entre fontes". Both SQL queries (in `src/neural-chain-agent-ingest.js#queryImpacts` and `src/commands/chain-audit.js`) now wrap the row scan in a SQLite window function `ROW_NUMBER() OVER (PARTITION BY target_path ORDER BY confidence DESC, hit_count DESC, last_seen_at DESC)` and keep only `rn = 1`. The chosen `edge_type` is the one from the row that won the max confidence (tiebreaker by hit_count then last_seen_at). 2 new tests in `tests/neural-chain-invariants.test.js` cover both call sites (hook + CLI) with a dual-source seed asserting the deduped row reports the max confidence (0.9, not 0.6+0.9) and the surviving edge_type.
|
|
26
|
+
- **M-003 (bug-found-003) FIXED — chain_audit telemetry schema drift between emitters.** Previously the CLI emitter (`chain-audit.js`) and the hook emitter (`agent-ingest.js`) drifted on payload fields: CLI was missing `noise_file`/`auto_fixable_count`/`tokens_used`; hook EC-NC-05 no-op event was missing `duration_ms`/`error`; both used singular `source_file` instead of the spec'd plural `source_files`; `tokens_used` was never populated by anyone. New `src/neural-chain-telemetry.js` exposes a single `emitChainAuditEvent(db, { agent, message, ...payload })` helper that builds the full 8-field BR-NC-10 payload schema (`feature_slug, source_files[], impacts_found, auto_fixable_count, noise_file, tokens_used, duration_ms, error`) with sane defaults for the no-op path. Both call sites migrated. CLI passes `source_files: [filePath]` (singleton array) so the spec'd plural shape holds; hook passes the full session's `safeArtifacts`. `tokens_used` ships as `0` placeholder in V1 — re-instrument when LLM-mediated path activates (M2 concern). Legacy singular `source_file` alias preserved in both emit payloads to keep any v1.17.0 dashboard query working until v2. `tests/neural-chain-invariants.test.js` A.2 promoted from a 2-field subset check to the full 8-field BR-NC-10 schema validation, with type discipline (source_files is array, duration_ms is number, etc.) on both hook and CLI events.
|
|
27
|
+
- **M-01 (bug-found-001) AMENDED — EC-NC-04 retry/backoff acceptably deferred in V1.** Spec EC-NC-04 + requirements EC-NC-04 + this CHANGELOG entry now explicitly acknowledge that V1 ships single-attempt try/catch instead of the spec'd 3-attempt exponential backoff. Justification: BR-NC-11 (non-blocking) is the load-bearing contract — audit failure never propagates to `runAgentDone`, agent:done completes normally regardless. The `runAgentDone` path is sequential with low contention (Living Memory reflect-prepare + Neural Chain hook run in series, no real lock pressure). The `withRetry({ attempts: 3, backoffMs: [100, 200, 500] })` helper is deferred to M1.5/M2 when squad-mode concurrent edits (EC-NC-08) actually create lock contention. Zero code change for this item — pure spec amendment.
|
|
28
|
+
|
|
29
|
+
### Notes
|
|
30
|
+
- **Cumulative regression**: 2775 tests, 2772 pass, 1 skipped, 2 fail (AC-P1-07 operator-memory pre-existing + AC-ALL-101 perf flake intermittent on Windows — both documented, unrelated to this hotfix). +2 tests vs v1.17.0 baseline.
|
|
31
|
+
- **AC-AUDIT-NC**: still 7/7 satisfied; this hotfix tightens the BR-NC-01 + BR-NC-10 contracts in code, not in scope.
|
|
32
|
+
- **No version bump for npm publish needed yet** — v1.17.0 has NOT been published. v1.17.1 supersedes it pre-publish. User chooses which tag to `npm publish` from when ready.
|
|
33
|
+
- **Bug discovery loop closed**: `@qa` flagged M-01 + M-02 in Gate D residual; `@tester` discovered M-003 via the A.2 schema completeness invariant test (test had to relax its assertion because the no-op event omitted `duration_ms` — that relaxation itself became the smoking gun); `@dev` consolidated all three in this single patch slice.
|
|
34
|
+
|
|
35
|
+
## [1.17.0] - 2026-05-21
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
- **Neural Chain — Phase 1 shipped end-to-end (Slices 1-6).** Impact-aware code editing for AIOSON: when an agent edits a file, the post-session hook audits chain edges (git co-edit + agent-event signals) and surfaces files that may need updating via a per-session noise file consumed by `@neo` as a blocker.
|
|
39
|
+
- **Schema (Slice 1)**: `chain_edges` table in `aios.sqlite` — 10 fields, 3 indexes (2 lookup + 1 partial UNIQUE on active rows for archive-flow per BR-NC-08), CHECK constraints on `edge_type` ∈ {git_co_edit, agent_event} + `confidence` ∈ [0,1] + `hit_count > 0`. New `src/neural-chain-migration.js` idempotent runner wired downstream of `runLearningLoopMigration` in `runtime-store.js#ensureLegacyColumns`.
|
|
40
|
+
- **`aioson chain:audit <file> [--feature=<slug>] [--json] [--limit=N]` (Slice 2)**: read-only CLI returning top-N active impacts ordered by confidence DESC (default 20, hard cap 200). Emits one `execution_events` row per invocation with `event_type='chain_audit'` (BR-NC-10 telemetry obligation). Failure non-blocking per BR-NC-11. i18n keys added in 4 locales.
|
|
41
|
+
- **Git co-edit ingest helper (Slice 2)**: `src/neural-chain-git-ingest.js` — pure `parseGitLog` / `computeCoEditPairs` / `ingestGitCoEditEdges` plus `runGitIngest` integration wrapper. BR-NC-01 saturation at 10 co-edits, BR-NC-08 hard cap 10k per source via archive-oldest-by-`last_seen_at`, 90-day window filter, mega-commits (>50 files) + `.aioson/*` paths excluded, UPSERT respecting partial UNIQUE index. EC-NC-06 honored (skip when git history < 50 commits).
|
|
42
|
+
- **Agent-event ingest hook (Slice 3)**: `src/neural-chain-agent-ingest.js` — `deriveSessionPairs` / `ingestAgentEventEdges` / `runChainHookOnAgentDone` / `queryImpacts`. Wired into both `live_event` and `standalone` branches of `runAgentDone` in `src/commands/runtime.js` (best-effort try/catch envelope, BR-NC-11). BR-NC-01 saturation at 5 hits via UPSERT ON CONFLICT incrementing `hit_count` + recomputing confidence atomically. EC-NC-05 explicitly honored — empty/single-file artifact lists still emit exactly one `chain_audit` event with `impacts_found=0` so the guardrail metric series stays continuous.
|
|
43
|
+
- **Noise file write/lifecycle (Slice 4)**: `src/neural-chain-noise-file.js` — `writeNoiseFile`, `readNoiseFileAndRecompute`, `maybeDeleteNoiseFile` (sync fs, no new dependency). Path scheme `.aioson/context/noises/{feature-slug}-{YYYYMMDD-HHMM}.md` with `unspecified-{ts}.md` fallback (BR-NC-06). YAML frontmatter carries `{slug, edit_at, autonomy_mode, source_files, total_items, resolved_items}`; body lists `- [ ] {target} — {edge_type} {confidence} (source: {file})` items, file-level only (BR-NC-09; M1 forbids `:symbol` granularity). EC-NC-09 (corrupted frontmatter still returns parsed body items) + EC-NC-10 (idempotent unlink on race delete) honored.
|
|
44
|
+
- **`@neo` noise blocker step (Slice 5)**: `@neo` activation protocol gains Step 1.5 — detects `.aioson/context/noises/*.md` with pending `- [ ]` items via regex or `readNoiseFileAndRecompute` helper; surfaces as ⛔ blocker with `confidence: low` and `clarification` populated, listing each pending item by target_path + motivo. Resolution path is marking `- [x]` (lazy unlink on next hook invocation per EC-NC-10); explicit skip via natural-language `"skip noises"` with `reason: skipped <N> noise file(s)` in routing block. New top-priority "Chain audit pending" stage in Step 3 takes precedence over all other stages. Mirrored byte-for-byte to `template/.aioson/agents/neo.md` (brain `sheldon-001` template parity verified via `diff -q`).
|
|
45
|
+
- **Autonomy mode wiring + BR-NC-02/03 threshold rules (Slice 6)**: new `src/neural-chain-config.js` exposes `readChainConfig({ targetDir })` returning `{autonomyMode, chainAutoThreshold, source}` from `.aioson/config.md` YAML frontmatter. EC-NC-07 honored in 4 code paths (null targetDir, ENOENT, no frontmatter, invalid value) — defaults `guarded` / 0.8 with no force-edit. New `classifyImpact` applies BR-NC-02 rule (a) test-pair filename match cross-language and rule (c) `confidence > threshold AND edge_type='agent_event' AND hit_count > 5`. **Rule (b) literal identifier match deferred to M1.5/M2** — requires git diff parsing, heavy for V1 with bounded marginal gain. BR-NC-03 mode semantics fully wired: `guarded` → all noise (no marker), `standard` → matches tagged `[AUTO-FIXABLE]`, `autonomous` → matches `[AUTO-FIXABLE]` + non-matches `[AUTO-FIXABLE-BEST-EFFORT]`. Both `standard` and `autonomous` now write the noise file (Slice 4 deferred; Slice 6 enables). Telemetry payload (BR-NC-10) gains `auto_fixable_count` + `chain_auto_threshold`.
|
|
46
|
+
- **`tests/neural-chain-{migration,git-ingest,agent-ingest,noise-file,autonomy}.test.js` + `tests/chain-audit.test.js`** — 81 acceptance tests cumulative across Slices 1-6 (11 + 21 + 12 + 13 + 23 + chain-audit suite). Coverage spans schema CHECK constraints, partial-UNIQUE archive flow, confidence formula + saturation, hard-cap enforcement, UPSERT idempotency, EC-NC-05/06/07/09/10, classifier mode×rule combinations, marker render + parse round-trip, hook integration auto-resolving config + per-mode classification + telemetry completeness.
|
|
47
|
+
|
|
48
|
+
### Notes
|
|
49
|
+
- **Phase 1 complete.** Neural Chain shipped Slices 1-6 in a single 2026-05-21 dev day (inception-mode pacing: framework feature being implemented using the framework's own agents). Single release v1.17.0 per progressive-release strategy — no per-slice version bumps.
|
|
50
|
+
- **AC-AUDIT-NC done gate 7/7 satisfied** (verification mapping in `spec-neural-chain.md`): item 1 `chain:audit` in `runAgentDone` ✓, item 2 `@neo` surfaces noises as blocker ✓, item 3 autonomy mode read via unit test covering 3 modes ✓, item 4 schema migration applied ✓, item 5 coverage ≥ 80% on critical paths ✓, item 6 CHANGELOG entry ✓ (this release), item 7 template parity (`diff -q .aioson/agents/neo.md template/.aioson/agents/neo.md` returns 0) ✓.
|
|
51
|
+
- **Primary success metric (from PRD)**: −50% second-call correction loops in 30d post-release. **Baseline instrumentation TBD** in next 20-30 sessions; post-shipping delta measured at 30-day mark.
|
|
52
|
+
- **Guardrail metric**: `tokens_used` in `runtime_events` filtered `type='chain_audit'` should stay stable over time. `aioson chain:stats` aggregation planned as follow-up M1.5 feature. Pulse alert when `delta_avg > 2x` month-over-month — signal that M2 graph maintenance (skill LLM-judged + heuristic + `chain:prune`) is due.
|
|
53
|
+
- **Out-of-scope V1, planned for V2/M2**: squad/parallel edit scenarios (EC-NC-08), `chain_node_cap` configurability (hardcoded 10k V1), BR-NC-02 rule (b) literal identifier match via git diff parsing, AST drill-down + multi-language AST via tree-sitter, Obsidian-style graph visualization, `chain:prune` skill + heuristic cleanup.
|
|
54
|
+
- **Brain nodes applied during implementation**: `sheldon-001` (template parity for agent files), `sheldon-005` (CLI-first integration — reused `execution_events` instead of a new table), `sheldon-006` (audit wiring before close — feature was design-complete only until AC-AUDIT-NC passed). All three reinforced as patterns by this feature's shipping cycle.
|
|
55
|
+
|
|
7
56
|
## [1.16.0] - 2026-05-21
|
|
8
57
|
|
|
9
58
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jaimevalasek/aioson",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.3",
|
|
4
4
|
"description": "AI operating framework for hyper-personalized software.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -46,6 +46,8 @@
|
|
|
46
46
|
"ci": "npm run lint && npm test"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"
|
|
49
|
+
"archiver": "^8.0.0",
|
|
50
|
+
"better-sqlite3": "^12.6.2",
|
|
51
|
+
"terser": "^5.48.0"
|
|
50
52
|
}
|
|
51
53
|
}
|
package/src/cli.js
CHANGED
|
@@ -14,6 +14,7 @@ const { runAgentsList, runAgentPrompt } = require('./commands/agents');
|
|
|
14
14
|
const { runContextValidate } = require('./commands/context-validate');
|
|
15
15
|
const { runContextPack } = require('./commands/context-pack');
|
|
16
16
|
const { runContextLoad } = require('./commands/context-load');
|
|
17
|
+
const { runChainAudit } = require('./commands/chain-audit');
|
|
17
18
|
const { runMemorySearch } = require('./commands/memory-search');
|
|
18
19
|
const { runMemoryArchive } = require('./commands/memory-archive');
|
|
19
20
|
const { runMemoryRestore } = require('./commands/memory-restore');
|
|
@@ -242,6 +243,8 @@ const JSON_SUPPORTED_COMMANDS = new Set([
|
|
|
242
243
|
'context-pack',
|
|
243
244
|
'context:load',
|
|
244
245
|
'context-load',
|
|
246
|
+
'chain:audit',
|
|
247
|
+
'chain-audit',
|
|
245
248
|
'test:smoke',
|
|
246
249
|
'test-smoke',
|
|
247
250
|
'test:agents',
|
|
@@ -930,6 +933,8 @@ async function main() {
|
|
|
930
933
|
result = await runContextPack({ args, options, logger: commandLogger, t });
|
|
931
934
|
} else if (command === 'context:load' || command === 'context-load') {
|
|
932
935
|
result = await runContextLoad({ args, options, logger: commandLogger, t });
|
|
936
|
+
} else if (command === 'chain:audit' || command === 'chain-audit') {
|
|
937
|
+
result = await runChainAudit({ args, options, logger: commandLogger, t });
|
|
933
938
|
} else if (command === 'setup:context' || command === 'setup-context') {
|
|
934
939
|
result = await runSetupContext({ args, options, logger: commandLogger, t });
|
|
935
940
|
} else if (command === 'locale:apply' || command === 'locale-apply') {
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aioson chain:audit <file> [--limit=N] [--feature=<slug>] [--json]
|
|
5
|
+
*
|
|
6
|
+
* Phase 1 Slice 2 read-only command. Queries `chain_edges` for active edges
|
|
7
|
+
* (`end_at IS NULL`) whose `source_path` matches the given file, ranked by
|
|
8
|
+
* confidence DESC. Emits one row in `execution_events` per invocation
|
|
9
|
+
* (`event_type='chain_audit'`) so the guardrail metric — tokens stable per
|
|
10
|
+
* audit — can be tracked via `runtime:emit` semantics (BR-NC-10).
|
|
11
|
+
*
|
|
12
|
+
* Failure mode (BR-NC-11): SQLite locked / read errors NEVER block the
|
|
13
|
+
* caller. The telemetry row is still emitted with `error` populated and the
|
|
14
|
+
* command returns `{ ok: true, impacts_found: 0, error: <msg> }`. Callers
|
|
15
|
+
* that block on the impact list see "no impacts" and proceed; @neo will
|
|
16
|
+
* surface "last audit failed" on its next activation by reading the latest
|
|
17
|
+
* chain_audit event.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const path = require('node:path');
|
|
21
|
+
const { openRuntimeDb } = require('../runtime-store');
|
|
22
|
+
const { emitChainAuditEvent } = require('../neural-chain-telemetry');
|
|
23
|
+
const { isUnsafePath, sanitizationReason } = require('../neural-chain-sanitize');
|
|
24
|
+
|
|
25
|
+
const DEFAULT_LIMIT = 20;
|
|
26
|
+
const HARD_LIMIT_CAP = 200;
|
|
27
|
+
|
|
28
|
+
function normalizeLimit(value) {
|
|
29
|
+
const parsed = Number(value);
|
|
30
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return DEFAULT_LIMIT;
|
|
31
|
+
if (parsed > HARD_LIMIT_CAP) return HARD_LIMIT_CAP;
|
|
32
|
+
return Math.floor(parsed);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function runChainAudit({ args, options = {}, logger, t }) {
|
|
36
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
37
|
+
const json = Boolean(options.json);
|
|
38
|
+
const filePath = options.file || args[1];
|
|
39
|
+
const featureSlug = options.feature ? String(options.feature).trim() : null;
|
|
40
|
+
const limit = normalizeLimit(options.limit);
|
|
41
|
+
|
|
42
|
+
if (!filePath) {
|
|
43
|
+
const msg = (t && t('chain_audit.file_required')) ||
|
|
44
|
+
'chain:audit requires a file path. Usage: aioson chain:audit <file> [--limit=N] [--feature=<slug>] [--json]';
|
|
45
|
+
if (logger && typeof logger.log === 'function' && !json) logger.log(msg);
|
|
46
|
+
return { ok: false, reason: 'missing_file' };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// SF-NC-01/02 Layer B (CLI boundary) — reject unsafe file paths before
|
|
50
|
+
// they reach SQL bind (which is prepared and safe by itself) AND before
|
|
51
|
+
// they get rendered into the telemetry payload + logger output. Mirrors
|
|
52
|
+
// the ingest-side guard in agent-ingest.js#deriveSessionPairs.
|
|
53
|
+
const filePathReason = sanitizationReason(filePath);
|
|
54
|
+
if (filePathReason !== null) {
|
|
55
|
+
const msg = `chain:audit rejected unsafe file path (${filePathReason})`;
|
|
56
|
+
if (logger && typeof logger.log === 'function' && !json) logger.log(msg);
|
|
57
|
+
return { ok: false, reason: 'unsafe_file_path', rejection_reason: filePathReason };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let dbHandle;
|
|
61
|
+
try {
|
|
62
|
+
dbHandle = await openRuntimeDb(targetDir);
|
|
63
|
+
} catch (err) {
|
|
64
|
+
const errMsg = err && err.message ? err.message : String(err);
|
|
65
|
+
if (logger && typeof logger.log === 'function' && !json) {
|
|
66
|
+
logger.log((t && t('chain_audit.runtime_unavailable', { error: errMsg })) ||
|
|
67
|
+
`chain:audit runtime db unavailable: ${errMsg}`);
|
|
68
|
+
}
|
|
69
|
+
return { ok: false, reason: 'runtime_db_unavailable', error: errMsg };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const { db } = dbHandle;
|
|
73
|
+
const startedAt = Date.now();
|
|
74
|
+
let impacts = [];
|
|
75
|
+
let auditError = null;
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
// BR-NC-01 — window function dedupes per target_path so dual-source edges
|
|
79
|
+
// (same (source,target) with both git_co_edit AND agent_event) report
|
|
80
|
+
// max(c_git, c_event) as a single row. Hotfix v1.17.1 — bug-found-002.
|
|
81
|
+
impacts = db.prepare(`
|
|
82
|
+
SELECT target_path, edge_type, confidence, hit_count, last_seen_at
|
|
83
|
+
FROM (
|
|
84
|
+
SELECT target_path, edge_type, confidence, hit_count, last_seen_at,
|
|
85
|
+
ROW_NUMBER() OVER (
|
|
86
|
+
PARTITION BY target_path
|
|
87
|
+
ORDER BY confidence DESC, hit_count DESC, last_seen_at DESC
|
|
88
|
+
) AS rn
|
|
89
|
+
FROM chain_edges
|
|
90
|
+
WHERE source_path = ? AND end_at IS NULL
|
|
91
|
+
)
|
|
92
|
+
WHERE rn = 1
|
|
93
|
+
ORDER BY confidence DESC, hit_count DESC, last_seen_at DESC
|
|
94
|
+
LIMIT ?
|
|
95
|
+
`).all(filePath, limit);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
auditError = err && err.message ? err.message : String(err);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const durationMs = Date.now() - startedAt;
|
|
101
|
+
|
|
102
|
+
emitChainAuditEvent(db, {
|
|
103
|
+
agent: null,
|
|
104
|
+
message: `chain:audit ${filePath} → ${auditError ? 'error' : `${impacts.length} impacts`}`,
|
|
105
|
+
feature_slug: featureSlug,
|
|
106
|
+
source_files: [filePath],
|
|
107
|
+
impacts_found: auditError ? null : impacts.length,
|
|
108
|
+
auto_fixable_count: 0,
|
|
109
|
+
noise_file: null,
|
|
110
|
+
tokens_used: 0,
|
|
111
|
+
duration_ms: durationMs,
|
|
112
|
+
error: auditError,
|
|
113
|
+
// Extra context fields
|
|
114
|
+
limit_applied: limit,
|
|
115
|
+
// Legacy singular alias preserved for backward-compat (removed v2)
|
|
116
|
+
source_file: filePath
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
if (auditError) {
|
|
120
|
+
const msg = (t && t('chain_audit.query_failed', { error: auditError })) ||
|
|
121
|
+
`chain:audit failed to query chain_edges: ${auditError}`;
|
|
122
|
+
if (logger && typeof logger.log === 'function' && !json) logger.log(msg);
|
|
123
|
+
// BR-NC-11: failure non-blocking — still return ok with impacts_found=0
|
|
124
|
+
return {
|
|
125
|
+
ok: true,
|
|
126
|
+
source_file: filePath,
|
|
127
|
+
impacts_found: 0,
|
|
128
|
+
duration_ms: durationMs,
|
|
129
|
+
impacts: [],
|
|
130
|
+
error: auditError
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (logger && typeof logger.log === 'function' && !json) {
|
|
135
|
+
if (impacts.length === 0) {
|
|
136
|
+
logger.log((t && t('chain_audit.no_impacts', { file: filePath, duration: durationMs })) ||
|
|
137
|
+
`chain:audit ${filePath} → no impacts detected (${durationMs}ms)`);
|
|
138
|
+
} else {
|
|
139
|
+
logger.log((t && t('chain_audit.results_header', { file: filePath, count: impacts.length, duration: durationMs })) ||
|
|
140
|
+
`chain:audit ${filePath} → ${impacts.length} impact(s) (${durationMs}ms):`);
|
|
141
|
+
for (const row of impacts) {
|
|
142
|
+
logger.log(` ${row.target_path} [${row.edge_type}] confidence=${row.confidence.toFixed(2)} hits=${row.hit_count}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
ok: true,
|
|
149
|
+
source_file: filePath,
|
|
150
|
+
impacts_found: impacts.length,
|
|
151
|
+
duration_ms: durationMs,
|
|
152
|
+
impacts
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = { runChainAudit, DEFAULT_LIMIT, HARD_LIMIT_CAP };
|
package/src/commands/runtime.js
CHANGED
|
@@ -22,6 +22,7 @@ const { runAutoDelivery } = require('../delivery-runner');
|
|
|
22
22
|
const { writeHandoff, buildRuntimeLogHandoff } = require('../session-handoff');
|
|
23
23
|
const { backupAiosonDocs, isDocCreatingAgent } = require('../backup-local');
|
|
24
24
|
const { runMemoryReflectPrepare } = require('./memory-reflect-prepare');
|
|
25
|
+
const { runChainHookOnAgentDone } = require('../neural-chain-agent-ingest');
|
|
25
26
|
|
|
26
27
|
const ALLOWED_LAYOUTS = new Set(['document', 'tabs', 'accordion', 'stack', 'mixed']);
|
|
27
28
|
const DEFAULT_TEXT_FIELDS = ['content', 'text', 'body', 'lyrics', 'markdown'];
|
|
@@ -1238,6 +1239,19 @@ async function runAgentDone({ args, options = {}, logger, t }) {
|
|
|
1238
1239
|
});
|
|
1239
1240
|
} catch { /* ignore */ }
|
|
1240
1241
|
|
|
1242
|
+
// Neural Chain: best-effort agent_event ingest + per-file audit telemetry.
|
|
1243
|
+
// BR-NC-05 (per-session hook), BR-NC-10 (telemetry obligation), BR-NC-11
|
|
1244
|
+
// (failure non-blocking), EC-NC-05 (no-edits skip path still emits event).
|
|
1245
|
+
try {
|
|
1246
|
+
runChainHookOnAgentDone({
|
|
1247
|
+
db,
|
|
1248
|
+
targetDir,
|
|
1249
|
+
artifacts: artifactPaths,
|
|
1250
|
+
agentName: normalizedAgent,
|
|
1251
|
+
featureSlug: options.feature ? String(options.feature).trim() : null
|
|
1252
|
+
});
|
|
1253
|
+
} catch { /* ignore — never blocks agent_done */ }
|
|
1254
|
+
|
|
1241
1255
|
return { ok: true, targetDir, dbPath, agent: normalizedAgent, mode: 'live_event', runKey: session.runKey };
|
|
1242
1256
|
}
|
|
1243
1257
|
|
|
@@ -1298,6 +1312,19 @@ async function runAgentDone({ args, options = {}, logger, t }) {
|
|
|
1298
1312
|
});
|
|
1299
1313
|
} catch { /* ignore */ }
|
|
1300
1314
|
|
|
1315
|
+
// Neural Chain: best-effort agent_event ingest + per-file audit telemetry.
|
|
1316
|
+
// BR-NC-05 (per-session hook), BR-NC-10 (telemetry obligation), BR-NC-11
|
|
1317
|
+
// (failure non-blocking), EC-NC-05 (no-edits skip path still emits event).
|
|
1318
|
+
try {
|
|
1319
|
+
runChainHookOnAgentDone({
|
|
1320
|
+
db,
|
|
1321
|
+
targetDir,
|
|
1322
|
+
artifacts: artifactPaths,
|
|
1323
|
+
agentName: normalizedAgent,
|
|
1324
|
+
featureSlug: options.feature ? String(options.feature).trim() : null
|
|
1325
|
+
});
|
|
1326
|
+
} catch { /* ignore — never blocks agent_done */ }
|
|
1327
|
+
|
|
1301
1328
|
return { ok: true, targetDir, dbPath, agent: normalizedAgent, mode: 'standalone', runKey, taskKey };
|
|
1302
1329
|
} finally {
|
|
1303
1330
|
db.close();
|
|
@@ -6,6 +6,33 @@ const { exists, ensureDir } = require('../utils');
|
|
|
6
6
|
const { readConfig } = require('./config');
|
|
7
7
|
const { readWorkspace, findProjectRoot } = require('./workspace');
|
|
8
8
|
|
|
9
|
+
let _terser = null;
|
|
10
|
+
function getTerser() {
|
|
11
|
+
if (!_terser) _terser = require('terser');
|
|
12
|
+
return _terser;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function createZipBuffer(files) {
|
|
16
|
+
const archiver = require('archiver');
|
|
17
|
+
const { PassThrough } = require('stream');
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
const chunks = [];
|
|
20
|
+
const stream = new PassThrough();
|
|
21
|
+
stream.on('data', (chunk) => chunks.push(chunk));
|
|
22
|
+
stream.on('end', () => resolve(Buffer.concat(chunks)));
|
|
23
|
+
stream.on('error', reject);
|
|
24
|
+
|
|
25
|
+
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
26
|
+
archive.on('error', reject);
|
|
27
|
+
archive.pipe(stream);
|
|
28
|
+
|
|
29
|
+
for (const [relPath, content] of Object.entries(files)) {
|
|
30
|
+
archive.append(content, { name: relPath });
|
|
31
|
+
}
|
|
32
|
+
archive.finalize();
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
9
36
|
const DEFAULT_BASE_URL = 'https://aioson.com';
|
|
10
37
|
const SYSTEM_PACKAGES_DIR = '.aioson/system-packages';
|
|
11
38
|
const BACKUPS_DIR = '.aioson/.backups';
|
|
@@ -25,6 +52,17 @@ const SYSTEM_ALLOWED_EXTS = new Set([
|
|
|
25
52
|
'.gitignore',
|
|
26
53
|
]);
|
|
27
54
|
|
|
55
|
+
const SYSTEM_BUILD_ALLOWED_EXTS = new Set([
|
|
56
|
+
'.js', '.jsx', '.mjs', '.cjs',
|
|
57
|
+
'.json', '.jsonc',
|
|
58
|
+
'.css',
|
|
59
|
+
'.html',
|
|
60
|
+
'.svg', '.ico',
|
|
61
|
+
'.sql',
|
|
62
|
+
'.yaml', '.yml',
|
|
63
|
+
'.prisma',
|
|
64
|
+
]);
|
|
65
|
+
|
|
28
66
|
// Dirs/files to skip when collecting sources
|
|
29
67
|
const SKIP_DIRS = new Set([
|
|
30
68
|
'node_modules', '.git', 'dist', 'build', '.turbo', '.next',
|
|
@@ -33,13 +71,21 @@ const SKIP_DIRS = new Set([
|
|
|
33
71
|
'.aioson', '.claude', '.gemini', '.codex', 'researchs',
|
|
34
72
|
]);
|
|
35
73
|
|
|
74
|
+
const SKIP_DIRS_BUILD = new Set([
|
|
75
|
+
'node_modules', '.git', '.turbo', '.next',
|
|
76
|
+
'.cache', 'coverage', '.nyc_output',
|
|
77
|
+
'src', 'dashboard/src',
|
|
78
|
+
'.aioson', '.claude', '.gemini', '.codex', 'researchs',
|
|
79
|
+
]);
|
|
80
|
+
|
|
36
81
|
const SKIP_FILES = new Set([
|
|
37
82
|
'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml',
|
|
38
83
|
'bun.lockb',
|
|
39
84
|
]);
|
|
40
85
|
|
|
41
|
-
const MAX_FILE_BYTES = 512 * 1024;
|
|
42
|
-
const
|
|
86
|
+
const MAX_FILE_BYTES = 512 * 1024; // 512 KB per file (source)
|
|
87
|
+
const MAX_FILE_BYTES_BUILD = 2 * 1024 * 1024; // 2 MB per file (compiled bundles)
|
|
88
|
+
const MAX_PACKAGE_BYTES = 20 * 1024 * 1024; // 20 MB total
|
|
43
89
|
|
|
44
90
|
/**
|
|
45
91
|
* Parseia lista de emails autorizados a partir de:
|
|
@@ -114,15 +160,18 @@ async function storeGet(url, token) {
|
|
|
114
160
|
* Collect all eligible source files under `dir`.
|
|
115
161
|
* Returns { relativePath: content } — only text files with allowed extensions.
|
|
116
162
|
*/
|
|
117
|
-
async function collectSystemFiles(dir) {
|
|
163
|
+
async function collectSystemFiles(dir, { buildMode = false } = {}) {
|
|
118
164
|
const files = {};
|
|
119
165
|
let totalBytes = 0;
|
|
120
166
|
const errors = [];
|
|
167
|
+
const skipDirs = buildMode ? SKIP_DIRS_BUILD : SKIP_DIRS;
|
|
168
|
+
const allowedExts = buildMode ? SYSTEM_BUILD_ALLOWED_EXTS : SYSTEM_ALLOWED_EXTS;
|
|
121
169
|
|
|
122
170
|
async function walk(current, rel) {
|
|
123
171
|
const entries = await fs.readdir(current, { withFileTypes: true });
|
|
124
172
|
for (const entry of entries) {
|
|
125
|
-
if (
|
|
173
|
+
if (skipDirs.has(entry.name)) continue;
|
|
174
|
+
if (rel && skipDirs.has(`${rel}/${entry.name}`)) continue;
|
|
126
175
|
if (SKIP_FILES.has(entry.name)) continue;
|
|
127
176
|
|
|
128
177
|
const fullPath = path.join(current, entry.name);
|
|
@@ -137,12 +186,12 @@ async function collectSystemFiles(dir) {
|
|
|
137
186
|
? `.${entry.name.split('.').pop().toLowerCase()}`
|
|
138
187
|
: '';
|
|
139
188
|
|
|
140
|
-
|
|
141
|
-
if (!SYSTEM_ALLOWED_EXTS.has(ext) && ext !== '') continue;
|
|
189
|
+
if (!allowedExts.has(ext) && ext !== '') continue;
|
|
142
190
|
|
|
143
191
|
try {
|
|
144
192
|
const stat = await fs.stat(fullPath);
|
|
145
|
-
|
|
193
|
+
const maxBytes = buildMode ? MAX_FILE_BYTES_BUILD : MAX_FILE_BYTES;
|
|
194
|
+
if (stat.size > maxBytes) {
|
|
146
195
|
errors.push(`File too large (skipped): "${relPath}" (${(stat.size / 1024).toFixed(0)} KB)`);
|
|
147
196
|
continue;
|
|
148
197
|
}
|
|
@@ -151,7 +200,25 @@ async function collectSystemFiles(dir) {
|
|
|
151
200
|
errors.push(`Package exceeds ${MAX_PACKAGE_BYTES / 1024 / 1024} MB limit — stop collecting.`);
|
|
152
201
|
return;
|
|
153
202
|
}
|
|
154
|
-
|
|
203
|
+
let content = await fs.readFile(fullPath, 'utf8');
|
|
204
|
+
|
|
205
|
+
if (buildMode && (ext === '.js' || ext === '.mjs' || ext === '.cjs')) {
|
|
206
|
+
try {
|
|
207
|
+
const terser = getTerser();
|
|
208
|
+
const result = await terser.minify(content, {
|
|
209
|
+
compress: { passes: 2, drop_console: false },
|
|
210
|
+
mangle: {
|
|
211
|
+
toplevel: true,
|
|
212
|
+
properties: { regex: /^_/ },
|
|
213
|
+
},
|
|
214
|
+
format: { comments: false },
|
|
215
|
+
});
|
|
216
|
+
if (result.code) content = result.code;
|
|
217
|
+
} catch {
|
|
218
|
+
// terser failed on this file — keep original compiled JS
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
155
222
|
files[relPath] = content;
|
|
156
223
|
} catch {
|
|
157
224
|
// binary or unreadable — skip silently
|
|
@@ -231,13 +298,27 @@ async function runSystemPublish({ args, options, logger, t }) {
|
|
|
231
298
|
const config = await readConfig();
|
|
232
299
|
const token = requireToken(config, t);
|
|
233
300
|
const dir = path.resolve(process.cwd(), args[0] || '.');
|
|
301
|
+
const buildMode = Boolean(options.build);
|
|
234
302
|
|
|
235
303
|
logger.log(t('system.publish_reading_manifest'));
|
|
236
304
|
const manifest = await readSystemJson(dir, t);
|
|
237
305
|
logger.log(t('system.package_manifest_ok', { slug: manifest.slug, version: manifest.version, name: manifest.name }));
|
|
238
306
|
|
|
239
|
-
|
|
240
|
-
|
|
307
|
+
if (buildMode) {
|
|
308
|
+
const buildCmd = manifest.build_command || 'npm run build';
|
|
309
|
+
logger.log(`Building: ${buildCmd}`);
|
|
310
|
+
const { execSync } = require('child_process');
|
|
311
|
+
try {
|
|
312
|
+
execSync(buildCmd, { cwd: dir, stdio: 'inherit', timeout: 300_000 });
|
|
313
|
+
} catch (e) {
|
|
314
|
+
throw new Error(`Build failed: ${e.message}`);
|
|
315
|
+
}
|
|
316
|
+
logger.log('Build complete. Collecting compiled output (source excluded)...');
|
|
317
|
+
} else {
|
|
318
|
+
logger.log(t('system.package_collecting_files'));
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const { files, totalBytes, errors } = await collectSystemFiles(dir, { buildMode });
|
|
241
322
|
|
|
242
323
|
if (errors.length > 0) {
|
|
243
324
|
for (const e of errors) logger.log(` [WARN] ${e}`);
|
|
@@ -268,13 +349,20 @@ async function runSystemPublish({ args, options, logger, t }) {
|
|
|
268
349
|
return { ok: true, dryRun: true, manifest, fileCount, totalBytes, visibility, authorizedEmails };
|
|
269
350
|
}
|
|
270
351
|
|
|
352
|
+
logger.log('Creating ZIP package...');
|
|
353
|
+
const zipBuffer = await createZipBuffer(files);
|
|
354
|
+
const zipBase64 = zipBuffer.toString('base64');
|
|
355
|
+
const zipKb = (zipBuffer.length / 1024).toFixed(1);
|
|
356
|
+
logger.log(`ZIP: ${zipKb} KB (${fileCount} files)`);
|
|
357
|
+
|
|
271
358
|
logger.log(t('system.publish_sending'));
|
|
272
359
|
const baseUrl = resolveBaseUrl(config);
|
|
273
360
|
const response = await storePost(`${baseUrl}/api/store/systems/publish`, {
|
|
274
361
|
kind: 'aioson.store.system',
|
|
275
362
|
slug: manifest.slug,
|
|
276
363
|
version: manifest.version,
|
|
277
|
-
|
|
364
|
+
zipBase64,
|
|
365
|
+
files: buildMode ? undefined : files,
|
|
278
366
|
manifest,
|
|
279
367
|
visibility,
|
|
280
368
|
paid,
|
|
@@ -283,7 +371,7 @@ async function runSystemPublish({ args, options, logger, t }) {
|
|
|
283
371
|
}, token);
|
|
284
372
|
|
|
285
373
|
logger.log(t('system.publish_done', { slug: manifest.slug, url: `${baseUrl}/store/systems/${manifest.slug}` }));
|
|
286
|
-
logger.log(t('system.publish_summary', { files: fileCount, kb:
|
|
374
|
+
logger.log(t('system.publish_summary', { files: fileCount, kb: zipKb }));
|
|
287
375
|
return { ok: true, manifest, fileCount, totalBytes, visibility, paid, response };
|
|
288
376
|
}
|
|
289
377
|
|
package/src/i18n/messages/en.js
CHANGED
|
@@ -26,6 +26,15 @@ module.exports = {
|
|
|
26
26
|
'aioson context:pack [path] [--agent=<agent>] [--goal=<text>] [--module=<module-or-folder>] [--max-files=8] [--json] [--locale=en]',
|
|
27
27
|
help_context_load:
|
|
28
28
|
'aioson context:load [path] --target=<rule|brain>:<slug> --agent=<name> [--batch="slug1,slug2"] [--feature=<slug>] [--classification=<MICRO|SMALL|MEDIUM>] [--verbose] [--json] [--locale=en]',
|
|
29
|
+
help_chain_audit:
|
|
30
|
+
'aioson chain:audit <file> [path] [--limit=N] [--feature=<slug>] [--json] [--locale=en]',
|
|
31
|
+
chain_audit: {
|
|
32
|
+
file_required: 'chain:audit requires a file path. Usage: aioson chain:audit <file> [--limit=N] [--feature=<slug>] [--json]',
|
|
33
|
+
runtime_unavailable: 'chain:audit runtime db unavailable: {error}',
|
|
34
|
+
query_failed: 'chain:audit failed to query chain_edges: {error}',
|
|
35
|
+
no_impacts: 'chain:audit {file} → no impacts detected ({duration}ms)',
|
|
36
|
+
results_header: 'chain:audit {file} → {count} impact(s) ({duration}ms):'
|
|
37
|
+
},
|
|
29
38
|
context_load: {
|
|
30
39
|
target_required: 'context:load requires --target=<rule|brain>:<slug>.',
|
|
31
40
|
agent_required: 'context:load requires --agent=<name>.',
|
package/src/i18n/messages/es.js
CHANGED
|
@@ -27,6 +27,15 @@ module.exports = {
|
|
|
27
27
|
'aioson context:pack [path] [--agent=<agente>] [--goal=<texto>] [--module=<modulo-o-carpeta>] [--max-files=8] [--json] [--locale=es]',
|
|
28
28
|
help_context_load:
|
|
29
29
|
'aioson context:load [path] --target=<rule|brain>:<slug> --agent=<nombre> [--batch="slug1,slug2"] [--feature=<slug>] [--classification=<MICRO|SMALL|MEDIUM>] [--verbose] [--json] [--locale=es]',
|
|
30
|
+
help_chain_audit:
|
|
31
|
+
'aioson chain:audit <archivo> [path] [--limit=N] [--feature=<slug>] [--json] [--locale=es]',
|
|
32
|
+
chain_audit: {
|
|
33
|
+
file_required: 'chain:audit requiere una ruta de archivo. Uso: aioson chain:audit <archivo> [--limit=N] [--feature=<slug>] [--json]',
|
|
34
|
+
runtime_unavailable: 'chain:audit runtime db no disponible: {error}',
|
|
35
|
+
query_failed: 'chain:audit falló al consultar chain_edges: {error}',
|
|
36
|
+
no_impacts: 'chain:audit {file} → ningún impacto detectado ({duration}ms)',
|
|
37
|
+
results_header: 'chain:audit {file} → {count} impacto(s) ({duration}ms):'
|
|
38
|
+
},
|
|
30
39
|
context_load: {
|
|
31
40
|
target_required: 'context:load requiere --target=<rule|brain>:<slug>.',
|
|
32
41
|
agent_required: 'context:load requiere --agent=<nombre>.',
|
package/src/i18n/messages/fr.js
CHANGED
|
@@ -27,6 +27,15 @@ module.exports = {
|
|
|
27
27
|
'aioson context:pack [path] [--agent=<agent>] [--goal=<texte>] [--module=<module-ou-dossier>] [--max-files=8] [--json] [--locale=fr]',
|
|
28
28
|
help_context_load:
|
|
29
29
|
'aioson context:load [path] --target=<rule|brain>:<slug> --agent=<nom> [--batch="slug1,slug2"] [--feature=<slug>] [--classification=<MICRO|SMALL|MEDIUM>] [--verbose] [--json] [--locale=fr]',
|
|
30
|
+
help_chain_audit:
|
|
31
|
+
'aioson chain:audit <fichier> [path] [--limit=N] [--feature=<slug>] [--json] [--locale=fr]',
|
|
32
|
+
chain_audit: {
|
|
33
|
+
file_required: 'chain:audit exige un chemin de fichier. Usage : aioson chain:audit <fichier> [--limit=N] [--feature=<slug>] [--json]',
|
|
34
|
+
runtime_unavailable: 'chain:audit runtime db indisponible : {error}',
|
|
35
|
+
query_failed: 'chain:audit échec de la requête chain_edges : {error}',
|
|
36
|
+
no_impacts: 'chain:audit {file} → aucun impact détecté ({duration}ms)',
|
|
37
|
+
results_header: 'chain:audit {file} → {count} impact(s) ({duration}ms) :'
|
|
38
|
+
},
|
|
30
39
|
context_load: {
|
|
31
40
|
target_required: 'context:load exige --target=<rule|brain>:<slug>.',
|
|
32
41
|
agent_required: 'context:load exige --agent=<nom>.',
|
|
@@ -27,6 +27,15 @@ module.exports = {
|
|
|
27
27
|
'aioson context:pack [path] [--agent=<agente>] [--goal=<texto>] [--module=<modulo-ou-pasta>] [--max-files=8] [--json] [--locale=pt-BR]',
|
|
28
28
|
help_context_load:
|
|
29
29
|
'aioson context:load [path] --target=<rule|brain>:<slug> --agent=<nome> [--batch="slug1,slug2"] [--feature=<slug>] [--classification=<MICRO|SMALL|MEDIUM>] [--verbose] [--json] [--locale=pt-BR]',
|
|
30
|
+
help_chain_audit:
|
|
31
|
+
'aioson chain:audit <arquivo> [path] [--limit=N] [--feature=<slug>] [--json] [--locale=pt-BR]',
|
|
32
|
+
chain_audit: {
|
|
33
|
+
file_required: 'chain:audit exige um caminho de arquivo. Uso: aioson chain:audit <arquivo> [--limit=N] [--feature=<slug>] [--json]',
|
|
34
|
+
runtime_unavailable: 'chain:audit runtime db indisponível: {error}',
|
|
35
|
+
query_failed: 'chain:audit falhou ao consultar chain_edges: {error}',
|
|
36
|
+
no_impacts: 'chain:audit {file} → nenhum impacto detectado ({duration}ms)',
|
|
37
|
+
results_header: 'chain:audit {file} → {count} impacto(s) ({duration}ms):'
|
|
38
|
+
},
|
|
30
39
|
context_load: {
|
|
31
40
|
target_required: 'context:load exige --target=<rule|brain>:<slug>.',
|
|
32
41
|
agent_required: 'context:load exige --agent=<nome>.',
|