opencode-swarm 6.84.6 → 6.85.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.
package/dist/cli/index.js CHANGED
@@ -45227,13 +45227,17 @@ async function install() {
45227
45227
  \uD83D\uDE80 Installation complete!`);
45228
45228
  console.log(`
45229
45229
  Next steps:`);
45230
- console.log("1. Edit the plugin config to customize models and settings");
45231
- console.log('2. Run "opencode" to start using the swarm');
45232
- console.log("3. The Architect agent will orchestrate your requests");
45230
+ console.log('1. Run "opencode" in your project directory');
45231
+ console.log("2. Select the Architect agent in the OpenCode agent/mode dropdown");
45232
+ console.log("3. Ask it anything \u2014 the Architect coordinates all other agents automatically");
45233
+ console.log("4. Run /swarm diagnose inside OpenCode to confirm the plugin loaded");
45234
+ console.log(" (also try: /swarm agents /swarm config)");
45233
45235
  console.log(`
45234
- \uD83D\uDCD6 SME agent:`);
45235
- console.log(" The SME agent supports any domain \u2014 the Architect determines");
45236
- console.log(" what expertise is needed and requests it dynamically.");
45236
+ \uD83D\uDCA1 Model configuration:`);
45237
+ console.log(` Global config: ${PLUGIN_CONFIG_PATH}`);
45238
+ console.log(" Project override: .opencode/opencode-swarm.json (create in your project root)");
45239
+ console.log(" On first OpenCode startup, .swarm/config.example.json will be written to your project root");
45240
+ console.log(" \u2014 use it as a reference for customizing model assignments.");
45237
45241
  return 0;
45238
45242
  }
45239
45243
  async function uninstall() {
@@ -5,6 +5,7 @@
5
5
  * Write-trigger hook that incrementally updates the graph when write tools are called.
6
6
  * Wrapped in try/catch — failures are logged but never block plugin initialization.
7
7
  */
8
+ import { type RepoGraph } from '../tools/repo-graph';
8
9
  export interface RepoGraphBuilderHook {
9
10
  init(): Promise<void>;
10
11
  toolAfter(input: {
@@ -17,8 +18,15 @@ export interface RepoGraphBuilderHook {
17
18
  }): Promise<void>;
18
19
  }
19
20
  export interface RepoGraphDeps {
20
- buildWorkspaceGraph: (workspace: string, options?: any) => any;
21
- saveGraph: (workspace: string, graph: any) => Promise<void>;
22
- updateGraphForFiles: (workspace: string, files: string[], options?: any) => Promise<any>;
21
+ buildWorkspaceGraph: (workspace: string, options?: {
22
+ maxFileSizeBytes?: number;
23
+ maxFiles?: number;
24
+ }) => RepoGraph;
25
+ saveGraph: (workspace: string, graph: RepoGraph, options?: {
26
+ createAtomic?: boolean;
27
+ }) => Promise<void>;
28
+ updateGraphForFiles: (workspace: string, files: string[], options?: {
29
+ forceRebuild?: boolean;
30
+ }) => Promise<RepoGraph>;
23
31
  }
24
32
  export declare function createRepoGraphBuilderHook(workspaceRoot: string, deps?: Partial<RepoGraphDeps>): RepoGraphBuilderHook;
package/dist/index.js CHANGED
@@ -23112,11 +23112,11 @@ function dcExtractPowerShellTargets(segment) {
23112
23112
  function redactShellCommand(cmd) {
23113
23113
  if (typeof cmd !== "string")
23114
23114
  return "";
23115
- let out2 = cmd.replace(/\b([A-Z_]*(?:TOKEN|SECRET|PASSWORD|PASSWD|API[_]?KEY|APIKEY|AUTH|CREDENTIAL|PRIVATE[_]?KEY|ACCESS[_]?KEY)[A-Z_0-9]*)\s*=\s*(\S+)/gi, "$1=[REDACTED]");
23115
+ let out2 = cmd.replace(/\b([A-Z_]*(?:TOKEN|SECRET|PASSWORD|PASSWD|API[_]?KEY|APIKEY|AUTH|CREDENTIAL|PRIVATE[_]?KEY|ACCESS[_]?KEY|_KEY)[A-Z_0-9]*)\s*=\s*(\S+)/gi, "$1=[REDACTED]");
23116
23116
  out2 = out2.replace(/--([a-zA-Z-]*(?:token|secret|password|passwd|api[_-]?key|apikey|auth|credential|private[_-]?key|access[_-]?key)[a-zA-Z-]*)=(\S+)/gi, "--$1=[REDACTED]");
23117
23117
  out2 = out2.replace(/(--[a-zA-Z-]*(?:token|secret|password|passwd|api[_-]?key|apikey|auth|credential|private[_-]?key|access[_-]?key)[a-zA-Z-]*)(\s+)(?!--)(\S+)/gi, "$1$2[REDACTED]");
23118
23118
  out2 = out2.replace(/\b(Bearer|Basic)\s+[A-Za-z0-9+/=._-]{4,}/gi, "$1 [REDACTED]");
23119
- out2 = out2.replace(/(-H\s+['"]?(?:Authorization|X-API-Key|X-Auth-Token):\s*)([^'">\s][^'">\n]*)(['"]?)/gi, "$1[REDACTED]$3");
23119
+ out2 = out2.replace(/(-H\s+['"]?(?:Authorization|X-API-Key|X-Auth-Token|[A-Za-z][A-Za-z-]*-(?:key|token|secret|auth|credential)):\s*)([^'">\s][^'">\n]*)(['"]?)/gi, "$1[REDACTED]$3");
23120
23120
  return out2;
23121
23121
  }
23122
23122
  function createGuardrailsHooks(directory, directoryOrConfig, config2, authorityConfig) {
@@ -62828,7 +62828,8 @@ var init_curator_drift = __esm(() => {
62828
62828
 
62829
62829
  // src/index.ts
62830
62830
  init_agents();
62831
- import * as path103 from "path";
62831
+ import * as fs88 from "fs";
62832
+ import * as path104 from "path";
62832
62833
 
62833
62834
  // src/background/index.ts
62834
62835
  init_event_bus();
@@ -88084,6 +88085,67 @@ init_write_retro();
88084
88085
  // src/index.ts
88085
88086
  init_utils();
88086
88087
 
88088
+ // src/utils/gitignore-warning.ts
88089
+ import * as fs87 from "fs";
88090
+ import * as path103 from "path";
88091
+ var _gitignoreWarningEmitted = false;
88092
+ function findGitRoot(startDir) {
88093
+ let current = startDir;
88094
+ while (true) {
88095
+ try {
88096
+ const gitPath = path103.join(current, ".git");
88097
+ const stat4 = fs87.statSync(gitPath);
88098
+ if (stat4.isDirectory()) {
88099
+ return current;
88100
+ }
88101
+ } catch {}
88102
+ const parent = path103.dirname(current);
88103
+ if (parent === current) {
88104
+ return null;
88105
+ }
88106
+ current = parent;
88107
+ }
88108
+ }
88109
+ function fileCoversSwarm(content) {
88110
+ for (const rawLine of content.split(`
88111
+ `)) {
88112
+ const line = rawLine.trim();
88113
+ if (line.startsWith("#") || line.length === 0)
88114
+ continue;
88115
+ if (line === ".swarm" || line === ".swarm/")
88116
+ return true;
88117
+ }
88118
+ return false;
88119
+ }
88120
+ function readFileSafe(filePath) {
88121
+ try {
88122
+ return fs87.readFileSync(filePath, "utf8");
88123
+ } catch {
88124
+ return null;
88125
+ }
88126
+ }
88127
+ function warnIfSwarmNotGitignored(directory) {
88128
+ if (_gitignoreWarningEmitted)
88129
+ return;
88130
+ try {
88131
+ const gitRoot = findGitRoot(directory);
88132
+ if (!gitRoot)
88133
+ return;
88134
+ const gitignoreContent = readFileSafe(path103.join(gitRoot, ".gitignore"));
88135
+ if (gitignoreContent !== null && fileCoversSwarm(gitignoreContent)) {
88136
+ _gitignoreWarningEmitted = true;
88137
+ return;
88138
+ }
88139
+ const excludeContent = readFileSafe(path103.join(gitRoot, ".git", "info", "exclude"));
88140
+ if (excludeContent !== null && fileCoversSwarm(excludeContent)) {
88141
+ _gitignoreWarningEmitted = true;
88142
+ return;
88143
+ }
88144
+ _gitignoreWarningEmitted = true;
88145
+ console.warn('[opencode-swarm] WARNING: .swarm/ is not in your .gitignore. Shell audit logs may contain API keys. Add ".swarm/" to your .gitignore to prevent accidental commits.');
88146
+ } catch {}
88147
+ }
88148
+
88087
88149
  // src/utils/tool-output.ts
88088
88150
  function truncateToolOutput(output, maxLines, toolName, tailLines = 10) {
88089
88151
  if (!output) {
@@ -88117,6 +88179,26 @@ ${footerLines.join(`
88117
88179
 
88118
88180
  // src/index.ts
88119
88181
  var _heartbeatTimers = new Map;
88182
+ function writeSwarmConfigExampleIfNew(projectDirectory) {
88183
+ try {
88184
+ const swarmDir = path104.join(projectDirectory, ".swarm");
88185
+ const dest = path104.join(swarmDir, "config.example.json");
88186
+ if (fs88.existsSync(dest))
88187
+ return;
88188
+ const example = {
88189
+ agents: Object.fromEntries(Object.entries(DEFAULT_MODELS).filter(([name2]) => name2 !== "default").map(([name2, model]) => [
88190
+ name2,
88191
+ {
88192
+ model,
88193
+ fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
88194
+ }
88195
+ ])),
88196
+ max_iterations: 5
88197
+ };
88198
+ fs88.writeFileSync(dest, `${JSON.stringify(example, null, 2)}
88199
+ `, "utf-8");
88200
+ } catch {}
88201
+ }
88120
88202
  var OpenCodeSwarm = async (ctx) => {
88121
88203
  const { config: config3, loadedFromFile } = loadPluginConfigWithMeta(ctx.directory);
88122
88204
  if (config3.full_auto?.enabled === true) {
@@ -88130,6 +88212,8 @@ var OpenCodeSwarm = async (ctx) => {
88130
88212
  swarmState.opencodeClient = ctx.client;
88131
88213
  await loadSnapshot(ctx.directory);
88132
88214
  initTelemetry(ctx.directory);
88215
+ writeSwarmConfigExampleIfNew(ctx.directory);
88216
+ warnIfSwarmNotGitignored(ctx.directory);
88133
88217
  const repoGraphHook = createRepoGraphBuilderHook(ctx.directory);
88134
88218
  repoGraphHook.init().catch(() => {});
88135
88219
  const agents = getAgentConfigs(config3, ctx.directory);
@@ -88249,7 +88333,7 @@ var OpenCodeSwarm = async (ctx) => {
88249
88333
  const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
88250
88334
  preflightTriggerManager = new PTM(automationConfig);
88251
88335
  const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
88252
- const swarmDir = path103.resolve(ctx.directory, ".swarm");
88336
+ const swarmDir = path104.resolve(ctx.directory, ".swarm");
88253
88337
  statusArtifact = new ASA(swarmDir);
88254
88338
  statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
88255
88339
  if (automationConfig.capabilities?.evidence_auto_summaries === true) {
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Module-level flag so the warning fires at most once per process.
3
+ * Exported for test reset purposes only — do not use in production code.
4
+ */
5
+ export declare let _gitignoreWarningEmitted: boolean;
6
+ /**
7
+ * Reset the deduplication flag. Exposed for test isolation only.
8
+ */
9
+ export declare function resetGitignoreWarningState(): void;
10
+ /**
11
+ * Checks whether `.swarm/` is covered by `.gitignore` or `.git/info/exclude`
12
+ * in the git repo rooted at or above `directory`. If not covered, emits a
13
+ * single `console.warn`. Fires at most once per process.
14
+ *
15
+ * Never throws — any file-system error silently skips the check.
16
+ */
17
+ export declare function warnIfSwarmNotGitignored(directory: string): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "6.84.6",
3
+ "version": "6.85.0",
4
4
  "description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",