maskweaver 0.9.6 → 0.9.8
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/dist/plugin/index.js +13 -2
- package/dist/shared/generate-agents.d.ts +22 -0
- package/dist/shared/generate-agents.js +341 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/weave/gherkin.d.ts +43 -0
- package/dist/weave/gherkin.js +307 -0
- package/dist/weave/phase-manager.js +59 -0
- package/dist/weave/stages/build.js +16 -0
- package/dist/weave/stages/execute.d.ts +8 -1
- package/dist/weave/stages/execute.js +105 -0
- package/dist/weave/stages/plan.js +24 -0
- package/dist/weave/stages/refine.js +75 -0
- package/dist/weave/types.d.ts +11 -1
- package/package.json +3 -3
- package/postinstall.mjs +174 -71
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parseGherkinBlock } from '../gherkin.js';
|
|
1
2
|
const STATUS_VALUES = new Set([
|
|
2
3
|
'pending',
|
|
3
4
|
'in_progress',
|
|
@@ -347,6 +348,80 @@ export function refinePlanFromNotes(plan, notesContent) {
|
|
|
347
348
|
changes.push(`~ ${phase.id} task ${taskId}: "${old}" -> "${name}"`);
|
|
348
349
|
}
|
|
349
350
|
}
|
|
351
|
+
if (matched)
|
|
352
|
+
continue;
|
|
353
|
+
const addCriteria = /^@phase\s+([A-Za-z0-9_-]+)\s+add_criteria\s*:\s*(.+)$/is.exec(line);
|
|
354
|
+
if (addCriteria) {
|
|
355
|
+
directivesParsed += 1;
|
|
356
|
+
matched = true;
|
|
357
|
+
const phaseId = addCriteria[1].toUpperCase();
|
|
358
|
+
const rawBlock = addCriteria[2].trim();
|
|
359
|
+
const phase = findPhase(updated, phaseId);
|
|
360
|
+
if (!phase) {
|
|
361
|
+
warnings.push(`Line ${i + 1}: phase ${phaseId} not found (skipped criteria add).`);
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
const scenarios = parseGherkinBlock(rawBlock);
|
|
365
|
+
if (scenarios.length === 0) {
|
|
366
|
+
warnings.push(`Line ${i + 1}: could not parse Gherkin block for ${phaseId}.`);
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
if (!phase.acceptanceCriteria)
|
|
370
|
+
phase.acceptanceCriteria = [];
|
|
371
|
+
phase.acceptanceCriteria.push(...scenarios);
|
|
372
|
+
changes.push(`+ ${phaseId} acceptance criteria: ${scenarios.length} scenario(s)`);
|
|
373
|
+
}
|
|
374
|
+
if (matched)
|
|
375
|
+
continue;
|
|
376
|
+
const replaceCriteria = /^@phase\s+([A-Za-z0-9_-]+)\s+replace_criteria\s*:\s*(.+)$/is.exec(line);
|
|
377
|
+
if (replaceCriteria) {
|
|
378
|
+
directivesParsed += 1;
|
|
379
|
+
matched = true;
|
|
380
|
+
const phaseId = replaceCriteria[1].toUpperCase();
|
|
381
|
+
const rawBlock = replaceCriteria[2].trim();
|
|
382
|
+
const phase = findPhase(updated, phaseId);
|
|
383
|
+
if (!phase) {
|
|
384
|
+
warnings.push(`Line ${i + 1}: phase ${phaseId} not found (skipped criteria replace).`);
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
const scenarios = parseGherkinBlock(rawBlock);
|
|
388
|
+
if (scenarios.length === 0) {
|
|
389
|
+
warnings.push(`Line ${i + 1}: could not parse Gherkin block for ${phaseId}.`);
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
phase.acceptanceCriteria = scenarios;
|
|
393
|
+
changes.push(`~ ${phaseId} acceptance criteria replaced: ${scenarios.length} scenario(s)`);
|
|
394
|
+
}
|
|
395
|
+
if (matched)
|
|
396
|
+
continue;
|
|
397
|
+
const taskCriteria = /^@task\s+([A-Za-z0-9_-]+)\s+([A-Za-z0-9_-]+)\s+criteria\s*:\s*(.+)$/is.exec(line);
|
|
398
|
+
if (taskCriteria) {
|
|
399
|
+
directivesParsed += 1;
|
|
400
|
+
matched = true;
|
|
401
|
+
const phaseId = taskCriteria[1].toUpperCase();
|
|
402
|
+
const taskId = taskCriteria[2].trim();
|
|
403
|
+
const rawBlock = taskCriteria[3].trim();
|
|
404
|
+
const phase = findPhase(updated, phaseId);
|
|
405
|
+
if (!phase) {
|
|
406
|
+
warnings.push(`Line ${i + 1}: phase ${phaseId} not found (skipped task criteria).`);
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
const task = phase.tasks.find(t => t.id === taskId);
|
|
410
|
+
if (!task) {
|
|
411
|
+
warnings.push(`Line ${i + 1}: task ${taskId} not found in ${phaseId} (skipped criteria).`);
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
const scenarios = parseGherkinBlock(rawBlock);
|
|
415
|
+
if (scenarios.length === 0) {
|
|
416
|
+
warnings.push(`Line ${i + 1}: could not parse Gherkin block for ${taskId}.`);
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
task.acceptanceCriteria = scenarios;
|
|
420
|
+
if (!task.verify)
|
|
421
|
+
task.verify = [];
|
|
422
|
+
task.verify.push({ kind: 'gherkin', value: `${scenarios.length} scenario(s)` });
|
|
423
|
+
changes.push(`~ ${phaseId}/${taskId} acceptance criteria: ${scenarios.length} scenario(s)`);
|
|
424
|
+
}
|
|
350
425
|
if (matched)
|
|
351
426
|
continue;
|
|
352
427
|
warnings.push(`Line ${i + 1}: unrecognized directive: ${line}`);
|
package/dist/weave/types.d.ts
CHANGED
|
@@ -123,6 +123,15 @@ export interface WeavePhase {
|
|
|
123
123
|
masksUsed?: string[];
|
|
124
124
|
startedAt?: string;
|
|
125
125
|
completedAt?: string;
|
|
126
|
+
acceptanceCriteria?: GherkinScenario[];
|
|
127
|
+
featurePath?: string;
|
|
128
|
+
}
|
|
129
|
+
export interface GherkinScenario {
|
|
130
|
+
feature: string;
|
|
131
|
+
scenario: string;
|
|
132
|
+
given: string[];
|
|
133
|
+
when: string[];
|
|
134
|
+
then: string[];
|
|
126
135
|
}
|
|
127
136
|
export interface WeaveTask {
|
|
128
137
|
id: string;
|
|
@@ -134,10 +143,11 @@ export interface WeaveTask {
|
|
|
134
143
|
files?: string[];
|
|
135
144
|
dependsOn?: string[];
|
|
136
145
|
verify?: Array<{
|
|
137
|
-
kind: 'command' | 'checklist';
|
|
146
|
+
kind: 'command' | 'checklist' | 'gherkin';
|
|
138
147
|
value: string;
|
|
139
148
|
}>;
|
|
140
149
|
acceptanceRefs?: string[];
|
|
150
|
+
acceptanceCriteria?: GherkinScenario[];
|
|
141
151
|
retryCount: number;
|
|
142
152
|
maxRetries: number;
|
|
143
153
|
lastError?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "maskweaver",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.8",
|
|
4
4
|
"description": "AI Expert Persona System - Give your AI coding assistant expert personalities (가면술사)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -138,11 +138,11 @@
|
|
|
138
138
|
"@rollup/rollup-win32-x64-msvc": "^4.57.1",
|
|
139
139
|
"@types/better-sqlite3": "^7.6.13",
|
|
140
140
|
"@types/node": "^20.0.0",
|
|
141
|
-
"better-sqlite3": "^12.
|
|
141
|
+
"better-sqlite3": "^12.9.0",
|
|
142
142
|
"typescript": "^5.3.0",
|
|
143
143
|
"vitest": "^4.0.18"
|
|
144
144
|
},
|
|
145
145
|
"optionalDependencies": {
|
|
146
|
-
"better-sqlite3": "^9.
|
|
146
|
+
"better-sqlite3": "^12.9.0"
|
|
147
147
|
}
|
|
148
148
|
}
|
package/postinstall.mjs
CHANGED
|
@@ -71,112 +71,209 @@ function getPackageVersion() {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
costTier: 'low',
|
|
84
|
-
description: 'DeepSeek V4 Flash - 빠름. 단순 검색/포매팅/파일작업',
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
id: 'deepseek-general',
|
|
88
|
-
model: 'opencode-go/deepseek-v4-flash',
|
|
89
|
-
tier: 'human',
|
|
90
|
-
maxConcurrent: 3,
|
|
91
|
-
capabilities: ['coding', 'testing', 'refactoring', 'backend'],
|
|
92
|
-
costTier: 'medium',
|
|
93
|
-
description: 'DeepSeek V4 Flash - 일반. 코딩/리팩토링/백엔드',
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
id: 'qwen-vision',
|
|
97
|
-
model: 'opencode-go/qwen3.6-plus',
|
|
98
|
-
tier: 'human',
|
|
99
|
-
maxConcurrent: 3,
|
|
100
|
-
capabilities: ['vision', 'frontend', 'testing'],
|
|
101
|
-
costTier: 'medium',
|
|
102
|
-
description: 'Qwen 3.6 Plus - 비전. 이미지 분석/프론트엔드/테스트',
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
id: 'deepseek-pro',
|
|
106
|
-
model: 'opencode-go/deepseek-v4-pro',
|
|
107
|
-
tier: 'premium',
|
|
108
|
-
maxConcurrent: 2,
|
|
109
|
-
capabilities: ['architecture', 'debugging', 'reasoning', 'complex-coding', 'refactoring'],
|
|
110
|
-
costTier: 'high',
|
|
111
|
-
description: 'DeepSeek V4 Pro - 고급 추론. 아키텍처/복잡 디버깅',
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
id: 'kimi-vision',
|
|
115
|
-
model: 'opencode-go/kimi-k2.6',
|
|
116
|
-
tier: 'premium',
|
|
117
|
-
maxConcurrent: 2,
|
|
118
|
-
capabilities: ['vision', 'reasoning', 'complex-coding', 'architecture', 'debugging'],
|
|
119
|
-
costTier: 'high',
|
|
120
|
-
description: 'Kimi K2.6 - 비전 고급. 이미지 분석/복잡 추론',
|
|
121
|
-
},
|
|
122
|
-
],
|
|
74
|
+
const ZAI_POOL = [
|
|
75
|
+
{
|
|
76
|
+
id: 'glm-flash',
|
|
77
|
+
model: 'zai-coding-plan/glm-5-turbo',
|
|
78
|
+
tier: 'flash',
|
|
79
|
+
maxConcurrent: 1,
|
|
80
|
+
capabilities: ['search', 'formatting', 'simple-coding', 'file-ops'],
|
|
81
|
+
costTier: 'low',
|
|
82
|
+
description: 'GLM-5 Turbo - 빠름. 단순 검색/포매팅/파일작업',
|
|
123
83
|
},
|
|
124
|
-
|
|
84
|
+
{
|
|
85
|
+
id: 'glm-general',
|
|
86
|
+
model: 'zai-coding-plan/glm-5.1',
|
|
87
|
+
tier: 'human',
|
|
88
|
+
maxConcurrent: 10,
|
|
89
|
+
capabilities: ['coding', 'testing', 'refactoring', 'backend'],
|
|
90
|
+
costTier: 'medium',
|
|
91
|
+
description: 'GLM-5.1 - 일반. 코딩/리팩토링/백엔드',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: 'glm-premium',
|
|
95
|
+
model: 'zai-coding-plan/glm-5.1',
|
|
96
|
+
tier: 'premium',
|
|
97
|
+
maxConcurrent: 10,
|
|
98
|
+
capabilities: ['architecture', 'debugging', 'reasoning', 'complex-coding', 'refactoring'],
|
|
99
|
+
costTier: 'high',
|
|
100
|
+
description: 'GLM-5.1 - 고급 추론. 아키텍처/복잡 디버깅',
|
|
101
|
+
},
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
const OPENCODE_GO_POOL = [
|
|
105
|
+
{
|
|
106
|
+
id: 'deepseek-flash',
|
|
107
|
+
model: 'opencode-go/deepseek-v4-flash',
|
|
108
|
+
tier: 'flash',
|
|
109
|
+
maxConcurrent: 5,
|
|
110
|
+
capabilities: ['search', 'formatting', 'simple-coding', 'file-ops'],
|
|
111
|
+
costTier: 'low',
|
|
112
|
+
description: 'DeepSeek V4 Flash - 빠름. 단순 검색/포매팅/파일작업',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: 'deepseek-general',
|
|
116
|
+
model: 'opencode-go/deepseek-v4-flash',
|
|
117
|
+
tier: 'human',
|
|
118
|
+
maxConcurrent: 3,
|
|
119
|
+
capabilities: ['coding', 'testing', 'refactoring', 'backend'],
|
|
120
|
+
costTier: 'medium',
|
|
121
|
+
description: 'DeepSeek V4 Flash - 일반. 코딩/리팩토링/백엔드',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: 'qwen-vision',
|
|
125
|
+
model: 'opencode-go/qwen3.6-plus',
|
|
126
|
+
tier: 'human',
|
|
127
|
+
maxConcurrent: 3,
|
|
128
|
+
capabilities: ['vision', 'frontend', 'testing'],
|
|
129
|
+
costTier: 'medium',
|
|
130
|
+
description: 'Qwen 3.6 Plus - 비전. 이미지 분석/프론트엔드/테스트',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
id: 'deepseek-pro',
|
|
125
134
|
model: 'opencode-go/deepseek-v4-pro',
|
|
135
|
+
tier: 'premium',
|
|
126
136
|
maxConcurrent: 2,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
provider: 'text-only',
|
|
131
|
-
enabled: false,
|
|
137
|
+
capabilities: ['architecture', 'debugging', 'reasoning', 'complex-coding', 'refactoring'],
|
|
138
|
+
costTier: 'high',
|
|
139
|
+
description: 'DeepSeek V4 Pro - 고급 추론. 아키텍처/복잡 디버깅',
|
|
132
140
|
},
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
141
|
+
{
|
|
142
|
+
id: 'kimi-vision',
|
|
143
|
+
model: 'opencode-go/kimi-k2.6',
|
|
144
|
+
tier: 'premium',
|
|
145
|
+
maxConcurrent: 2,
|
|
146
|
+
capabilities: ['vision', 'reasoning', 'complex-coding', 'architecture', 'debugging'],
|
|
147
|
+
costTier: 'high',
|
|
148
|
+
description: 'Kimi K2.6 - 비전 고급. 이미지 분석/복잡 추론',
|
|
137
149
|
},
|
|
138
|
-
|
|
139
|
-
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
function runCli(command, args) {
|
|
153
|
+
try {
|
|
154
|
+
const result = spawnSync(command, args, {
|
|
155
|
+
encoding: 'utf-8',
|
|
156
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
157
|
+
timeout: 8000,
|
|
158
|
+
windowsHide: true,
|
|
159
|
+
});
|
|
160
|
+
if (result.error || result.status !== 0) return null;
|
|
161
|
+
return result.stdout || null;
|
|
162
|
+
} catch {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function detectSubscription() {
|
|
168
|
+
let hasOpencodeGo = false;
|
|
169
|
+
let hasZai = false;
|
|
170
|
+
|
|
171
|
+
const providersOutput = runCli('opencode', ['providers', 'list']);
|
|
172
|
+
if (providersOutput) {
|
|
173
|
+
const stripped = providersOutput.replace(/\x1b\[[0-9;]*m/g, '');
|
|
174
|
+
if (/opencode\s*go/i.test(stripped)) hasOpencodeGo = true;
|
|
175
|
+
if (/z\.ai\s*coding\s*plan|zai-coding-plan/i.test(stripped)) hasZai = true;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const modelsOutput = runCli('opencode', ['models']);
|
|
179
|
+
if (modelsOutput) {
|
|
180
|
+
if (/^opencode-go\//m.test(modelsOutput)) hasOpencodeGo = true;
|
|
181
|
+
if (/^zai-coding-plan\//m.test(modelsOutput)) hasZai = true;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (hasZai) return 'zai-coding-plan';
|
|
185
|
+
if (hasOpencodeGo) return 'opencode-go';
|
|
186
|
+
|
|
187
|
+
const candidates = [
|
|
188
|
+
join(homedir(), '.config', 'opencode', 'opencode.json'),
|
|
189
|
+
join(homedir(), '.config', 'opencode', 'opencode.jsonc'),
|
|
190
|
+
];
|
|
191
|
+
|
|
192
|
+
for (const candidate of candidates) {
|
|
193
|
+
if (!existsSync(candidate)) continue;
|
|
194
|
+
try {
|
|
195
|
+
let content = readFileSync(candidate, 'utf-8');
|
|
196
|
+
content = content.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
|
|
197
|
+
const parsed = JSON.parse(content);
|
|
198
|
+
if (!parsed || typeof parsed !== 'object') continue;
|
|
199
|
+
|
|
200
|
+
const modelFields = ['model', 'small_model', 'large_model'];
|
|
201
|
+
for (const field of modelFields) {
|
|
202
|
+
const val = parsed[field];
|
|
203
|
+
if (typeof val !== 'string' || !val) continue;
|
|
204
|
+
if (val.startsWith('opencode-go/')) hasOpencodeGo = true;
|
|
205
|
+
if (val.startsWith('zai-coding-plan/')) hasZai = true;
|
|
206
|
+
}
|
|
207
|
+
} catch { continue; }
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (hasZai) return 'zai-coding-plan';
|
|
211
|
+
if (hasOpencodeGo) return 'opencode-go';
|
|
212
|
+
return 'opencode-go';
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function buildConfigForSubscription(subscription) {
|
|
216
|
+
const pool = subscription === 'zai-coding-plan'
|
|
217
|
+
? [...ZAI_POOL, ...OPENCODE_GO_POOL]
|
|
218
|
+
: [...OPENCODE_GO_POOL];
|
|
219
|
+
|
|
220
|
+
const operatorModel = subscription === 'zai-coding-plan'
|
|
221
|
+
? 'zai-coding-plan/glm-5.1'
|
|
222
|
+
: 'opencode-go/deepseek-v4-pro';
|
|
223
|
+
|
|
224
|
+
const operatorConcurrent = subscription === 'zai-coding-plan' ? 10 : 2;
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
dummyHumans: { pool },
|
|
228
|
+
operator: {
|
|
229
|
+
model: operatorModel,
|
|
230
|
+
maxConcurrent: operatorConcurrent,
|
|
231
|
+
description: 'Squad Operator model - 작업 오케스트레이션 및 고급 추론',
|
|
232
|
+
},
|
|
233
|
+
memory: { provider: 'text-only', enabled: false },
|
|
234
|
+
gdc: { enabled: 'auto', strictVerify: false, autoSyncOnPrepare: true },
|
|
235
|
+
language: 'ko',
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const DEFAULT_GLOBAL_CONFIG_TEMPLATE = buildConfigForSubscription('opencode-go');
|
|
140
240
|
|
|
141
241
|
function ensureGlobalConfig() {
|
|
142
242
|
const globalDir = join(homedir(), '.config', 'opencode');
|
|
143
243
|
const globalConfigPath = join(globalDir, 'maskweaver.config.json');
|
|
144
244
|
|
|
145
245
|
if (!existsSync(globalConfigPath)) {
|
|
146
|
-
|
|
246
|
+
const subscription = detectSubscription();
|
|
247
|
+
const template = buildConfigForSubscription(subscription);
|
|
147
248
|
try {
|
|
148
249
|
if (!existsSync(globalDir)) {
|
|
149
250
|
mkdirSync(globalDir, { recursive: true });
|
|
150
251
|
}
|
|
151
252
|
writeFileSync(
|
|
152
253
|
globalConfigPath,
|
|
153
|
-
JSON.stringify(
|
|
254
|
+
JSON.stringify(template, null, 2) + '\n',
|
|
154
255
|
'utf-8'
|
|
155
256
|
);
|
|
156
|
-
return { created: true, migrated: false };
|
|
257
|
+
return { created: true, migrated: false, subscription };
|
|
157
258
|
} catch {
|
|
158
|
-
return { created: false, migrated: false };
|
|
259
|
+
return { created: false, migrated: false, subscription };
|
|
159
260
|
}
|
|
160
261
|
}
|
|
161
262
|
|
|
162
|
-
// Existing config: migrate — add missing fields without overwriting user edits
|
|
163
263
|
try {
|
|
164
264
|
const existing = JSON.parse(readFileSync(globalConfigPath, 'utf-8'));
|
|
165
265
|
let changed = false;
|
|
166
266
|
|
|
167
|
-
// Migrate: add operator if missing
|
|
168
267
|
if (!existing.operator) {
|
|
169
268
|
existing.operator = DEFAULT_GLOBAL_CONFIG_TEMPLATE.operator;
|
|
170
269
|
changed = true;
|
|
171
270
|
}
|
|
172
271
|
|
|
173
|
-
// Migrate: add gdc if missing
|
|
174
272
|
if (!existing.gdc) {
|
|
175
273
|
existing.gdc = DEFAULT_GLOBAL_CONFIG_TEMPLATE.gdc;
|
|
176
274
|
changed = true;
|
|
177
275
|
}
|
|
178
276
|
|
|
179
|
-
// Migrate: add dummyHumans if missing
|
|
180
277
|
if (!existing.dummyHumans) {
|
|
181
278
|
existing.dummyHumans = DEFAULT_GLOBAL_CONFIG_TEMPLATE.dummyHumans;
|
|
182
279
|
changed = true;
|
|
@@ -190,9 +287,10 @@ function ensureGlobalConfig() {
|
|
|
190
287
|
);
|
|
191
288
|
}
|
|
192
289
|
|
|
193
|
-
|
|
290
|
+
const subscription = detectSubscription();
|
|
291
|
+
return { created: false, migrated: changed, subscription };
|
|
194
292
|
} catch {
|
|
195
|
-
return { created: false, migrated: false };
|
|
293
|
+
return { created: false, migrated: false, subscription: 'opencode-go' };
|
|
196
294
|
}
|
|
197
295
|
}
|
|
198
296
|
|
|
@@ -204,6 +302,7 @@ function main() {
|
|
|
204
302
|
if (configResult.created) {
|
|
205
303
|
console.log(`✓ maskweaver v${pkgVersion}: 글로벌 설정 파일 생성됨`);
|
|
206
304
|
console.log(` → ~/.config/opencode/maskweaver.config.json`);
|
|
305
|
+
console.log(` 감지된 구독: ${configResult.subscription}`);
|
|
207
306
|
console.log(` 편집 후 프로젝트에서 \`weave sync-agents\`를 실행하세요`);
|
|
208
307
|
console.log('');
|
|
209
308
|
} else if (configResult.migrated) {
|
|
@@ -211,6 +310,10 @@ function main() {
|
|
|
211
310
|
console.log(` → ~/.config/opencode/maskweaver.config.json`);
|
|
212
311
|
console.log(` operator 및 gdc 설정이 추가되었습니다.`);
|
|
213
312
|
console.log('');
|
|
313
|
+
} else if (configResult.subscription === 'zai-coding-plan') {
|
|
314
|
+
console.log(`✓ maskweaver v${pkgVersion}: zai-coding-plan 구독 감지됨`);
|
|
315
|
+
console.log(` GLM-5.1 모델이 풀에 포함되어 있습니다.`);
|
|
316
|
+
console.log('');
|
|
214
317
|
}
|
|
215
318
|
|
|
216
319
|
const versionCheck = checkOpenCodeVersion();
|