maskweaver 0.10.1 → 0.11.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.
@@ -91,7 +91,7 @@ const INLINE_DEFAULT = {
91
91
  name: 'craft',
92
92
  aliases: [],
93
93
  deprecatedAliases: [],
94
- description: 'Prepare execution context for a phase (phase auto-select if omitted)',
94
+ description: '[DEPRECATED] Use build instead it now auto-approves and runs craft+build+verify',
95
95
  category: 'execution',
96
96
  args: [
97
97
  { name: 'phaseId', type: 'string', required: false, description: 'Phase ID (auto-select if omitted)' },
@@ -99,7 +99,7 @@ const INLINE_DEFAULT = {
99
99
  ],
100
100
  mdFile: 'weave-craft.md',
101
101
  handler: 'handleCraft',
102
- examples: ['weave command=craft', 'weave command=craft phaseId="P1"'],
102
+ examples: ['weave command=build (use this instead)'],
103
103
  },
104
104
  {
105
105
  name: 'build',
@@ -112,6 +112,7 @@ const INLINE_DEFAULT = {
112
112
  { name: 'phaseIds', type: 'string', required: false, description: 'Comma-separated phase IDs for run action' },
113
113
  { name: 'buildId', type: 'string', required: false, description: 'Build ID for status/stop/resume/sync actions' },
114
114
  { name: 'maxRetries', type: 'number', default: 3, min: 1, max: 10, description: 'Maximum retries per task (for run action)' },
115
+ { name: 'taskResults', type: 'string', required: false, description: 'JSON array of TaskResult from previous wave (for resume)' },
115
116
  { name: 'maxIterations', type: 'number', default: 1, min: 1, max: 20, description: 'Maximum loop iterations before blocking' },
116
117
  { name: 'maxNoProgress', type: 'number', default: 1, min: 0, max: 10, description: 'Maximum repeated no-progress failures before blocking' },
117
118
  ],
@@ -216,12 +217,14 @@ const INLINE_DEFAULT = {
216
217
  args: [
217
218
  { name: 'sync', type: 'boolean', default: false, description: 'Force regenerate agent .md files from config pool' },
218
219
  { name: 'init', type: 'boolean', default: false, description: 'Create default maskweaver.config.json with pool template' },
220
+ { name: 'force', type: 'boolean', default: false, description: 'Force re-detect subscription and overwrite maskweaver.config.json' },
219
221
  ],
220
222
  mdFile: 'weave-agents.md',
221
223
  handler: 'handleAgents',
222
224
  examples: [
223
225
  'weave command=agents sync=true',
224
226
  'weave command=agents init=true',
227
+ 'weave command=agents force=true',
225
228
  ],
226
229
  },
227
230
  {
@@ -13,6 +13,7 @@ export declare function createWeaveTool(): {
13
13
  }>>;
14
14
  sync: z.ZodOptional<z.ZodBoolean>;
15
15
  init: z.ZodOptional<z.ZodBoolean>;
16
+ force: z.ZodOptional<z.ZodBoolean>;
16
17
  docsPath: z.ZodOptional<z.ZodString>;
17
18
  phaseId: z.ZodOptional<z.ZodString>;
18
19
  projectName: z.ZodOptional<z.ZodString>;
@@ -56,6 +57,7 @@ export declare function createWeaveTool(): {
56
57
  deep: z.ZodOptional<z.ZodBoolean>;
57
58
  maxRetries: z.ZodOptional<z.ZodNumber>;
58
59
  buildId: z.ZodOptional<z.ZodString>;
60
+ taskResults: z.ZodOptional<z.ZodString>;
59
61
  phaseIds: z.ZodOptional<z.ZodString>;
60
62
  };
61
63
  execute: (args: {
@@ -97,6 +99,7 @@ export declare function createWeaveTool(): {
97
99
  deep?: boolean;
98
100
  maxRetries?: number;
99
101
  buildId?: string;
102
+ taskResults?: string;
100
103
  phaseIds?: string;
101
104
  }, context: {
102
105
  worktree: string;
@@ -18,8 +18,7 @@ import { archiveChange } from '../../weave/stages/archive.js';
18
18
  import { generateStatusReport, handleUserResponse } from '../../weave/stages/handoff.js';
19
19
  import { analyzeCodebase, runGraphifyAnalysis, readMapResult } from '../../weave/stages/map.js';
20
20
  import { interview as interviewStage, listInterviewStates } from '../../weave/stages/intake.js';
21
- import { executeBuildLoop, generateBuildState, generateBuildId, loadBuildState } from '../../weave/stages/build.js';
22
- import { WeaveOrchestrator } from '../../weave/orchestrator.js';
21
+ import { generateBuildId } from '../../weave/stages/build.js';
23
22
  import { getPhaseManager } from '../../weave/phase-manager.js';
24
23
  import { recommendVerificationCommands, formatRecommendedCommandsAsBash } from '../../weave/verification/index.js';
25
24
  import { createWeaveWorktree, listWeaveWorktrees, resolveWeaveWorktree, removeWeaveWorktree, ensureIgnoreOverride, ensureWeaveState, } from '../../weave/worktree.js';
@@ -27,10 +26,11 @@ import { ensureGitRepo, stageAllChanges, listStagedFiles, hasStagedChanges, comm
27
26
  import { scanFilesForSecrets, loadSecretScanConfig, shouldBlockOnFindings, formatSecretScanReport } from '../../weave/security/secret-scan.js';
28
27
  import { searchTroubleshooting, recordTroubleshooting, GlobalKnowledge } from '../../weave/knowledge/global.js';
29
28
  import { ensureChangeArtifact, readChangeMetadata, writeChangeVerificationReport } from '../../weave/change-artifacts.js';
29
+ import { advanceBuildStep } from '../../weave/wave-executor.js';
30
30
  import { analyzeParallelOpportunities, executionPlanToSquadTasks } from '../../weave/bridge.js';
31
31
  import { acquireLoopOperatorLock, appendLoopEvent, createLoopRun, ensureLoopContract, listLoopRuns, readLoopRun, releaseLoopOperatorLock, refreshLoopOperatorLock, requestLoopStop, toLoopOperatorStatePath, resolveLoopId, toLoopRunPath, updateLoopRun, writeLoopOperatorState, writeLoopAttemptControllerNotes, writeLoopAttemptTaskBundle, writeLoopAttemptWorkerBrief, writeLoopAttemptVerificationReport, } from '../../weave/loop.js';
32
32
  import { getEffectiveGdcConfig, runGdcMachineCommand, countGdcCheckIssues, getStatsNodeSummary, } from '../../weave/gdc.js';
33
- import { generatePoolAgentFilesFromConfig, writeDefaultRuntimeConfig, writeDefaultPluginConfig, } from '../../shared/generate-agents.js';
33
+ import { generatePoolAgentFilesFromConfig, writeDefaultRuntimeConfig, writeDefaultPluginConfig, writeAutoDetectedConfig, formatProviderChecklist, } from '../../shared/generate-agents.js';
34
34
  import { resolveCommand, loadCommandsJson } from './command-registry.js';
35
35
  export function createWeaveTool() {
36
36
  return {
@@ -61,6 +61,8 @@ export function createWeaveTool() {
61
61
  .describe('Force regenerate agent .md files from config pool (for agents command)'),
62
62
  init: z.boolean().optional()
63
63
  .describe('Create default maskweaver.config.json with pool template (for agents command)'),
64
+ force: z.boolean().optional()
65
+ .describe('Force re-detect subscription and overwrite maskweaver.config.json (for agents command)'),
64
66
  docsPath: z.string().optional()
65
67
  .describe('Path to requirements documents (for design command)'),
66
68
  phaseId: z.string().optional()
@@ -129,6 +131,8 @@ export function createWeaveTool() {
129
131
  .describe('Maximum retries per task (for build command)'),
130
132
  buildId: z.string().optional()
131
133
  .describe('Build ID to resume (for build-resume command)'),
134
+ taskResults: z.string().optional()
135
+ .describe('JSON array of TaskResult from previous wave (for resume)'),
132
136
  phaseIds: z.string().optional()
133
137
  .describe('Comma-separated phase IDs (for build command)'),
134
138
  },
@@ -163,7 +167,7 @@ export function createWeaveTool() {
163
167
  result = await handleApprovePlan(args, basePath);
164
168
  break;
165
169
  case 'craft':
166
- result = await handleCraft(args, basePath);
170
+ result = '> ⚠️ `craft` is deprecated. Use `weave command=build` instead — it now auto-approves and runs the full build loop (craft + build + verify).\n\n' + await handleBuildUnified(args, basePath);
167
171
  break;
168
172
  case 'build':
169
173
  result = await handleBuildUnified(args, basePath);
@@ -1945,48 +1949,90 @@ async function handleInterview(args, basePath) {
1945
1949
  }
1946
1950
  async function handleBuild(args, basePath) {
1947
1951
  const lines = [];
1948
- lines.push('## 🏗️ Build');
1952
+ lines.push('## 🏗️ Build (Wave)');
1949
1953
  lines.push('');
1950
1954
  const manager = getPhaseManager(basePath);
1951
1955
  const plan = await manager.loadPlan();
1952
1956
  if (!plan) {
1953
- return 'Error: No active plan found. Run `weave command=design docsPath="docs/"` first.';
1957
+ return 'Error: No active plan found. Run `weave command=prepare docsPath="docs/"` first.';
1954
1958
  }
1955
1959
  if (!plan.planApproved) {
1956
- return 'Error: Plan not approved. Run `weave command=approve` first.';
1960
+ plan.planApproved = true;
1961
+ plan.planApprovedAt = new Date().toISOString();
1962
+ plan.planApprovalNotes = 'Auto-approved by build command.';
1963
+ await manager.savePlan(plan);
1964
+ lines.push(`> ⚡ Plan auto-approved: **${plan.projectName}**`);
1965
+ lines.push('');
1957
1966
  }
1958
- lines.push(`Plan: **${plan.projectName}** (approved at ${plan.planApprovedAt || 'N/A'})`);
1959
- lines.push('');
1960
- const orchestrator = new WeaveOrchestrator();
1967
+ const changeId = plan.activeChangeId || plan.planName || 'main';
1961
1968
  const buildId = generateBuildId();
1962
- const state = generateBuildState(buildId, plan.planName || plan.projectName, args.maxRetries || 3);
1963
- const onMessages = [];
1964
- lines.push('Starting autonomous build loop...');
1965
- lines.push('');
1966
- const result = await executeBuildLoop({
1967
- plan,
1968
- state,
1969
- orchestrator,
1970
- basePath,
1971
- maxRetries: args.maxRetries,
1972
- phaseIds: args.phaseIds ? args.phaseIds.split(',').map((id) => id.trim()).filter(Boolean) : undefined,
1973
- onMessage: (msg) => { onMessages.push(msg); },
1974
- });
1975
- for (const msg of onMessages) {
1976
- lines.push(msg);
1977
- }
1969
+ lines.push(`Plan: **${plan.projectName}** (approved at ${plan.planApprovedAt || 'N/A'})`);
1970
+ lines.push(`Build: \`${buildId}\``);
1978
1971
  lines.push('');
1979
- if (result.success) {
1980
- lines.push('## Build Complete');
1981
- }
1982
- else {
1983
- lines.push('## ⚠️ Build Blocked');
1972
+ try {
1973
+ const decision = await advanceBuildStep({
1974
+ plan,
1975
+ basePath,
1976
+ buildId,
1977
+ changeId,
1978
+ maxRetries: args.maxRetries || 3,
1979
+ phaseIds: args.phaseIds ? args.phaseIds.split(',').map(s => s.trim()).filter(Boolean) : undefined,
1980
+ });
1981
+ switch (decision.kind) {
1982
+ case 'dispatch_wave': {
1983
+ lines.push(`### Wave ${decision.wave.waveIndex} — ${decision.contracts.length} task(s)`);
1984
+ lines.push(`Parallel-safe: ${decision.wave.parallelSafe ? '✅ Yes' : '⚠️ No (sequential)'}`);
1985
+ lines.push('');
1986
+ for (const contract of decision.contracts) {
1987
+ lines.push(`#### ${contract.taskId} — \`${contract.subagentType}\`${contract.mask ? ` (${contract.mask})` : ''}`);
1988
+ lines.push(`- Allowed: ${contract.allowedPaths.length > 0 ? contract.allowedPaths.join(', ') : '*'}`);
1989
+ lines.push(`- Verify: ${contract.verifyCommands.join('; ') || 'none'}`);
1990
+ lines.push(`- Brief: \`${contract.briefPath}\``);
1991
+ lines.push(`- Context: \`${contract.contextPath}\``);
1992
+ lines.push('');
1993
+ lines.push('```');
1994
+ lines.push(`Task(${contract.subagentType}, prompt=Read ${contract.briefPath} and execute the task.)`);
1995
+ lines.push('```');
1996
+ lines.push('');
1997
+ }
1998
+ lines.push('---');
1999
+ lines.push(`After Task() calls complete, pass results:`);
2000
+ lines.push('```');
2001
+ lines.push(`weave command=build action=resume buildId="${buildId}" taskResults='[{"taskId":"<id>","phaseId":"<pid>","status":"succeeded","changedFiles":["file.ts"],"createdSymbols":[],"downstreamExports":[]}]'`);
2002
+ lines.push('```');
2003
+ break;
2004
+ }
2005
+ case 'verify': {
2006
+ lines.push(`### Verifying Wave ${decision.waveIndex}`);
2007
+ lines.push('Running verification commands...');
2008
+ break;
2009
+ }
2010
+ case 'repair': {
2011
+ lines.push(`### 🔧 Repair: ${decision.contract.taskId}`);
2012
+ lines.push(`Failure: ${decision.failureKind}`);
2013
+ lines.push('');
2014
+ lines.push('```');
2015
+ lines.push(`Task(${decision.contract.subagentType}, prompt=Read ${decision.contract.briefPath} and fix the issues.)`);
2016
+ lines.push('```');
2017
+ break;
2018
+ }
2019
+ case 'blocked': {
2020
+ lines.push(`### ⛔ Blocked`);
2021
+ lines.push(decision.reason);
2022
+ if (decision.failedTasks.length > 0) {
2023
+ lines.push(`Failed tasks: ${decision.failedTasks.join(', ')}`);
2024
+ }
2025
+ break;
2026
+ }
2027
+ case 'complete': {
2028
+ lines.push('### ✅ Build Complete');
2029
+ lines.push(decision.summary);
2030
+ break;
2031
+ }
2032
+ }
1984
2033
  }
1985
- lines.push('');
1986
- lines.push(result.summary);
1987
- if (result.tasksEscalated > 0 || result.tasksFailed > 0) {
1988
- lines.push('');
1989
- lines.push('To resume after fixing issues: `weave command=build-resume buildId="<buildId>"`');
2034
+ catch (e) {
2035
+ lines.push(`❌ Error: ${e instanceof Error ? e.message : String(e)}`);
1990
2036
  }
1991
2037
  return lines.join('\n');
1992
2038
  }
@@ -1995,31 +2041,87 @@ async function handleBuildResume(args, basePath) {
1995
2041
  lines.push('## 🔄 Build Resume');
1996
2042
  lines.push('');
1997
2043
  if (!args.buildId) {
1998
- return 'Error: buildId is required. Use `weave command=build-resume buildId="<id>"`.';
1999
- }
2000
- const state = await loadBuildState(basePath, args.buildId);
2001
- if (!state) {
2002
- return `Error: Build state not found: ${args.buildId}`;
2003
- }
2004
- if (state.status !== 'blocked') {
2005
- return `Build ${args.buildId} is not blocked (status: ${state.status}). No need to resume.`;
2044
+ return 'Error: buildId is required. Use `weave command=build action=resume buildId="<id>"`.';
2006
2045
  }
2007
2046
  const manager = getPhaseManager(basePath);
2008
2047
  const plan = await manager.loadPlan();
2009
2048
  if (!plan) {
2010
2049
  return 'Error: No active plan found.';
2011
2050
  }
2012
- state.status = 'running';
2013
- state.escalationReason = undefined;
2014
- const orchestrator = new WeaveOrchestrator();
2015
- const result = await executeBuildLoop({
2016
- plan,
2017
- state,
2018
- orchestrator,
2019
- basePath,
2020
- maxRetries: args.maxRetries || 3,
2021
- });
2022
- lines.push(result.summary);
2051
+ const changeId = plan.activeChangeId || plan.planName || 'main';
2052
+ let lastResults = [];
2053
+ if (args.taskResults) {
2054
+ try {
2055
+ lastResults = JSON.parse(args.taskResults);
2056
+ }
2057
+ catch {
2058
+ lines.push('> ⚠️ Could not parse taskResults, proceeding without previous results.');
2059
+ }
2060
+ }
2061
+ else {
2062
+ lines.push('> ⚠️ No taskResults provided. Pass results from Task() calls as JSON:');
2063
+ lines.push('> `weave command=build action=resume buildId="..." taskResults=\'[{"taskId":"...","phaseId":"...","status":"succeeded","changedFiles":[],"createdSymbols":[],"downstreamExports":[]}]\'`');
2064
+ lines.push('');
2065
+ }
2066
+ try {
2067
+ const decision = await advanceBuildStep({
2068
+ plan,
2069
+ basePath,
2070
+ buildId: args.buildId,
2071
+ changeId,
2072
+ lastResults: lastResults.length > 0 ? lastResults : undefined,
2073
+ maxRetries: args.maxRetries || 3,
2074
+ });
2075
+ switch (decision.kind) {
2076
+ case 'dispatch_wave': {
2077
+ lines.push(`### Next Wave ${decision.wave.waveIndex} — ${decision.contracts.length} task(s)`);
2078
+ lines.push(`Parallel-safe: ${decision.wave.parallelSafe ? '✅ Yes' : '⚠️ No'}`);
2079
+ lines.push('');
2080
+ for (const contract of decision.contracts) {
2081
+ lines.push(`#### ${contract.taskId} — \`${contract.subagentType}\``);
2082
+ lines.push('```');
2083
+ lines.push(`Task(${contract.subagentType}, prompt=Read ${contract.briefPath} and execute the task.)`);
2084
+ lines.push('```');
2085
+ lines.push('');
2086
+ }
2087
+ lines.push(`After Task() calls complete, pass results:`);
2088
+ lines.push('```');
2089
+ lines.push(`weave command=build action=resume buildId="${args.buildId}" taskResults='[{"taskId":"<id>","phaseId":"<pid>","status":"succeeded","changedFiles":["file.ts"],"createdSymbols":[],"downstreamExports":[]}]'`);
2090
+ lines.push('```');
2091
+ break;
2092
+ }
2093
+ case 'repair': {
2094
+ lines.push(`### 🔧 Repair: ${decision.contract.taskId}`);
2095
+ lines.push(`Failure: ${decision.failureKind}`);
2096
+ lines.push('```');
2097
+ lines.push(`Task(${decision.contract.subagentType}, prompt=Read ${decision.contract.briefPath} and fix.)`);
2098
+ lines.push('```');
2099
+ lines.push('');
2100
+ lines.push(`After fix, pass results:`);
2101
+ lines.push('```');
2102
+ lines.push(`weave command=build action=resume buildId="${args.buildId}" taskResults='[{"taskId":"${decision.contract.taskId}","phaseId":"${decision.contract.phaseId}","status":"succeeded","changedFiles":[],"createdSymbols":[],"downstreamExports":[]}]'`);
2103
+ lines.push('```');
2104
+ break;
2105
+ }
2106
+ case 'blocked': {
2107
+ lines.push('### ⛔ Build Blocked');
2108
+ lines.push(decision.reason);
2109
+ break;
2110
+ }
2111
+ case 'complete': {
2112
+ lines.push('### ✅ Build Complete');
2113
+ lines.push(decision.summary);
2114
+ break;
2115
+ }
2116
+ case 'verify': {
2117
+ lines.push(`### Verifying Wave ${decision.waveIndex}...`);
2118
+ break;
2119
+ }
2120
+ }
2121
+ }
2122
+ catch (e) {
2123
+ lines.push(`❌ Error: ${e instanceof Error ? e.message : String(e)}`);
2124
+ }
2023
2125
  return lines.join('\n');
2024
2126
  }
2025
2127
  async function handleCraft(args, basePath) {
@@ -2429,6 +2531,59 @@ async function handleInitConfig(basePath) {
2429
2531
  lines.push('> with your model pool, then run `weave sync-agents` in any project to apply it.');
2430
2532
  return lines.join('\n');
2431
2533
  }
2534
+ async function handleWaveBuildStatus(buildId, basePath) {
2535
+ const manager = getPhaseManager(basePath);
2536
+ const plan = await manager.loadPlan();
2537
+ if (!plan)
2538
+ return null;
2539
+ const changeId = plan.activeChangeId || plan.planName || 'main';
2540
+ const buildDir = path.join(basePath, 'changes', changeId, 'builds', buildId);
2541
+ if (!fs.existsSync(buildDir))
2542
+ return null;
2543
+ const lines = [];
2544
+ lines.push(`## Wave Build Status: \`${buildId}\``);
2545
+ lines.push('');
2546
+ const wavesDir = path.join(buildDir, 'waves');
2547
+ if (fs.existsSync(wavesDir)) {
2548
+ const waveFiles = fs.readdirSync(wavesDir).filter(f => f.startsWith('wave-')).sort();
2549
+ for (const wf of waveFiles) {
2550
+ const content = fs.readFileSync(path.join(wavesDir, wf), 'utf-8');
2551
+ lines.push(`### ${wf.replace('.md', '')}`);
2552
+ lines.push('```');
2553
+ lines.push(content.slice(0, 2000));
2554
+ lines.push('```');
2555
+ lines.push('');
2556
+ }
2557
+ }
2558
+ const tasksDir = path.join(buildDir, 'tasks');
2559
+ if (fs.existsSync(tasksDir)) {
2560
+ const taskDirs = fs.readdirSync(tasksDir, { withFileTypes: true }).filter(d => d.isDirectory());
2561
+ lines.push(`### Tasks (${taskDirs.length})`);
2562
+ lines.push('');
2563
+ for (const td of taskDirs) {
2564
+ const resultPath = path.join(tasksDir, td.name, 'result.md');
2565
+ const briefPath = path.join(tasksDir, td.name, 'brief.md');
2566
+ if (fs.existsSync(resultPath)) {
2567
+ const resultContent = fs.readFileSync(resultPath, 'utf-8');
2568
+ const statusMatch = resultContent.match(/\*\*Status:\*\*\s*(\w+)/);
2569
+ lines.push(`- ${td.name}: ${statusMatch?.[1] || 'unknown'}`);
2570
+ }
2571
+ else if (fs.existsSync(briefPath)) {
2572
+ lines.push(`- ${td.name}: dispatched (no result yet)`);
2573
+ }
2574
+ }
2575
+ lines.push('');
2576
+ }
2577
+ const contextIndexPath = path.join(buildDir, 'context-index.yaml');
2578
+ if (fs.existsSync(contextIndexPath)) {
2579
+ lines.push('### Context Index');
2580
+ lines.push('```yaml');
2581
+ lines.push(fs.readFileSync(contextIndexPath, 'utf-8').slice(0, 1500));
2582
+ lines.push('```');
2583
+ lines.push('');
2584
+ }
2585
+ return lines.join('\n');
2586
+ }
2432
2587
  async function handleBuildUnified(args, basePath) {
2433
2588
  const action = args.action || 'run';
2434
2589
  switch (action) {
@@ -2439,13 +2594,16 @@ async function handleBuildUnified(args, basePath) {
2439
2594
  case 'status': {
2440
2595
  const loopId = args.buildId || args.loopId;
2441
2596
  if (!loopId)
2442
- return 'Error: buildId or loopId is required for status action. Example: weave command=build action=status buildId="build-20250428-a1b2"';
2597
+ return 'Error: buildId is required. Example: weave command=build action=status buildId="build-20250428-a1b2"';
2598
+ const waveStatus = await handleWaveBuildStatus(loopId, basePath);
2599
+ if (waveStatus)
2600
+ return waveStatus;
2443
2601
  return handleLoopStatus({ loopId }, basePath);
2444
2602
  }
2445
2603
  case 'stop': {
2446
2604
  const loopId = args.buildId || args.loopId;
2447
2605
  if (!loopId)
2448
- return 'Error: buildId or loopId is required for stop action. Example: weave command=build action=stop buildId="build-20250428-a1b2"';
2606
+ return 'Error: buildId is required. Example: weave command=build action=stop buildId="build-20250428-a1b2"';
2449
2607
  return handleLoopStop({ loopId, context: undefined }, basePath);
2450
2608
  }
2451
2609
  case 'list':
@@ -2461,10 +2619,20 @@ async function handleBuildUnified(args, basePath) {
2461
2619
  }
2462
2620
  }
2463
2621
  async function handleAgents(args, basePath) {
2464
- if (!args.sync && !args.init) {
2465
- return 'Error: agents requires an action. Use `sync=true` to regenerate agent files, or `init=true` to create default config.';
2622
+ if (!args.sync && !args.init && !args.force) {
2623
+ return 'Error: agents requires an action. Use `sync=true` to regenerate agent files, `init=true` to create default config, or `force=true` to re-detect subscription and overwrite config.';
2466
2624
  }
2467
2625
  const sections = [];
2626
+ if (args.force) {
2627
+ const result = writeAutoDetectedConfig(basePath, true);
2628
+ if (result) {
2629
+ sections.push(`## ✅ Config Force-Updated\n\nAuto-detected subscription: \`${result.detection.primary}\` (${result.detection.subscriptions.join(', ')})\n\n\`\`\`\n${formatProviderChecklist(result.detection)}\n\`\`\`\n\nWrote to: \`${toWorkspaceRelative(basePath, result.path)}\``);
2630
+ }
2631
+ else {
2632
+ sections.push('## ❌ Force update failed\n\nCould not auto-detect subscription. Make sure opencode CLI is available.');
2633
+ }
2634
+ sections.push(await handleSyncAgents(basePath));
2635
+ }
2468
2636
  if (args.sync) {
2469
2637
  sections.push(await handleSyncAgents(basePath));
2470
2638
  }
@@ -117,6 +117,7 @@ export interface ModelPoolEntry {
117
117
  maxConcurrent: number;
118
118
  capabilities: ModelCapability[];
119
119
  costTier: ModelCostTier;
120
+ priority?: number;
120
121
  description?: string;
121
122
  }
122
123
  export type DummyHumansConfig = Record<string, string> | {
@@ -35,7 +35,7 @@ export declare function detectSubscriptionsFromConfig(opencodeConfig: Record<str
35
35
  export declare function buildPoolFromDetection(detection: SubscriptionDetectionResult): any[];
36
36
  export declare function buildConfigFromDetection(detection: SubscriptionDetectionResult): Record<string, any>;
37
37
  export declare function formatProviderChecklist(detection: SubscriptionDetectionResult): string;
38
- export declare function writeAutoDetectedConfig(projectDir: string): {
38
+ export declare function writeAutoDetectedConfig(projectDir: string, force?: boolean): {
39
39
  path: string;
40
40
  detection: SubscriptionDetectionResult;
41
41
  } | null;
@@ -48,6 +48,7 @@ export declare const DEFAULT_RUNTIME_CONFIG_TEMPLATE: {
48
48
  readonly maxConcurrent: 5;
49
49
  readonly capabilities: readonly ["search", "formatting", "simple-coding", "file-ops"];
50
50
  readonly costTier: "low";
51
+ readonly priority: 1;
51
52
  readonly description: "DeepSeek V4 Flash - 빠름. 단순 검색/포매팅/파일작업";
52
53
  }, {
53
54
  readonly id: "deepseek-general";
@@ -56,6 +57,7 @@ export declare const DEFAULT_RUNTIME_CONFIG_TEMPLATE: {
56
57
  readonly maxConcurrent: 3;
57
58
  readonly capabilities: readonly ["coding", "testing", "refactoring", "backend"];
58
59
  readonly costTier: "medium";
60
+ readonly priority: 2;
59
61
  readonly description: "DeepSeek V4 Flash - 일반. 코딩/리팩토링/백엔드";
60
62
  }, {
61
63
  readonly id: "qwen-vision";
@@ -64,6 +66,7 @@ export declare const DEFAULT_RUNTIME_CONFIG_TEMPLATE: {
64
66
  readonly maxConcurrent: 3;
65
67
  readonly capabilities: readonly ["vision", "frontend", "testing"];
66
68
  readonly costTier: "medium";
69
+ readonly priority: 1;
67
70
  readonly description: "Qwen 3.6 Plus - 비전. 이미지 분석/프론트엔드/테스트";
68
71
  }, {
69
72
  readonly id: "deepseek-pro";
@@ -72,6 +75,7 @@ export declare const DEFAULT_RUNTIME_CONFIG_TEMPLATE: {
72
75
  readonly maxConcurrent: 2;
73
76
  readonly capabilities: readonly ["architecture", "debugging", "reasoning", "complex-coding", "refactoring"];
74
77
  readonly costTier: "high";
78
+ readonly priority: 2;
75
79
  readonly description: "DeepSeek V4 Pro - 고급 추론. 아키텍처/복잡 디버깅";
76
80
  }, {
77
81
  readonly id: "kimi-vision";
@@ -80,6 +84,7 @@ export declare const DEFAULT_RUNTIME_CONFIG_TEMPLATE: {
80
84
  readonly maxConcurrent: 2;
81
85
  readonly capabilities: readonly ["vision", "reasoning", "complex-coding", "architecture", "debugging"];
82
86
  readonly costTier: "high";
87
+ readonly priority: 1;
83
88
  readonly description: "Kimi K2.6 - 비전 고급. 이미지 분석/복잡 추론";
84
89
  }];
85
90
  };