codymaster 4.4.4 → 4.5.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.
- package/CHANGELOG.md +33 -0
- package/README.md +29 -14
- package/commands/demo.md +1 -1
- package/dist/context-bus.js +70 -0
- package/dist/context-db.js +265 -0
- package/dist/continuity.js +12 -0
- package/dist/file-watcher.js +79 -0
- package/dist/index.js +152 -1
- package/dist/l0-indexer.js +158 -0
- package/dist/mcp-context-server.js +400 -0
- package/dist/migrate-json-to-sqlite.js +126 -0
- package/dist/skill-chain.js +19 -3
- package/dist/token-budget.js +108 -0
- package/dist/uri-resolver.js +203 -0
- package/package.json +7 -1
- package/skills/_shared/helpers.md +50 -14
- package/skills/cm-autopilot/SKILL.md +29 -0
- package/skills/cm-autopilot/scripts/autopilot.py +190 -0
- package/skills/cm-continuity/SKILL.md +90 -28
- package/skills/cm-quality-gate/SKILL.md +11 -1
- package/skills/cm-safe-deploy/SKILL.md +38 -2
- package/skills/cm-security-gate/SKILL.md +158 -34
- package/skills/cm-skill-chain/SKILL.md +47 -1
- package/skills/cm-start/SKILL.md +11 -2
- package/skills/cm-test-gate/SKILL.md +3 -0
- package/skills/boxme-git-config/SKILL.md +0 -56
- package/skills/boxme-local-dev/SKILL.md +0 -66
- package/skills/jobs-to-be-done/SKILL.md +0 -266
- package/skills/jobs-to-be-done/references/case-studies.md +0 -154
- package/skills/jobs-to-be-done/references/competitive-strategy.md +0 -280
- package/skills/jobs-to-be-done/references/diagnostics.md +0 -158
- package/skills/jobs-to-be-done/references/innovation-process.md +0 -392
- package/skills/jobs-to-be-done/references/organizational-change.md +0 -328
- package/skills/marketplace-report-crawler/SKILL.md +0 -176
- package/skills/marketplace-report-crawler/config/accounts.json +0 -41
- package/skills/marketplace-report-crawler/config/report-types.json +0 -422
- package/skills/marketplace-report-crawler/config/sessions.json +0 -3
- package/skills/marketplace-report-crawler/scripts/ab-wrapper.sh +0 -102
- package/skills/marketplace-report-crawler/scripts/browser-actions/lazada/lazada-actions.js +0 -114
- package/skills/marketplace-report-crawler/scripts/browser-actions/shopee/shopee-actions.js +0 -94
- package/skills/marketplace-report-crawler/scripts/browser-actions/tiktok/tiktok-actions.js +0 -272
- package/skills/marketplace-report-crawler/scripts/crawl-runner.js +0 -281
- package/skills/marketplace-report-crawler/scripts/session-check.sh +0 -72
- package/skills/marketplace-report-crawler/scripts/session-manager.sh +0 -349
- package/skills/marketplace-report-crawler/scripts/setup-folders.sh +0 -83
- package/skills/medical-research/SKILL.md +0 -194
- package/skills/medical-research/scripts/evidence_checker.py +0 -288
- package/skills/mom-test/SKILL.md +0 -267
- package/skills/mom-test/references/avoiding-bad-data.md +0 -221
- package/skills/mom-test/references/case-studies.md +0 -306
- package/skills/mom-test/references/commitment-advancement.md +0 -219
- package/skills/mom-test/references/finding-conversations.md +0 -251
- package/skills/mom-test/references/processing-learning.md +0 -256
- package/skills/mom-test/references/question-patterns.md +0 -198
- package/skills/pandasai-analytics/SKILL.md +0 -251
- package/skills/release-it/SKILL.md +0 -235
- package/skills/release-it/references/anti-patterns.md +0 -279
- package/skills/release-it/references/capacity-planning.md +0 -285
- package/skills/release-it/references/chaos-engineering.md +0 -325
- package/skills/release-it/references/deployment-strategies.md +0 -331
- package/skills/release-it/references/observability.md +0 -301
- package/skills/release-it/references/stability-patterns.md +0 -355
- package/skills/skill-creator-ultra/.agents/workflows/skill-audit.md +0 -37
- package/skills/skill-creator-ultra/.agents/workflows/skill-compare.md +0 -34
- package/skills/skill-creator-ultra/.agents/workflows/skill-export.md +0 -51
- package/skills/skill-creator-ultra/.agents/workflows/skill-generate.md +0 -39
- package/skills/skill-creator-ultra/.agents/workflows/skill-scaffold.md +0 -52
- package/skills/skill-creator-ultra/.agents/workflows/skill-simulate.md +0 -25
- package/skills/skill-creator-ultra/.agents/workflows/skill-stats.md +0 -31
- package/skills/skill-creator-ultra/.agents/workflows/skill-validate.md +0 -25
- package/skills/skill-creator-ultra/README.md +0 -1242
- package/skills/skill-creator-ultra/SKILL.md +0 -388
- package/skills/skill-creator-ultra/agents/analyzer.md +0 -274
- package/skills/skill-creator-ultra/agents/comparator.md +0 -202
- package/skills/skill-creator-ultra/agents/grader.md +0 -223
- package/skills/skill-creator-ultra/assets/eval_review.html +0 -146
- package/skills/skill-creator-ultra/eval-viewer/generate_review.py +0 -471
- package/skills/skill-creator-ultra/eval-viewer/viewer.html +0 -1325
- package/skills/skill-creator-ultra/examples/example_anthropic_frontend.md +0 -109
- package/skills/skill-creator-ultra/examples/example_anthropic_pdf.md +0 -116
- package/skills/skill-creator-ultra/examples/example_api_docs.md +0 -189
- package/skills/skill-creator-ultra/examples/example_db_migration.md +0 -253
- package/skills/skill-creator-ultra/examples/example_git_commit.md +0 -111
- package/skills/skill-creator-ultra/install.ps1 +0 -289
- package/skills/skill-creator-ultra/install.sh +0 -313
- package/skills/skill-creator-ultra/phases/phase1_interview.md +0 -202
- package/skills/skill-creator-ultra/phases/phase2_extract.md +0 -55
- package/skills/skill-creator-ultra/phases/phase3_detect.md +0 -57
- package/skills/skill-creator-ultra/phases/phase4_generate.md +0 -543
- package/skills/skill-creator-ultra/phases/phase5_test.md +0 -319
- package/skills/skill-creator-ultra/phases/phase6_eval.md +0 -301
- package/skills/skill-creator-ultra/phases/phase7_iterate.md +0 -103
- package/skills/skill-creator-ultra/phases/phase8_optimize.md +0 -113
- package/skills/skill-creator-ultra/resources/advanced_patterns.md +0 -499
- package/skills/skill-creator-ultra/resources/anti_patterns.md +0 -376
- package/skills/skill-creator-ultra/resources/blueprints.md +0 -498
- package/skills/skill-creator-ultra/resources/checklist.md +0 -243
- package/skills/skill-creator-ultra/resources/composition_cookbook.md +0 -291
- package/skills/skill-creator-ultra/resources/description_optimization.md +0 -90
- package/skills/skill-creator-ultra/resources/eval_guide.md +0 -133
- package/skills/skill-creator-ultra/resources/industry_questions.md +0 -189
- package/skills/skill-creator-ultra/resources/interview_questions.md +0 -200
- package/skills/skill-creator-ultra/resources/pattern_detection.md +0 -200
- package/skills/skill-creator-ultra/resources/prompt_engineering.md +0 -531
- package/skills/skill-creator-ultra/resources/schemas.md +0 -430
- package/skills/skill-creator-ultra/resources/script_integration.md +0 -593
- package/skills/skill-creator-ultra/resources/scripts_guide.md +0 -339
- package/skills/skill-creator-ultra/resources/skill_template.md +0 -124
- package/skills/skill-creator-ultra/resources/skill_writing_guide.md +0 -634
- package/skills/skill-creator-ultra/resources/versioning_guide.md +0 -193
- package/skills/skill-creator-ultra/scripts/ci_eval.py +0 -200
- package/skills/skill-creator-ultra/scripts/package_skill.py +0 -165
- package/skills/skill-creator-ultra/scripts/simulate_skill.py +0 -398
- package/skills/skill-creator-ultra/scripts/skill_audit.py +0 -611
- package/skills/skill-creator-ultra/scripts/skill_compare.py +0 -265
- package/skills/skill-creator-ultra/scripts/skill_export.py +0 -334
- package/skills/skill-creator-ultra/scripts/skill_scaffold.py +0 -403
- package/skills/skill-creator-ultra/scripts/skill_stats.py +0 -339
- package/skills/skill-creator-ultra/scripts/validate_skill.py +0 -411
- package/skills/tailwind-mastery/SKILL.md +0 -229
- package/skills/vercel-react-best-practices/AGENTS.md +0 -3373
- package/skills/vercel-react-best-practices/README.md +0 -123
- package/skills/vercel-react-best-practices/SKILL.md +0 -143
- package/skills/vercel-react-best-practices/rules/_sections.md +0 -46
- package/skills/vercel-react-best-practices/rules/_template.md +0 -28
- package/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -55
- package/skills/vercel-react-best-practices/rules/advanced-init-once.md +0 -42
- package/skills/vercel-react-best-practices/rules/advanced-use-latest.md +0 -39
- package/skills/vercel-react-best-practices/rules/async-api-routes.md +0 -38
- package/skills/vercel-react-best-practices/rules/async-defer-await.md +0 -80
- package/skills/vercel-react-best-practices/rules/async-dependencies.md +0 -51
- package/skills/vercel-react-best-practices/rules/async-parallel.md +0 -28
- package/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -99
- package/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -59
- package/skills/vercel-react-best-practices/rules/bundle-conditional.md +0 -31
- package/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -49
- package/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -35
- package/skills/vercel-react-best-practices/rules/bundle-preload.md +0 -50
- package/skills/vercel-react-best-practices/rules/client-event-listeners.md +0 -74
- package/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -71
- package/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -48
- package/skills/vercel-react-best-practices/rules/client-swr-dedup.md +0 -56
- package/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -107
- package/skills/vercel-react-best-practices/rules/js-cache-function-results.md +0 -80
- package/skills/vercel-react-best-practices/rules/js-cache-property-access.md +0 -28
- package/skills/vercel-react-best-practices/rules/js-cache-storage.md +0 -70
- package/skills/vercel-react-best-practices/rules/js-combine-iterations.md +0 -32
- package/skills/vercel-react-best-practices/rules/js-early-exit.md +0 -50
- package/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +0 -60
- package/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -45
- package/skills/vercel-react-best-practices/rules/js-index-maps.md +0 -37
- package/skills/vercel-react-best-practices/rules/js-length-check-first.md +0 -49
- package/skills/vercel-react-best-practices/rules/js-min-max-loop.md +0 -82
- package/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -24
- package/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -57
- package/skills/vercel-react-best-practices/rules/rendering-activity.md +0 -26
- package/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
- package/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -40
- package/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -38
- package/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -46
- package/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
- package/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +0 -30
- package/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +0 -85
- package/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +0 -68
- package/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -28
- package/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +0 -75
- package/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -39
- package/skills/vercel-react-best-practices/rules/rerender-dependencies.md +0 -45
- package/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +0 -40
- package/skills/vercel-react-best-practices/rules/rerender-derived-state.md +0 -29
- package/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -74
- package/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -58
- package/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +0 -38
- package/skills/vercel-react-best-practices/rules/rerender-memo.md +0 -44
- package/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +0 -45
- package/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +0 -82
- package/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -35
- package/skills/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +0 -64
- package/skills/vercel-react-best-practices/rules/rerender-transitions.md +0 -40
- package/skills/vercel-react-best-practices/rules/rerender-use-deferred-value.md +0 -59
- package/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +0 -73
- package/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -73
- package/skills/vercel-react-best-practices/rules/server-auth-actions.md +0 -96
- package/skills/vercel-react-best-practices/rules/server-cache-lru.md +0 -41
- package/skills/vercel-react-best-practices/rules/server-cache-react.md +0 -76
- package/skills/vercel-react-best-practices/rules/server-dedup-props.md +0 -65
- package/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +0 -142
- package/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -83
- package/skills/vercel-react-best-practices/rules/server-serialization.md +0 -38
- package/skills/web-design-guidelines/SKILL.md +0 -39
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getDefaultBudget = getDefaultBudget;
|
|
7
|
+
exports.loadBudget = loadBudget;
|
|
8
|
+
exports.checkBudget = checkBudget;
|
|
9
|
+
exports.estimateTokens = estimateTokens;
|
|
10
|
+
exports.generateBudgetReport = generateBudgetReport;
|
|
11
|
+
const fs_1 = __importDefault(require("fs"));
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
// ─── Constants ──────────────────────────────────────────────────────────────
|
|
14
|
+
const CM_DIR = '.cm';
|
|
15
|
+
const BUDGET_FILE = 'token-budget.json';
|
|
16
|
+
// ─── Default Budget ─────────────────────────────────────────────────────────
|
|
17
|
+
function getDefaultBudget() {
|
|
18
|
+
return {
|
|
19
|
+
model_context_window: 200000,
|
|
20
|
+
allocations: {
|
|
21
|
+
system_prompt: 5000, // 2.5%
|
|
22
|
+
skill_index_L0: 2500, // 1.25%
|
|
23
|
+
skill_active_full: 5000, // 2.5%
|
|
24
|
+
memory_working: 500, // 0.25%
|
|
25
|
+
memory_learnings: 650, // 0.325%
|
|
26
|
+
codebase_skeleton: 1500, // 0.75%
|
|
27
|
+
context_retrieval: 10000, // 5%
|
|
28
|
+
conversation_history: 30000, // 15%
|
|
29
|
+
generation_budget: 144850, // 72.425%
|
|
30
|
+
},
|
|
31
|
+
enforcement: 'soft',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// ─── Load Budget ────────────────────────────────────────────────────────────
|
|
35
|
+
function loadBudget(projectPath) {
|
|
36
|
+
const budgetPath = path_1.default.join(projectPath, CM_DIR, BUDGET_FILE);
|
|
37
|
+
if (!fs_1.default.existsSync(budgetPath)) {
|
|
38
|
+
return getDefaultBudget();
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const raw = fs_1.default.readFileSync(budgetPath, 'utf-8');
|
|
42
|
+
return JSON.parse(raw);
|
|
43
|
+
}
|
|
44
|
+
catch (_a) {
|
|
45
|
+
return getDefaultBudget();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// ─── Check Budget ────────────────────────────────────────────────────────────
|
|
49
|
+
function checkBudget(budget, category, tokenCount) {
|
|
50
|
+
const allocs = budget.allocations;
|
|
51
|
+
const allocated = allocs[category];
|
|
52
|
+
if (allocated === undefined) {
|
|
53
|
+
return {
|
|
54
|
+
allowed: false,
|
|
55
|
+
remaining: 0,
|
|
56
|
+
suggestion: `Unknown category "${category}". Valid: ${Object.keys(allocs).join(', ')}`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const remaining = allocated - tokenCount;
|
|
60
|
+
const overBudget = remaining < 0;
|
|
61
|
+
if (!overBudget) {
|
|
62
|
+
return { allowed: true, remaining };
|
|
63
|
+
}
|
|
64
|
+
const suggestion = buildSuggestion(category, tokenCount, allocated);
|
|
65
|
+
if (budget.enforcement === 'hard') {
|
|
66
|
+
return { allowed: false, remaining, suggestion };
|
|
67
|
+
}
|
|
68
|
+
// Soft mode: allow but warn
|
|
69
|
+
return { allowed: true, remaining, suggestion };
|
|
70
|
+
}
|
|
71
|
+
function buildSuggestion(category, used, allocated) {
|
|
72
|
+
const over = used - allocated;
|
|
73
|
+
if (category === 'memory_learnings') {
|
|
74
|
+
return `memory_learnings over by ~${over} tokens. Switch to L0 index (cm://memory/learnings/L0) to reduce to ~100 tokens.`;
|
|
75
|
+
}
|
|
76
|
+
if (category === 'codebase_skeleton') {
|
|
77
|
+
return `codebase_skeleton over by ~${over} tokens. Use cm://resources/skeleton/L0 for module-level index (~500 tokens).`;
|
|
78
|
+
}
|
|
79
|
+
if (category === 'memory_working') {
|
|
80
|
+
return `memory_working over by ~${over} tokens. Read CONTINUITY abstract only (first 3 lines).`;
|
|
81
|
+
}
|
|
82
|
+
return `${category} over budget by ~${over} tokens. Consider using L0 index instead of full content.`;
|
|
83
|
+
}
|
|
84
|
+
// ─── Estimate Tokens ─────────────────────────────────────────────────────────
|
|
85
|
+
function estimateTokens(text) {
|
|
86
|
+
if (!text)
|
|
87
|
+
return 0;
|
|
88
|
+
return Math.ceil(text.length / 4);
|
|
89
|
+
}
|
|
90
|
+
// ─── Budget Report ────────────────────────────────────────────────────────────
|
|
91
|
+
function generateBudgetReport(budget) {
|
|
92
|
+
const total = budget.model_context_window;
|
|
93
|
+
const lines = [
|
|
94
|
+
`Token Budget Report (${total.toLocaleString()} context window, enforcement: ${budget.enforcement})`,
|
|
95
|
+
'─'.repeat(70),
|
|
96
|
+
`${'Category'.padEnd(25)} ${'Allocated'.padStart(10)} ${'% of CTX'.padStart(10)}`,
|
|
97
|
+
'─'.repeat(70),
|
|
98
|
+
];
|
|
99
|
+
const allocs = budget.allocations;
|
|
100
|
+
for (const [cat, allocated] of Object.entries(allocs)) {
|
|
101
|
+
const pct = ((allocated / total) * 100).toFixed(2);
|
|
102
|
+
lines.push(`${cat.padEnd(25)} ${allocated.toLocaleString().padStart(10)} ${(pct + '%').padStart(10)}`);
|
|
103
|
+
}
|
|
104
|
+
const sum = Object.values(allocs).reduce((a, b) => a + b, 0);
|
|
105
|
+
lines.push('─'.repeat(70));
|
|
106
|
+
lines.push(`${'TOTAL'.padEnd(25)} ${sum.toLocaleString().padStart(10)} ${(((sum / total) * 100).toFixed(2) + '%').padStart(10)}`);
|
|
107
|
+
return lines.join('\n');
|
|
108
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resolve = resolve;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const context_db_1 = require("./context-db");
|
|
10
|
+
const context_bus_1 = require("./context-bus");
|
|
11
|
+
// ─── Main Resolver ───────────────────────────────────────────────────────────
|
|
12
|
+
/**
|
|
13
|
+
* Resolve a cm:// URI to content at the requested depth.
|
|
14
|
+
*
|
|
15
|
+
* URI patterns:
|
|
16
|
+
* cm://memory/working → CONTINUITY.md abstract (L0) or full (L2)
|
|
17
|
+
* cm://memory/learnings → learnings index (L0) or all learnings (L2)
|
|
18
|
+
* cm://memory/learnings/{id} → specific learning by ID
|
|
19
|
+
* cm://memory/decisions → decisions index (L0) or all (L2)
|
|
20
|
+
* cm://skills/{name} → SKILL.md at depth
|
|
21
|
+
* cm://skills/{name}/L0 → index entry only
|
|
22
|
+
* cm://resources/skeleton → skeleton-index.md (L0) or full (L2)
|
|
23
|
+
* cm://resources/architecture → architecture.mmd
|
|
24
|
+
* cm://pipeline/current → context bus state
|
|
25
|
+
*/
|
|
26
|
+
function resolve(uri, projectPath, depth = 'L1') {
|
|
27
|
+
if (!uri.startsWith('cm://')) {
|
|
28
|
+
return notFound(uri, depth, `URI must start with cm://`);
|
|
29
|
+
}
|
|
30
|
+
const rest = uri.slice('cm://'.length); // e.g. "memory/learnings/L005"
|
|
31
|
+
const parts = rest.split('/').filter(Boolean);
|
|
32
|
+
if (parts.length === 0) {
|
|
33
|
+
return notFound(uri, depth, 'Empty URI path');
|
|
34
|
+
}
|
|
35
|
+
const [ns, ...tail] = parts;
|
|
36
|
+
switch (ns) {
|
|
37
|
+
case 'memory': return resolveMemory(uri, tail, projectPath, depth);
|
|
38
|
+
case 'skills': return resolveSkill(uri, tail, projectPath, depth);
|
|
39
|
+
case 'resources': return resolveResource(uri, tail, projectPath, depth);
|
|
40
|
+
case 'pipeline': return resolvePipeline(uri, tail, projectPath, depth);
|
|
41
|
+
default:
|
|
42
|
+
return notFound(uri, depth, `Unknown namespace "${ns}". Valid: memory, skills, resources, pipeline`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// ─── memory/* ────────────────────────────────────────────────────────────────
|
|
46
|
+
function resolveMemory(uri, tail, projectPath, depth) {
|
|
47
|
+
const [resource, id] = tail;
|
|
48
|
+
switch (resource) {
|
|
49
|
+
case 'working': {
|
|
50
|
+
const contPath = path_1.default.join(projectPath, '.cm', 'CONTINUITY.md');
|
|
51
|
+
if (!fs_1.default.existsSync(contPath))
|
|
52
|
+
return notFound(uri, depth, 'CONTINUITY.md not found');
|
|
53
|
+
const full = fs_1.default.readFileSync(contPath, 'utf-8');
|
|
54
|
+
if (depth === 'L0' || depth === 'L1') {
|
|
55
|
+
// Return first 10 non-empty lines as abstract
|
|
56
|
+
const abstract = full.split('\n').filter(l => l.trim()).slice(0, 10).join('\n');
|
|
57
|
+
return found(uri, depth, abstract);
|
|
58
|
+
}
|
|
59
|
+
return found(uri, depth, full);
|
|
60
|
+
}
|
|
61
|
+
case 'learnings': {
|
|
62
|
+
if (id) {
|
|
63
|
+
// cm://memory/learnings/L005 — specific entry
|
|
64
|
+
const dbPath = (0, context_db_1.getDbPath)(projectPath);
|
|
65
|
+
const learning = (0, context_db_1.getLearningById)(dbPath, id);
|
|
66
|
+
if (!learning)
|
|
67
|
+
return notFound(uri, depth, `Learning "${id}" not found`);
|
|
68
|
+
return found(uri, depth, formatLearning(learning));
|
|
69
|
+
}
|
|
70
|
+
if (depth === 'L0') {
|
|
71
|
+
// Return cached L0 index
|
|
72
|
+
const indexPath = path_1.default.join(projectPath, '.cm', 'learnings-index.md');
|
|
73
|
+
if (fs_1.default.existsSync(indexPath)) {
|
|
74
|
+
return found(uri, depth, fs_1.default.readFileSync(indexPath, 'utf-8'));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// L1/L2: query all from SQLite
|
|
78
|
+
const dbPath = (0, context_db_1.getDbPath)(projectPath);
|
|
79
|
+
const learnings = (0, context_db_1.queryLearnings)(dbPath, '', undefined, 50);
|
|
80
|
+
if (learnings.length === 0) {
|
|
81
|
+
// Fallback to JSON file
|
|
82
|
+
const jsonPath = path_1.default.join(projectPath, '.cm', 'memory', 'learnings.json');
|
|
83
|
+
if (fs_1.default.existsSync(jsonPath)) {
|
|
84
|
+
return found(uri, depth, fs_1.default.readFileSync(jsonPath, 'utf-8'));
|
|
85
|
+
}
|
|
86
|
+
return found(uri, depth, '[]');
|
|
87
|
+
}
|
|
88
|
+
return found(uri, depth, JSON.stringify(learnings, null, 2));
|
|
89
|
+
}
|
|
90
|
+
case 'decisions': {
|
|
91
|
+
if (depth === 'L0') {
|
|
92
|
+
// Short list of decision IDs + 1-line summary
|
|
93
|
+
const dbPath = (0, context_db_1.getDbPath)(projectPath);
|
|
94
|
+
const decisions = (0, context_db_1.queryDecisions)(dbPath, '', 20);
|
|
95
|
+
const lines = ['# Decisions Index', ''];
|
|
96
|
+
for (const d of decisions) {
|
|
97
|
+
lines.push(`- ${d.id}: ${d.decision.slice(0, 80)}`);
|
|
98
|
+
}
|
|
99
|
+
return found(uri, depth, lines.join('\n'));
|
|
100
|
+
}
|
|
101
|
+
const dbPath = (0, context_db_1.getDbPath)(projectPath);
|
|
102
|
+
const decisions = (0, context_db_1.queryDecisions)(dbPath, '', 50);
|
|
103
|
+
if (decisions.length === 0) {
|
|
104
|
+
const jsonPath = path_1.default.join(projectPath, '.cm', 'memory', 'decisions.json');
|
|
105
|
+
if (fs_1.default.existsSync(jsonPath)) {
|
|
106
|
+
return found(uri, depth, fs_1.default.readFileSync(jsonPath, 'utf-8'));
|
|
107
|
+
}
|
|
108
|
+
return found(uri, depth, '[]');
|
|
109
|
+
}
|
|
110
|
+
return found(uri, depth, JSON.stringify(decisions, null, 2));
|
|
111
|
+
}
|
|
112
|
+
default:
|
|
113
|
+
return notFound(uri, depth, `Unknown memory resource "${resource}". Valid: working, learnings, decisions`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// ─── skills/* ────────────────────────────────────────────────────────────────
|
|
117
|
+
function resolveSkill(uri, tail, projectPath, depth) {
|
|
118
|
+
const [skillName, depthOverride] = tail;
|
|
119
|
+
if (!skillName)
|
|
120
|
+
return notFound(uri, depth, 'Skill name required: cm://skills/{name}');
|
|
121
|
+
const effectiveDepth = depthOverride || depth;
|
|
122
|
+
// Look in project skills/ dir, then global ~/.claude/skills/
|
|
123
|
+
const candidates = [
|
|
124
|
+
path_1.default.join(projectPath, 'skills', skillName, 'SKILL.md'),
|
|
125
|
+
path_1.default.join(projectPath, '.claude', 'skills', skillName, 'SKILL.md'),
|
|
126
|
+
path_1.default.join(process.env.HOME || '', '.claude', 'skills', skillName, 'SKILL.md'),
|
|
127
|
+
];
|
|
128
|
+
const skillPath = candidates.find(p => fs_1.default.existsSync(p));
|
|
129
|
+
if (!skillPath)
|
|
130
|
+
return notFound(uri, depth, `Skill "${skillName}" not found`);
|
|
131
|
+
const full = fs_1.default.readFileSync(skillPath, 'utf-8');
|
|
132
|
+
if (effectiveDepth === 'L0') {
|
|
133
|
+
// Front matter + description only (~50 tokens)
|
|
134
|
+
const lines = full.split('\n');
|
|
135
|
+
const summary = lines.slice(0, 10).join('\n');
|
|
136
|
+
return found(uri, effectiveDepth, summary);
|
|
137
|
+
}
|
|
138
|
+
if (effectiveDepth === 'L1') {
|
|
139
|
+
// First 40 lines (~600 tokens)
|
|
140
|
+
return found(uri, effectiveDepth, full.split('\n').slice(0, 40).join('\n'));
|
|
141
|
+
}
|
|
142
|
+
return found(uri, effectiveDepth, full);
|
|
143
|
+
}
|
|
144
|
+
// ─── resources/* ─────────────────────────────────────────────────────────────
|
|
145
|
+
function resolveResource(uri, tail, projectPath, depth) {
|
|
146
|
+
const [resource] = tail;
|
|
147
|
+
switch (resource) {
|
|
148
|
+
case 'skeleton': {
|
|
149
|
+
if (depth === 'L0' || depth === 'L1') {
|
|
150
|
+
const indexPath = path_1.default.join(projectPath, '.cm', 'skeleton-index.md');
|
|
151
|
+
if (fs_1.default.existsSync(indexPath)) {
|
|
152
|
+
return found(uri, depth, fs_1.default.readFileSync(indexPath, 'utf-8'));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const fullPath = path_1.default.join(projectPath, '.cm', 'skeleton.md');
|
|
156
|
+
if (!fs_1.default.existsSync(fullPath))
|
|
157
|
+
return notFound(uri, depth, 'skeleton.md not found — run: cm continuity index');
|
|
158
|
+
return found(uri, depth, fs_1.default.readFileSync(fullPath, 'utf-8'));
|
|
159
|
+
}
|
|
160
|
+
case 'architecture': {
|
|
161
|
+
const mmdPath = path_1.default.join(projectPath, '.cm', 'architecture.mmd');
|
|
162
|
+
if (!fs_1.default.existsSync(mmdPath))
|
|
163
|
+
return notFound(uri, depth, 'architecture.mmd not found');
|
|
164
|
+
return found(uri, depth, fs_1.default.readFileSync(mmdPath, 'utf-8'));
|
|
165
|
+
}
|
|
166
|
+
default:
|
|
167
|
+
return notFound(uri, depth, `Unknown resource "${resource}". Valid: skeleton, architecture`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// ─── pipeline/* ──────────────────────────────────────────────────────────────
|
|
171
|
+
function resolvePipeline(uri, tail, projectPath, depth) {
|
|
172
|
+
const [sub] = tail;
|
|
173
|
+
if (!sub || sub === 'current') {
|
|
174
|
+
const bus = (0, context_bus_1.readBus)(projectPath);
|
|
175
|
+
if (!bus)
|
|
176
|
+
return notFound(uri, depth, 'No active context bus. Start a chain first.');
|
|
177
|
+
if (depth === 'L0') {
|
|
178
|
+
const summary = `Pipeline: ${bus.pipeline} | Step: ${bus.current_step} | Steps done: ${Object.keys(bus.shared_context).length}`;
|
|
179
|
+
return found(uri, depth, summary);
|
|
180
|
+
}
|
|
181
|
+
return found(uri, depth, JSON.stringify(bus, null, 2));
|
|
182
|
+
}
|
|
183
|
+
return notFound(uri, depth, `Unknown pipeline resource "${sub}"`);
|
|
184
|
+
}
|
|
185
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
186
|
+
function found(uri, depth, content) {
|
|
187
|
+
return { uri, depth, content, tokenEstimate: Math.ceil(content.length / 4), found: true };
|
|
188
|
+
}
|
|
189
|
+
function notFound(uri, depth, reason) {
|
|
190
|
+
const content = `# Not Found\n\nURI: ${uri}\nReason: ${reason}`;
|
|
191
|
+
return { uri, depth, content, tokenEstimate: Math.ceil(content.length / 4), found: false };
|
|
192
|
+
}
|
|
193
|
+
function formatLearning(l) {
|
|
194
|
+
var _a, _b;
|
|
195
|
+
if (!l)
|
|
196
|
+
return '';
|
|
197
|
+
return [
|
|
198
|
+
`### ${l.id}: ${l.what_failed}`,
|
|
199
|
+
`- **Why:** ${l.why_failed}`,
|
|
200
|
+
`- **Fix:** ${l.how_to_prevent}`,
|
|
201
|
+
`- **Scope:** ${(_a = l.scope) !== null && _a !== void 0 ? _a : 'global'} | **TTL:** ${(_b = l.ttl) !== null && _b !== void 0 ? _b : 60}d`,
|
|
202
|
+
].join('\n');
|
|
203
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codymaster",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.1",
|
|
4
4
|
"description": "68+ Skills. Ship 10x faster. AI-powered coding skill kit for Claude, Cursor, Gemini & more.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"repository": {
|
|
@@ -59,12 +59,15 @@
|
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@clack/prompts": "^1.1.0",
|
|
62
|
+
"better-sqlite3": "^12.8.0",
|
|
62
63
|
"chalk": "^5.6.2",
|
|
64
|
+
"chokidar": "^5.0.0",
|
|
63
65
|
"commander": "^14.0.3",
|
|
64
66
|
"express": "^5.2.1",
|
|
65
67
|
"prompts": "^2.4.2"
|
|
66
68
|
},
|
|
67
69
|
"devDependencies": {
|
|
70
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
68
71
|
"@types/express": "^5.0.6",
|
|
69
72
|
"@types/node": "^25.5.0",
|
|
70
73
|
"@types/prompts": "^2.4.9",
|
|
@@ -73,5 +76,8 @@
|
|
|
73
76
|
"ts-node": "^10.9.2",
|
|
74
77
|
"typescript": "^5.9.3",
|
|
75
78
|
"vitest": "^4.1.0"
|
|
79
|
+
},
|
|
80
|
+
"overrides": {
|
|
81
|
+
"path-to-regexp": "^8.4.0"
|
|
76
82
|
}
|
|
77
83
|
}
|
|
@@ -7,20 +7,56 @@
|
|
|
7
7
|
|
|
8
8
|
## #Load-Working-Memory
|
|
9
9
|
|
|
10
|
-
Before executing any significant action, ALWAYS:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
10
|
+
Before executing any significant action, ALWAYS load context in this order (cheapest → richest):
|
|
11
|
+
|
|
12
|
+
### Step 1 — Check context bus (free, ~50 tokens)
|
|
13
|
+
```
|
|
14
|
+
Read .cm/context-bus.json (or: cm continuity bus)
|
|
15
|
+
→ If active pipeline found:
|
|
16
|
+
- Note current_step and pipeline name
|
|
17
|
+
- Read shared_context to see what upstream skills already produced
|
|
18
|
+
- SKIP re-doing any work already recorded in shared_context
|
|
19
|
+
→ If no bus: fresh session, proceed normally
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Step 2 — Load L0 indexes first (~600 tokens total)
|
|
23
|
+
```
|
|
24
|
+
Read .cm/learnings-index.md (~100 tokens) — IDs + 1-line summaries
|
|
25
|
+
Read .cm/skeleton-index.md (~500 tokens) — modules, entry points, config files
|
|
26
|
+
|
|
27
|
+
→ If a specific learning ID looks relevant → resolve cm://memory/learnings/{id} for full detail
|
|
28
|
+
→ If a specific module looks relevant → resolve cm://resources/skeleton at L2 for full detail
|
|
29
|
+
→ Otherwise: L0 is sufficient — DO NOT load full files
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Step 3 — Scope-filter learnings (only if L0 flags relevant entries)
|
|
33
|
+
```
|
|
34
|
+
Query: cm_query(scope="learnings", query="{current module or error type}", limit=5)
|
|
35
|
+
OR read .cm/memory/learnings.json filtered to scope == "global" | "module:X"
|
|
36
|
+
|
|
37
|
+
Rules:
|
|
38
|
+
NEVER load status = "invalidated" (proven wrong)
|
|
39
|
+
CAUTION status = "corrected" (verify before applying)
|
|
40
|
+
TRUST high reinforceCount + recent lastRelevant
|
|
41
|
+
SKIP learnings for other modules (noise + wasted tokens)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Step 4 — Check working memory
|
|
45
|
+
```
|
|
46
|
+
Read .cm/CONTINUITY.md → Active Goal, Next Actions, current phase
|
|
47
|
+
Run Memory Audit (decay + conflict detection) — see cm-continuity
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Step 5 — Token budget check (before injecting large context)
|
|
51
|
+
```
|
|
52
|
+
cm continuity budget (or: loadBudget + checkBudget in code)
|
|
53
|
+
→ If category is over soft limit → use L0/L1 depth instead of L2
|
|
54
|
+
→ Never inject full skeleton (20KB) when skeleton-index.md (~2KB) suffices
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
> **Token savings v5:** Full cold load ~3,200 tokens → Smart Spine load ~700 tokens (78% reduction).
|
|
58
|
+
> L0 indexes + context bus + scope filter make this possible.
|
|
59
|
+
> Only escalate to L2 when L0/L1 explicitly flag the need.
|
|
24
60
|
|
|
25
61
|
---
|
|
26
62
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cm-autopilot
|
|
3
|
+
description: Easy-to-use conversational CLI (Claude Code style) for non-technical users to spawn parallel AI tasks supervised by a visual web dashboard.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CM AutoPilot CLI — Conversational Task Supervisor
|
|
7
|
+
|
|
8
|
+
> **Just talk to it. It plans, splits, and watches parallel tasks for you.**
|
|
9
|
+
|
|
10
|
+
## What it does
|
|
11
|
+
- Provides a conversational CLI interface using `rich` and `prompt_toolkit`.
|
|
12
|
+
- Translates user intent into multiple parallel tasks.
|
|
13
|
+
- Integrates with `cm-content-factory`'s Dashboard (`localhost:5050`) for a visual way to track multi-threading.
|
|
14
|
+
- Allows non-technical users to utilize the Cody Master skill set effortlessly.
|
|
15
|
+
|
|
16
|
+
## Requirements
|
|
17
|
+
- Python 3.9+
|
|
18
|
+
- `rich`
|
|
19
|
+
- `prompt_toolkit`
|
|
20
|
+
|
|
21
|
+
## How to run
|
|
22
|
+
|
|
23
|
+
1. Launch the conversational CLI:
|
|
24
|
+
```bash
|
|
25
|
+
python3 skills/cm-autopilot/scripts/autopilot.py
|
|
26
|
+
```
|
|
27
|
+
2. The CLI will ask what you want to do. Explain your complex request (e.g., "Dịch 10 bài báo sang tiếng anh", "Research 5 competitors").
|
|
28
|
+
3. The AutoPilot will generate tasks and push them into the Queue.
|
|
29
|
+
4. AutoPilot will automatically start the visual Dashboard at `http://localhost:5050` so you can watch your jobs execute in parallel.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
AutoPilot CLI — Conversational Interface for Cody Master Skills
|
|
4
|
+
|
|
5
|
+
This is a Claude Code-style interactive CLI. It talks to the user,
|
|
6
|
+
understands their goals, creates a plan, and then parallelizes
|
|
7
|
+
tasks into the Agent Dispatcher (queue) while launching the Visual
|
|
8
|
+
Dashboard for easy tracking.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import sys
|
|
12
|
+
import time
|
|
13
|
+
import os
|
|
14
|
+
import subprocess
|
|
15
|
+
import threading
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
# Add cm-content-factory to sys.path to reuse the dispatcher and state manager
|
|
19
|
+
SKILLS_DIR = Path(__file__).resolve().parent.parent.parent
|
|
20
|
+
CF_SCRIPTS = SKILLS_DIR / "cm-content-factory" / "scripts"
|
|
21
|
+
sys.path.append(str(CF_SCRIPTS))
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
from agent_dispatcher import AgentDispatcher
|
|
25
|
+
from state_manager import StateManager
|
|
26
|
+
from rich.console import Console
|
|
27
|
+
from rich.markdown import Markdown
|
|
28
|
+
from rich.panel import Panel
|
|
29
|
+
from rich.prompt import Prompt
|
|
30
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
31
|
+
except ImportError:
|
|
32
|
+
print("Please install requirements: pip install rich prompt_toolkit")
|
|
33
|
+
sys.exit(1)
|
|
34
|
+
|
|
35
|
+
console = Console()
|
|
36
|
+
project_root = Path(os.getcwd()).resolve()
|
|
37
|
+
|
|
38
|
+
dispatcher = AgentDispatcher(str(project_root))
|
|
39
|
+
state_mgr = StateManager(str(project_root))
|
|
40
|
+
|
|
41
|
+
DASHBOARD_PROCESS = None
|
|
42
|
+
|
|
43
|
+
def start_dashboard():
|
|
44
|
+
"""Starts the cm-content-factory dashboard server in the background."""
|
|
45
|
+
global DASHBOARD_PROCESS
|
|
46
|
+
dashboard_script = CF_SCRIPTS / "dashboard_server.py"
|
|
47
|
+
if dashboard_script.exists():
|
|
48
|
+
DASHBOARD_PROCESS = subprocess.Popen(
|
|
49
|
+
[sys.executable, str(dashboard_script), "--port", "5050", "--no-open"],
|
|
50
|
+
stdout=subprocess.DEVNULL,
|
|
51
|
+
stderr=subprocess.DEVNULL
|
|
52
|
+
)
|
|
53
|
+
return True
|
|
54
|
+
return False
|
|
55
|
+
|
|
56
|
+
def show_welcome():
|
|
57
|
+
console.print(Panel.fit(
|
|
58
|
+
"[bold cyan]🚀 Welcome to Cody Master AutoPilot[/bold cyan]\n"
|
|
59
|
+
"[dim]Your conversational AI orchestrator.[/dim]\n\n"
|
|
60
|
+
"Tell me what you want to achieve, and I will plan, split,\n"
|
|
61
|
+
"and execute parallel tasks for you. No technical skills required.",
|
|
62
|
+
title="AutoPilot v1.0", border_style="cyan"
|
|
63
|
+
))
|
|
64
|
+
|
|
65
|
+
def mock_llm_task_parser(prompt: str) -> list:
|
|
66
|
+
"""
|
|
67
|
+
Mock parser that simulates an LLM breaking down a user request
|
|
68
|
+
into parallel tasks based on keywords.
|
|
69
|
+
"""
|
|
70
|
+
tasks = []
|
|
71
|
+
lower_prompt = prompt.lower()
|
|
72
|
+
|
|
73
|
+
if "dịch" in lower_prompt or "translate" in lower_prompt:
|
|
74
|
+
# Example: Dịch 5 bài báo
|
|
75
|
+
count = 5
|
|
76
|
+
for w in lower_prompt.split():
|
|
77
|
+
if w.isdigit():
|
|
78
|
+
count = int(w)
|
|
79
|
+
break
|
|
80
|
+
for i in range(1, count + 1):
|
|
81
|
+
tasks.append({
|
|
82
|
+
"id": f"translate-{int(time.time()*100)}-{i}",
|
|
83
|
+
"type": "translate",
|
|
84
|
+
"meta": {"file": f"article_{i}.txt", "target_lang": "en"}
|
|
85
|
+
})
|
|
86
|
+
elif "research" in lower_prompt or "tìm hiểu" in lower_prompt:
|
|
87
|
+
tasks.append({"id": f"res-1", "type": "research", "meta": {"topic": "Market Trends"}})
|
|
88
|
+
tasks.append({"id": f"res-2", "type": "research", "meta": {"topic": "Competitors"}})
|
|
89
|
+
tasks.append({"id": f"res-3", "type": "research", "meta": {"topic": "Keywords"}})
|
|
90
|
+
else:
|
|
91
|
+
# Generic fallback
|
|
92
|
+
tasks.append({"id": f"task-1", "type": "general", "meta": {"instruction": prompt}})
|
|
93
|
+
tasks.append({"id": f"task-2", "type": "general", "meta": {"instruction": "Review output"}})
|
|
94
|
+
|
|
95
|
+
return tasks
|
|
96
|
+
|
|
97
|
+
def background_worker(worker_id: str):
|
|
98
|
+
"""A simple worker loop simulating parallel execution of tasks."""
|
|
99
|
+
state_mgr.register_agent(worker_id, "autopilot_worker")
|
|
100
|
+
while True:
|
|
101
|
+
task = dispatcher.claim_next(worker_id)
|
|
102
|
+
if not task:
|
|
103
|
+
time.sleep(2)
|
|
104
|
+
continue
|
|
105
|
+
|
|
106
|
+
# Log active phase
|
|
107
|
+
phase_map = {"translate": "write", "research": "extract", "general": "plan"}
|
|
108
|
+
phase = phase_map.get(task["type"], "write")
|
|
109
|
+
state_mgr.update_phase(phase, "running", progress=0.1)
|
|
110
|
+
state_mgr.add_task(task["id"], "running", task["meta"])
|
|
111
|
+
|
|
112
|
+
# Simulate work
|
|
113
|
+
dispatcher.heartbeat(worker_id, task["id"])
|
|
114
|
+
time.sleep(3) # Heavy work
|
|
115
|
+
|
|
116
|
+
state_mgr.add_task(task["id"], "done", task["meta"])
|
|
117
|
+
dispatcher.complete(task["id"], worker_id, {"result": "success"})
|
|
118
|
+
state_mgr.log_event("info", f"[{worker_id}] Completed task: {task['id']}")
|
|
119
|
+
|
|
120
|
+
# Check if phase done
|
|
121
|
+
q = dispatcher.get_queue()
|
|
122
|
+
if q["queued"] == 0 and q["claimed"] == 0:
|
|
123
|
+
state_mgr.update_phase(phase, "done", progress=1.0)
|
|
124
|
+
|
|
125
|
+
def main_loop():
|
|
126
|
+
# Reset queue and state for fresh start
|
|
127
|
+
dispatcher.reset()
|
|
128
|
+
state_mgr.reset()
|
|
129
|
+
|
|
130
|
+
# Start dashboard
|
|
131
|
+
if start_dashboard():
|
|
132
|
+
state_mgr.log_event("info", "Dashboard Server started on port 5050")
|
|
133
|
+
|
|
134
|
+
# Start background workers (simulating multiple parallel agents)
|
|
135
|
+
for i in range(3):
|
|
136
|
+
t = threading.Thread(target=background_worker, args=(f"worker-{i+1}",), daemon=True)
|
|
137
|
+
t.start()
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
while True:
|
|
141
|
+
user_input = Prompt.ask("\n[bold green]You[/bold green]")
|
|
142
|
+
if user_input.lower() in ("exit", "quit", "q"):
|
|
143
|
+
break
|
|
144
|
+
|
|
145
|
+
if not user_input.strip():
|
|
146
|
+
continue
|
|
147
|
+
|
|
148
|
+
with Progress(
|
|
149
|
+
SpinnerColumn(),
|
|
150
|
+
TextColumn("[progress.description]{task.description}"),
|
|
151
|
+
transient=True
|
|
152
|
+
) as progress:
|
|
153
|
+
progress.add_task("Thinking and Planning...", total=None)
|
|
154
|
+
time.sleep(1.5) # Simulate LLM thinking
|
|
155
|
+
tasks = mock_llm_task_parser(user_input)
|
|
156
|
+
|
|
157
|
+
console.print(f"[bold blue]AutoPilot:[/bold blue] I've analyzed your request and created [bold]{len(tasks)}[/bold] parallel tasks.")
|
|
158
|
+
|
|
159
|
+
# Queue them
|
|
160
|
+
dispatcher.enqueue_batch(tasks)
|
|
161
|
+
for t in tasks:
|
|
162
|
+
state_mgr.add_task(t["id"], "queued", t["meta"])
|
|
163
|
+
|
|
164
|
+
console.print("[dim]Tasks have been dispatched to the worker queue.[/dim]")
|
|
165
|
+
console.print(f"👉 [bold magenta]Watch live progress at: http://localhost:5050[/bold magenta]")
|
|
166
|
+
|
|
167
|
+
# Simple live status wait
|
|
168
|
+
with Progress() as pb:
|
|
169
|
+
task_pb = pb.add_task("Executing Pipeline...", total=len(tasks))
|
|
170
|
+
while True:
|
|
171
|
+
q = dispatcher.get_queue()
|
|
172
|
+
completed = q["done"] + q["failed"]
|
|
173
|
+
pb.update(task_pb, completed=completed)
|
|
174
|
+
|
|
175
|
+
if completed >= len(tasks):
|
|
176
|
+
break
|
|
177
|
+
time.sleep(1)
|
|
178
|
+
|
|
179
|
+
console.print("\n[bold green]✅ All tasks completed successfully![/bold green]")
|
|
180
|
+
|
|
181
|
+
except KeyboardInterrupt:
|
|
182
|
+
console.print("\n[dim]Shutting down...[/dim]")
|
|
183
|
+
|
|
184
|
+
finally:
|
|
185
|
+
if DASHBOARD_PROCESS:
|
|
186
|
+
DASHBOARD_PROCESS.terminate()
|
|
187
|
+
|
|
188
|
+
if __name__ == "__main__":
|
|
189
|
+
show_welcome()
|
|
190
|
+
main_loop()
|