@jaimevalasek/aioson 1.28.1 → 1.30.0
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 +42 -0
- package/README.md +7 -5
- package/docs/en/5-reference/cli-reference.md +40 -10
- package/docs/pt/4-agentes/briefing.md +2 -0
- package/docs/pt/4-agentes/copywriter.md +2 -0
- package/docs/pt/4-agentes/genome.md +1 -0
- package/docs/pt/4-agentes/pm.md +1 -1
- package/docs/pt/4-agentes/profiler-enricher.md +2 -0
- package/docs/pt/4-agentes/profiler-forge.md +2 -0
- package/docs/pt/4-agentes/sheldon.md +2 -0
- package/docs/pt/4-agentes/squad.md +12 -10
- package/docs/pt/5-referencia/autopilot-handoff.md +4 -4
- package/docs/pt/5-referencia/comandos-cli.md +7 -3
- package/docs/pt/5-referencia/fluxo-artefatos.md +1 -1
- package/docs/pt/5-referencia/memoria-e-contexto.md +62 -2
- package/docs/pt/_arquivo/monitor-de-contexto.md +2 -2
- package/package.json +4 -2
- package/src/cli.js +72 -24
- package/src/commands/ac-test-audit.js +45 -0
- package/src/commands/artifact-validate.js +62 -50
- package/src/commands/classify.js +73 -2
- package/src/commands/context-brief.js +59 -0
- package/src/commands/context-guard.js +88 -0
- package/src/commands/context-monitor.js +1 -1
- package/src/commands/context-search.js +101 -52
- package/src/commands/context-select.js +11 -2
- package/src/commands/feature-archive.js +21 -12
- package/src/commands/feature-current.js +82 -0
- package/src/commands/gate-check.js +32 -15
- package/src/commands/harness-check.js +17 -1
- package/src/commands/hooks-install.js +169 -26
- package/src/commands/hygiene-scan.js +423 -0
- package/src/commands/rules-lint.js +124 -0
- package/src/commands/sdd-benchmark.js +134 -0
- package/src/commands/spec-analyze.js +6 -4
- package/src/commands/store-system.js +329 -49
- package/src/constants.js +8 -3
- package/src/context-brief.js +585 -0
- package/src/context-guard.js +209 -0
- package/src/context-search.js +796 -96
- package/src/context-selector.js +802 -420
- package/src/handoff-contract.js +14 -6
- package/src/harness/contract-schema.js +1 -1
- package/src/i18n/messages/en.js +12 -5
- package/src/i18n/messages/es.js +11 -4
- package/src/i18n/messages/fr.js +11 -4
- package/src/i18n/messages/pt-BR.js +12 -5
- package/src/lib/ac-test-audit.js +194 -0
- package/src/preflight-engine.js +10 -6
- package/src/squad/state-manager.js +1 -1
- package/template/.aioson/agents/analyst.md +93 -53
- package/template/.aioson/agents/architect.md +41 -32
- package/template/.aioson/agents/briefing-refiner.md +15 -2
- package/template/.aioson/agents/briefing.md +105 -86
- package/template/.aioson/agents/committer.md +1 -1
- package/template/.aioson/agents/copywriter.md +53 -10
- package/template/.aioson/agents/design-hybrid-forge.md +9 -5
- package/template/.aioson/agents/dev.md +22 -25
- package/template/.aioson/agents/deyvin.md +126 -124
- package/template/.aioson/agents/discover.md +8 -9
- package/template/.aioson/agents/discovery-design-doc.md +52 -36
- package/template/.aioson/agents/forge-run.md +3 -0
- package/template/.aioson/agents/genome.md +12 -6
- package/template/.aioson/agents/neo.md +30 -24
- package/template/.aioson/agents/orache.md +16 -21
- package/template/.aioson/agents/orchestrator.md +40 -31
- package/template/.aioson/agents/pentester.md +22 -12
- package/template/.aioson/agents/pm.md +11 -2
- package/template/.aioson/agents/product.md +162 -183
- package/template/.aioson/agents/profiler-enricher.md +29 -6
- package/template/.aioson/agents/profiler-forge.md +16 -6
- package/template/.aioson/agents/profiler-researcher.md +10 -6
- package/template/.aioson/agents/qa.md +29 -19
- package/template/.aioson/agents/scope-check.md +14 -2
- package/template/.aioson/agents/sheldon.md +51 -21
- package/template/.aioson/agents/site-forge.md +4 -6
- package/template/.aioson/agents/squad.md +7 -12
- package/template/.aioson/agents/tester.md +40 -30
- package/template/.aioson/agents/ux-ui.md +56 -41
- package/template/.aioson/agents/validator.md +2 -2
- package/template/.aioson/config.md +4 -3
- package/template/.aioson/design-docs/agent-loading-contract.md +3 -3
- package/template/.aioson/docs/LAYERS.md +2 -0
- package/template/.aioson/docs/autonomy-protocol.md +7 -5
- package/template/.aioson/docs/autopilot-handoff.md +5 -3
- package/template/.aioson/docs/dev/execution-discipline.md +3 -0
- package/template/.aioson/docs/dev/simple-plan-lane.md +126 -77
- package/template/.aioson/docs/dev/stack-conventions.md +4 -1
- package/template/.aioson/docs/deyvin/continuity-recovery.md +21 -18
- package/template/.aioson/docs/deyvin/debugging-escalation.md +3 -0
- package/template/.aioson/docs/deyvin/pair-execution.md +3 -0
- package/template/.aioson/docs/deyvin/runtime-handoffs.md +6 -3
- package/template/.aioson/docs/dossier/agent-templates.md +3 -0
- package/template/.aioson/docs/dossier/schema.md +3 -0
- package/template/.aioson/docs/example-external-api-context.md +2 -0
- package/template/.aioson/docs/feature-expansion-taxonomy.md +53 -0
- package/template/.aioson/docs/handoff-persistence.md +95 -91
- package/template/.aioson/docs/pentester/app-playbooks.md +3 -0
- package/template/.aioson/docs/pentester/browser-dast-playbook.md +401 -398
- package/template/.aioson/docs/pentester/llm-supplychain.md +3 -0
- package/template/.aioson/docs/product/conversation-playbook.md +1 -1
- package/template/.aioson/docs/quality/code-health-analysis.md +2 -0
- package/template/.aioson/docs/sheldon/enrichment-paths.md +47 -1
- package/template/.aioson/docs/sheldon/harness-contract.md +26 -21
- package/template/.aioson/docs/sheldon/quality-lens.md +3 -0
- package/template/.aioson/docs/sheldon/research-loop.md +3 -0
- package/template/.aioson/docs/sheldon/web-intelligence.md +3 -0
- package/template/.aioson/docs/site-forge-build.md +4 -2
- package/template/.aioson/docs/site-forge-extraction.md +2 -0
- package/template/.aioson/docs/site-forge-qa.md +2 -0
- package/template/.aioson/docs/site-forge-recon.md +7 -5
- package/template/.aioson/docs/site-forge-transform.md +2 -0
- package/template/.aioson/docs/squad/content-output.md +3 -0
- package/template/.aioson/docs/squad/creation-flow.md +22 -1
- package/template/.aioson/docs/squad/domain-breadth.md +3 -0
- package/template/.aioson/docs/squad/domain-classification.md +3 -0
- package/template/.aioson/docs/squad/eval-gate.md +3 -0
- package/template/.aioson/docs/squad/genome-bindings.md +14 -0
- package/template/.aioson/docs/squad/package-contract.md +5 -0
- package/template/.aioson/docs/squad/persona-grounding.md +65 -62
- package/template/.aioson/docs/squad/quality-lens.md +3 -0
- package/template/.aioson/docs/squad/research-loop.md +3 -0
- package/template/.aioson/docs/squad/session-operations.md +3 -0
- package/template/.aioson/docs/squad/workflow-quality.md +3 -0
- package/template/.aioson/docs/tester/coverage-quality.md +4 -1
- package/template/.aioson/docs/ux-ui/design-execution.md +9 -7
- package/template/.aioson/rules/README.md +48 -2
- package/template/.aioson/rules/agent-language-policy.md +26 -21
- package/template/.aioson/rules/agent-structural-contract.md +168 -158
- package/template/.aioson/rules/aioson-context-boundary.md +7 -1
- package/template/.aioson/rules/canonical-path-contract.md +16 -10
- package/template/.aioson/rules/data-format-convention.md +17 -11
- package/template/.aioson/rules/disk-first-artifacts.md +12 -8
- package/template/.aioson/rules/example-monetary-values.md +4 -0
- package/template/.aioson/rules/implementation-structure-and-data-access.md +50 -0
- package/template/.aioson/rules/output-brevity.md +2 -0
- package/template/.aioson/rules/prd-section-ownership.md +17 -12
- package/template/.aioson/rules/security-baseline.md +8 -3
- package/template/.aioson/rules/simple-plan-lane.md +22 -5
- package/template/.aioson/rules/source-code-language-convention.md +34 -0
- package/template/.aioson/rules/spec-level-ownership.md +10 -5
- package/template/.aioson/rules/squad-driver-pattern.md +5 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/artifact-map.md +24 -23
- package/template/.aioson/skills/process/aioson-spec-driven/references/classification-map.md +4 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/dev.md +2 -2
- package/template/.aioson/skills/process/aioson-spec-driven/references/qa.md +1 -1
- package/template/.aioson/skills/process/briefing-expansion-scout/SKILL.md +72 -0
- package/template/.aioson/skills/process/product-scope-expansion/SKILL.md +74 -0
- package/template/.aioson/skills/process/sheldon-expansion-audit/SKILL.md +67 -0
- package/template/.aioson/skills/static/context-budget-guide.md +1 -1
- package/template/.aioson/skills/static/multi-agent-patterns.md +5 -4
- package/template/.aioson/tasks/squad-create.md +11 -0
- package/template/.aioson/tasks/squad-design.md +3 -3
- package/template/AGENTS.md +36 -19
- package/template/CLAUDE.md +9 -5
package/src/cli.js
CHANGED
|
@@ -14,6 +14,8 @@ 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 { runContextSelect } = require('./commands/context-select');
|
|
17
|
+
const { runContextBrief } = require('./commands/context-brief');
|
|
18
|
+
const { runRulesLint } = require('./commands/rules-lint');
|
|
17
19
|
const { runContextLoad } = require('./commands/context-load');
|
|
18
20
|
const { runChainAudit } = require('./commands/chain-audit');
|
|
19
21
|
const { runMemorySearch } = require('./commands/memory-search');
|
|
@@ -147,15 +149,17 @@ const { runBackupLocal } = require('./commands/backup-local-cmd');
|
|
|
147
149
|
const { runRecoveryGenerate, runRecoveryShow } = require('./commands/recovery');
|
|
148
150
|
const { runContextMonitor } = require('./commands/context-monitor');
|
|
149
151
|
const { runContextSearch, runContextSearchIndex } = require('./commands/context-search');
|
|
152
|
+
const { runContextGuard } = require('./commands/context-guard');
|
|
150
153
|
const { runContextCacheList, runContextCacheSave, runContextCacheRestore, runContextCacheCleanup } = require('./commands/context-cache');
|
|
151
154
|
const { runSandboxExec } = require('./commands/sandbox');
|
|
152
155
|
const { runAgentLoad, runAgentShardIndex } = require('./commands/agent-loader');
|
|
153
156
|
const { runLearningEvolve, runLearningApply } = require('./commands/learning-evolve');
|
|
154
157
|
const { runLearningRollback } = require('./commands/learning-rollback');
|
|
155
|
-
const { runToolRegistry } = require('./commands/tool-registry-cmd');
|
|
156
|
-
const { runHealth } = require('./commands/health');
|
|
157
|
-
const { runContextHealth } = require('./commands/context-health');
|
|
158
|
-
const {
|
|
158
|
+
const { runToolRegistry } = require('./commands/tool-registry-cmd');
|
|
159
|
+
const { runHealth } = require('./commands/health');
|
|
160
|
+
const { runContextHealth } = require('./commands/context-health');
|
|
161
|
+
const { runHygieneScan } = require('./commands/hygiene-scan');
|
|
162
|
+
const { runContextTrim } = require('./commands/context-trim');
|
|
159
163
|
const { runHooksEmit } = require('./commands/hooks-emit');
|
|
160
164
|
const { runHooksInstall, runHooksUninstall } = require('./commands/hooks-install');
|
|
161
165
|
const { runSessionGuard } = require('./commands/session-guard');
|
|
@@ -197,12 +201,15 @@ const { runOpMigrate } = require('./commands/op-migrate');
|
|
|
197
201
|
const { runFeatureClose } = require('./commands/feature-close');
|
|
198
202
|
const { runFeatureArchive, runFeatureSweep } = require('./commands/feature-archive');
|
|
199
203
|
const { runFeatureExport } = require('./commands/feature-export');
|
|
204
|
+
const { runFeatureCurrent } = require('./commands/feature-current');
|
|
200
205
|
const { runDossierInit, runDossierShow, runDossierAddFinding, runDossierAddCodemap, runDossierLinkRule, runDossierCompact } = require('./commands/dossier');
|
|
201
206
|
const { runDossierAddResearch } = require('./commands/dossier-add-research');
|
|
202
207
|
const { runDossierAudit } = require('./commands/dossier-audit');
|
|
203
208
|
const { runDevResumeData } = require('./commands/dev-resume');
|
|
204
|
-
const { runRevisionOpen, runRevisionList, runRevisionResolve } = require('./commands/revision');
|
|
205
|
-
const {
|
|
209
|
+
const { runRevisionOpen, runRevisionList, runRevisionResolve } = require('./commands/revision');
|
|
210
|
+
const { runAcTestAudit } = require('./commands/ac-test-audit');
|
|
211
|
+
const { runSddBenchmark } = require('./commands/sdd-benchmark');
|
|
212
|
+
const { runGateCheck } = require('./commands/gate-check');
|
|
206
213
|
const { runGateApprove } = require('./commands/gate-approve');
|
|
207
214
|
const { runArtifactValidate } = require('./commands/artifact-validate');
|
|
208
215
|
const { runWorkflowExecute } = require('./commands/workflow-execute');
|
|
@@ -257,6 +264,12 @@ const JSON_SUPPORTED_COMMANDS = new Set([
|
|
|
257
264
|
'context-pack',
|
|
258
265
|
'context:select',
|
|
259
266
|
'context-select',
|
|
267
|
+
'context:brief',
|
|
268
|
+
'context-brief',
|
|
269
|
+
'context:guard',
|
|
270
|
+
'context-guard',
|
|
271
|
+
'rules:lint',
|
|
272
|
+
'rules-lint',
|
|
260
273
|
'context:load',
|
|
261
274
|
'context-load',
|
|
262
275
|
'chain:audit',
|
|
@@ -275,6 +288,8 @@ const JSON_SUPPORTED_COMMANDS = new Set([
|
|
|
275
288
|
'workflow-next',
|
|
276
289
|
'workflow:status',
|
|
277
290
|
'workflow-status',
|
|
291
|
+
'feature:current',
|
|
292
|
+
'feature-current',
|
|
278
293
|
'harness:retro',
|
|
279
294
|
'harness-retro',
|
|
280
295
|
'harness:preview',
|
|
@@ -596,12 +611,16 @@ const JSON_SUPPORTED_COMMANDS = new Set([
|
|
|
596
611
|
'recovery-show',
|
|
597
612
|
'context:monitor',
|
|
598
613
|
'context-monitor',
|
|
599
|
-
'context:health',
|
|
600
|
-
'context-health',
|
|
601
|
-
'
|
|
614
|
+
'context:health',
|
|
615
|
+
'context-health',
|
|
616
|
+
'hygiene:scan',
|
|
617
|
+
'hygiene-scan',
|
|
618
|
+
'context:trim',
|
|
602
619
|
'context-trim',
|
|
603
620
|
'context:search',
|
|
604
621
|
'context-search',
|
|
622
|
+
'context:index',
|
|
623
|
+
'context-index',
|
|
605
624
|
'context:search:index',
|
|
606
625
|
'context-search-index',
|
|
607
626
|
'context:cache',
|
|
@@ -666,6 +685,8 @@ const JSON_SUPPORTED_COMMANDS = new Set([
|
|
|
666
685
|
'feature-sweep',
|
|
667
686
|
'feature:export',
|
|
668
687
|
'feature-export',
|
|
688
|
+
'feature:current',
|
|
689
|
+
'feature-current',
|
|
669
690
|
'dossier:init',
|
|
670
691
|
'dossier-init',
|
|
671
692
|
'dossier:show',
|
|
@@ -688,9 +709,13 @@ const JSON_SUPPORTED_COMMANDS = new Set([
|
|
|
688
709
|
'revision-open',
|
|
689
710
|
'revision:list',
|
|
690
711
|
'revision-list',
|
|
691
|
-
'revision:resolve',
|
|
692
|
-
'revision-resolve',
|
|
693
|
-
'
|
|
712
|
+
'revision:resolve',
|
|
713
|
+
'revision-resolve',
|
|
714
|
+
'ac:test-audit',
|
|
715
|
+
'ac-test-audit',
|
|
716
|
+
'sdd:benchmark',
|
|
717
|
+
'sdd-benchmark',
|
|
718
|
+
'gate:check',
|
|
694
719
|
'gate-check',
|
|
695
720
|
'gate:approve',
|
|
696
721
|
'gate-approve',
|
|
@@ -807,9 +832,10 @@ function printHelp(t, logger) {
|
|
|
807
832
|
logHelpLine(t, logger, 'cli.help_install');
|
|
808
833
|
logHelpLine(t, logger, 'cli.help_setup');
|
|
809
834
|
logHelpLine(t, logger, 'cli.help_update');
|
|
810
|
-
logHelpLine(t, logger, 'cli.help_info');
|
|
811
|
-
logHelpLine(t, logger, 'cli.help_doctor');
|
|
812
|
-
logHelpLine(t, logger, 'cli.
|
|
835
|
+
logHelpLine(t, logger, 'cli.help_info');
|
|
836
|
+
logHelpLine(t, logger, 'cli.help_doctor');
|
|
837
|
+
logHelpLine(t, logger, 'cli.help_hygiene_scan');
|
|
838
|
+
logHelpLine(t, logger, 'cli.help_i18n_add');
|
|
813
839
|
logHelpLine(t, logger, 'cli.help_agents');
|
|
814
840
|
logHelpLine(t, logger, 'cli.help_agent_prompt');
|
|
815
841
|
logHelpLine(t, logger, 'cli.help_agent_help');
|
|
@@ -817,7 +843,10 @@ function printHelp(t, logger) {
|
|
|
817
843
|
logHelpLine(t, logger, 'cli.help_agent_epilogue');
|
|
818
844
|
logHelpLine(t, logger, 'cli.help_context_validate');
|
|
819
845
|
logHelpLine(t, logger, 'cli.help_context_pack');
|
|
846
|
+
logHelpLine(t, logger, 'cli.help_context_search');
|
|
820
847
|
logHelpLine(t, logger, 'cli.help_context_select');
|
|
848
|
+
logHelpLine(t, logger, 'cli.help_context_brief');
|
|
849
|
+
logHelpLine(t, logger, 'cli.help_context_guard');
|
|
821
850
|
logHelpLine(t, logger, 'cli.help_context_load');
|
|
822
851
|
logHelpLine(t, logger, 'cli.help_memory_status');
|
|
823
852
|
logHelpLine(t, logger, 'cli.help_memory_summary');
|
|
@@ -1105,6 +1134,12 @@ async function main() {
|
|
|
1105
1134
|
result = await runContextPack({ args, options, logger: commandLogger, t });
|
|
1106
1135
|
} else if (command === 'context:select' || command === 'context-select') {
|
|
1107
1136
|
result = await runContextSelect({ args, options, logger: commandLogger, t });
|
|
1137
|
+
} else if (command === 'context:brief' || command === 'context-brief') {
|
|
1138
|
+
result = await runContextBrief({ args, options, logger: commandLogger, t });
|
|
1139
|
+
} else if (command === 'context:guard' || command === 'context-guard') {
|
|
1140
|
+
result = await runContextGuard({ args, options, logger: commandLogger, t });
|
|
1141
|
+
} else if (command === 'rules:lint' || command === 'rules-lint') {
|
|
1142
|
+
result = await runRulesLint({ args, options, logger: commandLogger, t });
|
|
1108
1143
|
} else if (command === 'context:load' || command === 'context-load') {
|
|
1109
1144
|
result = await runContextLoad({ args, options, logger: commandLogger, t });
|
|
1110
1145
|
} else if (command === 'chain:audit' || command === 'chain-audit') {
|
|
@@ -1505,13 +1540,20 @@ async function main() {
|
|
|
1505
1540
|
result = await runRecoveryShow({ args, options, logger: commandLogger, t });
|
|
1506
1541
|
} else if (command === 'context:monitor' || command === 'context-monitor') {
|
|
1507
1542
|
result = await runContextMonitor({ args, options, logger: commandLogger, t });
|
|
1508
|
-
} else if (command === 'context:health' || command === 'context-health') {
|
|
1509
|
-
result = await runContextHealth({ args, options, logger: commandLogger });
|
|
1510
|
-
} else if (command === '
|
|
1511
|
-
result = await
|
|
1543
|
+
} else if (command === 'context:health' || command === 'context-health') {
|
|
1544
|
+
result = await runContextHealth({ args, options, logger: commandLogger });
|
|
1545
|
+
} else if (command === 'hygiene:scan' || command === 'hygiene-scan') {
|
|
1546
|
+
result = await runHygieneScan({ args, options, logger: commandLogger });
|
|
1547
|
+
} else if (command === 'context:trim' || command === 'context-trim') {
|
|
1548
|
+
result = await runContextTrim({ args, options, logger: commandLogger });
|
|
1512
1549
|
} else if (command === 'context:search' || command === 'context-search') {
|
|
1513
1550
|
result = await runContextSearch({ args, options, logger: commandLogger, t });
|
|
1514
|
-
} else if (
|
|
1551
|
+
} else if (
|
|
1552
|
+
command === 'context:index' ||
|
|
1553
|
+
command === 'context-index' ||
|
|
1554
|
+
command === 'context:search:index' ||
|
|
1555
|
+
command === 'context-search-index'
|
|
1556
|
+
) {
|
|
1515
1557
|
result = await runContextSearchIndex({ args, options, logger: commandLogger, t });
|
|
1516
1558
|
} else if (command === 'context:cache' || command === 'context-cache') {
|
|
1517
1559
|
result = await runContextCacheList({ args, options, logger: commandLogger, t });
|
|
@@ -1591,6 +1633,8 @@ async function main() {
|
|
|
1591
1633
|
result = await runFeatureSweep({ args, options, logger: commandLogger });
|
|
1592
1634
|
} else if (command === 'feature:export' || command === 'feature-export') {
|
|
1593
1635
|
result = await runFeatureExport({ args, options, logger: commandLogger });
|
|
1636
|
+
} else if (command === 'feature:current' || command === 'feature-current') {
|
|
1637
|
+
result = await runFeatureCurrent({ args, options, logger: commandLogger });
|
|
1594
1638
|
} else if (command === 'dossier:init' || command === 'dossier-init') {
|
|
1595
1639
|
result = await runDossierInit({ args, options, logger: commandLogger });
|
|
1596
1640
|
} else if (command === 'dossier:show' || command === 'dossier-show') {
|
|
@@ -1613,10 +1657,14 @@ async function main() {
|
|
|
1613
1657
|
result = await runRevisionOpen({ args, options, logger: commandLogger });
|
|
1614
1658
|
} else if (command === 'revision:list' || command === 'revision-list') {
|
|
1615
1659
|
result = await runRevisionList({ args, options, logger: commandLogger });
|
|
1616
|
-
} else if (command === 'revision:resolve' || command === 'revision-resolve') {
|
|
1617
|
-
result = await runRevisionResolve({ args, options, logger: commandLogger });
|
|
1618
|
-
} else if (command === '
|
|
1619
|
-
result = await
|
|
1660
|
+
} else if (command === 'revision:resolve' || command === 'revision-resolve') {
|
|
1661
|
+
result = await runRevisionResolve({ args, options, logger: commandLogger });
|
|
1662
|
+
} else if (command === 'ac:test-audit' || command === 'ac-test-audit') {
|
|
1663
|
+
result = await runAcTestAudit({ args, options, logger: commandLogger });
|
|
1664
|
+
} else if (command === 'sdd:benchmark' || command === 'sdd-benchmark') {
|
|
1665
|
+
result = await runSddBenchmark({ args, options, logger: commandLogger });
|
|
1666
|
+
} else if (command === 'gate:check' || command === 'gate-check') {
|
|
1667
|
+
result = await runGateCheck({ args, options, logger: commandLogger });
|
|
1620
1668
|
} else if (command === 'gate:approve' || command === 'gate-approve') {
|
|
1621
1669
|
result = await runGateApprove({ args, options, logger: commandLogger });
|
|
1622
1670
|
} else if (command === 'artifact:validate' || command === 'artifact-validate') {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { auditAcceptanceCriteriaTests } = require('../lib/ac-test-audit');
|
|
5
|
+
|
|
6
|
+
async function runAcTestAudit({ args, options = {}, logger }) {
|
|
7
|
+
const targetDir = path.resolve(process.cwd(), args?.[0] || '.');
|
|
8
|
+
const slug = String(options.feature || options.slug || '').trim();
|
|
9
|
+
|
|
10
|
+
if (!slug) {
|
|
11
|
+
if (options.json) return { ok: false, error: 'missing_feature' };
|
|
12
|
+
logger.error('--feature=<slug> is required.');
|
|
13
|
+
return { ok: false, error: 'missing_feature' };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const report = await auditAcceptanceCriteriaTests(targetDir, slug);
|
|
17
|
+
|
|
18
|
+
if (options.json) {
|
|
19
|
+
logger.log(JSON.stringify(report, null, 2));
|
|
20
|
+
return report;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
logger.log('');
|
|
24
|
+
logger.log(`AC test audit — ${slug}`);
|
|
25
|
+
logger.log('━'.repeat(45));
|
|
26
|
+
logger.log(`ACs: ${report.summary.covered}/${report.summary.acs_total} covered; tests scanned: ${report.summary.test_files_scanned}`);
|
|
27
|
+
|
|
28
|
+
if (report.summary.acs_total === 0) {
|
|
29
|
+
logger.log('No acceptance criteria IDs found in requirements, PRD, or conformance artifacts.');
|
|
30
|
+
} else {
|
|
31
|
+
for (const item of report.items) {
|
|
32
|
+
const mark = item.status === 'covered' ? '✓' : '✗';
|
|
33
|
+
const evidence = item.evidence.length
|
|
34
|
+
? ` — ${item.evidence.map((e) => e.file).join(', ')}`
|
|
35
|
+
: '';
|
|
36
|
+
logger.log(` ${mark} ${item.ac}: ${item.status}${evidence}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
logger.log('');
|
|
41
|
+
logger.log(report.ok ? 'Result: PASS' : `Result: BLOCKED — missing tests for ${report.missing.join(', ')}`);
|
|
42
|
+
return report;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = { runAcTestAudit };
|
|
@@ -19,23 +19,25 @@ const {
|
|
|
19
19
|
parseFrontmatter,
|
|
20
20
|
contextDir
|
|
21
21
|
} = require('../preflight-engine');
|
|
22
|
+
const { AC_ID_RE } = require('../lib/ac-test-audit');
|
|
22
23
|
|
|
23
24
|
const BAR = '━'.repeat(45);
|
|
25
|
+
const REQ_ID_RE = /\bREQ(?:-[A-Za-z0-9]+)+\b/g;
|
|
24
26
|
|
|
25
|
-
function gateDisplay(gates) {
|
|
26
|
-
const letters = { requirements: 'A', design: 'B', plan: 'C', execution: 'D' };
|
|
27
|
+
function gateDisplay(gates) {
|
|
28
|
+
const letters = { requirements: 'A', design: 'B', plan: 'C', execution: 'D' };
|
|
27
29
|
return Object.entries(letters).map(([name, letter]) => {
|
|
28
30
|
const status = gates[name];
|
|
29
31
|
return status === 'approved' ? `${letter}✓` : `${letter}○`;
|
|
30
|
-
}).join(' ');
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function artifactDisplayName(artifact, fallbackName) {
|
|
34
|
-
if (artifact && artifact.exists && artifact.path) return path.basename(artifact.path);
|
|
35
|
-
return fallbackName;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async function runArtifactValidate({ args, options = {}, logger }) {
|
|
32
|
+
}).join(' ');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function artifactDisplayName(artifact, fallbackName) {
|
|
36
|
+
if (artifact && artifact.exists && artifact.path) return path.basename(artifact.path);
|
|
37
|
+
return fallbackName;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function runArtifactValidate({ args, options = {}, logger }) {
|
|
39
41
|
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
40
42
|
const slug = options.feature ? String(options.feature) : null;
|
|
41
43
|
|
|
@@ -60,6 +62,9 @@ async function runArtifactValidate({ args, options = {}, logger }) {
|
|
|
60
62
|
const sheldonReady = artifacts.sheldon_enrichment.exists
|
|
61
63
|
? (artifacts.sheldon_enrichment.frontmatter.readiness === 'ready_for_downstream' ? 'ready_for_downstream' : 'present')
|
|
62
64
|
: null;
|
|
65
|
+
const sheldonValidationReady = artifacts.sheldon_validation.exists
|
|
66
|
+
? (artifacts.sheldon_validation.frontmatter.verdict || artifacts.sheldon_validation.frontmatter.readiness || 'present')
|
|
67
|
+
: null;
|
|
63
68
|
|
|
64
69
|
// Implementation plan status
|
|
65
70
|
const planStatus = artifacts.implementation_plan.exists
|
|
@@ -70,19 +75,19 @@ async function runArtifactValidate({ args, options = {}, logger }) {
|
|
|
70
75
|
// (REQ-SDLC-01), because feature contracts use slugged identifiers.
|
|
71
76
|
let reqCount = null;
|
|
72
77
|
if (artifacts.requirements.exists && artifacts.requirements.content) {
|
|
73
|
-
const reqs = artifacts.requirements.content.match(
|
|
74
|
-
const acs = artifacts.requirements.content.match(
|
|
78
|
+
const reqs = artifacts.requirements.content.match(REQ_ID_RE) || [];
|
|
79
|
+
const acs = artifacts.requirements.content.match(AC_ID_RE) || [];
|
|
75
80
|
reqCount = `${new Set(reqs).size} REQs, ${new Set(acs).size} ACs`;
|
|
76
81
|
}
|
|
77
82
|
|
|
78
|
-
// Conformance required?
|
|
79
|
-
const conformanceRequired = classification === 'MEDIUM';
|
|
80
|
-
const designDocRequired = classification === 'SMALL' || classification === 'MEDIUM';
|
|
81
|
-
const designDocName = artifactDisplayName(artifacts.design_doc, `design-doc-${slug}.md`);
|
|
82
|
-
const readinessName = artifactDisplayName(artifacts.readiness, `readiness-${slug}.md`);
|
|
83
|
-
|
|
84
|
-
// Build chain items
|
|
85
|
-
const chain = [
|
|
83
|
+
// Conformance required?
|
|
84
|
+
const conformanceRequired = classification === 'MEDIUM';
|
|
85
|
+
const designDocRequired = classification === 'SMALL' || classification === 'MEDIUM';
|
|
86
|
+
const designDocName = artifactDisplayName(artifacts.design_doc, `design-doc-${slug}.md`);
|
|
87
|
+
const readinessName = artifactDisplayName(artifacts.readiness, `readiness-${slug}.md`);
|
|
88
|
+
|
|
89
|
+
// Build chain items
|
|
90
|
+
const chain = [
|
|
86
91
|
{
|
|
87
92
|
name: 'project.context.md',
|
|
88
93
|
exists: artifacts.project_context.exists,
|
|
@@ -104,6 +109,13 @@ async function runArtifactValidate({ args, options = {}, logger }) {
|
|
|
104
109
|
required: false,
|
|
105
110
|
indent: 1
|
|
106
111
|
},
|
|
112
|
+
{
|
|
113
|
+
name: `sheldon-validation-${slug}.md`,
|
|
114
|
+
exists: artifacts.sheldon_validation.exists,
|
|
115
|
+
detail: sheldonValidationReady ? `verdict: ${sheldonValidationReady}` : 'MEDIUM readiness verdict when @sheldon runs',
|
|
116
|
+
required: false,
|
|
117
|
+
indent: 1
|
|
118
|
+
},
|
|
107
119
|
{
|
|
108
120
|
name: `requirements-${slug}.md`,
|
|
109
121
|
exists: artifacts.requirements.exists,
|
|
@@ -118,29 +130,29 @@ async function runArtifactValidate({ args, options = {}, logger }) {
|
|
|
118
130
|
required: true,
|
|
119
131
|
indent: 1
|
|
120
132
|
},
|
|
121
|
-
{
|
|
122
|
-
name: 'architecture.md',
|
|
123
|
-
exists: artifacts.architecture.exists,
|
|
124
|
-
detail: null,
|
|
125
|
-
required: true,
|
|
126
|
-
indent: 1
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
name: designDocName,
|
|
130
|
-
exists: artifacts.design_doc.exists,
|
|
131
|
-
detail: designDocRequired ? 'pre-dev design governance contract' : `SMALL/MEDIUM only — NOT required for ${classification || 'MICRO'}`,
|
|
132
|
-
required: designDocRequired,
|
|
133
|
-
indent: 1
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
name: readinessName,
|
|
137
|
-
exists: artifacts.readiness.exists,
|
|
138
|
-
detail: designDocRequired ? 'pre-dev readiness contract' : `SMALL/MEDIUM only — NOT required for ${classification || 'MICRO'}`,
|
|
139
|
-
required: designDocRequired,
|
|
140
|
-
indent: 1
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
name: `implementation-plan-${slug}.md`,
|
|
133
|
+
{
|
|
134
|
+
name: 'architecture.md',
|
|
135
|
+
exists: artifacts.architecture.exists,
|
|
136
|
+
detail: null,
|
|
137
|
+
required: true,
|
|
138
|
+
indent: 1
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
name: designDocName,
|
|
142
|
+
exists: artifacts.design_doc.exists,
|
|
143
|
+
detail: designDocRequired ? 'pre-dev design governance contract' : `SMALL/MEDIUM only — NOT required for ${classification || 'MICRO'}`,
|
|
144
|
+
required: designDocRequired,
|
|
145
|
+
indent: 1
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: readinessName,
|
|
149
|
+
exists: artifacts.readiness.exists,
|
|
150
|
+
detail: designDocRequired ? 'pre-dev readiness contract' : `SMALL/MEDIUM only — NOT required for ${classification || 'MICRO'}`,
|
|
151
|
+
required: designDocRequired,
|
|
152
|
+
indent: 1
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: `implementation-plan-${slug}.md`,
|
|
144
156
|
exists: artifacts.implementation_plan.exists,
|
|
145
157
|
detail: planStatus ? `status: ${planStatus}` : null,
|
|
146
158
|
required: true,
|
|
@@ -164,12 +176,12 @@ async function runArtifactValidate({ args, options = {}, logger }) {
|
|
|
164
176
|
// Determine next_missing and next_agent (AC-SDLC-22)
|
|
165
177
|
const ARTIFACT_OWNER_MAP = {
|
|
166
178
|
'project.context.md': { agent: '@setup', reason: 'setup not complete' },
|
|
167
|
-
[`prd-${slug}.md`]: { agent: '@product', reason: 'PRD not produced yet' },
|
|
168
|
-
[`requirements-${slug}.md`]: { agent: '@analyst', reason: 'requirements not produced yet (Gate A)' },
|
|
169
|
-
'architecture.md': { agent: '@architect', reason: 'architecture not produced yet (Gate B)' },
|
|
170
|
-
[designDocName]: { agent: '@discovery-design-doc', reason: 'design governance contract not produced yet' },
|
|
171
|
-
[readinessName]: { agent: '@discovery-design-doc', reason: 'readiness contract not produced yet' },
|
|
172
|
-
[`implementation-plan-${slug}.md`]: { agent: '@pm', reason: 'implementation plan not produced yet (Gate C)' },
|
|
179
|
+
[`prd-${slug}.md`]: { agent: '@product', reason: 'PRD not produced yet' },
|
|
180
|
+
[`requirements-${slug}.md`]: { agent: '@analyst', reason: 'requirements not produced yet (Gate A)' },
|
|
181
|
+
'architecture.md': { agent: '@architect', reason: 'architecture not produced yet (Gate B)' },
|
|
182
|
+
[designDocName]: { agent: '@discovery-design-doc', reason: 'design governance contract not produced yet' },
|
|
183
|
+
[readinessName]: { agent: '@discovery-design-doc', reason: 'readiness contract not produced yet' },
|
|
184
|
+
[`implementation-plan-${slug}.md`]: { agent: '@pm', reason: 'implementation plan not produced yet (Gate C)' },
|
|
173
185
|
[`spec-${slug}.md`]: { agent: '@analyst', reason: 'spec not produced yet — @analyst seeds the feature memory' },
|
|
174
186
|
[`conformance-${slug}.yaml`]: { agent: '@analyst', reason: 'conformance contract missing — @analyst creates it for MEDIUM features' }
|
|
175
187
|
};
|
package/src/commands/classify.js
CHANGED
|
@@ -116,6 +116,60 @@ const COMPLEXITY_SOME_PATTERNS = [
|
|
|
116
116
|
/\b(notification|trigger|event)\b/gi
|
|
117
117
|
];
|
|
118
118
|
|
|
119
|
+
// Sensitive-surface floor (Gap 3B): a feature touching any of these surfaces is
|
|
120
|
+
// never MICRO. Mirrors the secure-tdd sensitive list in @dev. The floor can only
|
|
121
|
+
// RAISE the tier (MICRO -> SMALL); it never lowers it. Keep patterns tight — a
|
|
122
|
+
// false positive needlessly costs the SMALL chain. Tune as the project learns.
|
|
123
|
+
const SENSITIVE_SURFACE_PATTERNS = [
|
|
124
|
+
{ surface: 'money', re: /\b(money|stripe|paypal|braintree|square|payments?|payouts?|refunds?|subscriptions?|billing|invoices?|credit card)\b/i },
|
|
125
|
+
{ surface: 'auth', re: /\b(oauth|jwt|saml|sso|auth0|firebase auth|log[- ]?in|sign[- ]?in|sign[- ]?up|passwords?|authenticat\w*|2fa|mfa)\b/i },
|
|
126
|
+
{ surface: 'authz', re: /\b(authoriz\w*|access control|role[- ]based|rbac|ownership|owner[- ]only|only the owner)\b/i },
|
|
127
|
+
{ surface: 'uploads', re: /\b(file uploads?|uploads?|attachments?)\b/i },
|
|
128
|
+
{ surface: 'external_url', re: /\b(webhooks?|callback urls?|ssrf|user[- ]?supplied urls?)\b/i },
|
|
129
|
+
{ surface: 'secrets', re: /\b(secrets?|api keys?|credentials?|private key|access tokens?)\b/i },
|
|
130
|
+
{ surface: 'sensitive_storage', re: /\b(pii|personal data|ssn|sensitive (data|storage|information))\b/i }
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
function detectSensitiveSurfaces(content) {
|
|
134
|
+
const found = [];
|
|
135
|
+
for (const { surface, re } of SENSITIVE_SURFACE_PATTERNS) {
|
|
136
|
+
if (re.test(content)) found.push(surface);
|
|
137
|
+
}
|
|
138
|
+
return found;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Explicit `sensitive_surfaces:` frontmatter override — additive, can only force
|
|
142
|
+
// the floor when content detection misses. Supports inline (`[a, b]` / `a, b`)
|
|
143
|
+
// and YAML block list forms.
|
|
144
|
+
function parseSensitiveSurfacesOverride(content) {
|
|
145
|
+
const fm = String(content || '').match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
146
|
+
if (!fm) return [];
|
|
147
|
+
const body = fm[1];
|
|
148
|
+
const items = [];
|
|
149
|
+
const inline = body.match(/^sensitive_surfaces:[ \t]*(.+)$/m);
|
|
150
|
+
if (inline) {
|
|
151
|
+
inline[1].trim().replace(/^\[|\]$/g, '').split(',').forEach((s) => {
|
|
152
|
+
const v = s.trim().replace(/^["']|["']$/g, '');
|
|
153
|
+
if (v) items.push(v);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
const block = body.match(/^sensitive_surfaces:[ \t]*\r?\n((?:[ \t]*-[ \t]*.+\r?\n?)+)/m);
|
|
157
|
+
if (block) {
|
|
158
|
+
block[1].split(/\r?\n/).forEach((line) => {
|
|
159
|
+
const m = line.match(/^[ \t]*-[ \t]*(.+)$/);
|
|
160
|
+
if (m) {
|
|
161
|
+
const v = m[1].trim().replace(/^["']|["']$/g, '');
|
|
162
|
+
if (v) items.push(v);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return items;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function applySensitiveFloor(classification) {
|
|
170
|
+
return classification === 'MICRO' ? 'SMALL' : classification;
|
|
171
|
+
}
|
|
172
|
+
|
|
119
173
|
function analyzeContent(content) {
|
|
120
174
|
// Count unique user types
|
|
121
175
|
const userTypeSet = new Set();
|
|
@@ -185,6 +239,7 @@ async function runClassify({ args, options = {}, logger }) {
|
|
|
185
239
|
|
|
186
240
|
let userTypeCount, integrationCount, complexityLevel;
|
|
187
241
|
let sourceFile = null;
|
|
242
|
+
let content = null;
|
|
188
243
|
|
|
189
244
|
if (interactive) {
|
|
190
245
|
({ userTypeCount, integrationCount, complexityLevel } = await runInteractive(logger));
|
|
@@ -199,7 +254,6 @@ async function runClassify({ args, options = {}, logger }) {
|
|
|
199
254
|
]
|
|
200
255
|
: [path.join(dir, 'requirements.md'), path.join(dir, 'prd.md')];
|
|
201
256
|
|
|
202
|
-
let content = null;
|
|
203
257
|
for (const candidate of candidates) {
|
|
204
258
|
content = await readFileSafe(candidate);
|
|
205
259
|
if (content) { sourceFile = path.relative(targetDir, candidate); break; }
|
|
@@ -218,7 +272,19 @@ async function runClassify({ args, options = {}, logger }) {
|
|
|
218
272
|
const intScore = scoreIntegrations(integrationCount);
|
|
219
273
|
const cxScore = scoreComplexity(complexityLevel);
|
|
220
274
|
const totalScore = utScore + intScore + cxScore;
|
|
221
|
-
|
|
275
|
+
let classification = scoreToClassification(totalScore);
|
|
276
|
+
|
|
277
|
+
// Gap 3B — sensitive-surface floor (deterministic; raises MICRO -> SMALL only).
|
|
278
|
+
const detectedSurfaces = content ? detectSensitiveSurfaces(content) : [];
|
|
279
|
+
const declaredSurfaces = content ? parseSensitiveSurfacesOverride(content) : [];
|
|
280
|
+
const sensitiveSurfaces = [...new Set([...detectedSurfaces, ...declaredSurfaces])];
|
|
281
|
+
let floored = false;
|
|
282
|
+
if (sensitiveSurfaces.length > 0) {
|
|
283
|
+
const scored = classification;
|
|
284
|
+
classification = applySensitiveFloor(classification);
|
|
285
|
+
floored = classification !== scored;
|
|
286
|
+
}
|
|
287
|
+
|
|
222
288
|
const phaseDepth = classificationToPhaseDepth(classification);
|
|
223
289
|
|
|
224
290
|
const result = {
|
|
@@ -228,6 +294,8 @@ async function runClassify({ args, options = {}, logger }) {
|
|
|
228
294
|
inputs: { user_types: userTypeCount, external_integrations: integrationCount, rule_complexity: complexityLevel },
|
|
229
295
|
scores: { user_types: utScore, integrations: intScore, complexity: cxScore, total: totalScore },
|
|
230
296
|
classification,
|
|
297
|
+
sensitive_surfaces: sensitiveSurfaces,
|
|
298
|
+
floored,
|
|
231
299
|
phase_depth: phaseDepth
|
|
232
300
|
};
|
|
233
301
|
|
|
@@ -243,6 +311,9 @@ async function runClassify({ args, options = {}, logger }) {
|
|
|
243
311
|
logger.log(`Business rule complexity: ${complexityLevel} → +${cxScore}`);
|
|
244
312
|
logger.log(BAR);
|
|
245
313
|
logger.log(`Score: ${totalScore} → ${classification}`);
|
|
314
|
+
if (sensitiveSurfaces.length > 0) {
|
|
315
|
+
logger.log(`Sensitive surfaces: ${sensitiveSurfaces.join(', ')}${floored ? ' → floored to SMALL' : ''}`);
|
|
316
|
+
}
|
|
246
317
|
logger.log('');
|
|
247
318
|
logger.log('Phase depth:');
|
|
248
319
|
for (const [phase, desc] of Object.entries(phaseDepth)) {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { buildContextBrief } = require('../context-brief');
|
|
5
|
+
|
|
6
|
+
async function runContextBrief({ args, options = {}, logger }) {
|
|
7
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
8
|
+
const result = await buildContextBrief(targetDir, {
|
|
9
|
+
agent: options.agent || options.a || 'dev',
|
|
10
|
+
mode: options.mode || 'planning',
|
|
11
|
+
task: options.task || options.goal || '',
|
|
12
|
+
paths: options.paths || options.path || '',
|
|
13
|
+
feature: options.feature || options.slug || '',
|
|
14
|
+
semantic: options.semantic,
|
|
15
|
+
noSemantic: options.noSemantic || options['no-semantic'],
|
|
16
|
+
recall: !(options['no-recall'] || options.recall === false)
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
if (options.json) return result;
|
|
20
|
+
|
|
21
|
+
logger.log(`Context brief for @${result.agent} (${result.mode})`);
|
|
22
|
+
if (result.task) logger.log(`Task: ${result.task}`);
|
|
23
|
+
logger.log(`Intent: ${result.intent.operation}${result.intent.stack ? ` / ${result.intent.stack}` : ''}`);
|
|
24
|
+
if (result.intent.concerns.length > 0) logger.log(`Concerns: ${result.intent.concerns.join(', ')}`);
|
|
25
|
+
logger.log(`Confidence: ${result.confidence}`);
|
|
26
|
+
|
|
27
|
+
if (result.must_load.length > 0) {
|
|
28
|
+
logger.log('Must load:');
|
|
29
|
+
for (const item of result.must_load) logger.log(`- ${item.path} [${item.surface}] ${item.reason}`);
|
|
30
|
+
}
|
|
31
|
+
if (result.should_load.length > 0) {
|
|
32
|
+
logger.log('Should load when needed:');
|
|
33
|
+
for (const item of result.should_load) logger.log(`- ${item.path} [${item.surface}] ${item.reason}`);
|
|
34
|
+
}
|
|
35
|
+
if (result.constraints.length > 0) {
|
|
36
|
+
logger.log('Constraints:');
|
|
37
|
+
for (const item of result.constraints.slice(0, 8)) logger.log(`- ${item}`);
|
|
38
|
+
}
|
|
39
|
+
if (result.forbidden_patterns.length > 0) {
|
|
40
|
+
logger.log('Forbidden patterns:');
|
|
41
|
+
for (const item of result.forbidden_patterns.slice(0, 8)) logger.log(`- ${item}`);
|
|
42
|
+
}
|
|
43
|
+
if (result.verification_hints.length > 0) {
|
|
44
|
+
logger.log('Verification hints:');
|
|
45
|
+
for (const item of result.verification_hints.slice(0, 8)) logger.log(`- ${item}`);
|
|
46
|
+
}
|
|
47
|
+
if (result.gaps.length > 0) {
|
|
48
|
+
logger.log('Gaps:');
|
|
49
|
+
for (const gap of result.gaps) logger.log(`- ${gap.code}: ${gap.message}`);
|
|
50
|
+
}
|
|
51
|
+
if (result.related && result.related.length > 0) {
|
|
52
|
+
logger.log('Related (recall — history/archive select cannot see):');
|
|
53
|
+
for (const item of result.related) logger.log(`- ${item.path} [${item.source_type}] ${item.reason || ''}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = { runContextBrief };
|