maskweaver 0.8.6 → 0.8.7
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/README.ko.md +217 -217
- package/README.md +235 -235
- package/assets/agents/squad-operator.md +56 -56
- package/assets/commands/weave-approve-plan.md +57 -57
- package/assets/commands/weave-craft.md +43 -43
- package/assets/commands/weave-design.md +64 -64
- package/assets/commands/weave-flow.md +48 -48
- package/assets/commands/weave-help.md +101 -101
- package/assets/commands/weave-init.md +23 -23
- package/assets/commands/weave-plan.md +15 -15
- package/assets/commands/weave-prepare.md +69 -69
- package/assets/commands/weave-refine-plan.md +59 -59
- package/assets/commands/weave-repair.md +70 -70
- package/assets/commands/weave-research.md +51 -51
- package/assets/commands/weave-spec.md +227 -227
- package/assets/commands/weave-status.md +2 -2
- package/assets/commands/weave-verify.md +44 -44
- package/assets/commands/weave-worktree.md +69 -69
- package/dist/cli/doctor.d.ts +16 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +355 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/install.js +9 -0
- package/dist/cli/install.js.map +1 -1
- package/dist/plugin/config/index.d.ts +3 -10
- package/dist/plugin/config/index.d.ts.map +1 -1
- package/dist/plugin/config/index.js +12 -15
- package/dist/plugin/config/index.js.map +1 -1
- package/dist/plugin/index.d.ts +1 -27
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +40 -240
- package/dist/plugin/index.js.map +1 -1
- package/dist/plugin/tools/slashcommand.js +59 -59
- package/dist/plugin/tools/squad.js +3 -3
- package/dist/plugin/tools/weave.js +111 -111
- package/dist/plugin/types.d.ts +10 -8
- package/dist/plugin/types.d.ts.map +1 -1
- package/dist/plugin/types.js +2 -0
- package/dist/plugin/types.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +4 -2
- package/postinstall.mjs +97 -0
|
@@ -12,6 +12,15 @@ import { parse as parseJsonc } from 'jsonc-parser';
|
|
|
12
12
|
import * as fs from 'node:fs';
|
|
13
13
|
import * as path from 'node:path';
|
|
14
14
|
import * as os from 'node:os';
|
|
15
|
+
function pluginLog(ctx, level, message) {
|
|
16
|
+
ctx.client.app.log({
|
|
17
|
+
body: {
|
|
18
|
+
service: 'maskweaver',
|
|
19
|
+
level,
|
|
20
|
+
message,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
}
|
|
15
24
|
// ============================================================================
|
|
16
25
|
// Configuration Loader
|
|
17
26
|
// ============================================================================
|
|
@@ -66,33 +75,21 @@ export function loadPluginConfig(directory, ctx) {
|
|
|
66
75
|
const config = parseJsoncContent(content);
|
|
67
76
|
// Log successful config load
|
|
68
77
|
if (ctx?.verbose) {
|
|
69
|
-
ctx
|
|
70
|
-
service: 'maskweaver',
|
|
71
|
-
level: 'info',
|
|
72
|
-
message: `Loaded config from: ${location}`,
|
|
73
|
-
});
|
|
78
|
+
pluginLog(ctx, 'info', `Loaded config from: ${location}`);
|
|
74
79
|
}
|
|
75
80
|
return config;
|
|
76
81
|
}
|
|
77
82
|
catch (error) {
|
|
78
83
|
// Log error but continue searching
|
|
79
84
|
if (ctx) {
|
|
80
|
-
ctx
|
|
81
|
-
service: 'maskweaver',
|
|
82
|
-
level: 'warn',
|
|
83
|
-
message: `Failed to load config from ${location}: ${error}`,
|
|
84
|
-
});
|
|
85
|
+
pluginLog(ctx, 'warn', `Failed to load config from ${location}: ${error}`);
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
}
|
|
89
90
|
// No configuration found - return empty config
|
|
90
91
|
if (ctx?.verbose) {
|
|
91
|
-
ctx.
|
|
92
|
-
service: 'maskweaver',
|
|
93
|
-
level: 'info',
|
|
94
|
-
message: 'No maskweaver.json found, using defaults',
|
|
95
|
-
});
|
|
92
|
+
pluginLog(ctx, 'info', 'No maskweaver.json found, using defaults');
|
|
96
93
|
}
|
|
97
94
|
return {};
|
|
98
95
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugin/config/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,KAAK,IAAI,UAAU,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugin/config/index.ts"],"names":[],"mappings":"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"}
|
package/dist/plugin/index.d.ts
CHANGED
|
@@ -11,33 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Based on oh-my-opencode plugin development patterns.
|
|
13
13
|
*/
|
|
14
|
-
|
|
15
|
-
client: {
|
|
16
|
-
app: {
|
|
17
|
-
log(entry: {
|
|
18
|
-
service: string;
|
|
19
|
-
level: 'debug' | 'info' | 'warn' | 'error';
|
|
20
|
-
message: string;
|
|
21
|
-
}): void;
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
directory: string;
|
|
25
|
-
}
|
|
26
|
-
interface PluginEvent {
|
|
27
|
-
type: string;
|
|
28
|
-
[key: string]: unknown;
|
|
29
|
-
}
|
|
30
|
-
type Plugin = (context: PluginContext) => Promise<{
|
|
31
|
-
agent?: Record<string, unknown>;
|
|
32
|
-
'experimental.chat.system.transform'?: (input: unknown, output: {
|
|
33
|
-
system?: string[];
|
|
34
|
-
}) => Promise<void>;
|
|
35
|
-
tool?: Record<string, unknown>;
|
|
36
|
-
event?: (context: {
|
|
37
|
-
event: PluginEvent;
|
|
38
|
-
}) => Promise<void>;
|
|
39
|
-
config?: (config: unknown) => Promise<void>;
|
|
40
|
-
}>;
|
|
14
|
+
import { type Plugin } from '@opencode-ai/plugin';
|
|
41
15
|
export declare const MaskweaverPlugin: Plugin;
|
|
42
16
|
export default MaskweaverPlugin;
|
|
43
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;EAYE;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;EAYE;AAGF,OAAO,EAAQ,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AA8wBxD,eAAO,MAAM,gBAAgB,EAAE,MAiV9B,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
package/dist/plugin/index.js
CHANGED
|
@@ -12,17 +12,13 @@
|
|
|
12
12
|
* Based on oh-my-opencode plugin development patterns.
|
|
13
13
|
*/
|
|
14
14
|
import { z } from 'zod';
|
|
15
|
-
// Inline shim: tool() is just an identity function in @opencode-ai/plugin
|
|
16
|
-
// We inline it to avoid bundler resolution bugs with the upstream package
|
|
17
|
-
const tool = (input) => input;
|
|
18
15
|
import * as fs from 'node:fs';
|
|
19
16
|
import * as path from 'node:path';
|
|
20
17
|
import * as os from 'node:os';
|
|
21
18
|
import { spawnSync } from 'node:child_process';
|
|
22
19
|
import { fileURLToPath } from 'node:url';
|
|
23
|
-
import { parse as parseYaml } from 'yaml';
|
|
24
20
|
import { VERSION } from '../version.js';
|
|
25
|
-
import { loadPluginConfig, isMaskEnabled, isToolEnabled, getDefaultMask, isAutoActivateEnabled,
|
|
21
|
+
import { loadPluginConfig, isMaskEnabled, isToolEnabled, getDefaultMask, isAutoActivateEnabled, isVerboseLoggingEnabled, isCompletionSoundEnabled, validateConfig, } from './config/index.js';
|
|
26
22
|
// New tool imports
|
|
27
23
|
import { createMemorySearchTool } from './tools/memorySearch.js';
|
|
28
24
|
import { createMemoryWriteTool } from './tools/memoryWrite.js';
|
|
@@ -425,8 +421,17 @@ function buildRichPrompt(mask) {
|
|
|
425
421
|
}
|
|
426
422
|
return parts.join('\n');
|
|
427
423
|
}
|
|
424
|
+
function pluginLog(client, level, message) {
|
|
425
|
+
client.app.log({
|
|
426
|
+
body: {
|
|
427
|
+
service: 'maskweaver',
|
|
428
|
+
level,
|
|
429
|
+
message,
|
|
430
|
+
},
|
|
431
|
+
});
|
|
432
|
+
}
|
|
428
433
|
// ============================================================================
|
|
429
|
-
//
|
|
434
|
+
// Helper functions for tool factories
|
|
430
435
|
// ============================================================================
|
|
431
436
|
function createListMasksTool(maskLoader, activeMask) {
|
|
432
437
|
return {
|
|
@@ -602,81 +607,8 @@ function playCompletionSound(config) {
|
|
|
602
607
|
}
|
|
603
608
|
}
|
|
604
609
|
let state = null;
|
|
605
|
-
function parseAgentMarkdown(content) {
|
|
606
|
-
const parts = content.split('---');
|
|
607
|
-
if (parts.length < 3) {
|
|
608
|
-
return { prompt: content.trim() };
|
|
609
|
-
}
|
|
610
|
-
try {
|
|
611
|
-
const frontmatter = parseYaml(parts[1]);
|
|
612
|
-
const prompt = parts.slice(2).join('---').trim();
|
|
613
|
-
return { ...frontmatter, prompt };
|
|
614
|
-
}
|
|
615
|
-
catch (e) {
|
|
616
|
-
return { prompt: content.trim() };
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
610
|
// ============================================================================
|
|
620
|
-
|
|
621
|
-
// ============================================================================
|
|
622
|
-
const DEFAULT_AGENTS = {
|
|
623
|
-
'dummy-human': {
|
|
624
|
-
description: 'Dummy-Human - Pure execution agent that performs tasks with masks assigned by Mask Weaver',
|
|
625
|
-
mode: 'subagent',
|
|
626
|
-
temperature: 0.2,
|
|
627
|
-
permission: {
|
|
628
|
-
edit: 'allow',
|
|
629
|
-
bash: 'allow',
|
|
630
|
-
webfetch: 'allow',
|
|
631
|
-
},
|
|
632
|
-
prompt: `# Dummy-Human
|
|
633
|
-
|
|
634
|
-
You are a **Dummy-Human**.
|
|
635
|
-
|
|
636
|
-
## Identity
|
|
637
|
-
|
|
638
|
-
You are a pure execution agent. You accurately perform work instructions received from the Mask Weaver.
|
|
639
|
-
|
|
640
|
-
## Behavior Principles
|
|
641
|
-
|
|
642
|
-
1. If the Mask Weaver provides a **mask (persona)**, become that expert and work accordingly
|
|
643
|
-
2. If no mask is provided, work as a competent software engineer
|
|
644
|
-
3. Complete assigned tasks accurately
|
|
645
|
-
4. Report results clearly
|
|
646
|
-
|
|
647
|
-
## Result Reporting
|
|
648
|
-
|
|
649
|
-
When work is complete:
|
|
650
|
-
- Summary of work performed
|
|
651
|
-
- Generated outputs
|
|
652
|
-
- Additional considerations (if any)`,
|
|
653
|
-
},
|
|
654
|
-
};
|
|
655
|
-
function loadAgentAssets(...assetsDirs) {
|
|
656
|
-
// Start with default embedded agents (always available)
|
|
657
|
-
const agents = { ...DEFAULT_AGENTS };
|
|
658
|
-
// Load from each directory in order (later directories override earlier ones)
|
|
659
|
-
for (const assetsDir of assetsDirs) {
|
|
660
|
-
const agentsDir = path.join(assetsDir, 'agents');
|
|
661
|
-
if (!fs.existsSync(agentsDir))
|
|
662
|
-
continue;
|
|
663
|
-
try {
|
|
664
|
-
const files = fs.readdirSync(agentsDir);
|
|
665
|
-
for (const file of files) {
|
|
666
|
-
if (file.endsWith('.md') && file !== 'dummy-template.md') {
|
|
667
|
-
const agentId = path.basename(file, '.md');
|
|
668
|
-
const content = fs.readFileSync(path.join(agentsDir, file), 'utf-8');
|
|
669
|
-
agents[agentId] = parseAgentMarkdown(content);
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
catch (e) {
|
|
674
|
-
// Ignore errors - default agents still available
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
return agents;
|
|
678
|
-
}
|
|
679
|
-
export const MaskweaverPlugin = async ({ client, directory }) => {
|
|
611
|
+
export const MaskweaverPlugin = async ({ client, directory, project, worktree, $, serverUrl }) => {
|
|
680
612
|
// ==========================================================================
|
|
681
613
|
// 1. Load Configuration (oh-my-opencode pattern)
|
|
682
614
|
// ==========================================================================
|
|
@@ -684,11 +616,7 @@ export const MaskweaverPlugin = async ({ client, directory }) => {
|
|
|
684
616
|
// Validate configuration
|
|
685
617
|
const configErrors = validateConfig(pluginConfig);
|
|
686
618
|
if (configErrors.length > 0) {
|
|
687
|
-
client.
|
|
688
|
-
service: 'maskweaver',
|
|
689
|
-
level: 'warn',
|
|
690
|
-
message: `Configuration validation errors: ${configErrors.join(', ')}`,
|
|
691
|
-
});
|
|
619
|
+
pluginLog(client, 'warn', `Configuration validation errors: ${configErrors.join(', ')}`);
|
|
692
620
|
}
|
|
693
621
|
const verbose = isVerboseLoggingEnabled(pluginConfig);
|
|
694
622
|
// ==========================================================================
|
|
@@ -698,24 +626,12 @@ export const MaskweaverPlugin = async ({ client, directory }) => {
|
|
|
698
626
|
// Track if this is a first-time installation
|
|
699
627
|
const isFirstInstall = installResult.installed.length > 0;
|
|
700
628
|
if (isFirstInstall) {
|
|
701
|
-
client.
|
|
702
|
-
service: 'maskweaver',
|
|
703
|
-
level: 'info',
|
|
704
|
-
message: `Installed ${installResult.installed.length} files to .opencode/ (agents, masks)`,
|
|
705
|
-
});
|
|
629
|
+
pluginLog(client, 'info', `Installed ${installResult.installed.length} files to .opencode/ (agents, masks)`);
|
|
706
630
|
// Show prominent restart message for first-time installation
|
|
707
|
-
client
|
|
708
|
-
service: 'maskweaver',
|
|
709
|
-
level: 'warn',
|
|
710
|
-
message: `⚠️ RESTART REQUIRED: Please restart OpenCode to activate all Maskweaver features (agents, masks, commands).`,
|
|
711
|
-
});
|
|
631
|
+
pluginLog(client, 'warn', `⚠️ RESTART REQUIRED: Please restart OpenCode to activate all Maskweaver features (agents, masks, commands).`);
|
|
712
632
|
}
|
|
713
633
|
if (installResult.errors.length > 0) {
|
|
714
|
-
client.
|
|
715
|
-
service: 'maskweaver',
|
|
716
|
-
level: 'warn',
|
|
717
|
-
message: `Asset errors: ${installResult.errors.join(', ')}`,
|
|
718
|
-
});
|
|
634
|
+
pluginLog(client, 'warn', `Asset errors: ${installResult.errors.join(', ')}`);
|
|
719
635
|
}
|
|
720
636
|
// ==========================================================================
|
|
721
637
|
// 3. Initialize masks
|
|
@@ -734,29 +650,17 @@ export const MaskweaverPlugin = async ({ client, directory }) => {
|
|
|
734
650
|
};
|
|
735
651
|
state = pluginState;
|
|
736
652
|
// Log plugin loaded
|
|
737
|
-
client
|
|
738
|
-
service: 'maskweaver',
|
|
739
|
-
level: 'info',
|
|
740
|
-
message: `Maskweaver plugin loaded v${VERSION}`,
|
|
741
|
-
});
|
|
653
|
+
pluginLog(client, 'info', `Maskweaver plugin loaded v${VERSION}`);
|
|
742
654
|
if (fs.existsSync(masksDir)) {
|
|
743
655
|
pluginState.maskLoader = new MaskLoader(masksDir, pluginConfig);
|
|
744
656
|
try {
|
|
745
657
|
await pluginState.maskLoader.loadCatalog();
|
|
746
658
|
if (verbose) {
|
|
747
|
-
client
|
|
748
|
-
service: 'maskweaver',
|
|
749
|
-
level: 'info',
|
|
750
|
-
message: `Masks found at: ${masksDir}`,
|
|
751
|
-
});
|
|
659
|
+
pluginLog(client, 'info', `Masks found at: ${masksDir}`);
|
|
752
660
|
}
|
|
753
661
|
}
|
|
754
662
|
catch (e) {
|
|
755
|
-
client
|
|
756
|
-
service: 'maskweaver',
|
|
757
|
-
level: 'warn',
|
|
758
|
-
message: `Failed to load masks: ${e}`,
|
|
759
|
-
});
|
|
663
|
+
pluginLog(client, 'warn', `Failed to load masks: ${e}`);
|
|
760
664
|
pluginState.maskLoader = null;
|
|
761
665
|
}
|
|
762
666
|
}
|
|
@@ -770,26 +674,14 @@ export const MaskweaverPlugin = async ({ client, directory }) => {
|
|
|
770
674
|
const defaultMask = await pluginState.maskLoader.load(defaultMaskId);
|
|
771
675
|
if (defaultMask) {
|
|
772
676
|
pluginState.activeMask = defaultMask;
|
|
773
|
-
client.
|
|
774
|
-
service: 'maskweaver',
|
|
775
|
-
level: 'info',
|
|
776
|
-
message: `Auto-activated default mask: ${defaultMaskId} (${defaultMask.profile.name})`,
|
|
777
|
-
});
|
|
677
|
+
pluginLog(client, 'info', `Auto-activated default mask: ${defaultMaskId} (${defaultMask.profile.name})`);
|
|
778
678
|
}
|
|
779
679
|
else {
|
|
780
|
-
client
|
|
781
|
-
service: 'maskweaver',
|
|
782
|
-
level: 'warn',
|
|
783
|
-
message: `Default mask "${defaultMaskId}" not found or disabled`,
|
|
784
|
-
});
|
|
680
|
+
pluginLog(client, 'warn', `Default mask "${defaultMaskId}" not found or disabled`);
|
|
785
681
|
}
|
|
786
682
|
}
|
|
787
683
|
catch (e) {
|
|
788
|
-
client
|
|
789
|
-
service: 'maskweaver',
|
|
790
|
-
level: 'warn',
|
|
791
|
-
message: `Failed to auto-activate default mask: ${e}`,
|
|
792
|
-
});
|
|
684
|
+
pluginLog(client, 'warn', `Failed to auto-activate default mask: ${e}`);
|
|
793
685
|
}
|
|
794
686
|
}
|
|
795
687
|
// ==========================================================================
|
|
@@ -805,14 +697,15 @@ export const MaskweaverPlugin = async ({ client, directory }) => {
|
|
|
805
697
|
const isToolActive = (toolName) => isToolEnabled(pluginConfig, toolName);
|
|
806
698
|
// Helper to ensure tool arguments are compatible with opencode's expected format.
|
|
807
699
|
// opencode expects a ZodRawShape (raw object), NOT a ZodObject instance.
|
|
700
|
+
// Zod 4: schema.def.shape, Zod 3: schema._def.shape()
|
|
808
701
|
const wrapSchema = (schema) => {
|
|
809
702
|
if (!schema || typeof schema !== 'object')
|
|
810
703
|
return schema;
|
|
811
|
-
//
|
|
812
|
-
if (schema.def && typeof schema.def === 'object' && schema.type === 'object') {
|
|
704
|
+
// Zod 4 — def.shape is a plain object
|
|
705
|
+
if (schema.def && typeof schema.def === 'object' && schema.type === 'object' && schema.def.shape && typeof schema.def.shape === 'object') {
|
|
813
706
|
return schema.def.shape;
|
|
814
707
|
}
|
|
815
|
-
//
|
|
708
|
+
// Zod 3 — _def.shape() returns a plain object
|
|
816
709
|
if (schema._def && typeof schema._def.shape === 'function') {
|
|
817
710
|
return schema._def.shape();
|
|
818
711
|
}
|
|
@@ -934,104 +827,20 @@ export const MaskweaverPlugin = async ({ client, directory }) => {
|
|
|
934
827
|
};
|
|
935
828
|
}
|
|
936
829
|
// ==========================================================================
|
|
937
|
-
// 8.
|
|
938
|
-
//
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
//
|
|
942
|
-
const loadedAgents = loadAgentAssets(assetsDir, projectOpencodeDir);
|
|
943
|
-
// ==========================================================================
|
|
944
|
-
// 8b. Generate agents from model pool (or legacy fallback)
|
|
830
|
+
// 8. Agents are loaded from .opencode/agents/*.md files by OpenCode's
|
|
831
|
+
// filesystem-based agent loader (see config/agent.ts:110-140).
|
|
832
|
+
// installAssets() in step 2 copies agent .md files so they are picked up.
|
|
833
|
+
// The 'agent' property in Hooks is NOT consumed by OpenCode — confirmed
|
|
834
|
+
// by source analysis (packages/opencode/src/plugin/index.ts:92-103).
|
|
945
835
|
// ==========================================================================
|
|
946
|
-
{
|
|
947
|
-
const { loadRuntimeConfig, normalizeDummyHumansConfig } = await import('../shared/config.js');
|
|
948
|
-
const { createModelRegistry } = await import('../shared/model-registry.js');
|
|
949
|
-
const runtimeConfig = loadRuntimeConfig(directory);
|
|
950
|
-
if (runtimeConfig.dummyHumans) {
|
|
951
|
-
const pool = normalizeDummyHumansConfig(runtimeConfig.dummyHumans);
|
|
952
|
-
// Initialize the global model registry
|
|
953
|
-
createModelRegistry(pool);
|
|
954
|
-
if (loadedAgents['dummy-human']) {
|
|
955
|
-
// Generate agent variants from pool entries
|
|
956
|
-
for (const entry of pool) {
|
|
957
|
-
const agentName = `dummy-${entry.id}`;
|
|
958
|
-
if (!loadedAgents[agentName]) {
|
|
959
|
-
const tierLabel = entry.tier === 'flash' ? 'Flash' : entry.tier === 'premium' ? 'Premium' : 'Standard';
|
|
960
|
-
const capStr = entry.capabilities.slice(0, 3).join(', ');
|
|
961
|
-
loadedAgents[agentName] = {
|
|
962
|
-
...loadedAgents['dummy-human'],
|
|
963
|
-
description: `Dummy-Human (${entry.id}) - ${tierLabel}. ${entry.description || capStr}. [max ${entry.maxConcurrent} concurrent]`,
|
|
964
|
-
model: entry.model,
|
|
965
|
-
};
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
// Also ensure legacy dummy-flash / dummy-premium aliases exist (for backward compat)
|
|
969
|
-
const flashEntry = pool.find(e => e.tier === 'flash');
|
|
970
|
-
const humanEntry = pool.find(e => e.tier === 'human');
|
|
971
|
-
const premiumEntry = pool.find(e => e.tier === 'premium');
|
|
972
|
-
if (flashEntry && !loadedAgents['dummy-flash']) {
|
|
973
|
-
loadedAgents['dummy-flash'] = loadedAgents[`dummy-${flashEntry.id}`];
|
|
974
|
-
}
|
|
975
|
-
if (humanEntry) {
|
|
976
|
-
// dummy-human already exists as the base agent; just update its model from pool
|
|
977
|
-
loadedAgents['dummy-human'].model = humanEntry.model;
|
|
978
|
-
}
|
|
979
|
-
if (premiumEntry && !loadedAgents['dummy-premium']) {
|
|
980
|
-
loadedAgents['dummy-premium'] = loadedAgents[`dummy-${premiumEntry.id}`];
|
|
981
|
-
}
|
|
982
|
-
// Fallback: if no tier mapping found, use defaults
|
|
983
|
-
if (!loadedAgents['dummy-flash']) {
|
|
984
|
-
loadedAgents['dummy-flash'] = {
|
|
985
|
-
...loadedAgents['dummy-human'],
|
|
986
|
-
description: 'Dummy-Human (Flash) - Fast and cheap',
|
|
987
|
-
model: 'google/gemini-2.0-flash',
|
|
988
|
-
};
|
|
989
|
-
}
|
|
990
|
-
if (!loadedAgents['dummy-premium']) {
|
|
991
|
-
loadedAgents['dummy-premium'] = {
|
|
992
|
-
...loadedAgents['dummy-human'],
|
|
993
|
-
description: 'Dummy-Human (Premium) - Powerful and reasoning',
|
|
994
|
-
model: 'google/gemini-2.0-pro-exp-02-05',
|
|
995
|
-
};
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
else {
|
|
1000
|
-
// No pool config → legacy hardcoded defaults
|
|
1001
|
-
if (loadedAgents['dummy-human']) {
|
|
1002
|
-
if (!loadedAgents['dummy-flash']) {
|
|
1003
|
-
loadedAgents['dummy-flash'] = {
|
|
1004
|
-
...loadedAgents['dummy-human'],
|
|
1005
|
-
description: 'Dummy-Human (Flash) - Fast and cheap',
|
|
1006
|
-
model: 'google/gemini-2.0-flash',
|
|
1007
|
-
};
|
|
1008
|
-
}
|
|
1009
|
-
if (!loadedAgents['dummy-premium']) {
|
|
1010
|
-
loadedAgents['dummy-premium'] = {
|
|
1011
|
-
...loadedAgents['dummy-human'],
|
|
1012
|
-
description: 'Dummy-Human (Premium) - Powerful and reasoning',
|
|
1013
|
-
model: 'google/gemini-2.0-pro-exp-02-05',
|
|
1014
|
-
};
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
// Apply config overrides to agents
|
|
1020
|
-
for (const agentId of Object.keys(loadedAgents)) {
|
|
1021
|
-
const override = getAgentOverride(pluginConfig, agentId);
|
|
1022
|
-
if (override) {
|
|
1023
|
-
if (override.model)
|
|
1024
|
-
loadedAgents[agentId].model = override.model;
|
|
1025
|
-
if (override.systemPrompt)
|
|
1026
|
-
loadedAgents[agentId].prompt = override.systemPrompt;
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
836
|
// ==========================================================================
|
|
1030
|
-
// 9. Return plugin hooks
|
|
837
|
+
// 9. Return plugin hooks (official OpenCode Hooks interface only)
|
|
838
|
+
// Note: Agents are registered via .opencode/agents/*.md files (installed by
|
|
839
|
+
// installAssets()), NOT via the plugin return. The Hooks type does not
|
|
840
|
+
// include 'agent' — OpenCode loads agents from the filesystem exclusively.
|
|
1031
841
|
// ==========================================================================
|
|
1032
842
|
return {
|
|
1033
|
-
// Agent registration
|
|
1034
|
-
agent: loadedAgents,
|
|
843
|
+
// Agent registration handled via .opencode/agents/*.md files (see installAssets)
|
|
1035
844
|
// System prompt transform - inject active mask
|
|
1036
845
|
'experimental.chat.system.transform': async (_input, output) => {
|
|
1037
846
|
if (state?.activeMask) {
|
|
@@ -1054,11 +863,7 @@ ${buildRichPrompt(state.activeMask)}
|
|
|
1054
863
|
try {
|
|
1055
864
|
const masks = await pluginState.maskLoader.listAll();
|
|
1056
865
|
const categories = await pluginState.maskLoader.listCategories();
|
|
1057
|
-
client.
|
|
1058
|
-
service: 'maskweaver',
|
|
1059
|
-
level: 'info',
|
|
1060
|
-
message: `Session started - ${masks.length} masks available across ${categories.length} categories`,
|
|
1061
|
-
});
|
|
866
|
+
pluginLog(client, 'info', `Session started - ${masks.length} masks available across ${categories.length} categories`);
|
|
1062
867
|
}
|
|
1063
868
|
catch (_e) {
|
|
1064
869
|
// Ignore errors
|
|
@@ -1085,19 +890,14 @@ ${buildRichPrompt(state.activeMask)}
|
|
|
1085
890
|
const wasActive = pluginState.activeMask !== null;
|
|
1086
891
|
pluginState.activeMask = null;
|
|
1087
892
|
if (wasActive) {
|
|
1088
|
-
client
|
|
1089
|
-
service: 'maskweaver',
|
|
1090
|
-
level: 'info',
|
|
1091
|
-
message: 'Session ended - active mask cleared',
|
|
1092
|
-
});
|
|
893
|
+
pluginLog(client, 'info', 'Session ended - active mask cleared');
|
|
1093
894
|
}
|
|
1094
895
|
}
|
|
1095
896
|
}
|
|
1096
897
|
},
|
|
1097
|
-
// Config hook -
|
|
898
|
+
// Config hook - allows plugins to modify opencode configuration
|
|
1098
899
|
config: async (config) => {
|
|
1099
|
-
//
|
|
1100
|
-
// Agent overrides are currently not supported via this hook in opencode core.
|
|
900
|
+
// Reserved for future configuration injection (model, provider, etc.)
|
|
1101
901
|
return;
|
|
1102
902
|
},
|
|
1103
903
|
};
|