@jaimevalasek/aioson 1.29.1 → 1.30.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.
Files changed (115) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +7 -5
  3. package/docs/en/5-reference/cli-reference.md +40 -10
  4. package/docs/pt/4-agentes/pm.md +1 -1
  5. package/docs/pt/5-referencia/autopilot-handoff.md +4 -4
  6. package/docs/pt/5-referencia/comandos-cli.md +5 -3
  7. package/docs/pt/5-referencia/fluxo-artefatos.md +1 -1
  8. package/docs/pt/5-referencia/memoria-e-contexto.md +2 -2
  9. package/docs/pt/_arquivo/monitor-de-contexto.md +2 -2
  10. package/package.json +4 -2
  11. package/src/cli.js +67 -24
  12. package/src/commands/ac-test-audit.js +45 -0
  13. package/src/commands/artifact-validate.js +62 -50
  14. package/src/commands/classify.js +73 -2
  15. package/src/commands/context-brief.js +59 -0
  16. package/src/commands/context-guard.js +88 -0
  17. package/src/commands/context-monitor.js +1 -1
  18. package/src/commands/context-search.js +101 -52
  19. package/src/commands/context-select.js +11 -2
  20. package/src/commands/feature-archive.js +21 -12
  21. package/src/commands/feature-current.js +82 -0
  22. package/src/commands/gate-check.js +32 -15
  23. package/src/commands/harness-check.js +17 -1
  24. package/src/commands/hooks-install.js +169 -26
  25. package/src/commands/hygiene-scan.js +423 -0
  26. package/src/commands/rules-lint.js +11 -3
  27. package/src/commands/sdd-benchmark.js +134 -0
  28. package/src/commands/spec-analyze.js +6 -4
  29. package/src/commands/store-system.js +329 -49
  30. package/src/constants.js +19 -6
  31. package/src/context-brief.js +585 -0
  32. package/src/context-guard.js +209 -0
  33. package/src/context-search.js +796 -96
  34. package/src/context-selector.js +802 -444
  35. package/src/handoff-contract.js +14 -6
  36. package/src/harness/contract-schema.js +1 -1
  37. package/src/i18n/messages/en.js +12 -5
  38. package/src/i18n/messages/es.js +11 -4
  39. package/src/i18n/messages/fr.js +11 -4
  40. package/src/i18n/messages/pt-BR.js +12 -5
  41. package/src/lib/ac-test-audit.js +194 -0
  42. package/src/preflight-engine.js +10 -6
  43. package/src/squad/state-manager.js +1 -1
  44. package/template/.aioson/agents/analyst.md +41 -17
  45. package/template/.aioson/agents/architect.md +4 -2
  46. package/template/.aioson/agents/briefing-refiner.md +15 -2
  47. package/template/.aioson/agents/briefing.md +12 -8
  48. package/template/.aioson/agents/committer.md +1 -1
  49. package/template/.aioson/agents/copywriter.md +20 -9
  50. package/template/.aioson/agents/design-hybrid-forge.md +9 -5
  51. package/template/.aioson/agents/dev.md +22 -25
  52. package/template/.aioson/agents/deyvin.md +126 -124
  53. package/template/.aioson/agents/discover.md +3 -1
  54. package/template/.aioson/agents/discovery-design-doc.md +11 -2
  55. package/template/.aioson/agents/forge-run.md +3 -0
  56. package/template/.aioson/agents/genome.md +9 -5
  57. package/template/.aioson/agents/neo.md +30 -24
  58. package/template/.aioson/agents/orache.md +10 -6
  59. package/template/.aioson/agents/orchestrator.md +4 -2
  60. package/template/.aioson/agents/pentester.md +22 -12
  61. package/template/.aioson/agents/pm.md +5 -3
  62. package/template/.aioson/agents/product.md +25 -18
  63. package/template/.aioson/agents/profiler-enricher.md +10 -6
  64. package/template/.aioson/agents/profiler-forge.md +10 -6
  65. package/template/.aioson/agents/profiler-researcher.md +10 -6
  66. package/template/.aioson/agents/qa.md +21 -19
  67. package/template/.aioson/agents/scope-check.md +9 -3
  68. package/template/.aioson/agents/sheldon.md +22 -8
  69. package/template/.aioson/agents/site-forge.md +2 -0
  70. package/template/.aioson/agents/squad.md +4 -2
  71. package/template/.aioson/agents/tester.md +19 -15
  72. package/template/.aioson/agents/ux-ui.md +16 -8
  73. package/template/.aioson/config.md +4 -3
  74. package/template/.aioson/design-docs/agent-loading-contract.md +3 -3
  75. package/template/.aioson/docs/autopilot-handoff.md +3 -3
  76. package/template/.aioson/docs/dev/simple-plan-lane.md +73 -27
  77. package/template/.aioson/docs/dev/stack-conventions.md +1 -1
  78. package/template/.aioson/docs/deyvin/continuity-recovery.md +1 -1
  79. package/template/.aioson/docs/deyvin/runtime-handoffs.md +3 -3
  80. package/template/.aioson/docs/feature-expansion-taxonomy.md +53 -0
  81. package/template/.aioson/docs/handoff-persistence.md +14 -12
  82. package/template/.aioson/docs/integrations/dashboard-app-form-publish-mapping.md +183 -0
  83. package/template/.aioson/docs/play/README.md +72 -0
  84. package/template/.aioson/docs/play/agent-usage-guide.md +106 -0
  85. package/template/.aioson/docs/play/app-compatibility-guide.md +112 -0
  86. package/template/.aioson/docs/play/auth-services-and-testing.md +220 -0
  87. package/template/.aioson/docs/play/llm-data-and-bindings.md +238 -0
  88. package/template/.aioson/docs/play/manifest-and-runtime.md +244 -0
  89. package/template/.aioson/docs/play/source-map.md +104 -0
  90. package/template/.aioson/docs/product/conversation-playbook.md +1 -1
  91. package/template/.aioson/docs/sheldon/enrichment-paths.md +44 -1
  92. package/template/.aioson/docs/sheldon/harness-contract.md +23 -21
  93. package/template/.aioson/docs/tester/coverage-quality.md +1 -1
  94. package/template/.aioson/docs/ux-ui/design-execution.md +9 -7
  95. package/template/.aioson/rules/README.md +35 -17
  96. package/template/.aioson/rules/agent-structural-contract.md +165 -160
  97. package/template/.aioson/rules/aioson-context-boundary.md +5 -4
  98. package/template/.aioson/rules/canonical-path-contract.md +5 -4
  99. package/template/.aioson/rules/data-format-convention.md +5 -4
  100. package/template/.aioson/rules/disk-first-artifacts.md +2 -2
  101. package/template/.aioson/rules/implementation-structure-and-data-access.md +50 -0
  102. package/template/.aioson/rules/security-baseline.md +4 -3
  103. package/template/.aioson/rules/simple-plan-lane.md +18 -6
  104. package/template/.aioson/rules/source-code-language-convention.md +34 -0
  105. package/template/.aioson/skills/process/aioson-spec-driven/references/artifact-map.md +24 -23
  106. package/template/.aioson/skills/process/aioson-spec-driven/references/classification-map.md +4 -0
  107. package/template/.aioson/skills/process/aioson-spec-driven/references/dev.md +2 -2
  108. package/template/.aioson/skills/process/aioson-spec-driven/references/qa.md +1 -1
  109. package/template/.aioson/skills/process/briefing-expansion-scout/SKILL.md +72 -0
  110. package/template/.aioson/skills/process/product-scope-expansion/SKILL.md +74 -0
  111. package/template/.aioson/skills/process/sheldon-expansion-audit/SKILL.md +67 -0
  112. package/template/.aioson/skills/static/context-budget-guide.md +1 -1
  113. package/template/.aioson/skills/static/multi-agent-patterns.md +5 -4
  114. package/template/AGENTS.md +36 -19
  115. package/template/CLAUDE.md +9 -5
@@ -0,0 +1,209 @@
1
+ 'use strict';
2
+
3
+ const path = require('node:path');
4
+ const { buildContextBrief, extractDocConstraints } = require('./context-brief');
5
+ const { parseFrontmatter, readFileSafe } = require('./preflight-engine');
6
+
7
+ // Harness-agnostic core for `context:guard`.
8
+ //
9
+ // Operational retrieval loop: a harness extension point (e.g. a Claude Code
10
+ // PreToolUse hook) feeds the pending tool event in, and the guard derives a
11
+ // query from the artifact itself — never from a model-emitted keyword list —
12
+ // runs the proven context:brief engine, and returns an injection payload when a
13
+ // project rule is genuinely salient to the change about to be written.
14
+
15
+ // File-mutating tools whose payload is worth checking against project rules.
16
+ const MUTATING_TOOLS = new Set(['Write', 'Edit', 'MultiEdit', 'NotebookEdit']);
17
+
18
+ // A rule only counts when context:brief routed it through a hard signal, never
19
+ // through a foundation always-load or a pure semantic guess.
20
+ const HARD_SIGNAL = /(?:triggers|paths|entities|aliases|task_types):/;
21
+
22
+ // Salience gate: a rule opts into guard injection by declaring `entities` or
23
+ // `aliases`, or by explicitly setting `guard: true` in frontmatter. The explicit
24
+ // opt-in is for project contracts that are path/task-bound but not domain-entity
25
+ // rules (e.g. agent prompt structure). Generic baseline rules remain silent.
26
+ const DOMAIN_SIGNAL = /(?:entities|aliases):/;
27
+
28
+ // A guard rule that declares `paths` is a contract over those files. It may
29
+ // still surface in the brief via fuzzy trigger/description keyword overlap when
30
+ // an UNRELATED file is edited — but it must only inject when the edited path is
31
+ // actually in scope. This `paths:` reason is the proof the file matched.
32
+ const PATH_MATCH_SIGNAL = /\bpaths:/;
33
+
34
+ // Tunable relevance gate.
35
+ const GUARD_GATE = {
36
+ minConfidence: 'medium', // 'low' briefs never inject
37
+ maxConstraints: 10,
38
+ maxForbidden: 6,
39
+ maxContentChars: 4000
40
+ };
41
+
42
+ const CONFIDENCE_RANK = { low: 0, medium: 1, high: 2 };
43
+
44
+ function emptyResponse() {
45
+ return {};
46
+ }
47
+
48
+ function extractEditedContent(toolInput = {}) {
49
+ const parts = [];
50
+ if (typeof toolInput.content === 'string') parts.push(toolInput.content);
51
+ if (typeof toolInput.new_string === 'string') parts.push(toolInput.new_string);
52
+ if (typeof toolInput.old_string === 'string') parts.push(toolInput.old_string);
53
+ if (typeof toolInput.new_source === 'string') parts.push(toolInput.new_source);
54
+ if (Array.isArray(toolInput.edits)) {
55
+ for (const edit of toolInput.edits) {
56
+ if (edit && typeof edit.new_string === 'string') parts.push(edit.new_string);
57
+ }
58
+ }
59
+ return parts.join('\n');
60
+ }
61
+
62
+ function deriveQuery(filePath, content, limit = GUARD_GATE.maxContentChars) {
63
+ const base = filePath
64
+ ? path.basename(String(filePath)).replace(/\.[^.]+$/, '').replace(/[_-]+/g, ' ')
65
+ : '';
66
+ const body = String(content || '').slice(0, limit);
67
+ return `${base} ${body}`.trim();
68
+ }
69
+
70
+ function matchedRules(brief) {
71
+ return (brief.must_load || []).filter((item) => (
72
+ item.surface === 'rules' && HARD_SIGNAL.test(item.reason || '')
73
+ ));
74
+ }
75
+
76
+ function truthyFrontmatter(value) {
77
+ return ['1', 'true', 'yes', 'on'].includes(String(value || '').trim().toLowerCase());
78
+ }
79
+
80
+ function ruleDeclaresPaths(frontmatter) {
81
+ return Boolean(frontmatter && (frontmatter.paths || frontmatter.globs));
82
+ }
83
+
84
+ function ruleAllowsGuard(rule, frontmatter) {
85
+ const reason = rule.reason || '';
86
+ if (DOMAIN_SIGNAL.test(reason)) return true;
87
+ if (!truthyFrontmatter(frontmatter.guard) || !HARD_SIGNAL.test(reason)) return false;
88
+ // Path-scoped guard rule: inject only when the edited file is genuinely in its
89
+ // declared path scope, never on fuzzy keyword spill from an unrelated file.
90
+ if (ruleDeclaresPaths(frontmatter) && !PATH_MATCH_SIGNAL.test(reason)) return false;
91
+ return true;
92
+ }
93
+
94
+ function confidenceAllows(confidence, gate) {
95
+ const have = CONFIDENCE_RANK[confidence] ?? 0;
96
+ const need = CONFIDENCE_RANK[gate.minConfidence] ?? 1;
97
+ return have >= need;
98
+ }
99
+
100
+ function dedupeStrings(items) {
101
+ const seen = new Set();
102
+ const out = [];
103
+ for (const item of items || []) {
104
+ const text = String(item || '').trim();
105
+ if (!text || seen.has(text)) continue;
106
+ seen.add(text);
107
+ out.push(text);
108
+ }
109
+ return out;
110
+ }
111
+
112
+ function normalizeRuleLine(value) {
113
+ return String(value || '').trim().toLowerCase();
114
+ }
115
+
116
+ // Read each salient rule file and extract ITS OWN constraints — so the
117
+ // injection is attributed per rule and never carries the generic concern-based
118
+ // constraints the brief aggregates from the whole selection.
119
+ async function buildRuleBlocks(targetDir, salient, gate) {
120
+ const blocks = [];
121
+ for (const rule of salient) {
122
+ const content = await readFileSafe(path.join(targetDir, rule.path));
123
+ if (!content) continue;
124
+ const frontmatter = parseFrontmatter(content);
125
+ if (!ruleAllowsGuard(rule, frontmatter)) continue;
126
+ const extracted = extractDocConstraints(content);
127
+ const constraints = dedupeStrings(extracted.constraints).slice(0, gate.maxConstraints);
128
+ const constraintSet = new Set(constraints.map(normalizeRuleLine));
129
+ const forbidden = dedupeStrings(extracted.forbidden_patterns)
130
+ .filter((item) => !constraintSet.has(normalizeRuleLine(item)))
131
+ .slice(0, gate.maxForbidden);
132
+ if (constraints.length === 0 && forbidden.length === 0) continue;
133
+ blocks.push({ path: rule.path, constraints, forbidden });
134
+ }
135
+ return blocks;
136
+ }
137
+
138
+ function formatInjectionText(filePath, ruleBlocks) {
139
+ const target = filePath ? path.basename(String(filePath)) : 'this change';
140
+ const lines = [`[AIOSON context:guard] Project rules apply to ${target}:`];
141
+ for (const block of ruleBlocks) {
142
+ lines.push(`Rule ${block.path}:`);
143
+ for (const constraint of block.constraints) lines.push(`- ${constraint}`);
144
+ for (const pattern of block.forbidden) lines.push(`- (forbidden) ${pattern}`);
145
+ }
146
+ return lines.join('\n');
147
+ }
148
+
149
+ function formatForTool(tool, additionalContext) {
150
+ // Only the Claude Code adapter exists today; other harnesses default to it
151
+ // until their own extension point is wired.
152
+ switch (tool) {
153
+ case 'claude':
154
+ default:
155
+ return {
156
+ hookSpecificOutput: {
157
+ hookEventName: 'PreToolUse',
158
+ additionalContext
159
+ }
160
+ };
161
+ }
162
+ }
163
+
164
+ async function buildGuardResponse(event, targetDir, options = {}) {
165
+ const gate = { ...GUARD_GATE, ...(options.gate || {}) };
166
+ const toolName = event && event.tool_name;
167
+ const toolInput = (event && event.tool_input) || {};
168
+ if (!MUTATING_TOOLS.has(toolName)) return emptyResponse();
169
+
170
+ const filePath = toolInput.file_path || toolInput.notebook_path || '';
171
+ const content = extractEditedContent(toolInput);
172
+ if (!filePath && !content) return emptyResponse();
173
+
174
+ const query = deriveQuery(filePath, content, gate.maxContentChars);
175
+ if (!query) return emptyResponse();
176
+
177
+ const brief = await buildContextBrief(targetDir, {
178
+ agent: options.agent || 'dev',
179
+ mode: 'executing',
180
+ task: query,
181
+ paths: filePath
182
+ });
183
+
184
+ const ruled = matchedRules(brief);
185
+ if (ruled.length === 0) return emptyResponse();
186
+ if (!confidenceAllows(brief.confidence, gate)) return emptyResponse();
187
+
188
+ const ruleBlocks = await buildRuleBlocks(targetDir, ruled, gate);
189
+ if (ruleBlocks.length === 0) return emptyResponse();
190
+
191
+ const additionalContext = formatInjectionText(filePath, ruleBlocks);
192
+ const response = formatForTool(options.tool || 'claude', additionalContext);
193
+ response._guard = {
194
+ injected: true,
195
+ rules: ruleBlocks.map((block) => block.path),
196
+ confidence: brief.confidence
197
+ };
198
+ return response;
199
+ }
200
+
201
+ module.exports = {
202
+ buildGuardResponse,
203
+ deriveQuery,
204
+ extractEditedContent,
205
+ matchedRules,
206
+ ruleAllowsGuard,
207
+ MUTATING_TOOLS,
208
+ GUARD_GATE
209
+ };