opencode-multiagent 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/AGENTS.md +83 -0
  2. package/CHANGELOG.md +31 -0
  3. package/CONTRIBUTING.md +36 -0
  4. package/README.md +44 -168
  5. package/README.tr.md +84 -0
  6. package/RELEASE.md +68 -0
  7. package/agents/AGENTS.md +91 -0
  8. package/agents/auditor.md +67 -23
  9. package/agents/{worker.md → coder.md} +24 -17
  10. package/agents/docmaster.md +91 -0
  11. package/agents/executor.md +63 -79
  12. package/agents/planner.md +78 -58
  13. package/agents/reviewer.md +31 -15
  14. package/agents/scout.md +25 -17
  15. package/agents/sec-coder.md +83 -0
  16. package/agents/ui-coder.md +77 -0
  17. package/commands/board.md +17 -0
  18. package/commands/execute.md +9 -7
  19. package/commands/init-deep.md +7 -6
  20. package/commands/init.md +5 -5
  21. package/commands/inspect.md +6 -5
  22. package/commands/plan.md +8 -6
  23. package/commands/quality.md +4 -3
  24. package/commands/review.md +5 -3
  25. package/commands/status.md +5 -3
  26. package/defaults/AGENTS.md +48 -0
  27. package/defaults/opencode-multiagent.json +180 -0
  28. package/defaults/opencode-multiagent.schema.json +265 -0
  29. package/dist/control-plane.d.ts +4 -0
  30. package/dist/control-plane.d.ts.map +1 -0
  31. package/dist/index.d.ts +5 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +1916 -0
  34. package/dist/opencode-multiagent/compiler.d.ts +25 -0
  35. package/dist/opencode-multiagent/compiler.d.ts.map +1 -0
  36. package/dist/opencode-multiagent/constants.d.ts +128 -0
  37. package/dist/opencode-multiagent/constants.d.ts.map +1 -0
  38. package/dist/opencode-multiagent/correlation.d.ts +21 -0
  39. package/dist/opencode-multiagent/correlation.d.ts.map +1 -0
  40. package/dist/opencode-multiagent/defaults.d.ts +10 -0
  41. package/dist/opencode-multiagent/defaults.d.ts.map +1 -0
  42. package/dist/opencode-multiagent/hooks.d.ts +62 -0
  43. package/dist/opencode-multiagent/hooks.d.ts.map +1 -0
  44. package/dist/opencode-multiagent/log.d.ts +2 -0
  45. package/dist/opencode-multiagent/log.d.ts.map +1 -0
  46. package/dist/opencode-multiagent/markdown.d.ts +8 -0
  47. package/dist/opencode-multiagent/markdown.d.ts.map +1 -0
  48. package/dist/opencode-multiagent/mcp.d.ts +3 -0
  49. package/dist/opencode-multiagent/mcp.d.ts.map +1 -0
  50. package/dist/opencode-multiagent/policy.d.ts +5 -0
  51. package/dist/opencode-multiagent/policy.d.ts.map +1 -0
  52. package/dist/opencode-multiagent/quality.d.ts +18 -0
  53. package/dist/opencode-multiagent/quality.d.ts.map +1 -0
  54. package/dist/opencode-multiagent/runtime.d.ts +7 -0
  55. package/dist/opencode-multiagent/runtime.d.ts.map +1 -0
  56. package/dist/opencode-multiagent/session-tracker.d.ts +32 -0
  57. package/dist/opencode-multiagent/session-tracker.d.ts.map +1 -0
  58. package/dist/opencode-multiagent/skills.d.ts +17 -0
  59. package/dist/opencode-multiagent/skills.d.ts.map +1 -0
  60. package/dist/opencode-multiagent/supervision.d.ts +26 -0
  61. package/dist/opencode-multiagent/supervision.d.ts.map +1 -0
  62. package/dist/opencode-multiagent/task-manager.d.ts +54 -0
  63. package/dist/opencode-multiagent/task-manager.d.ts.map +1 -0
  64. package/dist/opencode-multiagent/telemetry.d.ts +28 -0
  65. package/dist/opencode-multiagent/telemetry.d.ts.map +1 -0
  66. package/dist/opencode-multiagent/tools.d.ts +87 -0
  67. package/dist/opencode-multiagent/tools.d.ts.map +1 -0
  68. package/dist/opencode-multiagent/types.d.ts +36 -0
  69. package/dist/opencode-multiagent/types.d.ts.map +1 -0
  70. package/dist/opencode-multiagent/utils.d.ts +9 -0
  71. package/dist/opencode-multiagent/utils.d.ts.map +1 -0
  72. package/docs/agents.md +148 -0
  73. package/docs/agents.tr.md +149 -0
  74. package/docs/configuration.md +244 -0
  75. package/docs/configuration.tr.md +244 -0
  76. package/docs/usage-guide.md +224 -0
  77. package/docs/usage-guide.tr.md +225 -0
  78. package/examples/opencode.with-overrides.json +3 -7
  79. package/package.json +23 -13
  80. package/skills/AGENTS.md +51 -0
  81. package/skills/advanced-evaluation/SKILL.md +37 -21
  82. package/skills/advanced-evaluation/manifest.json +2 -13
  83. package/skills/cek-context-engineering/SKILL.md +159 -87
  84. package/skills/cek-context-engineering/manifest.json +1 -3
  85. package/skills/cek-prompt-engineering/SKILL.md +13 -10
  86. package/skills/cek-prompt-engineering/manifest.json +1 -3
  87. package/skills/cek-test-prompt/SKILL.md +38 -28
  88. package/skills/cek-test-prompt/manifest.json +1 -3
  89. package/skills/cek-thought-based-reasoning/SKILL.md +75 -21
  90. package/skills/cek-thought-based-reasoning/manifest.json +1 -3
  91. package/skills/context-degradation/SKILL.md +14 -13
  92. package/skills/context-degradation/manifest.json +1 -3
  93. package/skills/debate/SKILL.md +23 -78
  94. package/skills/debate/manifest.json +2 -12
  95. package/skills/design-first/manifest.json +2 -13
  96. package/skills/dispatching-parallel-agents/SKILL.md +14 -3
  97. package/skills/dispatching-parallel-agents/manifest.json +1 -4
  98. package/skills/drift-analysis/SKILL.md +50 -29
  99. package/skills/drift-analysis/manifest.json +2 -12
  100. package/skills/evaluation/manifest.json +2 -12
  101. package/skills/executing-plans/SKILL.md +15 -8
  102. package/skills/executing-plans/manifest.json +1 -3
  103. package/skills/handoff-protocols/manifest.json +2 -12
  104. package/skills/parallel-investigation/SKILL.md +25 -12
  105. package/skills/parallel-investigation/manifest.json +1 -4
  106. package/skills/reflexion-critique/SKILL.md +21 -10
  107. package/skills/reflexion-critique/manifest.json +1 -3
  108. package/skills/reflexion-reflect/SKILL.md +36 -34
  109. package/skills/reflexion-reflect/manifest.json +2 -10
  110. package/skills/root-cause-analysis/manifest.json +2 -13
  111. package/skills/sadd-judge-with-debate/SKILL.md +50 -26
  112. package/skills/sadd-judge-with-debate/manifest.json +1 -3
  113. package/skills/structured-code-review/manifest.json +2 -11
  114. package/skills/task-decomposition/manifest.json +2 -13
  115. package/skills/verification-before-completion/manifest.json +2 -15
  116. package/skills/verification-gates/SKILL.md +27 -19
  117. package/skills/verification-gates/manifest.json +2 -12
  118. package/agents/advisor.md +0 -57
  119. package/agents/critic.md +0 -127
  120. package/agents/deep-worker.md +0 -65
  121. package/agents/devil.md +0 -36
  122. package/agents/heavy-worker.md +0 -68
  123. package/agents/lead.md +0 -155
  124. package/agents/librarian.md +0 -62
  125. package/agents/qa.md +0 -50
  126. package/agents/quick.md +0 -65
  127. package/agents/scribe.md +0 -78
  128. package/agents/strategist.md +0 -63
  129. package/agents/ui-heavy-worker.md +0 -62
  130. package/agents/ui-worker.md +0 -69
  131. package/agents/validator.md +0 -47
  132. package/defaults/agent-settings.json +0 -102
  133. package/defaults/agent-settings.schema.json +0 -25
  134. package/defaults/flags.json +0 -35
  135. package/defaults/flags.schema.json +0 -119
  136. package/defaults/mcp-defaults.json +0 -47
  137. package/defaults/mcp-defaults.schema.json +0 -38
  138. package/defaults/profiles.json +0 -53
  139. package/defaults/profiles.schema.json +0 -60
  140. package/defaults/team-profiles.json +0 -83
  141. package/src/control-plane.ts +0 -21
  142. package/src/index.ts +0 -8
  143. package/src/opencode-multiagent/compiler.ts +0 -168
  144. package/src/opencode-multiagent/constants.ts +0 -178
  145. package/src/opencode-multiagent/file-lock.ts +0 -90
  146. package/src/opencode-multiagent/hooks.ts +0 -599
  147. package/src/opencode-multiagent/log.ts +0 -12
  148. package/src/opencode-multiagent/mailbox.ts +0 -287
  149. package/src/opencode-multiagent/markdown.ts +0 -99
  150. package/src/opencode-multiagent/mcp.ts +0 -35
  151. package/src/opencode-multiagent/policy.ts +0 -67
  152. package/src/opencode-multiagent/quality.ts +0 -140
  153. package/src/opencode-multiagent/runtime.ts +0 -55
  154. package/src/opencode-multiagent/skills.ts +0 -144
  155. package/src/opencode-multiagent/supervision.ts +0 -156
  156. package/src/opencode-multiagent/task-manager.ts +0 -148
  157. package/src/opencode-multiagent/team-manager.ts +0 -219
  158. package/src/opencode-multiagent/team-tools.ts +0 -359
  159. package/src/opencode-multiagent/telemetry.ts +0 -124
  160. package/src/opencode-multiagent/utils.ts +0 -54
@@ -1,53 +0,0 @@
1
- {
2
- "minimal": {
3
- "enforcement": true,
4
- "observation": false,
5
- "prompt_controls": false,
6
- "agent_compilation": true,
7
- "command_compilation": true,
8
- "mcp_compilation": true,
9
- "telemetry": false,
10
- "supervision": false,
11
- "quality_gate": false,
12
- "experimental": {
13
- "chat_system_transform": false,
14
- "chat_messages_transform": false,
15
- "session_compacting": false,
16
- "text_complete": false
17
- }
18
- },
19
- "standard": {
20
- "enforcement": true,
21
- "observation": true,
22
- "prompt_controls": true,
23
- "agent_compilation": true,
24
- "command_compilation": true,
25
- "mcp_compilation": true,
26
- "telemetry": true,
27
- "supervision": true,
28
- "quality_gate": true,
29
- "experimental": {
30
- "chat_system_transform": false,
31
- "chat_messages_transform": false,
32
- "session_compacting": false,
33
- "text_complete": false
34
- }
35
- },
36
- "strict": {
37
- "enforcement": true,
38
- "observation": true,
39
- "prompt_controls": true,
40
- "agent_compilation": true,
41
- "command_compilation": true,
42
- "mcp_compilation": true,
43
- "telemetry": true,
44
- "supervision": true,
45
- "quality_gate": true,
46
- "experimental": {
47
- "chat_system_transform": true,
48
- "chat_messages_transform": true,
49
- "session_compacting": true,
50
- "text_complete": true
51
- }
52
- }
53
- }
@@ -1,60 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "title": "opencode-multiagent profiles",
4
- "description": "Named flag bundles for switching plugin behavior by profile.",
5
- "type": "object",
6
- "additionalProperties": {
7
- "type": "object",
8
- "additionalProperties": false,
9
- "properties": {
10
- "enforcement": { "type": "boolean" },
11
- "observation": { "type": "boolean" },
12
- "prompt_controls": { "type": "boolean" },
13
- "agent_compilation": { "type": "boolean" },
14
- "command_compilation": { "type": "boolean" },
15
- "mcp_compilation": { "type": "boolean" },
16
- "telemetry": { "type": "boolean" },
17
- "supervision": { "type": "boolean" },
18
- "quality_gate": { "type": "boolean" },
19
- "skill_injection": { "type": "boolean" },
20
- "skill_sources": {
21
- "type": "array",
22
- "items": { "type": "string", "minLength": 1 },
23
- "minItems": 1
24
- },
25
- "compiler": {
26
- "type": "object",
27
- "additionalProperties": false,
28
- "properties": {
29
- "permission_compilation": { "type": "boolean" }
30
- }
31
- },
32
- "experimental": {
33
- "type": "object",
34
- "additionalProperties": false,
35
- "properties": {
36
- "chat_system_transform": { "type": "boolean" },
37
- "chat_messages_transform": { "type": "boolean" },
38
- "session_compacting": { "type": "boolean" },
39
- "text_complete": { "type": "boolean" }
40
- }
41
- },
42
- "supervision_config": {
43
- "type": "object",
44
- "additionalProperties": false,
45
- "properties": {
46
- "idle_timeout_ms": { "type": "number", "minimum": 0 },
47
- "cooldown_ms": { "type": "number", "minimum": 0 }
48
- }
49
- },
50
- "quality_config": {
51
- "type": "object",
52
- "additionalProperties": false,
53
- "properties": {
54
- "reminder_idle_ms": { "type": "number", "minimum": 0 },
55
- "reminder_cooldown_ms": { "type": "number", "minimum": 0 }
56
- }
57
- }
58
- }
59
- }
60
- }
@@ -1,83 +0,0 @@
1
- {
2
- "standard": {
3
- "description": "Full development team: backend, frontend, and QA. Members are spawned on demand by the lead.",
4
- "members": [
5
- {
6
- "name": "backend-dev",
7
- "agent": "backend-dev",
8
- "role": "Backend developer — API, business logic, database",
9
- "auto_spawn": false
10
- },
11
- {
12
- "name": "frontend-dev",
13
- "agent": "frontend-dev",
14
- "role": "Frontend developer — UI, state management, UX",
15
- "auto_spawn": false
16
- },
17
- {
18
- "name": "tester",
19
- "agent": "tester",
20
- "role": "QA engineer — unit, integration, and E2E tests",
21
- "auto_spawn": false
22
- }
23
- ]
24
- },
25
- "quick": {
26
- "description": "Single general-purpose developer spawned immediately. Good for fast, focused tasks.",
27
- "members": [
28
- {
29
- "name": "dev",
30
- "agent": "general-purpose",
31
- "role": "Developer — awaits task assignment from the lead",
32
- "auto_spawn": true,
33
- "initial_prompt": "You are a general-purpose developer on this team. Wait for the lead to assign a task via the team_read_messages tool, then execute it and report back."
34
- }
35
- ]
36
- },
37
- "review": {
38
- "description": "Code review and security audit team.",
39
- "members": [
40
- {
41
- "name": "reviewer",
42
- "agent": "code-reviewer",
43
- "role": "Code reviewer — PR review, code smells, standards",
44
- "auto_spawn": false
45
- },
46
- {
47
- "name": "security",
48
- "agent": "security-advisor",
49
- "role": "Security advisor — OWASP, vulnerability scanning",
50
- "auto_spawn": false
51
- }
52
- ]
53
- },
54
- "fullstack": {
55
- "description": "Full-stack team including a planner for task breakdown.",
56
- "members": [
57
- {
58
- "name": "planner",
59
- "agent": "planner",
60
- "role": "Task planner — breaks work into steps and assigns to developers",
61
- "auto_spawn": false
62
- },
63
- {
64
- "name": "backend-dev",
65
- "agent": "backend-dev",
66
- "role": "Backend developer",
67
- "auto_spawn": false
68
- },
69
- {
70
- "name": "frontend-dev",
71
- "agent": "frontend-dev",
72
- "role": "Frontend developer",
73
- "auto_spawn": false
74
- },
75
- {
76
- "name": "tester",
77
- "agent": "tester",
78
- "role": "QA engineer",
79
- "auto_spawn": false
80
- }
81
- ]
82
- }
83
- }
@@ -1,21 +0,0 @@
1
- import type { PluginInput } from "@opencode-ai/plugin";
2
-
3
- import { createPluginHooks } from "./opencode-multiagent/hooks.ts";
4
- import { loadRuntimeSettings } from "./opencode-multiagent/runtime.ts";
5
-
6
- export const OpenCodeMultiAgentPlugin = async (context: PluginInput) => {
7
- const client = context.client;
8
- const projectRoot = context.worktree || context.directory;
9
- const { flags, modelTiers, agentSettings } = await loadRuntimeSettings();
10
-
11
- return createPluginHooks({
12
- client,
13
- flags,
14
- modelTiers,
15
- agentSettings,
16
- projectRoot,
17
- });
18
- };
19
-
20
- export const ControlPlanePlugin = OpenCodeMultiAgentPlugin;
21
- export default OpenCodeMultiAgentPlugin;
package/src/index.ts DELETED
@@ -1,8 +0,0 @@
1
- import type { Plugin } from "@opencode-ai/plugin";
2
-
3
- import OpenCodeMultiAgentPlugin from "./control-plane.ts";
4
-
5
- const plugin: Plugin = OpenCodeMultiAgentPlugin;
6
-
7
- export default plugin;
8
- export { plugin as OpenCodeMultiAgentPlugin };
@@ -1,168 +0,0 @@
1
- import { disabledNativeAgents } from "./constants.ts";
2
- import { note } from "./log.ts";
3
- import { loadMarkdownDefs } from "./markdown.ts";
4
- import { resolveTier } from "./runtime.ts";
5
- import { clone, compact, merge, own } from "./utils.ts";
6
-
7
- type GenericRecord = Record<string, unknown>;
8
- type MergedConfig = GenericRecord & {
9
- agent?: Record<string, GenericRecord>;
10
- command?: Record<string, GenericRecord>;
11
- default_agent?: string;
12
- permission?: Record<string, unknown>;
13
- _mcpPermissionRegistry?: Map<string, MpcPermissionRegistry>;
14
- };
15
-
16
- type MpcPermissionRegistry = {
17
- allowed: string[];
18
- denied: string[];
19
- fallback: "allow" | "deny";
20
- };
21
-
22
- export const normalizeDefinitionData = (data: GenericRecord, modelTiers: Record<string, string>): GenericRecord => {
23
- const result = clone(data) ?? {};
24
- delete result.variant;
25
- if (typeof result.model === "string") result.model = resolveTier(result.model, modelTiers);
26
- return result;
27
- };
28
-
29
- const mcpPrefixes = ["exa_", "context7_", "gh_grep_", "github_", "code_index_", "repo_git_"];
30
-
31
- export const isMcpPermissionKey = (key: string): boolean =>
32
- mcpPrefixes.some((prefix) => key === prefix || key.startsWith(prefix));
33
-
34
- export const buildMcpPermissionRegistry = (permission: GenericRecord = {}): MpcPermissionRegistry => {
35
- const allowed: string[] = [];
36
- const denied: string[] = [];
37
- for (const [key, value] of Object.entries(permission)) {
38
- if (!isMcpPermissionKey(key)) continue;
39
- if (value === "allow") allowed.push(key);
40
- if (value === "deny") denied.push(key);
41
- }
42
- return { allowed, denied, fallback: permission["*"] === "allow" ? "allow" : "deny" };
43
- };
44
-
45
- export async function compileAgents(
46
- cfg: MergedConfig,
47
- dirs: Array<string | undefined>,
48
- modelTiers: Record<string, string>,
49
- agentSettings: GenericRecord = {},
50
- ): Promise<Map<string, MpcPermissionRegistry>> {
51
- const defs = await loadMarkdownDefs(dirs);
52
- if (!cfg.agent || typeof cfg.agent !== "object") cfg.agent = {};
53
- const mcpRegistry = new Map<string, MpcPermissionRegistry>();
54
-
55
- for (const [name, raw] of defs.entries()) {
56
- const data = normalizeDefinitionData(raw.data, modelTiers);
57
- if (!own(cfg.agent, name)) {
58
- cfg.agent[name] = {};
59
- } else if (!cfg.agent[name] || typeof cfg.agent[name] !== "object") {
60
- continue;
61
- }
62
-
63
- const target = cfg.agent[name] as GenericRecord;
64
- const explicitFields = new Set(Object.keys(target));
65
- for (const [field, value] of Object.entries(data)) {
66
- if (own(target, field)) continue;
67
- target[field] = clone(value);
68
- }
69
-
70
- const overrides = agentSettings?.[name];
71
- if (overrides && typeof overrides === "object") {
72
- for (const [field, value] of Object.entries(overrides as GenericRecord)) {
73
- if (["model", "temperature", "steps"].includes(field) && !explicitFields.has(field)) {
74
- target[field] = clone(value);
75
- }
76
- }
77
- }
78
-
79
- if (!own(target, "prompt") && typeof raw.body === "string") {
80
- target.prompt = raw.body.trim();
81
- }
82
-
83
- mcpRegistry.set(name, buildMcpPermissionRegistry((target.permission as GenericRecord | undefined) ?? {}));
84
- }
85
-
86
- cfg._mcpPermissionRegistry = mcpRegistry;
87
- return mcpRegistry;
88
- }
89
-
90
- export async function compileCommands(
91
- cfg: MergedConfig,
92
- dirs: Array<string | undefined>,
93
- modelTiers: Record<string, string>,
94
- ): Promise<void> {
95
- const defs = await loadMarkdownDefs(dirs);
96
- if (!cfg.command || typeof cfg.command !== "object") cfg.command = {};
97
-
98
- for (const [name, raw] of defs.entries()) {
99
- const data = normalizeDefinitionData(raw.data, modelTiers);
100
- if (!own(cfg.command, name)) {
101
- cfg.command[name] = {};
102
- } else if (!cfg.command[name] || typeof cfg.command[name] !== "object") {
103
- continue;
104
- }
105
-
106
- const target = cfg.command[name] as GenericRecord;
107
- for (const [field, value] of Object.entries(data)) {
108
- if (own(target, field)) continue;
109
- target[field] = clone(value);
110
- }
111
-
112
- if (!own(target, "template") && typeof raw.body === "string") {
113
- target.template = raw.body.trim();
114
- }
115
- }
116
- }
117
-
118
- export const applyBuiltInAgentPolicy = async (cfg: MergedConfig): Promise<void> => {
119
- if (!cfg.agent || typeof cfg.agent !== "object") cfg.agent = {};
120
- for (const name of disabledNativeAgents) {
121
- cfg.agent[name] = merge(cfg.agent[name], { disable: true });
122
- }
123
-
124
- const current = typeof cfg.default_agent === "string" ? cfg.default_agent : undefined;
125
- const currentAgent = current ? cfg.agent?.[current] : undefined;
126
- const preferred = cfg.agent.lead && cfg.agent.lead.disable !== true ? "lead" : cfg.agent.critic && cfg.agent.critic.disable !== true ? "critic" : undefined;
127
- const invalidCurrent =
128
- !current ||
129
- disabledNativeAgents.includes(current) ||
130
- !currentAgent ||
131
- currentAgent.disable === true ||
132
- currentAgent.hidden === true ||
133
- currentAgent.mode === "subagent" ||
134
- currentAgent.mode === "sub" ||
135
- (preferred === "lead" && current !== "lead");
136
-
137
- if (invalidCurrent && preferred) {
138
- const previous = current;
139
- cfg.default_agent = preferred;
140
- await note(
141
- "config_warning",
142
- compact({
143
- observation: true,
144
- warning: "default_agent_reset",
145
- previous,
146
- next: preferred,
147
- }),
148
- );
149
- }
150
- };
151
-
152
- export const applyPermissionDefaults = (cfg: MergedConfig): void => {
153
- if (!cfg.permission || typeof cfg.permission !== "object") cfg.permission = {};
154
- for (const [key, value] of Object.entries({
155
- bash: "allow",
156
- read: "allow",
157
- edit: "allow",
158
- glob: "allow",
159
- grep: "allow",
160
- list: "allow",
161
- })) {
162
- if (!own(cfg.permission, key)) {
163
- (cfg.permission as GenericRecord)[key] = value;
164
- }
165
- }
166
- };
167
-
168
- export type { MergedConfig, MpcPermissionRegistry };
@@ -1,178 +0,0 @@
1
- import { homedir } from "node:os";
2
- import { dirname, join, resolve } from "node:path";
3
- import { fileURLToPath } from "node:url";
4
-
5
- export const pluginName = "opencode-multiagent";
6
- export const pluginMode = "stable";
7
-
8
- export const opencodeDir = join(homedir(), ".config", "opencode");
9
- export const pluginDir = join(opencodeDir, "plugins");
10
- export const globalAgentsDir = join(opencodeDir, "agents");
11
- export const globalCommandsDir = join(opencodeDir, "commands");
12
- export const logDirPath = join(opencodeDir, "logs");
13
- export const logFilePath = join(logDirPath, `${pluginName}.jsonl`);
14
- export const flagsPath = join(pluginDir, `${pluginName}.flags.json`);
15
- export const agentSettingsPath = join(pluginDir, `${pluginName}.agent-settings.json`);
16
- export const profilesPath = join(pluginDir, `${pluginName}.profiles.json`);
17
-
18
- export const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
19
- export const bundledAgentSettingsPath = join(packageRoot, "defaults", "agent-settings.json");
20
- export const bundledAgentsDir = join(packageRoot, "agents");
21
- export const bundledCommandsDir = join(packageRoot, "commands");
22
- export const bundledSkillsDir = join(packageRoot, "skills");
23
-
24
- export const trackedEventTypes = new Set([
25
- "permission.updated",
26
- "permission.replied",
27
- "session.created",
28
- "session.status",
29
- "session.diff",
30
- "file.edited",
31
- "session.deleted",
32
- "session.idle",
33
- "message.updated",
34
- "message.part.updated",
35
- "message.part.delta",
36
- "command.executed",
37
- ]);
38
-
39
- export const supervisionEventTypes = new Set([
40
- "session.created",
41
- "message.updated",
42
- "message.part.updated",
43
- "message.part.delta",
44
- "session.idle",
45
- "session.deleted",
46
- ]);
47
-
48
- export const qualityEventTypes = new Set(["file.edited", "session.idle", "session.deleted"]);
49
- export const telemetryEventTypes = new Set(["session.created", "message.updated", "session.deleted"]);
50
- export const suspiciousTerms = ["blocked", "failed", "error", "permission", "refused"];
51
- export const qualitySignalRegex =
52
- /\b(test|tests|lint|typecheck|tsc|build|pytest|vitest|jest|cargo test|go test|ruff|mypy|eslint|biome|prettier)\b/i;
53
-
54
- export const mcpToolPrefixes = ["exa_", "context7_", "gh_grep_", "github_", "code_index_", "repo_git_"];
55
-
56
- export const defaultProfiles = {
57
- minimal: {
58
- enforcement: true,
59
- observation: false,
60
- prompt_controls: false,
61
- agent_compilation: true,
62
- command_compilation: true,
63
- mcp_compilation: true,
64
- telemetry: false,
65
- supervision: false,
66
- quality_gate: false,
67
- experimental: {
68
- chat_system_transform: false,
69
- chat_messages_transform: false,
70
- session_compacting: false,
71
- text_complete: false,
72
- },
73
- },
74
- standard: {
75
- enforcement: true,
76
- observation: true,
77
- prompt_controls: true,
78
- agent_compilation: true,
79
- command_compilation: true,
80
- mcp_compilation: true,
81
- telemetry: true,
82
- supervision: true,
83
- quality_gate: true,
84
- skill_sources: [bundledSkillsDir, join(homedir(), ".agents", "skills"), join(homedir(), "skills")],
85
- skill_injection: false,
86
- experimental: {
87
- chat_system_transform: false,
88
- chat_messages_transform: false,
89
- session_compacting: false,
90
- text_complete: false,
91
- },
92
- },
93
- strict: {
94
- enforcement: true,
95
- observation: true,
96
- prompt_controls: true,
97
- agent_compilation: true,
98
- command_compilation: true,
99
- mcp_compilation: true,
100
- telemetry: true,
101
- supervision: true,
102
- quality_gate: true,
103
- experimental: {
104
- chat_system_transform: true,
105
- chat_messages_transform: true,
106
- session_compacting: true,
107
- text_complete: true,
108
- },
109
- },
110
- };
111
-
112
- export const defaultFlags = {
113
- profile: "standard",
114
- enforcement: true,
115
- observation: true,
116
- prompt_controls: true,
117
- agent_compilation: true,
118
- command_compilation: true,
119
- mcp_compilation: true,
120
- telemetry: true,
121
- supervision: true,
122
- quality_gate: true,
123
- skill_sources: [bundledSkillsDir, join(homedir(), ".agents", "skills"), join(homedir(), "skills")],
124
- skill_injection: false,
125
- compiler: {
126
- permission_compilation: true,
127
- },
128
- experimental: {
129
- chat_system_transform: false,
130
- chat_messages_transform: false,
131
- session_compacting: false,
132
- text_complete: false,
133
- },
134
- supervision_config: {
135
- idle_timeout_ms: 180000,
136
- cooldown_ms: 300000,
137
- },
138
- quality_config: {
139
- reminder_idle_ms: 120000,
140
- reminder_cooldown_ms: 300000,
141
- },
142
- };
143
-
144
- export const disabledNativeAgents = ["build", "plan", "general", "explore"];
145
-
146
- export const blockedPathPrefixRegex = /^(\/etc|\/root|\/boot|\/proc|\/sys|\/dev)(?:\/|$)/;
147
- export const blockedPathFragments = ["/.ssh/", "/credentials", "/secrets", "/.aws/", "/.gcloud/", "/.kube/"];
148
- export const blockedPathSuffixes = ["/.ssh", "/credentials"];
149
- export const destructiveBashFragments = [
150
- "git reset --" + "hard",
151
- "git che" + "ckout --",
152
- "r" + "m -rf /",
153
- "r" + "m -rf ~",
154
- "su" + "do ",
155
- "shut" + "down",
156
- "re" + "boot",
157
- "mk" + "fs",
158
- "dd i" + "f=",
159
- "cu" + "rl | ba" + "sh",
160
- "cu" + "rl | sh",
161
- "wg" + "et | ba" + "sh",
162
- "wg" + "et | sh",
163
- "ev" + "al $(",
164
- "> /de" + "v/",
165
- ":" + "(){",
166
- "ch" + "mod 777",
167
- "ki" + "ll -9 -1",
168
- "no" + "hup ",
169
- ];
170
- export const sensitiveMentions = ["/etc", "/root", "/boot", "/proc", "/sys", "/dev", "/.ssh", "~/.ssh"];
171
-
172
- export const noteText =
173
- "[opencode-multiagent note] Sensitive system paths and destructive shell fragments are blocked by local runtime policy.";
174
- export const experimentalText =
175
- "[opencode-multiagent experimental] Experimental control-plane transforms are active for this session.";
176
-
177
- export type DefaultFlags = typeof defaultFlags;
178
- export type DefaultProfiles = typeof defaultProfiles;
@@ -1,90 +0,0 @@
1
- const cleanupIntervalMs = 5 * 60 * 1000;
2
- const staleLockTtlMs = 30 * 60 * 1000;
3
-
4
- type LockInfo = {
5
- sessionID: string;
6
- lastTouchedAt: number;
7
- };
8
-
9
- type AcquireResult =
10
- | { ok: true; filePath: string | undefined }
11
- | { ok: false; filePath: string; ownerSessionID: string };
12
-
13
- const normalizeFilePath = (filePath: unknown): string | undefined =>
14
- typeof filePath === "string" ? filePath.replace(/\\/g, "/") : undefined;
15
-
16
- export const createFileLockController = () => {
17
- const locks = new Map<string, LockInfo>();
18
- const sessionFiles = new Map<string, Set<string>>();
19
-
20
- const trackSessionFile = (sessionID: string, filePath: string): void => {
21
- if (!sessionFiles.has(sessionID)) sessionFiles.set(sessionID, new Set());
22
- sessionFiles.get(sessionID)?.add(filePath);
23
- };
24
-
25
- const untrackSessionFile = (sessionID: string, filePath: string): void => {
26
- const files = sessionFiles.get(sessionID);
27
- if (!files) return;
28
- files.delete(filePath);
29
- if (files.size === 0) sessionFiles.delete(sessionID);
30
- };
31
-
32
- const release = (sessionID: string, filePath: unknown): boolean => {
33
- const normalized = normalizeFilePath(filePath);
34
- if (!normalized) return false;
35
- const existing = locks.get(normalized);
36
- if (!existing || existing.sessionID !== sessionID) return false;
37
- locks.delete(normalized);
38
- untrackSessionFile(sessionID, normalized);
39
- return true;
40
- };
41
-
42
- const releaseAll = (sessionID: string): number => {
43
- const files = sessionFiles.get(sessionID);
44
- if (!files) return 0;
45
- let count = 0;
46
- for (const filePath of files) {
47
- const existing = locks.get(filePath);
48
- if (existing?.sessionID === sessionID) {
49
- locks.delete(filePath);
50
- count += 1;
51
- }
52
- }
53
- sessionFiles.delete(sessionID);
54
- return count;
55
- };
56
-
57
- const cleanupStaleLocks = (now = Date.now()): void => {
58
- for (const [filePath, info] of locks.entries()) {
59
- if (now - info.lastTouchedAt <= staleLockTtlMs) continue;
60
- locks.delete(filePath);
61
- untrackSessionFile(info.sessionID, filePath);
62
- }
63
- };
64
-
65
- const interval = setInterval(() => cleanupStaleLocks(), cleanupIntervalMs);
66
- interval.unref?.();
67
-
68
- return {
69
- acquire(sessionID: string, filePath: unknown): AcquireResult {
70
- const normalized = normalizeFilePath(filePath);
71
- if (!sessionID || !normalized) return { ok: true, filePath: normalized };
72
- const existing = locks.get(normalized);
73
- if (existing && existing.sessionID !== sessionID) {
74
- return { ok: false, filePath: normalized, ownerSessionID: existing.sessionID };
75
- }
76
- locks.set(normalized, { sessionID, lastTouchedAt: Date.now() });
77
- trackSessionFile(sessionID, normalized);
78
- return { ok: true, filePath: normalized };
79
- },
80
- release,
81
- releaseAll,
82
- inspect(filePath: unknown): LockInfo | undefined {
83
- return locks.get(normalizeFilePath(filePath) ?? "");
84
- },
85
- cleanup(now = Date.now()): void {
86
- cleanupStaleLocks(now);
87
- clearInterval(interval);
88
- },
89
- };
90
- };