tribunal-kit 6.0.1 → 7.0.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/.agent/ARCHITECTURE.md +9 -6
- package/.agent/agents/accessibility-reviewer.md +23 -16
- package/.agent/agents/ai-code-reviewer.md +25 -21
- package/.agent/agents/anti-pattern-reviewer.md +12 -7
- package/.agent/agents/api-architect.md +1 -0
- package/.agent/agents/backend-specialist.md +23 -22
- package/.agent/agents/cloud-engineer.md +1 -0
- package/.agent/agents/code-archaeologist.md +1 -0
- package/.agent/agents/complexity-reviewer.md +10 -7
- package/.agent/agents/database-architect.md +3 -2
- package/.agent/agents/db-latency-auditor.md +6 -2
- package/.agent/agents/debugger.md +3 -2
- package/.agent/agents/dependency-reviewer.md +1 -0
- package/.agent/agents/devops-engineer.md +9 -8
- package/.agent/agents/documentation-writer.md +6 -5
- package/.agent/agents/explorer-agent.md +1 -0
- package/.agent/agents/frontend-reviewer.md +21 -17
- package/.agent/agents/frontend-specialist.md +23 -20
- package/.agent/agents/game-developer.md +1 -0
- package/.agent/agents/interaction-reviewer.md +10 -5
- package/.agent/agents/logic-reviewer.md +3 -0
- package/.agent/agents/minimalist-reviewer.md +6 -0
- package/.agent/agents/mobile-developer.md +7 -6
- package/.agent/agents/mobile-reviewer.md +14 -13
- package/.agent/agents/orchestrator.md +3 -0
- package/.agent/agents/penetration-tester.md +1 -0
- package/.agent/agents/performance-optimizer.md +6 -5
- package/.agent/agents/performance-reviewer.md +6 -6
- package/.agent/agents/pipeline-reviewer.md +144 -0
- package/.agent/agents/precedence-reviewer.md +1 -0
- package/.agent/agents/product-manager.md +1 -0
- package/.agent/agents/product-owner.md +1 -0
- package/.agent/agents/product-reviewer.md +12 -7
- package/.agent/agents/project-planner.md +3 -0
- package/.agent/agents/qa-automation-engineer.md +50 -43
- package/.agent/agents/resilience-reviewer.md +1 -0
- package/.agent/agents/schema-reviewer.md +1 -0
- package/.agent/agents/security-auditor.md +24 -24
- package/.agent/agents/seo-specialist.md +33 -23
- package/.agent/agents/sql-reviewer.md +5 -4
- package/.agent/agents/supervisor-agent.md +12 -2
- package/.agent/agents/swarm-worker-contracts.md +13 -13
- package/.agent/agents/swarm-worker-registry.md +51 -51
- package/.agent/agents/system-architect.md +1 -0
- package/.agent/agents/test-coverage-reviewer.md +25 -22
- package/.agent/agents/test-engineer.md +12 -11
- package/.agent/agents/throughput-optimizer.md +45 -40
- package/.agent/agents/type-safety-reviewer.md +5 -4
- package/.agent/agents/ui-ux-auditor.md +6 -4
- package/.agent/agents/ui-visual-auditor.md +3 -0
- package/.agent/agents/ux-reviewer.md +11 -6
- package/.agent/agents/visual-reviewer.md +11 -6
- package/.agent/agents/vitals-reviewer.md +5 -4
- package/.agent/history/memory/.memory.idx +1532 -1
- package/.agent/history/memory/MEMORY.md +102 -1
- package/.agent/mcp_config.json +1 -6
- package/.agent/routing_index.json +2033 -263
- package/.agent/rules/GEMINI.md +11 -9
- package/.agent/rules/GEMINI_PLANNER.md +19 -21
- package/.agent/scripts/_colors.js +52 -54
- package/.agent/scripts/_utils.js +52 -53
- package/.agent/scripts/auto_preview.js +39 -43
- package/.agent/scripts/bundle_analyzer.js +47 -60
- package/.agent/scripts/case_law_manager.js +200 -294
- package/.agent/scripts/checklist.js +73 -94
- package/.agent/scripts/cicd_validator.js +305 -0
- package/.agent/scripts/compile_router.py +4 -111
- package/.agent/scripts/context_broker.js +317 -412
- package/.agent/scripts/contract_engine.js +402 -0
- package/.agent/scripts/dependency_analyzer.js +112 -124
- package/.agent/scripts/graph_builder.js +75 -103
- package/.agent/scripts/graph_visualizer.js +10 -12
- package/.agent/scripts/graph_zoom.js +38 -55
- package/.agent/scripts/guardrail_engine.js +195 -145
- package/.agent/scripts/impact_classifier.js +55 -30
- package/.agent/scripts/inner_loop_validator.js +108 -159
- package/.agent/scripts/integrity_manifest.js +59 -67
- package/.agent/scripts/lint_runner.js +65 -75
- package/.agent/scripts/marathon_harness.js +131 -208
- package/.agent/scripts/migrate_skills_frontmatter.py +4 -63
- package/.agent/scripts/minify_context.js +29 -33
- package/.agent/scripts/minimal_change_engine.js +95 -87
- package/.agent/scripts/mutation_runner.js +46 -62
- package/.agent/scripts/pipeline_engine.js +320 -209
- package/.agent/scripts/prompt_compiler.js +118 -93
- package/.agent/scripts/schema_validator.js +73 -121
- package/.agent/scripts/security_scan.js +88 -117
- package/.agent/scripts/session_manager.js +52 -69
- package/.agent/scripts/signal_detector.js +24 -22
- package/.agent/scripts/skill_evolution.js +184 -245
- package/.agent/scripts/skill_integrator.js +35 -48
- package/.agent/scripts/socratic_gate_policy.js +15 -12
- package/.agent/scripts/strengthen_skills.js +29 -33
- package/.agent/scripts/swarm_dispatcher.js +120 -151
- package/.agent/scripts/test_runner.js +54 -56
- package/.agent/scripts/token_budget_broker.js +9 -7
- package/.agent/scripts/trace_engine.js +126 -0
- package/.agent/scripts/verify_all.js +76 -93
- package/.agent/scripts/visual_audit.js +16 -21
- package/.agent/skill_topic_map.json +22 -3
- package/.agent/skills/12-principles-of-animation/SKILL.md +7 -0
- package/.agent/skills/60fps-animation/SKILL.md +7 -0
- package/.agent/skills/accessible-animation/SKILL.md +5 -1
- package/.agent/skills/adapt/SKILL.md +7 -1
- package/.agent/skills/advanced-rag-pipelines/SKILL.md +1 -0
- package/.agent/skills/agent-organizer/SKILL.md +1 -0
- package/.agent/skills/agentic-patterns/SKILL.md +33 -25
- package/.agent/skills/agentic-workflows-2026/SKILL.md +6 -2
- package/.agent/skills/ai-app-hardening/SKILL.md +9 -8
- package/.agent/skills/ai-prompt-injection-defense/SKILL.md +7 -6
- package/.agent/skills/animation-on-scroll/SKILL.md +24 -15
- package/.agent/skills/animation-systems/SKILL.md +11 -10
- package/.agent/skills/antfu-conventions/SKILL.md +7 -2
- package/.agent/skills/api-patterns/SKILL.md +14 -10
- package/.agent/skills/api-security-auditor/SKILL.md +15 -14
- package/.agent/skills/app-builder/SKILL.md +1 -0
- package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +2 -2
- package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +12 -12
- package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +3 -3
- package/.agent/skills/apple-design/SKILL.md +8 -7
- package/.agent/skills/architecture/SKILL.md +3 -2
- package/.agent/skills/audit-and-fix/SKILL.md +8 -5
- package/.agent/skills/authentication-best-practices/SKILL.md +9 -8
- package/.agent/skills/backend-security-expert/SKILL.md +1 -0
- package/.agent/skills/baseline-ui/SKILL.md +8 -7
- package/.agent/skills/bash-linux/SKILL.md +1 -0
- package/.agent/skills/behavioral-modes/SKILL.md +1 -0
- package/.agent/skills/better-colors/SKILL.md +11 -7
- package/.agent/skills/better-typography/SKILL.md +30 -16
- package/.agent/skills/better-ui/SKILL.md +17 -10
- package/.agent/skills/bolder/SKILL.md +6 -0
- package/.agent/skills/brainstorming/SKILL.md +6 -4
- package/.agent/skills/browser-native-ai/SKILL.md +5 -4
- package/.agent/skills/build-primitive/SKILL.md +5 -0
- package/.agent/skills/building-native-ui/SKILL.md +1 -0
- package/.agent/skills/cicd-pro/SKILL.md +2 -1
- package/.agent/skills/clarify/SKILL.md +19 -14
- package/.agent/skills/clean-code/SKILL.md +16 -15
- package/.agent/skills/cloud-architect/SKILL.md +1 -0
- package/.agent/skills/cobejs/SKILL.md +7 -9
- package/.agent/skills/code-review-checklist/SKILL.md +1 -0
- package/.agent/skills/codebase-design/SKILL.md +7 -2
- package/.agent/skills/colorize/SKILL.md +8 -3
- package/.agent/skills/compact-landing/SKILL.md +8 -3
- package/.agent/skills/company-logos/SKILL.md +6 -0
- package/.agent/skills/config-validator/SKILL.md +10 -9
- package/.agent/skills/containerization-pro/SKILL.md +6 -5
- package/.agent/skills/context-engineering-pro/SKILL.md +5 -4
- package/.agent/skills/create-design-md/SKILL.md +13 -5
- package/.agent/skills/critique/SKILL.md +10 -8
- package/.agent/skills/csharp-developer/SKILL.md +1 -0
- package/.agent/skills/data-validation-schemas/SKILL.md +28 -23
- package/.agent/skills/database-design/SKILL.md +2 -1
- package/.agent/skills/delight/SKILL.md +6 -0
- package/.agent/skills/deployment-procedures/SKILL.md +2 -1
- package/.agent/skills/design-lab/SKILL.md +5 -0
- package/.agent/skills/devops-engineer/SKILL.md +3 -2
- package/.agent/skills/devops-incident-responder/SKILL.md +2 -1
- package/.agent/skills/diagnosing-bugs/SKILL.md +12 -2
- package/.agent/skills/distill/SKILL.md +7 -2
- package/.agent/skills/documentation-templates/SKILL.md +3 -2
- package/.agent/skills/domain-modeling/SKILL.md +12 -4
- package/.agent/skills/duckdb-analytical-sql/SKILL.md +7 -3
- package/.agent/skills/edge-ai-mobile/SKILL.md +5 -1
- package/.agent/skills/edge-computing/SKILL.md +9 -8
- package/.agent/skills/emil-design-eng/SKILL.md +43 -27
- package/.agent/skills/error-resilience/SKILL.md +34 -16
- package/.agent/skills/expo-router-v4/SKILL.md +2 -1
- package/.agent/skills/extract-design-system/SKILL.md +12 -11
- package/.agent/skills/fabel-protocol/SKILL.md +24 -17
- package/.agent/skills/fixing-accessibility/SKILL.md +23 -16
- package/.agent/skills/fixing-metadata/SKILL.md +24 -13
- package/.agent/skills/fixing-motion-performance/SKILL.md +7 -5
- package/.agent/skills/framer-motion-expert/SKILL.md +29 -15
- package/.agent/skills/frontend-design/SKILL.md +21 -13
- package/.agent/skills/frontend-security-expert/SKILL.md +1 -0
- package/.agent/skills/game-design-expert/SKILL.md +1 -0
- package/.agent/skills/game-engineering-expert/SKILL.md +1 -0
- package/.agent/skills/generative-ui-expert/SKILL.md +3 -2
- package/.agent/skills/geo-fundamentals/SKILL.md +2 -1
- package/.agent/skills/git-pro/SKILL.md +10 -9
- package/.agent/skills/github-operations/SKILL.md +2 -1
- package/.agent/skills/gpt-taste/SKILL.md +7 -0
- package/.agent/skills/gsap-core/SKILL.md +26 -22
- package/.agent/skills/gsap-frameworks/SKILL.md +6 -5
- package/.agent/skills/gsap-performance/SKILL.md +4 -3
- package/.agent/skills/gsap-plugins/SKILL.md +34 -33
- package/.agent/skills/gsap-react/SKILL.md +9 -8
- package/.agent/skills/gsap-scrolltrigger/SKILL.md +34 -33
- package/.agent/skills/gsap-timeline/SKILL.md +18 -15
- package/.agent/skills/gsap-utils/SKILL.md +25 -24
- package/.agent/skills/harden/SKILL.md +9 -3
- package/.agent/skills/harness-protocol/SKILL.md +1 -0
- package/.agent/skills/i18n-localization/SKILL.md +10 -9
- package/.agent/skills/impeccable/SKILL.md +5 -0
- package/.agent/skills/improve-codebase-architecture/SKILL.md +10 -5
- package/.agent/skills/improve-ui/SKILL.md +12 -5
- package/.agent/skills/intelligent-routing/SKILL.md +7 -6
- package/.agent/skills/knowledge-graph/SKILL.md +1 -0
- package/.agent/skills/landing-page/SKILL.md +1 -0
- package/.agent/skills/lint-and-validate/SKILL.md +9 -4
- package/.agent/skills/llm-engineering/SKILL.md +55 -54
- package/.agent/skills/local-first/SKILL.md +20 -19
- package/.agent/skills/local-first-architecture/SKILL.md +6 -1
- package/.agent/skills/lottie-animation/SKILL.md +7 -3
- package/.agent/skills/marquee-loop/SKILL.md +1 -0
- package/.agent/skills/masked-reveal/SKILL.md +17 -4
- package/.agent/skills/mcp-builder/SKILL.md +13 -10
- package/.agent/skills/micro-interaction/SKILL.md +20 -5
- package/.agent/skills/mobile-design/SKILL.md +26 -15
- package/.agent/skills/monorepo-management/SKILL.md +3 -2
- package/.agent/skills/morphing-icons/SKILL.md +16 -6
- package/.agent/skills/motion-engineering/SKILL.md +19 -15
- package/.agent/skills/nextjs-react-expert/SKILL.md +26 -21
- package/.agent/skills/nodejs-best-practices/SKILL.md +89 -76
- package/.agent/skills/observability/SKILL.md +45 -44
- package/.agent/skills/opentelemetry-observability/SKILL.md +2 -1
- package/.agent/skills/page-transition-animation/SKILL.md +6 -3
- package/.agent/skills/parallel-agents/SKILL.md +7 -2
- package/.agent/skills/performance-profiling/SKILL.md +24 -13
- package/.agent/skills/plan-writing/SKILL.md +1 -0
- package/.agent/skills/platform-engineer/SKILL.md +3 -2
- package/.agent/skills/platform-engineering-opentofu/SKILL.md +1 -0
- package/.agent/skills/playwright-ai-e2e/SKILL.md +3 -2
- package/.agent/skills/playwright-best-practices/SKILL.md +29 -28
- package/.agent/skills/polish/SKILL.md +13 -12
- package/.agent/skills/powershell-windows/SKILL.md +1 -0
- package/.agent/skills/pricing-page/SKILL.md +8 -3
- package/.agent/skills/product-aware-heuristics/SKILL.md +122 -72
- package/.agent/skills/progressive-blur/SKILL.md +9 -4
- package/.agent/skills/project-idioms/SKILL.md +1 -0
- package/.agent/skills/property-based-testing/SKILL.md +10 -12
- package/.agent/skills/python-patterns/SKILL.md +1 -0
- package/.agent/skills/python-pro/SKILL.md +1 -0
- package/.agent/skills/quieter/SKILL.md +6 -0
- package/.agent/skills/react-doctor/SKILL.md +6 -0
- package/.agent/skills/react-specialist/SKILL.md +32 -28
- package/.agent/skills/readme-builder/SKILL.md +1 -0
- package/.agent/skills/realtime-patterns/SKILL.md +34 -33
- package/.agent/skills/red-team-tactics/SKILL.md +1 -0
- package/.agent/skills/redesign-skill/SKILL.md +6 -0
- package/.agent/skills/review-animations/SKILL.md +5 -2
- package/.agent/skills/review-animations/STANDARDS.md +37 -23
- package/.agent/skills/rust-pro/SKILL.md +1 -0
- package/.agent/skills/seo-fundamentals/SKILL.md +4 -3
- package/.agent/skills/server-management/SKILL.md +1 -0
- package/.agent/skills/shadcn-ui-expert/SKILL.md +28 -22
- package/.agent/skills/shape/SKILL.md +9 -2
- package/.agent/skills/skill-creator/SKILL.md +1 -0
- package/.agent/skills/soft-skill/SKILL.md +6 -0
- package/.agent/skills/sounds-on-the-web/SKILL.md +1 -0
- package/.agent/skills/sql-pro/SKILL.md +1 -0
- package/.agent/skills/supabase-postgres-best-practices/SKILL.md +1 -0
- package/.agent/skills/svg-animation/SKILL.md +16 -7
- package/.agent/skills/swiftui-expert/SKILL.md +1 -0
- package/.agent/skills/swiss-design/SKILL.md +5 -0
- package/.agent/skills/system-design-pro/SKILL.md +1 -0
- package/.agent/skills/systematic-debugging/SKILL.md +1 -0
- package/.agent/skills/tailwind-patterns/SKILL.md +25 -11
- package/.agent/skills/taste-skill/SKILL.md +6 -0
- package/.agent/skills/tdd-workflow/SKILL.md +5 -0
- package/.agent/skills/test-result-analyzer/SKILL.md +1 -0
- package/.agent/skills/testing-patterns/SKILL.md +123 -115
- package/.agent/skills/thermo-nuclear-code-quality-review/SKILL.md +5 -0
- package/.agent/skills/thinking-protocol/SKILL.md +3 -0
- package/.agent/skills/to-spring-or-not-to-spring/SKILL.md +9 -8
- package/.agent/skills/transitions-dev/SKILL.md +19 -6
- package/.agent/skills/trend-researcher/SKILL.md +1 -0
- package/.agent/skills/typescript-advanced/SKILL.md +23 -18
- package/.agent/skills/typeset/SKILL.md +10 -1
- package/.agent/skills/ui-reasoning-engine/SKILL.md +67 -48
- package/.agent/skills/ui-skill-packs/SKILL.md +6 -1
- package/.agent/skills/ui-skills-root/SKILL.md +39 -38
- package/.agent/skills/ui-ux-pro-max/SKILL.md +34 -26
- package/.agent/skills/ui-ux-researcher/SKILL.md +1 -0
- package/.agent/skills/vector-search-pgvector/SKILL.md +3 -2
- package/.agent/skills/vue-expert/SKILL.md +22 -19
- package/.agent/skills/vulnerability-scanner/SKILL.md +22 -21
- package/.agent/skills/web-accessibility-auditor/SKILL.md +2 -1
- package/.agent/skills/web-design-guidelines/SKILL.md +16 -10
- package/.agent/skills/web-quality-audit/SKILL.md +5 -0
- package/.agent/skills/webapp-testing/SKILL.md +14 -13
- package/.agent/skills/webgpu-performance/SKILL.md +1 -0
- package/.agent/skills/whimsy-injector/SKILL.md +9 -5
- package/.agent/skills/workflow-optimizer/SKILL.md +1 -0
- package/.agent/skills/zero-trust-passkeys/SKILL.md +11 -6
- package/.agent/templates/DESIGN.md +119 -110
- package/.agent/templates/design-tokens.json +9 -6
- package/.agent/workflows/acf.md +1 -0
- package/.agent/workflows/api-tester.md +1 -0
- package/.agent/workflows/audit.md +1 -0
- package/.agent/workflows/brainstorm.md +1 -0
- package/.agent/workflows/changelog.md +1 -0
- package/.agent/workflows/contract.md +60 -0
- package/.agent/workflows/create.md +1 -0
- package/.agent/workflows/debug.md +1 -0
- package/.agent/workflows/deploy.md +1 -0
- package/.agent/workflows/enhance.md +1 -0
- package/.agent/workflows/fix-ci.md +89 -0
- package/.agent/workflows/fix.md +1 -0
- package/.agent/workflows/generate.md +1 -0
- package/.agent/workflows/marathon.md +1 -0
- package/.agent/workflows/migrate.md +1 -0
- package/.agent/workflows/minimal.md +9 -7
- package/.agent/workflows/orchestrate.md +1 -0
- package/.agent/workflows/performance-benchmarker.md +1 -0
- package/.agent/workflows/pipeline.md +26 -21
- package/.agent/workflows/plan.md +1 -0
- package/.agent/workflows/preview.md +1 -0
- package/.agent/workflows/refactor.md +3 -2
- package/.agent/workflows/review-ai.md +4 -3
- package/.agent/workflows/review.md +1 -0
- package/.agent/workflows/session.md +1 -0
- package/.agent/workflows/status.md +1 -0
- package/.agent/workflows/strengthen-skills.md +1 -0
- package/.agent/workflows/super-prompt.md +1 -0
- package/.agent/workflows/swarm.md +15 -3
- package/.agent/workflows/test.md +8 -7
- package/.agent/workflows/tribunal-backend.md +3 -2
- package/.agent/workflows/tribunal-cicd.md +104 -0
- package/.agent/workflows/tribunal-database.md +1 -0
- package/.agent/workflows/tribunal-frontend.md +8 -6
- package/.agent/workflows/tribunal-full.md +2 -1
- package/.agent/workflows/tribunal-mobile.md +6 -5
- package/.agent/workflows/tribunal-performance.md +1 -0
- package/.agent/workflows/tribunal-speed.md +1 -0
- package/.agent/workflows/tribunal-ui.md +29 -21
- package/.agent/workflows/ui-ux-pro-max.md +19 -15
- package/CONTRIBUTING.md +3 -3
- package/README.md +94 -44
- package/SECURITY.md +10 -10
- package/bin/mcp-server.js +385 -252
- package/bin/tribunal-kit.js +29 -30
- package/bin/wrapper.js +40 -46
- package/dist/cli.js +6 -0
- package/dist/commands/case.js +2 -0
- package/dist/commands/contract.js +440 -0
- package/dist/commands/status.js +6 -0
- package/dist/index.d.ts +8 -1
- package/package.json +13 -12
- package/scripts/benchmark.js +62 -86
- package/scripts/changelog.js +67 -73
- package/scripts/fix-vbc.js +13 -15
- package/scripts/fix-vbc.ps1 +2 -118
- package/scripts/stress_benchmark.js +358 -0
- package/scripts/sync-version.js +71 -41
- package/scripts/validate-payload.js +23 -30
- package/scripts/visual_audit.js +23 -13
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
* node .agent/scripts/marathon_harness.js add-feature "category" "description" "step1" "step2" ...
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
'use strict';
|
|
23
23
|
|
|
24
|
-
const fs = require(
|
|
25
|
-
const path = require(
|
|
26
|
-
const { execSync } = require(
|
|
27
|
-
const { findAgentDir } = require(
|
|
24
|
+
const fs = require('fs');
|
|
25
|
+
const path = require('path');
|
|
26
|
+
const { execSync } = require('child_process');
|
|
27
|
+
const { findAgentDir } = require('./_utils');
|
|
28
28
|
|
|
29
29
|
const {
|
|
30
30
|
GREEN,
|
|
@@ -40,29 +40,29 @@ const {
|
|
|
40
40
|
ok,
|
|
41
41
|
warn,
|
|
42
42
|
info,
|
|
43
|
-
} = require(
|
|
43
|
+
} = require('./_colors');
|
|
44
44
|
|
|
45
45
|
// ── Paths ────────────────────────────────────────────────────────────────────
|
|
46
46
|
function getMarathonDir(startDir = process.cwd()) {
|
|
47
|
-
return path.join(findAgentDir(startDir),
|
|
47
|
+
return path.join(findAgentDir(startDir), 'history', 'marathon');
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
const MARATHON_DIR = getMarathonDir();
|
|
51
|
-
const FEATURE_LIST_FILE = path.join(MARATHON_DIR,
|
|
52
|
-
const PROGRESS_FILE = path.join(MARATHON_DIR,
|
|
53
|
-
const ARCHIVE_DIR = path.join(MARATHON_DIR,
|
|
51
|
+
const FEATURE_LIST_FILE = path.join(MARATHON_DIR, 'feature_list.json');
|
|
52
|
+
const PROGRESS_FILE = path.join(MARATHON_DIR, 'progress.json');
|
|
53
|
+
const ARCHIVE_DIR = path.join(MARATHON_DIR, 'archive');
|
|
54
54
|
|
|
55
55
|
const VALID_COMMANDS = new Set([
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
56
|
+
'init',
|
|
57
|
+
'status',
|
|
58
|
+
'next',
|
|
59
|
+
'mark',
|
|
60
|
+
'log',
|
|
61
|
+
'session-start',
|
|
62
|
+
'session-end',
|
|
63
|
+
'reset',
|
|
64
|
+
'add-feature',
|
|
65
|
+
'distill',
|
|
66
66
|
]);
|
|
67
67
|
|
|
68
68
|
// ── Schema Defaults ──────────────────────────────────────────────────────────
|
|
@@ -106,12 +106,10 @@ function createProgress(spec) {
|
|
|
106
106
|
function readJSON(filePath) {
|
|
107
107
|
if (!fs.existsSync(filePath)) return null;
|
|
108
108
|
try {
|
|
109
|
-
const content = fs.readFileSync(filePath,
|
|
109
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
110
110
|
return JSON.parse(content);
|
|
111
111
|
} catch (e) {
|
|
112
|
-
console.error(
|
|
113
|
-
`${RED}Error reading ${path.basename(filePath)}: ${e.message}${RESET}`,
|
|
114
|
-
);
|
|
112
|
+
console.error(`${RED}Error reading ${path.basename(filePath)}: ${e.message}${RESET}`);
|
|
115
113
|
return null;
|
|
116
114
|
}
|
|
117
115
|
}
|
|
@@ -123,7 +121,7 @@ function readJSON(filePath) {
|
|
|
123
121
|
*/
|
|
124
122
|
function writeJSON(filePath, data) {
|
|
125
123
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
126
|
-
fs.writeFileSync(filePath, JSON.stringify(data, null, 2),
|
|
124
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
|
|
127
125
|
}
|
|
128
126
|
|
|
129
127
|
/**
|
|
@@ -151,10 +149,10 @@ function isActive() {
|
|
|
151
149
|
function getGitLog(count = 20) {
|
|
152
150
|
try {
|
|
153
151
|
const output = execSync(`git log --oneline -${count}`, {
|
|
154
|
-
encoding:
|
|
155
|
-
stdio: [
|
|
152
|
+
encoding: 'utf8',
|
|
153
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
156
154
|
});
|
|
157
|
-
return output.trim().split(
|
|
155
|
+
return output.trim().split('\n').filter(Boolean);
|
|
158
156
|
} catch {
|
|
159
157
|
return [];
|
|
160
158
|
}
|
|
@@ -166,12 +164,12 @@ function getGitLog(count = 20) {
|
|
|
166
164
|
*/
|
|
167
165
|
function getGitBranch() {
|
|
168
166
|
try {
|
|
169
|
-
return execSync(
|
|
170
|
-
encoding:
|
|
171
|
-
stdio: [
|
|
167
|
+
return execSync('git branch --show-current', {
|
|
168
|
+
encoding: 'utf8',
|
|
169
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
172
170
|
}).trim();
|
|
173
171
|
} catch {
|
|
174
|
-
return
|
|
172
|
+
return 'unknown';
|
|
175
173
|
}
|
|
176
174
|
}
|
|
177
175
|
|
|
@@ -185,13 +183,13 @@ function getGitBranch() {
|
|
|
185
183
|
function countFeatures(featureList) {
|
|
186
184
|
const features = featureList.features || [];
|
|
187
185
|
const total = features.length;
|
|
188
|
-
const passing = features.filter(
|
|
186
|
+
const passing = features.filter(f => f.passes === true).length;
|
|
189
187
|
let blocked = 0;
|
|
190
188
|
|
|
191
|
-
features.forEach(
|
|
189
|
+
features.forEach(f => {
|
|
192
190
|
if (!f.passes && f.dependencies && f.dependencies.length > 0) {
|
|
193
|
-
const allPassed = f.dependencies.every(
|
|
194
|
-
const dep = features.find(
|
|
191
|
+
const allPassed = f.dependencies.every(depId => {
|
|
192
|
+
const dep = features.find(d => d.id === depId);
|
|
195
193
|
return dep && dep.passes === true;
|
|
196
194
|
});
|
|
197
195
|
if (!allPassed) blocked++;
|
|
@@ -209,13 +207,13 @@ function countFeatures(featureList) {
|
|
|
209
207
|
function getNextFeature(featureList) {
|
|
210
208
|
const features = featureList.features || [];
|
|
211
209
|
return (
|
|
212
|
-
features.find(
|
|
210
|
+
features.find(f => {
|
|
213
211
|
if (f.passes === true) return false;
|
|
214
212
|
|
|
215
213
|
// Check dependencies (DAG)
|
|
216
214
|
if (f.dependencies && f.dependencies.length > 0) {
|
|
217
|
-
const allPassed = f.dependencies.every(
|
|
218
|
-
const dep = features.find(
|
|
215
|
+
const allPassed = f.dependencies.every(depId => {
|
|
216
|
+
const dep = features.find(d => d.id === depId);
|
|
219
217
|
return dep && dep.passes === true;
|
|
220
218
|
});
|
|
221
219
|
if (!allPassed) return false; // Feature is blocked
|
|
@@ -234,7 +232,7 @@ function getNextFeature(featureList) {
|
|
|
234
232
|
* @returns {string}
|
|
235
233
|
*/
|
|
236
234
|
function progressBar(current, total, width = 30) {
|
|
237
|
-
if (total === 0) return `${DIM}[${
|
|
235
|
+
if (total === 0) return `${DIM}[${'░'.repeat(width)}]${RESET} 0%`;
|
|
238
236
|
const pct = Math.round((current / total) * 100);
|
|
239
237
|
const filled = Math.round((current / total) * width);
|
|
240
238
|
const empty = width - filled;
|
|
@@ -244,7 +242,7 @@ function progressBar(current, total, width = 30) {
|
|
|
244
242
|
else if (pct >= 40) color = YELLOW;
|
|
245
243
|
else if (pct >= 15) color = CYAN;
|
|
246
244
|
|
|
247
|
-
return `${color}[${
|
|
245
|
+
return `${color}[${'█'.repeat(filled)}${'░'.repeat(empty)}]${RESET} ${BOLD}${pct}%${RESET}`;
|
|
248
246
|
}
|
|
249
247
|
|
|
250
248
|
// ── Commands ─────────────────────────────────────────────────────────────────
|
|
@@ -277,23 +275,19 @@ function cmdInit(spec) {
|
|
|
277
275
|
writeJSON(FEATURE_LIST_FILE, featureList);
|
|
278
276
|
writeJSON(PROGRESS_FILE, progress);
|
|
279
277
|
|
|
280
|
-
console.log(banner(
|
|
278
|
+
console.log(banner('marathon_harness.js', { Mode: 'INIT' }));
|
|
281
279
|
console.log();
|
|
282
280
|
ok(`Marathon initialized for: ${BOLD}${spec}${RESET}`);
|
|
283
281
|
console.log();
|
|
284
|
-
info(
|
|
285
|
-
console.log(
|
|
286
|
-
` ${DIM}1.${RESET} Decompose the spec into 30-200 atomic features`,
|
|
287
|
-
);
|
|
282
|
+
info('Next steps for the agent:');
|
|
283
|
+
console.log(` ${DIM}1.${RESET} Decompose the spec into 30-200 atomic features`);
|
|
288
284
|
console.log(
|
|
289
285
|
` ${DIM}2.${RESET} Add each feature with: ${CYAN}add-feature "category" "description" "step1" "step2" ...${RESET}`,
|
|
290
286
|
);
|
|
291
287
|
console.log(
|
|
292
288
|
` ${DIM}3.${RESET} Make an initial git commit: ${CYAN}git commit -m "marathon: initial scaffold"${RESET}`,
|
|
293
289
|
);
|
|
294
|
-
console.log(
|
|
295
|
-
` ${DIM}4.${RESET} Start the first session: ${CYAN}session-start${RESET}`,
|
|
296
|
-
);
|
|
290
|
+
console.log(` ${DIM}4.${RESET} Start the first session: ${CYAN}session-start${RESET}`);
|
|
297
291
|
console.log();
|
|
298
292
|
console.log(` ${DIM}State directory: ${MARATHON_DIR}${RESET}`);
|
|
299
293
|
console.log();
|
|
@@ -308,9 +302,7 @@ function cmdInit(spec) {
|
|
|
308
302
|
*/
|
|
309
303
|
function cmdAddFeature(category, description, steps, deps = []) {
|
|
310
304
|
if (!isActive()) {
|
|
311
|
-
console.error(
|
|
312
|
-
`${RED}❌ No active marathon. Run ${CYAN}init${RED} first.${RESET}`,
|
|
313
|
-
);
|
|
305
|
+
console.error(`${RED}❌ No active marathon. Run ${CYAN}init${RED} first.${RESET}`);
|
|
314
306
|
process.exit(1);
|
|
315
307
|
}
|
|
316
308
|
|
|
@@ -325,15 +317,13 @@ function cmdAddFeature(category, description, steps, deps = []) {
|
|
|
325
317
|
if (!featureList) process.exit(1);
|
|
326
318
|
|
|
327
319
|
const newId =
|
|
328
|
-
featureList.features.length > 0
|
|
329
|
-
? Math.max(...featureList.features.map((f) => f.id)) + 1
|
|
330
|
-
: 1;
|
|
320
|
+
featureList.features.length > 0 ? Math.max(...featureList.features.map(f => f.id)) + 1 : 1;
|
|
331
321
|
|
|
332
322
|
const feature = {
|
|
333
323
|
id: newId,
|
|
334
324
|
category: category.toLowerCase(),
|
|
335
325
|
description,
|
|
336
|
-
steps: steps.length > 0 ? steps : [
|
|
326
|
+
steps: steps.length > 0 ? steps : ['Implement and verify'],
|
|
337
327
|
dependencies: deps,
|
|
338
328
|
attempts: 0,
|
|
339
329
|
failureReasons: [],
|
|
@@ -371,7 +361,7 @@ function cmdStatus() {
|
|
|
371
361
|
const sessions = progress.sessions || [];
|
|
372
362
|
const lastSession = sessions[sessions.length - 1] || null;
|
|
373
363
|
|
|
374
|
-
console.log(banner(
|
|
364
|
+
console.log(banner('marathon_harness.js', { Mode: 'STATUS' }));
|
|
375
365
|
console.log();
|
|
376
366
|
|
|
377
367
|
// ── Spec ──
|
|
@@ -380,8 +370,7 @@ function cmdStatus() {
|
|
|
380
370
|
console.log();
|
|
381
371
|
|
|
382
372
|
// ── Progress Bar ──
|
|
383
|
-
const blockedInfo =
|
|
384
|
-
blocked > 0 ? ` (${YELLOW}${blocked} blocked${RESET})` : "";
|
|
373
|
+
const blockedInfo = blocked > 0 ? ` (${YELLOW}${blocked} blocked${RESET})` : '';
|
|
385
374
|
console.log(
|
|
386
375
|
` ${BOLD}Progress:${RESET} ${progressBar(passing, total)} ${GREEN}${passing}${RESET}/${total} features${blockedInfo}`,
|
|
387
376
|
);
|
|
@@ -390,7 +379,7 @@ function cmdStatus() {
|
|
|
390
379
|
// ── Category Breakdown ──
|
|
391
380
|
const categories = {};
|
|
392
381
|
for (const f of featureList.features) {
|
|
393
|
-
const cat = f.category ||
|
|
382
|
+
const cat = f.category || 'uncategorized';
|
|
394
383
|
if (!categories[cat]) categories[cat] = { total: 0, passing: 0 };
|
|
395
384
|
categories[cat].total++;
|
|
396
385
|
if (f.passes) categories[cat].passing++;
|
|
@@ -399,10 +388,7 @@ function cmdStatus() {
|
|
|
399
388
|
if (Object.keys(categories).length > 0) {
|
|
400
389
|
console.log(` ${BOLD}By Category:${RESET}`);
|
|
401
390
|
for (const [cat, counts] of Object.entries(categories)) {
|
|
402
|
-
const catPct =
|
|
403
|
-
counts.total > 0
|
|
404
|
-
? Math.round((counts.passing / counts.total) * 100)
|
|
405
|
-
: 0;
|
|
391
|
+
const catPct = counts.total > 0 ? Math.round((counts.passing / counts.total) * 100) : 0;
|
|
406
392
|
const catColor = catPct === 100 ? GREEN : catPct >= 50 ? YELLOW : RED;
|
|
407
393
|
console.log(
|
|
408
394
|
` ${MAGENTA}${cat.padEnd(18)}${RESET} ${catColor}${counts.passing}/${counts.total}${RESET} (${catPct}%)`,
|
|
@@ -415,18 +401,14 @@ function cmdStatus() {
|
|
|
415
401
|
console.log(` ${BOLD}Sessions:${RESET} ${sessions.length} completed`);
|
|
416
402
|
if (lastSession) {
|
|
417
403
|
console.log(
|
|
418
|
-
` ${DIM}Last session:${RESET} #${lastSession.session} — ${lastSession.endedAt?.slice(0, 16) ||
|
|
404
|
+
` ${DIM}Last session:${RESET} #${lastSession.session} — ${lastSession.endedAt?.slice(0, 16) || 'in progress'}`,
|
|
419
405
|
);
|
|
420
406
|
if (lastSession.notes) {
|
|
421
407
|
console.log(` ${DIM}Notes:${RESET} ${lastSession.notes.slice(0, 80)}`);
|
|
422
408
|
}
|
|
423
409
|
if (lastSession.featuresAtEnd) {
|
|
424
|
-
const delta =
|
|
425
|
-
|
|
426
|
-
(lastSession.featuresAtStart?.passing || 0);
|
|
427
|
-
console.log(
|
|
428
|
-
` ${DIM}Features completed:${RESET} ${GREEN}+${delta}${RESET}`,
|
|
429
|
-
);
|
|
410
|
+
const delta = lastSession.featuresAtEnd.passing - (lastSession.featuresAtStart?.passing || 0);
|
|
411
|
+
console.log(` ${DIM}Features completed:${RESET} ${GREEN}+${delta}${RESET}`);
|
|
430
412
|
}
|
|
431
413
|
}
|
|
432
414
|
console.log();
|
|
@@ -444,9 +426,7 @@ function cmdStatus() {
|
|
|
444
426
|
}
|
|
445
427
|
}
|
|
446
428
|
} else if (total > 0) {
|
|
447
|
-
console.log(
|
|
448
|
-
` ${GREEN}${BOLD}🎉 All ${total} features are passing!${RESET}`,
|
|
449
|
-
);
|
|
429
|
+
console.log(` ${GREEN}${BOLD}🎉 All ${total} features are passing!${RESET}`);
|
|
450
430
|
}
|
|
451
431
|
console.log();
|
|
452
432
|
|
|
@@ -512,18 +492,14 @@ function cmdNext() {
|
|
|
512
492
|
}
|
|
513
493
|
|
|
514
494
|
if (nextFeature.failureReasons && nextFeature.failureReasons.length > 0) {
|
|
515
|
-
console.log(
|
|
516
|
-
` ${RED}${BOLD}Previous Failures (${nextFeature.attempts} attempts):${RESET}`,
|
|
517
|
-
);
|
|
495
|
+
console.log(` ${RED}${BOLD}Previous Failures (${nextFeature.attempts} attempts):${RESET}`);
|
|
518
496
|
for (const reason of nextFeature.failureReasons) {
|
|
519
497
|
console.log(` ${DIM}* ${reason}${RESET}`);
|
|
520
498
|
}
|
|
521
499
|
console.log();
|
|
522
500
|
}
|
|
523
501
|
|
|
524
|
-
console.log(
|
|
525
|
-
` ${DIM}When done: marathon_harness.js mark ${nextFeature.id} pass${RESET}`,
|
|
526
|
-
);
|
|
502
|
+
console.log(` ${DIM}When done: marathon_harness.js mark ${nextFeature.id} pass${RESET}`);
|
|
527
503
|
console.log();
|
|
528
504
|
}
|
|
529
505
|
|
|
@@ -539,18 +515,16 @@ function cmdMark(id, verdict, reason) {
|
|
|
539
515
|
process.exit(1);
|
|
540
516
|
}
|
|
541
517
|
|
|
542
|
-
const validVerdicts = [
|
|
518
|
+
const validVerdicts = ['pass', 'fail'];
|
|
543
519
|
if (!validVerdicts.includes(verdict)) {
|
|
544
|
-
console.error(
|
|
545
|
-
`${RED}❌ Invalid verdict "${verdict}". Use: pass | fail${RESET}`,
|
|
546
|
-
);
|
|
520
|
+
console.error(`${RED}❌ Invalid verdict "${verdict}". Use: pass | fail${RESET}`);
|
|
547
521
|
process.exit(1);
|
|
548
522
|
}
|
|
549
523
|
|
|
550
524
|
const featureList = readJSON(FEATURE_LIST_FILE);
|
|
551
525
|
if (!featureList) process.exit(1);
|
|
552
526
|
|
|
553
|
-
const feature = featureList.features.find(
|
|
527
|
+
const feature = featureList.features.find(f => f.id === id);
|
|
554
528
|
if (!feature) {
|
|
555
529
|
console.error(
|
|
556
530
|
`${RED}❌ Feature #${id} not found. Valid IDs: 1-${featureList.features.length}${RESET}`,
|
|
@@ -558,7 +532,7 @@ function cmdMark(id, verdict, reason) {
|
|
|
558
532
|
process.exit(1);
|
|
559
533
|
}
|
|
560
534
|
|
|
561
|
-
const newPasses = verdict ===
|
|
535
|
+
const newPasses = verdict === 'pass';
|
|
562
536
|
const oldPasses = feature.passes;
|
|
563
537
|
|
|
564
538
|
// Guard: don't allow editing description or steps
|
|
@@ -582,15 +556,11 @@ function cmdMark(id, verdict, reason) {
|
|
|
582
556
|
} else if (!newPasses && oldPasses) {
|
|
583
557
|
warn(`Feature #${id} marked as ${RED}FAILING${RESET}`);
|
|
584
558
|
} else {
|
|
585
|
-
info(
|
|
586
|
-
`Feature #${id} unchanged (already ${newPasses ? "passing" : "failing"})`,
|
|
587
|
-
);
|
|
559
|
+
info(`Feature #${id} unchanged (already ${newPasses ? 'passing' : 'failing'})`);
|
|
588
560
|
}
|
|
589
561
|
|
|
590
562
|
console.log(` ${DIM}${feature.description}${RESET}`);
|
|
591
|
-
console.log(
|
|
592
|
-
` ${progressBar(passing, total)} ${GREEN}${passing}${RESET}/${total}`,
|
|
593
|
-
);
|
|
563
|
+
console.log(` ${progressBar(passing, total)} ${GREEN}${passing}${RESET}/${total}`);
|
|
594
564
|
console.log();
|
|
595
565
|
}
|
|
596
566
|
|
|
@@ -605,9 +575,7 @@ function cmdLog(message) {
|
|
|
605
575
|
}
|
|
606
576
|
|
|
607
577
|
if (!message) {
|
|
608
|
-
console.error(
|
|
609
|
-
`${RED}❌ Message required. Usage: log "Your progress note"${RESET}`,
|
|
610
|
-
);
|
|
578
|
+
console.error(`${RED}❌ Message required. Usage: log "Your progress note"${RESET}`);
|
|
611
579
|
process.exit(1);
|
|
612
580
|
}
|
|
613
581
|
|
|
@@ -635,18 +603,16 @@ function cmdDistill(lesson) {
|
|
|
635
603
|
}
|
|
636
604
|
|
|
637
605
|
if (!lesson) {
|
|
638
|
-
console.error(
|
|
639
|
-
`${RED}❌ Lesson required. Usage: distill "Your architectural lesson"${RESET}`,
|
|
640
|
-
);
|
|
606
|
+
console.error(`${RED}❌ Lesson required. Usage: distill "Your architectural lesson"${RESET}`);
|
|
641
607
|
process.exit(1);
|
|
642
608
|
}
|
|
643
609
|
|
|
644
610
|
ensureDir();
|
|
645
|
-
const DISTILL_FILE = path.join(MARATHON_DIR,
|
|
611
|
+
const DISTILL_FILE = path.join(MARATHON_DIR, 'distilled_context.md');
|
|
646
612
|
const timestamp = new Date().toISOString().slice(0, 16);
|
|
647
613
|
const entry = `- [${timestamp}] ${lesson}\n`;
|
|
648
614
|
|
|
649
|
-
fs.appendFileSync(DISTILL_FILE, entry,
|
|
615
|
+
fs.appendFileSync(DISTILL_FILE, entry, 'utf8');
|
|
650
616
|
ok(`Distilled memory saved: ${lesson}`);
|
|
651
617
|
}
|
|
652
618
|
|
|
@@ -685,8 +651,8 @@ function cmdSessionStart() {
|
|
|
685
651
|
|
|
686
652
|
// Display bearings
|
|
687
653
|
console.log(
|
|
688
|
-
banner(
|
|
689
|
-
Mode:
|
|
654
|
+
banner('marathon_harness.js', {
|
|
655
|
+
Mode: 'SESSION START',
|
|
690
656
|
Session: `#${sessionNum}`,
|
|
691
657
|
}),
|
|
692
658
|
);
|
|
@@ -724,9 +690,7 @@ function cmdSessionStart() {
|
|
|
724
690
|
if (recentLogs.length > 0) {
|
|
725
691
|
console.log(` ${BOLD}Recent Log:${RESET}`);
|
|
726
692
|
for (const entry of recentLogs) {
|
|
727
|
-
console.log(
|
|
728
|
-
` ${DIM}${entry.timestamp.slice(0, 16)}${RESET} ${entry.message}`,
|
|
729
|
-
);
|
|
693
|
+
console.log(` ${DIM}${entry.timestamp.slice(0, 16)}${RESET} ${entry.message}`);
|
|
730
694
|
}
|
|
731
695
|
console.log();
|
|
732
696
|
}
|
|
@@ -744,9 +708,7 @@ function cmdSessionStart() {
|
|
|
744
708
|
}
|
|
745
709
|
} else {
|
|
746
710
|
if (passing === total) {
|
|
747
|
-
console.log(
|
|
748
|
-
` ${GREEN}${BOLD}🎉 All features passing! Nothing to implement.${RESET}`,
|
|
749
|
-
);
|
|
711
|
+
console.log(` ${GREEN}${BOLD}🎉 All features passing! Nothing to implement.${RESET}`);
|
|
750
712
|
} else {
|
|
751
713
|
console.log(
|
|
752
714
|
` ${RED}${BOLD}⚠️ Deadlock: ${total - passing} features are blocked by failing dependencies.${RESET}`,
|
|
@@ -760,13 +722,9 @@ function cmdSessionStart() {
|
|
|
760
722
|
console.log(
|
|
761
723
|
` ${DIM}1.${RESET} Start dev server (if applicable): ${CYAN}node .agent/scripts/auto_preview.js start${RESET}`,
|
|
762
724
|
);
|
|
763
|
-
console.log(
|
|
764
|
-
` ${DIM}2.${RESET} Smoke test the app to verify it's not broken`,
|
|
765
|
-
);
|
|
725
|
+
console.log(` ${DIM}2.${RESET} Smoke test the app to verify it's not broken`);
|
|
766
726
|
console.log(` ${DIM}3.${RESET} Implement the next feature shown above`);
|
|
767
|
-
console.log(
|
|
768
|
-
` ${DIM}4.${RESET} Test, mark as passing, commit, then pick next feature`,
|
|
769
|
-
);
|
|
727
|
+
console.log(` ${DIM}4.${RESET} Test, mark as passing, commit, then pick next feature`);
|
|
770
728
|
console.log();
|
|
771
729
|
}
|
|
772
730
|
|
|
@@ -786,9 +744,7 @@ function cmdSessionEnd(summary) {
|
|
|
786
744
|
|
|
787
745
|
const sessions = progress.sessions || [];
|
|
788
746
|
if (sessions.length === 0) {
|
|
789
|
-
console.error(
|
|
790
|
-
`${RED}❌ No active session. Run ${CYAN}session-start${RED} first.${RESET}`,
|
|
791
|
-
);
|
|
747
|
+
console.error(`${RED}❌ No active session. Run ${CYAN}session-start${RED} first.${RESET}`);
|
|
792
748
|
process.exit(1);
|
|
793
749
|
}
|
|
794
750
|
|
|
@@ -802,27 +758,22 @@ function cmdSessionEnd(summary) {
|
|
|
802
758
|
// Find which features were completed (have sessionCompleted in this session range)
|
|
803
759
|
const sessionStartTime = currentSession.startedAt;
|
|
804
760
|
const completedIds = featureList.features
|
|
805
|
-
.filter(
|
|
806
|
-
|
|
807
|
-
f.passes &&
|
|
808
|
-
f.sessionCompleted &&
|
|
809
|
-
f.sessionCompleted >= sessionStartTime,
|
|
810
|
-
)
|
|
811
|
-
.map((f) => f.id);
|
|
761
|
+
.filter(f => f.passes && f.sessionCompleted && f.sessionCompleted >= sessionStartTime)
|
|
762
|
+
.map(f => f.id);
|
|
812
763
|
|
|
813
764
|
// Get git commits since session start
|
|
814
765
|
let sessionCommits = [];
|
|
815
766
|
try {
|
|
816
767
|
const since = currentSession.startedAt;
|
|
817
768
|
const output = execSync(`git log --oneline --since="${since}"`, {
|
|
818
|
-
encoding:
|
|
819
|
-
stdio: [
|
|
769
|
+
encoding: 'utf8',
|
|
770
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
820
771
|
});
|
|
821
772
|
sessionCommits = output
|
|
822
773
|
.trim()
|
|
823
|
-
.split(
|
|
774
|
+
.split('\n')
|
|
824
775
|
.filter(Boolean)
|
|
825
|
-
.map(
|
|
776
|
+
.map(l => l.split(' ')[0]);
|
|
826
777
|
} catch {
|
|
827
778
|
// Git not available or no commits
|
|
828
779
|
}
|
|
@@ -832,16 +783,15 @@ function cmdSessionEnd(summary) {
|
|
|
832
783
|
currentSession.featuresAtEnd = { total, passing };
|
|
833
784
|
currentSession.featuresCompleted = completedIds;
|
|
834
785
|
currentSession.notes =
|
|
835
|
-
summary ||
|
|
836
|
-
`Session ${currentSession.session}: ${completedThisSession} features completed`;
|
|
786
|
+
summary || `Session ${currentSession.session}: ${completedThisSession} features completed`;
|
|
837
787
|
currentSession.gitCommits = sessionCommits;
|
|
838
788
|
|
|
839
789
|
writeJSON(PROGRESS_FILE, progress);
|
|
840
790
|
|
|
841
791
|
// Display summary
|
|
842
792
|
console.log(
|
|
843
|
-
banner(
|
|
844
|
-
Mode:
|
|
793
|
+
banner('marathon_harness.js', {
|
|
794
|
+
Mode: 'SESSION END',
|
|
845
795
|
Session: `#${currentSession.session}`,
|
|
846
796
|
}),
|
|
847
797
|
);
|
|
@@ -851,7 +801,7 @@ function cmdSessionEnd(summary) {
|
|
|
851
801
|
console.log(` Started: ${currentSession.startedAt.slice(0, 16)}`);
|
|
852
802
|
console.log(` Ended: ${currentSession.endedAt.slice(0, 16)}`);
|
|
853
803
|
console.log(
|
|
854
|
-
` Features: ${GREEN}+${completedThisSession}${RESET} completed (${completedIds.map(
|
|
804
|
+
` Features: ${GREEN}+${completedThisSession}${RESET} completed (${completedIds.map(id => `#${id}`).join(', ') || 'none'})`,
|
|
855
805
|
);
|
|
856
806
|
console.log(` Commits: ${sessionCommits.length}`);
|
|
857
807
|
if (summary) {
|
|
@@ -867,17 +817,13 @@ function cmdSessionEnd(summary) {
|
|
|
867
817
|
const remaining = total - passing;
|
|
868
818
|
if (remaining > 0) {
|
|
869
819
|
const avgPerSession =
|
|
870
|
-
sessions.length > 0
|
|
871
|
-
? Math.max(1, Math.round(passing / sessions.length))
|
|
872
|
-
: 1;
|
|
820
|
+
sessions.length > 0 ? Math.max(1, Math.round(passing / sessions.length)) : 1;
|
|
873
821
|
const estRemaining = Math.ceil(remaining / avgPerSession);
|
|
874
822
|
console.log(
|
|
875
823
|
` ${DIM}Estimated sessions remaining: ~${estRemaining} (avg ${avgPerSession} features/session)${RESET}`,
|
|
876
824
|
);
|
|
877
825
|
} else {
|
|
878
|
-
console.log(
|
|
879
|
-
` ${GREEN}${BOLD}🎉 Marathon complete! All features passing.${RESET}`,
|
|
880
|
-
);
|
|
826
|
+
console.log(` ${GREEN}${BOLD}🎉 Marathon complete! All features passing.${RESET}`);
|
|
881
827
|
}
|
|
882
828
|
console.log();
|
|
883
829
|
}
|
|
@@ -892,23 +838,18 @@ function cmdReset() {
|
|
|
892
838
|
}
|
|
893
839
|
|
|
894
840
|
const featureList = readJSON(FEATURE_LIST_FILE);
|
|
895
|
-
const { total, passing } = featureList
|
|
896
|
-
? countFeatures(featureList)
|
|
897
|
-
: { total: 0, passing: 0 };
|
|
841
|
+
const { total, passing } = featureList ? countFeatures(featureList) : { total: 0, passing: 0 };
|
|
898
842
|
|
|
899
843
|
// Archive current state
|
|
900
|
-
const archiveTimestamp = new Date()
|
|
901
|
-
.toISOString()
|
|
902
|
-
.replace(/[:.]/g, "-")
|
|
903
|
-
.slice(0, 19);
|
|
844
|
+
const archiveTimestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
904
845
|
const archivePath = path.join(ARCHIVE_DIR, archiveTimestamp);
|
|
905
846
|
fs.mkdirSync(archivePath, { recursive: true });
|
|
906
847
|
|
|
907
848
|
if (fs.existsSync(FEATURE_LIST_FILE)) {
|
|
908
|
-
fs.cpSync(FEATURE_LIST_FILE, path.join(archivePath,
|
|
849
|
+
fs.cpSync(FEATURE_LIST_FILE, path.join(archivePath, 'feature_list.json'));
|
|
909
850
|
}
|
|
910
851
|
if (fs.existsSync(PROGRESS_FILE)) {
|
|
911
|
-
fs.cpSync(PROGRESS_FILE, path.join(archivePath,
|
|
852
|
+
fs.cpSync(PROGRESS_FILE, path.join(archivePath, 'progress.json'));
|
|
912
853
|
}
|
|
913
854
|
|
|
914
855
|
// Remove current state files
|
|
@@ -916,19 +857,15 @@ function cmdReset() {
|
|
|
916
857
|
if (fs.existsSync(PROGRESS_FILE)) fs.unlinkSync(PROGRESS_FILE);
|
|
917
858
|
|
|
918
859
|
ok(`Marathon archived to: ${archivePath}`);
|
|
919
|
-
console.log(
|
|
920
|
-
|
|
921
|
-
);
|
|
922
|
-
console.log(
|
|
923
|
-
` ${DIM}Start a new marathon with: marathon_harness.js init "new spec"${RESET}`,
|
|
924
|
-
);
|
|
860
|
+
console.log(` ${DIM}Progress at archive: ${passing}/${total} features passing${RESET}`);
|
|
861
|
+
console.log(` ${DIM}Start a new marathon with: marathon_harness.js init "new spec"${RESET}`);
|
|
925
862
|
console.log();
|
|
926
863
|
}
|
|
927
864
|
|
|
928
865
|
// ── Help ─────────────────────────────────────────────────────────────────────
|
|
929
866
|
|
|
930
867
|
function showHelp() {
|
|
931
|
-
console.log(banner(
|
|
868
|
+
console.log(banner('marathon_harness.js', { Mode: 'HELP' }));
|
|
932
869
|
console.log();
|
|
933
870
|
console.log(` ${BOLD}Long-Running Agent Harness${RESET}`);
|
|
934
871
|
console.log(
|
|
@@ -936,26 +873,19 @@ function showHelp() {
|
|
|
936
873
|
);
|
|
937
874
|
console.log();
|
|
938
875
|
|
|
939
|
-
const cmd = (name, desc) =>
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
cmd('
|
|
943
|
-
cmd(
|
|
944
|
-
cmd(
|
|
945
|
-
cmd(
|
|
946
|
-
cmd(
|
|
947
|
-
cmd('
|
|
948
|
-
cmd('
|
|
949
|
-
cmd(
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
);
|
|
953
|
-
cmd("session-end", "End session with optional summary");
|
|
954
|
-
cmd(
|
|
955
|
-
"add-feature",
|
|
956
|
-
"Add a feature (supports --deps=1,2,3 for DAG dependencies)",
|
|
957
|
-
);
|
|
958
|
-
cmd("reset", "Archive current marathon and start fresh");
|
|
876
|
+
const cmd = (name, desc) => console.log(` ${CYAN}${name.padEnd(16)}${RESET} ${desc}`);
|
|
877
|
+
|
|
878
|
+
cmd('init "spec"', 'Start a new marathon with the given specification');
|
|
879
|
+
cmd('status', 'Show progress dashboard');
|
|
880
|
+
cmd('next', 'Show the next unfinished feature');
|
|
881
|
+
cmd('mark <id> pass', 'Mark a feature as passing');
|
|
882
|
+
cmd('mark <id> fail', 'Mark a feature as failing (optional: "reason")');
|
|
883
|
+
cmd('log "note"', 'Add a timestamped progress note');
|
|
884
|
+
cmd('distill "rule"', 'Save an architectural rule or lesson to memory');
|
|
885
|
+
cmd('session-start', 'Begin a new work session (reads state, shows bearings)');
|
|
886
|
+
cmd('session-end', 'End session with optional summary');
|
|
887
|
+
cmd('add-feature', 'Add a feature (supports --deps=1,2,3 for DAG dependencies)');
|
|
888
|
+
cmd('reset', 'Archive current marathon and start fresh');
|
|
959
889
|
console.log();
|
|
960
890
|
}
|
|
961
891
|
|
|
@@ -964,12 +894,7 @@ function showHelp() {
|
|
|
964
894
|
function main() {
|
|
965
895
|
const args = process.argv.slice(2);
|
|
966
896
|
|
|
967
|
-
if (
|
|
968
|
-
args.length === 0 ||
|
|
969
|
-
args[0] === "help" ||
|
|
970
|
-
args[0] === "--help" ||
|
|
971
|
-
args[0] === "-h"
|
|
972
|
-
) {
|
|
897
|
+
if (args.length === 0 || args[0] === 'help' || args[0] === '--help' || args[0] === '-h') {
|
|
973
898
|
showHelp();
|
|
974
899
|
return;
|
|
975
900
|
}
|
|
@@ -978,61 +903,59 @@ function main() {
|
|
|
978
903
|
|
|
979
904
|
if (!VALID_COMMANDS.has(cmd)) {
|
|
980
905
|
console.error(`${RED}Unknown command: "${cmd}"${RESET}`);
|
|
981
|
-
console.error(`Valid commands: ${[...VALID_COMMANDS].sort().join(
|
|
906
|
+
console.error(`Valid commands: ${[...VALID_COMMANDS].sort().join(', ')}`);
|
|
982
907
|
process.exit(1);
|
|
983
908
|
}
|
|
984
909
|
|
|
985
910
|
switch (cmd) {
|
|
986
|
-
case
|
|
987
|
-
const spec = args.slice(1).join(
|
|
911
|
+
case 'init': {
|
|
912
|
+
const spec = args.slice(1).join(' ').trim();
|
|
988
913
|
cmdInit(spec);
|
|
989
914
|
break;
|
|
990
915
|
}
|
|
991
|
-
case
|
|
916
|
+
case 'status':
|
|
992
917
|
cmdStatus();
|
|
993
918
|
break;
|
|
994
|
-
case
|
|
919
|
+
case 'next':
|
|
995
920
|
cmdNext();
|
|
996
921
|
break;
|
|
997
|
-
case
|
|
922
|
+
case 'mark': {
|
|
998
923
|
const id = parseInt(args[1], 10);
|
|
999
|
-
const verdict = (args[2] ||
|
|
1000
|
-
const reason = args.slice(3).join(
|
|
924
|
+
const verdict = (args[2] || '').toLowerCase();
|
|
925
|
+
const reason = args.slice(3).join(' ').trim();
|
|
1001
926
|
if (isNaN(id)) {
|
|
1002
|
-
console.error(
|
|
1003
|
-
`${RED}❌ Feature ID required. Usage: mark <id> pass|fail "reason"${RESET}`,
|
|
1004
|
-
);
|
|
927
|
+
console.error(`${RED}❌ Feature ID required. Usage: mark <id> pass|fail "reason"${RESET}`);
|
|
1005
928
|
process.exit(1);
|
|
1006
929
|
}
|
|
1007
930
|
cmdMark(id, verdict, reason);
|
|
1008
931
|
break;
|
|
1009
932
|
}
|
|
1010
|
-
case
|
|
1011
|
-
const message = args.slice(1).join(
|
|
933
|
+
case 'log': {
|
|
934
|
+
const message = args.slice(1).join(' ').trim();
|
|
1012
935
|
cmdLog(message);
|
|
1013
936
|
break;
|
|
1014
937
|
}
|
|
1015
|
-
case
|
|
938
|
+
case 'session-start':
|
|
1016
939
|
cmdSessionStart();
|
|
1017
940
|
break;
|
|
1018
|
-
case
|
|
1019
|
-
const summary = args.slice(1).join(
|
|
941
|
+
case 'session-end': {
|
|
942
|
+
const summary = args.slice(1).join(' ').trim() || null;
|
|
1020
943
|
cmdSessionEnd(summary);
|
|
1021
944
|
break;
|
|
1022
945
|
}
|
|
1023
|
-
case
|
|
1024
|
-
const category = args[1] ||
|
|
1025
|
-
const description = args[2] ||
|
|
946
|
+
case 'add-feature': {
|
|
947
|
+
const category = args[1] || '';
|
|
948
|
+
const description = args[2] || '';
|
|
1026
949
|
let steps = args.slice(3);
|
|
1027
950
|
let deps = [];
|
|
1028
951
|
|
|
1029
|
-
steps = steps.filter(
|
|
1030
|
-
if (step.startsWith(
|
|
952
|
+
steps = steps.filter(step => {
|
|
953
|
+
if (step.startsWith('--deps=')) {
|
|
1031
954
|
deps = step
|
|
1032
|
-
.replace(
|
|
1033
|
-
.split(
|
|
955
|
+
.replace('--deps=', '')
|
|
956
|
+
.split(',')
|
|
1034
957
|
.map(Number)
|
|
1035
|
-
.filter(
|
|
958
|
+
.filter(n => !isNaN(n));
|
|
1036
959
|
return false;
|
|
1037
960
|
}
|
|
1038
961
|
return true;
|
|
@@ -1041,12 +964,12 @@ function main() {
|
|
|
1041
964
|
cmdAddFeature(category, description, steps, deps);
|
|
1042
965
|
break;
|
|
1043
966
|
}
|
|
1044
|
-
case
|
|
1045
|
-
const lesson = args.slice(1).join(
|
|
967
|
+
case 'distill': {
|
|
968
|
+
const lesson = args.slice(1).join(' ').trim();
|
|
1046
969
|
cmdDistill(lesson);
|
|
1047
970
|
break;
|
|
1048
971
|
}
|
|
1049
|
-
case
|
|
972
|
+
case 'reset':
|
|
1050
973
|
cmdReset();
|
|
1051
974
|
break;
|
|
1052
975
|
default:
|