opencode-swarm 7.65.1 → 7.65.3

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
@@ -52,7 +52,7 @@ var package_default;
52
52
  var init_package = __esm(() => {
53
53
  package_default = {
54
54
  name: "opencode-swarm",
55
- version: "7.65.1",
55
+ version: "7.65.3",
56
56
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
57
57
  main: "dist/index.js",
58
58
  types: "dist/index.d.ts",
@@ -39937,7 +39937,7 @@ async function skillPropagationGateBefore(directory, input, config3) {
39937
39937
  }
39938
39938
  let scoringSkipped = false;
39939
39939
  let scored = [];
39940
- if (skillsValue && skillsValue.toLowerCase() !== "none" && availableSkills.length > 0) {
39940
+ if (skillsValue.toLowerCase() !== "none" && availableSkills.length > 0) {
39941
39941
  try {
39942
39942
  const sessionEntries = _internals14.readSkillUsageEntriesTail(directory, {
39943
39943
  sessionID
@@ -40063,7 +40063,7 @@ ${newSection}`;
40063
40063
  const blockedMsg = `Blocked by skill propagation gate: Delegating to ${targetBase} without SKILLS field. ` + `Available skills: ${skillNames.join(", ")}. ` + `Add a SKILLS: field or set enforce: false in config.`;
40064
40064
  return { blocked: true, reason: blockedMsg, recommendedSkills: undefined };
40065
40065
  }
40066
- return { blocked: false, reason: warningMsg, recommendedSkills: undefined };
40066
+ return { blocked: false, reason: warningMsg, recommendedSkills: scored };
40067
40067
  }
40068
40068
  async function skillPropagationTransformScan(directory, output, sessionID) {
40069
40069
  if (!output?.messages)
@@ -40254,7 +40254,7 @@ var init_skill_propagation_gate = __esm(() => {
40254
40254
  formatSkillIndexWithContext,
40255
40255
  loadRoutingSkills: null
40256
40256
  };
40257
- COMPLIANCE_PATTERN = /SKILL_COMPLIANCE\s*:\s*(COMPLIANT|PARTIAL|VIOLATED)(?:\s*(?:\u2014|-)\s*(.*))?\s*$/i;
40257
+ COMPLIANCE_PATTERN = /SKILL_COMPLIANCE\s*:\s*(COMPLIANT|PARTIAL|VIOLATED)(?:\s*(?:\u2014|-)\s*(.*))? \s*$/i;
40258
40258
  CODER_SKILLS_PATTERN = /SKILLS_USED_BY_CODER\s*:\s*(.+)/i;
40259
40259
  _internals14.skillPropagationGateBefore = skillPropagationGateBefore;
40260
40260
  _internals14.skillPropagationTransformScan = skillPropagationTransformScan;
@@ -46897,9 +46897,10 @@ import { extname as extname3, join as join30 } from "path";
46897
46897
  async function detectProjectLanguages(projectDir) {
46898
46898
  const detected = new Set;
46899
46899
  async function scanDir(dir) {
46900
+ let dirEntries;
46900
46901
  let entries;
46901
46902
  try {
46902
- const dirEntries = await readdir2(dir, { withFileTypes: true });
46903
+ dirEntries = await readdir2(dir, { withFileTypes: true });
46903
46904
  entries = dirEntries.map((e) => e.name);
46904
46905
  } catch {
46905
46906
  return;
@@ -46908,7 +46909,7 @@ async function detectProjectLanguages(projectDir) {
46908
46909
  for (const detectFile of profile.build.detectFiles) {
46909
46910
  if (detectFile.includes("*") || detectFile.includes("?")) {
46910
46911
  const regex = new RegExp(`^${detectFile.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`);
46911
- if (entries.some((name) => regex.test(name))) {
46912
+ if (dirEntries.some((e) => !e.isDirectory() && regex.test(e.name))) {
46912
46913
  detected.add(profile.id);
46913
46914
  break;
46914
46915
  }
@@ -123,8 +123,9 @@ export declare function extractTaskIdFromPrompt(prompt: string): string;
123
123
  * SKILLS field.
124
124
  *
125
125
  * @returns { blocked: boolean; reason: string | null; recommendedSkills?: Array<{ skillPath: string; score: number; usageCount: number }> }
126
- * When scoring has computed results, includes `recommendedSkills` with ranked skill recommendations.
127
- * When scoring was skipped or errored, `recommendedSkills` is undefined.
126
+ * `recommendedSkills` is populated (possibly `[]`) on both the happy path (SKILLS present)
127
+ * and the warn path (SKILLS missing or 'none'). It is `undefined` only on early-exit returns
128
+ * (unsupported tool/agent/target, no available skills in project, or enforce-blocked).
128
129
  */
129
130
  export declare function skillPropagationGateBefore(directory: string, input: SkillGateInput, config: SkillPropagationConfig): Promise<{
130
131
  blocked: boolean;
package/dist/index.js CHANGED
@@ -69,7 +69,7 @@ var package_default;
69
69
  var init_package = __esm(() => {
70
70
  package_default = {
71
71
  name: "opencode-swarm",
72
- version: "7.65.1",
72
+ version: "7.65.3",
73
73
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
74
74
  main: "dist/index.js",
75
75
  types: "dist/index.d.ts",
@@ -62854,7 +62854,7 @@ async function skillPropagationGateBefore(directory, input, config3) {
62854
62854
  }
62855
62855
  let scoringSkipped = false;
62856
62856
  let scored = [];
62857
- if (skillsValue && skillsValue.toLowerCase() !== "none" && availableSkills.length > 0) {
62857
+ if (skillsValue.toLowerCase() !== "none" && availableSkills.length > 0) {
62858
62858
  try {
62859
62859
  const sessionEntries = _internals25.readSkillUsageEntriesTail(directory, {
62860
62860
  sessionID
@@ -62980,7 +62980,7 @@ ${newSection}`;
62980
62980
  const blockedMsg = `Blocked by skill propagation gate: Delegating to ${targetBase} without SKILLS field. ` + `Available skills: ${skillNames.join(", ")}. ` + `Add a SKILLS: field or set enforce: false in config.`;
62981
62981
  return { blocked: true, reason: blockedMsg, recommendedSkills: undefined };
62982
62982
  }
62983
- return { blocked: false, reason: warningMsg, recommendedSkills: undefined };
62983
+ return { blocked: false, reason: warningMsg, recommendedSkills: scored };
62984
62984
  }
62985
62985
  async function skillPropagationTransformScan(directory, output, sessionID) {
62986
62986
  if (!output?.messages)
@@ -63171,7 +63171,7 @@ var init_skill_propagation_gate = __esm(() => {
63171
63171
  formatSkillIndexWithContext,
63172
63172
  loadRoutingSkills: null
63173
63173
  };
63174
- COMPLIANCE_PATTERN = /SKILL_COMPLIANCE\s*:\s*(COMPLIANT|PARTIAL|VIOLATED)(?:\s*(?:—|-)\s*(.*))?\s*$/i;
63174
+ COMPLIANCE_PATTERN = /SKILL_COMPLIANCE\s*:\s*(COMPLIANT|PARTIAL|VIOLATED)(?:\s*(?:—|-)\s*(.*))? \s*$/i;
63175
63175
  CODER_SKILLS_PATTERN = /SKILLS_USED_BY_CODER\s*:\s*(.+)/i;
63176
63176
  _internals25.skillPropagationGateBefore = skillPropagationGateBefore;
63177
63177
  _internals25.skillPropagationTransformScan = skillPropagationTransformScan;
@@ -70012,9 +70012,10 @@ function getProfileForFile(filePath) {
70012
70012
  async function detectProjectLanguages(projectDir) {
70013
70013
  const detected = new Set;
70014
70014
  async function scanDir(dir) {
70015
+ let dirEntries;
70015
70016
  let entries;
70016
70017
  try {
70017
- const dirEntries = await readdir3(dir, { withFileTypes: true });
70018
+ dirEntries = await readdir3(dir, { withFileTypes: true });
70018
70019
  entries = dirEntries.map((e) => e.name);
70019
70020
  } catch {
70020
70021
  return;
@@ -70023,7 +70024,7 @@ async function detectProjectLanguages(projectDir) {
70023
70024
  for (const detectFile of profile.build.detectFiles) {
70024
70025
  if (detectFile.includes("*") || detectFile.includes("?")) {
70025
70026
  const regex = new RegExp(`^${detectFile.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`);
70026
- if (entries.some((name2) => regex.test(name2))) {
70027
+ if (dirEntries.some((e) => !e.isDirectory() && regex.test(e.name))) {
70027
70028
  detected.add(profile.id);
70028
70029
  break;
70029
70030
  }
@@ -98412,10 +98413,16 @@ function writeProjectConfigIfNew(directory, quiet = false) {
98412
98413
  try {
98413
98414
  const opencodeDir = path85.join(directory, ".opencode");
98414
98415
  const dest = path85.join(opencodeDir, "opencode-swarm.json");
98416
+ const normalizePathForCompare = (p) => process.platform === "win32" ? p.toLowerCase() : p;
98415
98417
  try {
98416
98418
  const stat6 = fs49.lstatSync(opencodeDir);
98417
98419
  if (stat6.isSymbolicLink())
98418
98420
  return;
98421
+ const resolvedDir = fs49.realpathSync(opencodeDir);
98422
+ const canonicalOpencode = path85.join(fs49.realpathSync(directory), ".opencode");
98423
+ if (normalizePathForCompare(resolvedDir) !== normalizePathForCompare(canonicalOpencode)) {
98424
+ return;
98425
+ }
98419
98426
  } catch (err2) {
98420
98427
  if (err2.code !== "ENOENT")
98421
98428
  return;
@@ -101673,7 +101680,7 @@ import * as path103 from "node:path";
101673
101680
  init_logger();
101674
101681
  init_path_security();
101675
101682
  import * as fsSync5 from "node:fs";
101676
- import { existsSync as existsSync61, realpathSync as realpathSync12 } from "node:fs";
101683
+ import { existsSync as existsSync61, realpathSync as realpathSync13 } from "node:fs";
101677
101684
  import * as fsPromises5 from "node:fs/promises";
101678
101685
  import * as os14 from "node:os";
101679
101686
  import * as path99 from "node:path";
@@ -102145,8 +102152,8 @@ var symbols = createSwarmTool({
102145
102152
  });
102146
102153
 
102147
102154
  // src/tools/repo-graph/safe-realpath.ts
102148
- import { realpathSync as realpathSync11 } from "node:fs";
102149
- function safeRealpathSync(targetPath, fallback, realpathResolver = realpathSync11) {
102155
+ import { realpathSync as realpathSync12 } from "node:fs";
102156
+ function safeRealpathSync(targetPath, fallback, realpathResolver = realpathSync12) {
102150
102157
  try {
102151
102158
  return realpathResolver(targetPath);
102152
102159
  } catch (error93) {
@@ -102419,7 +102426,7 @@ function resolveModuleSpecifier(workspaceRoot, sourceFile, specifier) {
102419
102426
  function isRefusedWorkspaceRoot(target) {
102420
102427
  let resolved;
102421
102428
  try {
102422
- resolved = realpathSync12(target);
102429
+ resolved = realpathSync13(target);
102423
102430
  } catch {
102424
102431
  resolved = path99.resolve(target);
102425
102432
  }
@@ -112673,7 +112680,7 @@ import {
112673
112680
  mkdirSync as mkdirSync33,
112674
112681
  mkdtempSync as mkdtempSync2,
112675
112682
  readFileSync as readFileSync49,
112676
- realpathSync as realpathSync15,
112683
+ realpathSync as realpathSync16,
112677
112684
  renameSync as renameSync23,
112678
112685
  rmdirSync as rmdirSync2,
112679
112686
  unlinkSync as unlinkSync18,
@@ -112707,8 +112714,8 @@ function containsStrictControlChars(str) {
112707
112714
  }
112708
112715
  function isCanonicalProtectedPath(targetPath, workspace) {
112709
112716
  try {
112710
- const canonicalTarget = realpathSync15(targetPath);
112711
- const canonicalWorkspace = realpathSync15(workspace);
112717
+ const canonicalTarget = realpathSync16(targetPath);
112718
+ const canonicalWorkspace = realpathSync16(workspace);
112712
112719
  const relative25 = path127.relative(canonicalWorkspace, canonicalTarget).replace(/\\/g, "/");
112713
112720
  const segments = relative25.split("/").filter(Boolean);
112714
112721
  return segments.some((seg) => seg === ".git" || seg === ".swarm");
@@ -112717,8 +112724,8 @@ function isCanonicalProtectedPath(targetPath, workspace) {
112717
112724
  if (parentDir === targetPath)
112718
112725
  return false;
112719
112726
  try {
112720
- const canonicalParent = realpathSync15(parentDir);
112721
- const canonicalWorkspace = realpathSync15(workspace);
112727
+ const canonicalParent = realpathSync16(parentDir);
112728
+ const canonicalWorkspace = realpathSync16(workspace);
112722
112729
  const relative25 = path127.relative(canonicalWorkspace, canonicalParent).replace(/\\/g, "/");
112723
112730
  const segments = relative25.split("/").filter(Boolean);
112724
112731
  return segments.some((seg) => seg === ".git" || seg === ".swarm");
@@ -112729,8 +112736,8 @@ function isCanonicalProtectedPath(targetPath, workspace) {
112729
112736
  }
112730
112737
  function isCanonicalPathWithinWorkspace(targetPath, workspaceRoot) {
112731
112738
  try {
112732
- const canonicalTarget = realpathSync15(targetPath);
112733
- const canonicalWorkspace = realpathSync15(workspaceRoot);
112739
+ const canonicalTarget = realpathSync16(targetPath);
112740
+ const canonicalWorkspace = realpathSync16(workspaceRoot);
112734
112741
  const relative25 = path127.relative(canonicalWorkspace, canonicalTarget);
112735
112742
  if (relative25.startsWith("..") || path127.isAbsolute(relative25))
112736
112743
  return false;
@@ -112744,8 +112751,8 @@ function isCanonicalPathWithinWorkspace(targetPath, workspaceRoot) {
112744
112751
  return false;
112745
112752
  }
112746
112753
  try {
112747
- const canonicalParent = realpathSync15(parentDir);
112748
- const canonicalWorkspace = realpathSync15(workspaceRoot);
112754
+ const canonicalParent = realpathSync16(parentDir);
112755
+ const canonicalWorkspace = realpathSync16(workspaceRoot);
112749
112756
  const relative25 = path127.relative(canonicalWorkspace, canonicalParent);
112750
112757
  if (relative25.startsWith("..") || path127.isAbsolute(relative25))
112751
112758
  return false;
@@ -113023,7 +113030,7 @@ function atomicWriteFileSync(targetPath, content) {
113023
113030
  const tempPrefix = `.apply-patch-${Date.now()}-${process.pid}`;
113024
113031
  let tempPath;
113025
113032
  try {
113026
- const tempDir = realpathSync15(mkdtempSync2(path127.join(dir, tempPrefix)));
113033
+ const tempDir = realpathSync16(mkdtempSync2(path127.join(dir, tempPrefix)));
113027
113034
  tempPath = path127.join(tempDir, "content");
113028
113035
  } catch {
113029
113036
  tempPath = path127.join(dir, `${tempPrefix}.tmp`);
@@ -128904,6 +128911,8 @@ async function executeWithTimeout(command, args2, options) {
128904
128911
  });
128905
128912
  let stdout = "";
128906
128913
  let stderr = "";
128914
+ let stdoutBytes = 0;
128915
+ let stderrBytes = 0;
128907
128916
  let stdoutTruncated = false;
128908
128917
  let stderrTruncated = false;
128909
128918
  let settled = false;
@@ -128944,25 +128953,36 @@ async function executeWithTimeout(command, args2, options) {
128944
128953
  if (stdoutTruncated)
128945
128954
  return;
128946
128955
  const chunk = data.toString();
128947
- if (stdout.length + chunk.length > maxOutputBytes) {
128948
- stdout += chunk.slice(0, Math.max(0, maxOutputBytes - stdout.length));
128956
+ const chunkBytes = Buffer.byteLength(chunk, "utf8");
128957
+ if (stdoutBytes + chunkBytes > maxOutputBytes) {
128958
+ const remaining = Math.max(0, maxOutputBytes - stdoutBytes);
128959
+ stdout += Buffer.from(chunk, "utf8").subarray(0, remaining).toString("utf8");
128960
+ stdoutBytes = maxOutputBytes;
128949
128961
  stdoutTruncated = true;
128950
128962
  try {
128951
128963
  child.kill("SIGTERM");
128952
128964
  } catch {}
128953
128965
  } else {
128954
128966
  stdout += chunk;
128967
+ stdoutBytes += chunkBytes;
128955
128968
  }
128956
128969
  });
128957
128970
  child.stderr?.on("data", (data) => {
128958
128971
  if (stderrTruncated)
128959
128972
  return;
128960
128973
  const chunk = data.toString();
128961
- if (stderr.length + chunk.length > maxOutputBytes) {
128962
- stderr += chunk.slice(0, Math.max(0, maxOutputBytes - stderr.length));
128974
+ const chunkBytes = Buffer.byteLength(chunk, "utf8");
128975
+ if (stderrBytes + chunkBytes > maxOutputBytes) {
128976
+ const remaining = Math.max(0, maxOutputBytes - stderrBytes);
128977
+ stderr += Buffer.from(chunk, "utf8").subarray(0, remaining).toString("utf8");
128978
+ stderrBytes = maxOutputBytes;
128963
128979
  stderrTruncated = true;
128980
+ try {
128981
+ child.kill("SIGTERM");
128982
+ } catch {}
128964
128983
  } else {
128965
128984
  stderr += chunk;
128985
+ stderrBytes += chunkBytes;
128966
128986
  }
128967
128987
  });
128968
128988
  child.on("close", (code) => {
@@ -12,18 +12,8 @@
12
12
  * the rationale. `detectLaravelProject` / `getLaravelCommandOverlay` are
13
13
  * filesystem-only (no subprocess), so they are safe on the session-init path.
14
14
  */
15
- import type { FrameworkSelection, LanguageBackend } from '../backend';
16
- /**
17
- * Detect Laravel via the multi-signal heuristic (artisan + composer.json
18
- * require + config/app.php; ≥2 of 3). Returns null for generic Composer PHP
19
- * projects so the architect's PROJECT_FRAMEWORK stays unresolved.
20
- */
21
- declare function selectFramework(dir: string): Promise<FrameworkSelection | null>;
15
+ import type { LanguageBackend } from '../backend';
22
16
  /**
23
17
  * Build the PHP backend from the registered profile.
24
18
  */
25
19
  export declare function buildPhpBackend(): LanguageBackend;
26
- export declare const _internals: {
27
- selectFramework: typeof selectFramework;
28
- };
29
- export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.65.1",
3
+ "version": "7.65.3",
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",