opencode-swarm 7.68.0 → 7.68.2
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 +383 -246
- package/dist/hooks/knowledge-migrator.d.ts +23 -0
- package/dist/index.js +383 -246
- package/package.json +1 -1
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.68.
|
|
55
|
+
version: "7.68.2",
|
|
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",
|
|
@@ -49731,7 +49731,7 @@ var init_history = __esm(() => {
|
|
|
49731
49731
|
init_history_service();
|
|
49732
49732
|
});
|
|
49733
49733
|
|
|
49734
|
-
// src/commands/
|
|
49734
|
+
// src/commands/pr-ref.ts
|
|
49735
49735
|
import { execSync as execSync2 } from "child_process";
|
|
49736
49736
|
function sanitizeUrl(raw) {
|
|
49737
49737
|
let urlStr = raw.trim();
|
|
@@ -49750,6 +49750,22 @@ function sanitizeUrl(raw) {
|
|
|
49750
49750
|
}
|
|
49751
49751
|
return urlStr.trim();
|
|
49752
49752
|
}
|
|
49753
|
+
function sanitizeInstructions(raw) {
|
|
49754
|
+
const collapsed = raw.replace(/\s+/g, " ").trim();
|
|
49755
|
+
const stripped = collapsed.replace(/\[\s*MODE\s*:[^\]]*\]/gi, "");
|
|
49756
|
+
const normalized = stripped.replace(/\s+/g, " ").trim();
|
|
49757
|
+
if (normalized.length <= MAX_INSTRUCTIONS_LEN)
|
|
49758
|
+
return normalized;
|
|
49759
|
+
return `${normalized.slice(0, MAX_INSTRUCTIONS_LEN)}\u2026`;
|
|
49760
|
+
}
|
|
49761
|
+
function hasNonAsciiHostname(hostname5) {
|
|
49762
|
+
for (const ch of hostname5) {
|
|
49763
|
+
const cp = ch.codePointAt(0);
|
|
49764
|
+
if (cp !== undefined && cp > 127)
|
|
49765
|
+
return true;
|
|
49766
|
+
}
|
|
49767
|
+
return false;
|
|
49768
|
+
}
|
|
49753
49769
|
function isPrivateHost(url3) {
|
|
49754
49770
|
const host = url3.hostname.toLowerCase();
|
|
49755
49771
|
if (host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "0.0.0.0") {
|
|
@@ -49782,13 +49798,182 @@ function validateAndSanitizeUrl(rawUrl) {
|
|
|
49782
49798
|
if (!sanitized.startsWith("https://")) {
|
|
49783
49799
|
return { error: "URL must use HTTPS scheme" };
|
|
49784
49800
|
}
|
|
49801
|
+
try {
|
|
49802
|
+
const url3 = new URL(sanitized);
|
|
49803
|
+
if (hasNonAsciiHostname(url3.hostname)) {
|
|
49804
|
+
return { error: "Non-ASCII hostnames are not allowed" };
|
|
49805
|
+
}
|
|
49806
|
+
if (isPrivateHost(url3)) {
|
|
49807
|
+
return { error: "Private or localhost URLs are not allowed" };
|
|
49808
|
+
}
|
|
49809
|
+
const githubPrPattern = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/pull\/([0-9]+)\/?$/;
|
|
49810
|
+
if (!githubPrPattern.test(sanitized)) {
|
|
49811
|
+
return {
|
|
49812
|
+
error: "URL must be a GitHub pull request URL (https://github.com/owner/repo/pull/N)"
|
|
49813
|
+
};
|
|
49814
|
+
}
|
|
49815
|
+
return { sanitized };
|
|
49816
|
+
} catch {
|
|
49817
|
+
return { error: "Invalid URL format" };
|
|
49818
|
+
}
|
|
49819
|
+
}
|
|
49820
|
+
function parsePrRef(input, cwd) {
|
|
49821
|
+
const urlMatch = input.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)\/?$/i);
|
|
49822
|
+
if (urlMatch) {
|
|
49823
|
+
return {
|
|
49824
|
+
owner: urlMatch[1],
|
|
49825
|
+
repo: urlMatch[2],
|
|
49826
|
+
number: parseInt(urlMatch[3], 10)
|
|
49827
|
+
};
|
|
49828
|
+
}
|
|
49829
|
+
const shorthandMatch = input.match(/^([^/]+)\/([^#]+)#(\d+)$/);
|
|
49830
|
+
if (shorthandMatch) {
|
|
49831
|
+
return {
|
|
49832
|
+
owner: shorthandMatch[1],
|
|
49833
|
+
repo: shorthandMatch[2],
|
|
49834
|
+
number: parseInt(shorthandMatch[3], 10)
|
|
49835
|
+
};
|
|
49836
|
+
}
|
|
49837
|
+
const bareMatch = input.match(/^(\d+)$/);
|
|
49838
|
+
if (bareMatch) {
|
|
49839
|
+
const prNumber = parseInt(bareMatch[1], 10);
|
|
49840
|
+
const remoteUrl = detectGitRemote(cwd);
|
|
49841
|
+
if (!remoteUrl) {
|
|
49842
|
+
return null;
|
|
49843
|
+
}
|
|
49844
|
+
const parsed = parseGitRemoteUrl(remoteUrl);
|
|
49845
|
+
if (!parsed) {
|
|
49846
|
+
return null;
|
|
49847
|
+
}
|
|
49848
|
+
return {
|
|
49849
|
+
owner: parsed.owner,
|
|
49850
|
+
repo: parsed.repo,
|
|
49851
|
+
number: prNumber
|
|
49852
|
+
};
|
|
49853
|
+
}
|
|
49854
|
+
return null;
|
|
49855
|
+
}
|
|
49856
|
+
function detectGitRemote(cwd) {
|
|
49857
|
+
try {
|
|
49858
|
+
const remoteUrl = _internals23.execSync("git remote get-url origin", {
|
|
49859
|
+
encoding: "utf-8",
|
|
49860
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
49861
|
+
timeout: 5000,
|
|
49862
|
+
...cwd ? { cwd } : {}
|
|
49863
|
+
}).trim();
|
|
49864
|
+
return remoteUrl || null;
|
|
49865
|
+
} catch {
|
|
49866
|
+
return null;
|
|
49867
|
+
}
|
|
49868
|
+
}
|
|
49869
|
+
function parseGitRemoteUrl(remoteUrl) {
|
|
49870
|
+
const httpsMatch = remoteUrl.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/i);
|
|
49871
|
+
if (httpsMatch) {
|
|
49872
|
+
return {
|
|
49873
|
+
owner: httpsMatch[1],
|
|
49874
|
+
repo: httpsMatch[2].replace(/\.git$/, "")
|
|
49875
|
+
};
|
|
49876
|
+
}
|
|
49877
|
+
const sshMatch = remoteUrl.match(/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/i);
|
|
49878
|
+
if (sshMatch) {
|
|
49879
|
+
return {
|
|
49880
|
+
owner: sshMatch[1],
|
|
49881
|
+
repo: sshMatch[2].replace(/\.git$/, "")
|
|
49882
|
+
};
|
|
49883
|
+
}
|
|
49884
|
+
const pathMatch = remoteUrl.match(/\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
|
|
49885
|
+
if (pathMatch) {
|
|
49886
|
+
return {
|
|
49887
|
+
owner: pathMatch[1],
|
|
49888
|
+
repo: pathMatch[2].replace(/\.git$/, "")
|
|
49889
|
+
};
|
|
49890
|
+
}
|
|
49891
|
+
return null;
|
|
49892
|
+
}
|
|
49893
|
+
function looksLikePrRef(token) {
|
|
49894
|
+
return /^https?:\/\//i.test(token) || /^[^/]+\/[^#]+#\d+$/.test(token) || /^\d+$/.test(token);
|
|
49895
|
+
}
|
|
49896
|
+
function resolvePrCommandInput(rest, cwd) {
|
|
49897
|
+
if (rest.length === 0) {
|
|
49898
|
+
return null;
|
|
49899
|
+
}
|
|
49900
|
+
const refToken = rest[0];
|
|
49901
|
+
const instructions = sanitizeInstructions(rest.slice(1).join(" "));
|
|
49902
|
+
const isFullUrl = /^https?:\/\//i.test(refToken);
|
|
49903
|
+
const prInfo = parsePrRef(isFullUrl ? sanitizeUrl(refToken) : refToken, cwd);
|
|
49904
|
+
if (!prInfo) {
|
|
49905
|
+
return { error: `Could not parse PR reference from "${refToken}"` };
|
|
49906
|
+
}
|
|
49907
|
+
const prUrl = `https://github.com/${prInfo.owner}/${prInfo.repo}/pull/${prInfo.number}`;
|
|
49908
|
+
const result = validateAndSanitizeUrl(prUrl);
|
|
49909
|
+
if ("error" in result) {
|
|
49910
|
+
return { error: result.error };
|
|
49911
|
+
}
|
|
49912
|
+
return { prUrl: result.sanitized, instructions };
|
|
49913
|
+
}
|
|
49914
|
+
var _internals23, MAX_URL_LEN = 2048, MAX_INSTRUCTIONS_LEN = 1000;
|
|
49915
|
+
var init_pr_ref = __esm(() => {
|
|
49916
|
+
_internals23 = { execSync: execSync2 };
|
|
49917
|
+
});
|
|
49918
|
+
|
|
49919
|
+
// src/commands/issue.ts
|
|
49920
|
+
import { execSync as execSync3 } from "child_process";
|
|
49921
|
+
function sanitizeUrl2(raw) {
|
|
49922
|
+
let urlStr = raw.trim();
|
|
49923
|
+
urlStr = urlStr.replace(/\[\s*MODE\s*:[^\]]*\]/gi, "");
|
|
49924
|
+
const fragmentIdx = urlStr.indexOf("#");
|
|
49925
|
+
if (fragmentIdx !== -1) {
|
|
49926
|
+
urlStr = urlStr.slice(0, fragmentIdx);
|
|
49927
|
+
}
|
|
49928
|
+
const queryIdx = urlStr.indexOf("?");
|
|
49929
|
+
if (queryIdx !== -1) {
|
|
49930
|
+
urlStr = urlStr.slice(0, queryIdx);
|
|
49931
|
+
}
|
|
49932
|
+
urlStr = urlStr.replace(/^[A-Za-z][A-Za-z0-9+.-]*:\/\/[^@/]+@/, "https://");
|
|
49933
|
+
if (urlStr.length > MAX_URL_LEN2) {
|
|
49934
|
+
urlStr = urlStr.slice(0, MAX_URL_LEN2);
|
|
49935
|
+
}
|
|
49936
|
+
return urlStr.trim();
|
|
49937
|
+
}
|
|
49938
|
+
function isPrivateHost2(url3) {
|
|
49939
|
+
const host = url3.hostname.toLowerCase();
|
|
49940
|
+
if (host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "0.0.0.0") {
|
|
49941
|
+
return true;
|
|
49942
|
+
}
|
|
49943
|
+
if (host.startsWith("localhost") || host === "localhost.com") {
|
|
49944
|
+
return true;
|
|
49945
|
+
}
|
|
49946
|
+
const ipv4Private = /^10\./;
|
|
49947
|
+
const ipv4172 = /^172\.(1[6-9]|2\d|3[0-1])\./;
|
|
49948
|
+
const ipv4192 = /^192\.168\./;
|
|
49949
|
+
const ipv6Private = /^fe80:/i;
|
|
49950
|
+
const ipv6Unique = /^f[cd][0-9a-f]{2}:/i;
|
|
49951
|
+
if (ipv4Private.test(host) || ipv4172.test(host) || ipv4192.test(host) || ipv6Private.test(host) || ipv6Unique.test(host)) {
|
|
49952
|
+
return true;
|
|
49953
|
+
}
|
|
49954
|
+
if (host.startsWith("::ffff:")) {
|
|
49955
|
+
const inner = host.slice(7);
|
|
49956
|
+
if (ipv4Private.test(inner) || ipv4172.test(inner) || ipv4192.test(inner)) {
|
|
49957
|
+
return true;
|
|
49958
|
+
}
|
|
49959
|
+
}
|
|
49960
|
+
return false;
|
|
49961
|
+
}
|
|
49962
|
+
function validateAndSanitizeUrl2(rawUrl) {
|
|
49963
|
+
const sanitized = sanitizeUrl2(rawUrl);
|
|
49964
|
+
if (!sanitized) {
|
|
49965
|
+
return { error: "Empty URL" };
|
|
49966
|
+
}
|
|
49967
|
+
if (!sanitized.startsWith("https://")) {
|
|
49968
|
+
return { error: "URL must use HTTPS scheme" };
|
|
49969
|
+
}
|
|
49785
49970
|
try {
|
|
49786
49971
|
const url3 = new URL(sanitized);
|
|
49787
49972
|
const hostname5 = url3.hostname;
|
|
49788
49973
|
if (/[\u0080-\u{10FFFF}]/u.test(hostname5)) {
|
|
49789
49974
|
return { error: "Non-ASCII hostnames are not allowed" };
|
|
49790
49975
|
}
|
|
49791
|
-
if (
|
|
49976
|
+
if (isPrivateHost2(url3)) {
|
|
49792
49977
|
return { error: "Private or localhost URLs are not allowed" };
|
|
49793
49978
|
}
|
|
49794
49979
|
const githubIssuePattern = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/issues\/([0-9]+)\/?$/;
|
|
@@ -49847,7 +50032,7 @@ function parseIssueRef(input) {
|
|
|
49847
50032
|
const bareMatch = input.match(/^(\d+)$/);
|
|
49848
50033
|
if (bareMatch) {
|
|
49849
50034
|
const issueNumber = parseInt(bareMatch[1], 10);
|
|
49850
|
-
const remoteUrl =
|
|
50035
|
+
const remoteUrl = detectGitRemote2();
|
|
49851
50036
|
if (!remoteUrl) {
|
|
49852
50037
|
return null;
|
|
49853
50038
|
}
|
|
@@ -49863,9 +50048,9 @@ function parseIssueRef(input) {
|
|
|
49863
50048
|
}
|
|
49864
50049
|
return null;
|
|
49865
50050
|
}
|
|
49866
|
-
function
|
|
50051
|
+
function detectGitRemote2() {
|
|
49867
50052
|
try {
|
|
49868
|
-
const remoteUrl =
|
|
50053
|
+
const remoteUrl = execSync3("git remote get-url origin", {
|
|
49869
50054
|
encoding: "utf-8",
|
|
49870
50055
|
stdio: ["pipe", "pipe", "pipe"],
|
|
49871
50056
|
timeout: 5000
|
|
@@ -49875,23 +50060,6 @@ function detectGitRemote() {
|
|
|
49875
50060
|
return null;
|
|
49876
50061
|
}
|
|
49877
50062
|
}
|
|
49878
|
-
function parseGitRemoteUrl(remoteUrl) {
|
|
49879
|
-
const httpsMatch = remoteUrl.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/i);
|
|
49880
|
-
if (httpsMatch) {
|
|
49881
|
-
return {
|
|
49882
|
-
owner: httpsMatch[1],
|
|
49883
|
-
repo: httpsMatch[2].replace(/\.git$/, "")
|
|
49884
|
-
};
|
|
49885
|
-
}
|
|
49886
|
-
const sshMatch = remoteUrl.match(/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/i);
|
|
49887
|
-
if (sshMatch) {
|
|
49888
|
-
return {
|
|
49889
|
-
owner: sshMatch[1],
|
|
49890
|
-
repo: sshMatch[2].replace(/\.git$/, "")
|
|
49891
|
-
};
|
|
49892
|
-
}
|
|
49893
|
-
return null;
|
|
49894
|
-
}
|
|
49895
50063
|
function handleIssueCommand(_directory, args) {
|
|
49896
50064
|
const parsed = parseArgs5(args);
|
|
49897
50065
|
const rawInput = parsed.rest.join(" ").trim();
|
|
@@ -49899,14 +50067,14 @@ function handleIssueCommand(_directory, args) {
|
|
|
49899
50067
|
return USAGE5;
|
|
49900
50068
|
}
|
|
49901
50069
|
const isFullUrl = /^https?:\/\//i.test(rawInput);
|
|
49902
|
-
const issueInfo = parseIssueRef(isFullUrl ?
|
|
50070
|
+
const issueInfo = parseIssueRef(isFullUrl ? sanitizeUrl2(rawInput) : rawInput);
|
|
49903
50071
|
if (!issueInfo) {
|
|
49904
50072
|
return `Error: Could not parse issue reference from "${rawInput}"
|
|
49905
50073
|
|
|
49906
50074
|
${USAGE5}`;
|
|
49907
50075
|
}
|
|
49908
50076
|
const issueUrl = `https://github.com/${issueInfo.owner}/${issueInfo.repo}/issues/${issueInfo.number}`;
|
|
49909
|
-
const result =
|
|
50077
|
+
const result = validateAndSanitizeUrl2(issueUrl);
|
|
49910
50078
|
if ("error" in result) {
|
|
49911
50079
|
return `Error: ${result.error}
|
|
49912
50080
|
|
|
@@ -49922,8 +50090,9 @@ ${USAGE5}`;
|
|
|
49922
50090
|
const flagsStr = flags.length > 0 ? ` ${flags.join(" ")}` : "";
|
|
49923
50091
|
return `[MODE: ISSUE_INGEST issue="${result.sanitized}"${flagsStr}]`;
|
|
49924
50092
|
}
|
|
49925
|
-
var
|
|
50093
|
+
var MAX_URL_LEN2 = 2048, USAGE5;
|
|
49926
50094
|
var init_issue = __esm(() => {
|
|
50095
|
+
init_pr_ref();
|
|
49927
50096
|
USAGE5 = [
|
|
49928
50097
|
"Usage: /swarm issue <url|owner/repo#N|N> [--plan] [--trace] [--no-repro]",
|
|
49929
50098
|
"",
|
|
@@ -49948,6 +50117,7 @@ var KNOWLEDGE_SCHEMA_VERSION = 2;
|
|
|
49948
50117
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
49949
50118
|
import { existsSync as existsSync25, readFileSync as readFileSync15 } from "fs";
|
|
49950
50119
|
import { mkdir as mkdir12, readFile as readFile12, writeFile as writeFile10 } from "fs/promises";
|
|
50120
|
+
import * as os8 from "os";
|
|
49951
50121
|
import * as path37 from "path";
|
|
49952
50122
|
async function migrateKnowledgeToExternal(_directory, _config) {
|
|
49953
50123
|
return {
|
|
@@ -49990,9 +50160,9 @@ async function migrateContextToKnowledge(directory, config3) {
|
|
|
49990
50160
|
skippedReason: "empty-context"
|
|
49991
50161
|
};
|
|
49992
50162
|
}
|
|
49993
|
-
const rawEntries =
|
|
50163
|
+
const rawEntries = _internals24.parseContextMd(contextContent);
|
|
49994
50164
|
if (rawEntries.length === 0) {
|
|
49995
|
-
await
|
|
50165
|
+
await _internals24.writeSentinel(sentinelPath, 0, 0);
|
|
49996
50166
|
return {
|
|
49997
50167
|
migrated: true,
|
|
49998
50168
|
entriesMigrated: 0,
|
|
@@ -50003,10 +50173,10 @@ async function migrateContextToKnowledge(directory, config3) {
|
|
|
50003
50173
|
const existing = await readKnowledge(knowledgePath);
|
|
50004
50174
|
let migrated = 0;
|
|
50005
50175
|
let dropped = 0;
|
|
50006
|
-
const projectName =
|
|
50176
|
+
const projectName = _internals24.inferProjectName(directory);
|
|
50007
50177
|
for (const raw of rawEntries) {
|
|
50008
50178
|
if (config3.validation_enabled !== false) {
|
|
50009
|
-
const category = raw.categoryHint ??
|
|
50179
|
+
const category = raw.categoryHint ?? _internals24.inferCategoryFromText(raw.text);
|
|
50010
50180
|
const result = validateLesson(raw.text, existing.map((e) => e.lesson), {
|
|
50011
50181
|
category,
|
|
50012
50182
|
scope: "global",
|
|
@@ -50026,8 +50196,8 @@ async function migrateContextToKnowledge(directory, config3) {
|
|
|
50026
50196
|
const entry = {
|
|
50027
50197
|
id: randomUUID3(),
|
|
50028
50198
|
tier: "swarm",
|
|
50029
|
-
lesson:
|
|
50030
|
-
category: raw.categoryHint ??
|
|
50199
|
+
lesson: _internals24.truncateLesson(raw.text),
|
|
50200
|
+
category: raw.categoryHint ?? _internals24.inferCategoryFromText(raw.text),
|
|
50031
50201
|
tags: [...inferredTags, `migration:${raw.sourceSection}`],
|
|
50032
50202
|
scope: "global",
|
|
50033
50203
|
confidence: 0.3,
|
|
@@ -50050,7 +50220,7 @@ async function migrateContextToKnowledge(directory, config3) {
|
|
|
50050
50220
|
if (migrated > 0) {
|
|
50051
50221
|
await rewriteKnowledge(knowledgePath, existing);
|
|
50052
50222
|
}
|
|
50053
|
-
await
|
|
50223
|
+
await _internals24.writeSentinel(sentinelPath, migrated, dropped);
|
|
50054
50224
|
log(`[knowledge-migrator] Migrated ${migrated} entries, dropped ${dropped}`);
|
|
50055
50225
|
return {
|
|
50056
50226
|
migrated: true,
|
|
@@ -50059,8 +50229,125 @@ async function migrateContextToKnowledge(directory, config3) {
|
|
|
50059
50229
|
entriesTotal: rawEntries.length
|
|
50060
50230
|
};
|
|
50061
50231
|
}
|
|
50232
|
+
async function migrateHiveKnowledgeLegacy(config3) {
|
|
50233
|
+
const legacyHivePath = _internals24.resolveLegacyHiveKnowledgePath();
|
|
50234
|
+
const canonicalHivePath = resolveHiveKnowledgePath();
|
|
50235
|
+
const sentinelPath = path37.join(path37.dirname(canonicalHivePath), ".hive-knowledge-migrated");
|
|
50236
|
+
if (existsSync25(sentinelPath)) {
|
|
50237
|
+
return {
|
|
50238
|
+
migrated: false,
|
|
50239
|
+
entriesMigrated: 0,
|
|
50240
|
+
entriesDropped: 0,
|
|
50241
|
+
entriesTotal: 0,
|
|
50242
|
+
skippedReason: "sentinel-exists"
|
|
50243
|
+
};
|
|
50244
|
+
}
|
|
50245
|
+
if (!existsSync25(legacyHivePath)) {
|
|
50246
|
+
return {
|
|
50247
|
+
migrated: false,
|
|
50248
|
+
entriesMigrated: 0,
|
|
50249
|
+
entriesDropped: 0,
|
|
50250
|
+
entriesTotal: 0,
|
|
50251
|
+
skippedReason: "no-context-file"
|
|
50252
|
+
};
|
|
50253
|
+
}
|
|
50254
|
+
const legacyEntries = await readKnowledge(legacyHivePath);
|
|
50255
|
+
if (legacyEntries.length === 0) {
|
|
50256
|
+
await _internals24.writeSentinel(sentinelPath, 0, 0);
|
|
50257
|
+
return {
|
|
50258
|
+
migrated: true,
|
|
50259
|
+
entriesMigrated: 0,
|
|
50260
|
+
entriesDropped: 0,
|
|
50261
|
+
entriesTotal: 0
|
|
50262
|
+
};
|
|
50263
|
+
}
|
|
50264
|
+
const existingHiveEntries = await readKnowledge(canonicalHivePath);
|
|
50265
|
+
let migrated = 0;
|
|
50266
|
+
let dropped = 0;
|
|
50267
|
+
const entryErrors = [];
|
|
50268
|
+
for (const legacyEntry of legacyEntries) {
|
|
50269
|
+
try {
|
|
50270
|
+
const lesson = legacyEntry.lesson;
|
|
50271
|
+
if (!lesson || typeof lesson !== "string" || lesson.length < 15) {
|
|
50272
|
+
dropped++;
|
|
50273
|
+
continue;
|
|
50274
|
+
}
|
|
50275
|
+
const dup = findNearDuplicate(lesson, existingHiveEntries, config3.dedup_threshold ?? 0.6);
|
|
50276
|
+
if (dup) {
|
|
50277
|
+
dropped++;
|
|
50278
|
+
continue;
|
|
50279
|
+
}
|
|
50280
|
+
const category = legacyEntry.category || "process";
|
|
50281
|
+
const validationResult = validateLesson(lesson, existingHiveEntries.map((e) => e.lesson), {
|
|
50282
|
+
category,
|
|
50283
|
+
scope: "global",
|
|
50284
|
+
confidence: 0.3
|
|
50285
|
+
});
|
|
50286
|
+
if (!validationResult.valid) {
|
|
50287
|
+
const errorMsg = `Validation failed for legacy entry: ${validationResult.reason}`;
|
|
50288
|
+
entryErrors.push(errorMsg);
|
|
50289
|
+
warn(`[knowledge-migrator] ${errorMsg}`);
|
|
50290
|
+
dropped++;
|
|
50291
|
+
continue;
|
|
50292
|
+
}
|
|
50293
|
+
const confidence = legacyEntry.confidence ?? 0.8;
|
|
50294
|
+
const scopeTag = legacyEntry.scope_tag || "global";
|
|
50295
|
+
const legacyId = legacyEntry.id;
|
|
50296
|
+
const existingIds = new Set(existingHiveEntries.map((e) => e.id));
|
|
50297
|
+
const resolvedId = legacyId && existingIds.has(legacyId) ? randomUUID3() : legacyId || randomUUID3();
|
|
50298
|
+
if (legacyId && existingIds.has(legacyId)) {
|
|
50299
|
+
warn(`[knowledge-migrator] Legacy entry ID collision for "${legacyId}", generating new UUID`);
|
|
50300
|
+
}
|
|
50301
|
+
const newHiveEntry = {
|
|
50302
|
+
id: resolvedId,
|
|
50303
|
+
tier: "hive",
|
|
50304
|
+
lesson: _internals24.truncateLesson(lesson),
|
|
50305
|
+
category,
|
|
50306
|
+
tags: ["migration:legacy-hive"],
|
|
50307
|
+
scope: scopeTag,
|
|
50308
|
+
confidence: Math.min(Math.max(confidence, 0), 1),
|
|
50309
|
+
status: "established",
|
|
50310
|
+
confirmed_by: [],
|
|
50311
|
+
retrieval_outcomes: {
|
|
50312
|
+
applied_count: 0,
|
|
50313
|
+
succeeded_after_count: 0,
|
|
50314
|
+
failed_after_count: 0
|
|
50315
|
+
},
|
|
50316
|
+
schema_version: KNOWLEDGE_SCHEMA_VERSION,
|
|
50317
|
+
created_at: legacyEntry.created_at || new Date().toISOString(),
|
|
50318
|
+
updated_at: legacyEntry.updated_at || new Date().toISOString(),
|
|
50319
|
+
source_project: "legacy-promotion",
|
|
50320
|
+
encounter_score: 1
|
|
50321
|
+
};
|
|
50322
|
+
try {
|
|
50323
|
+
await _internals24.appendKnowledge(canonicalHivePath, newHiveEntry);
|
|
50324
|
+
existingHiveEntries.push(newHiveEntry);
|
|
50325
|
+
migrated++;
|
|
50326
|
+
} catch (appendError) {
|
|
50327
|
+
const errorMsg = `Failed to append entry: ${appendError instanceof Error ? appendError.message : String(appendError)}`;
|
|
50328
|
+
entryErrors.push(errorMsg);
|
|
50329
|
+
warn(`[knowledge-migrator] ${errorMsg}`);
|
|
50330
|
+
dropped++;
|
|
50331
|
+
}
|
|
50332
|
+
} catch (entryError) {
|
|
50333
|
+
const errorMsg = `Unexpected error processing legacy entry: ${entryError instanceof Error ? entryError.message : String(entryError)}`;
|
|
50334
|
+
entryErrors.push(errorMsg);
|
|
50335
|
+
warn(`[knowledge-migrator] ${errorMsg}`);
|
|
50336
|
+
dropped++;
|
|
50337
|
+
}
|
|
50338
|
+
}
|
|
50339
|
+
await _internals24.writeSentinel(sentinelPath, migrated, dropped);
|
|
50340
|
+
log(`[knowledge-migrator] Migrated ${migrated} legacy hive entries, dropped ${dropped}`);
|
|
50341
|
+
return {
|
|
50342
|
+
migrated: true,
|
|
50343
|
+
entriesMigrated: migrated,
|
|
50344
|
+
entriesDropped: dropped,
|
|
50345
|
+
entriesTotal: legacyEntries.length,
|
|
50346
|
+
...entryErrors.length > 0 && { entryErrors }
|
|
50347
|
+
};
|
|
50348
|
+
}
|
|
50062
50349
|
function parseContextMd(content) {
|
|
50063
|
-
const sections =
|
|
50350
|
+
const sections = _internals24.splitIntoSections(content);
|
|
50064
50351
|
const entries = [];
|
|
50065
50352
|
const seen = new Set;
|
|
50066
50353
|
const sectionPatterns = [
|
|
@@ -50076,7 +50363,7 @@ function parseContextMd(content) {
|
|
|
50076
50363
|
const match = sectionPatterns.find((sp) => sp.pattern.test(section.heading));
|
|
50077
50364
|
if (!match)
|
|
50078
50365
|
continue;
|
|
50079
|
-
const bullets =
|
|
50366
|
+
const bullets = _internals24.extractBullets(section.body);
|
|
50080
50367
|
for (const bullet of bullets) {
|
|
50081
50368
|
if (bullet.length < 15)
|
|
50082
50369
|
continue;
|
|
@@ -50085,9 +50372,9 @@ function parseContextMd(content) {
|
|
|
50085
50372
|
continue;
|
|
50086
50373
|
seen.add(normalized);
|
|
50087
50374
|
entries.push({
|
|
50088
|
-
text:
|
|
50375
|
+
text: _internals24.truncateLesson(bullet),
|
|
50089
50376
|
sourceSection: match.sourceSection,
|
|
50090
|
-
categoryHint:
|
|
50377
|
+
categoryHint: _internals24.inferCategoryFromText(bullet)
|
|
50091
50378
|
});
|
|
50092
50379
|
}
|
|
50093
50380
|
}
|
|
@@ -50180,21 +50467,37 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
50180
50467
|
await mkdir12(path37.dirname(sentinelPath), { recursive: true });
|
|
50181
50468
|
await writeFile10(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
|
|
50182
50469
|
}
|
|
50183
|
-
|
|
50470
|
+
function resolveLegacyHiveKnowledgePath() {
|
|
50471
|
+
const platform = process.platform;
|
|
50472
|
+
const home = process.env.HOME || os8.homedir();
|
|
50473
|
+
let dataDir;
|
|
50474
|
+
if (platform === "win32") {
|
|
50475
|
+
dataDir = path37.join(process.env.LOCALAPPDATA || path37.join(home, "AppData", "Local"), "opencode-swarm", "Data");
|
|
50476
|
+
} else if (platform === "darwin") {
|
|
50477
|
+
dataDir = path37.join(home, "Library", "Application Support", "opencode-swarm");
|
|
50478
|
+
} else {
|
|
50479
|
+
dataDir = path37.join(process.env.XDG_DATA_HOME || path37.join(home, ".local", "share"), "opencode-swarm");
|
|
50480
|
+
}
|
|
50481
|
+
return path37.join(dataDir, "hive-knowledge.jsonl");
|
|
50482
|
+
}
|
|
50483
|
+
var _internals24;
|
|
50184
50484
|
var init_knowledge_migrator = __esm(() => {
|
|
50185
50485
|
init_logger();
|
|
50186
50486
|
init_knowledge_store();
|
|
50187
50487
|
init_knowledge_validator();
|
|
50188
|
-
|
|
50488
|
+
_internals24 = {
|
|
50489
|
+
appendKnowledge,
|
|
50189
50490
|
migrateContextToKnowledge,
|
|
50190
50491
|
migrateKnowledgeToExternal,
|
|
50492
|
+
migrateHiveKnowledgeLegacy,
|
|
50191
50493
|
parseContextMd,
|
|
50192
50494
|
splitIntoSections,
|
|
50193
50495
|
extractBullets,
|
|
50194
50496
|
inferCategoryFromText,
|
|
50195
50497
|
truncateLesson: truncateLesson2,
|
|
50196
50498
|
inferProjectName,
|
|
50197
|
-
writeSentinel
|
|
50499
|
+
writeSentinel,
|
|
50500
|
+
resolveLegacyHiveKnowledgePath
|
|
50198
50501
|
};
|
|
50199
50502
|
});
|
|
50200
50503
|
|
|
@@ -50266,24 +50569,43 @@ async function handleKnowledgeRestoreCommand(directory, args) {
|
|
|
50266
50569
|
}
|
|
50267
50570
|
async function handleKnowledgeMigrateCommand(directory, args) {
|
|
50268
50571
|
const targetDir = args[0] || directory;
|
|
50572
|
+
const config3 = KnowledgeConfigSchema.parse({});
|
|
50269
50573
|
try {
|
|
50270
|
-
const
|
|
50271
|
-
|
|
50272
|
-
|
|
50574
|
+
const contextResult = await migrateContextToKnowledge(targetDir, config3);
|
|
50575
|
+
const hiveResult = await migrateHiveKnowledgeLegacy(config3);
|
|
50576
|
+
const messages = [];
|
|
50577
|
+
if (contextResult.skippedReason) {
|
|
50578
|
+
switch (contextResult.skippedReason) {
|
|
50273
50579
|
case "sentinel-exists":
|
|
50274
|
-
|
|
50580
|
+
messages.push("\u23ED Context migration already completed. Delete .swarm/.knowledge-migrated to re-run.");
|
|
50581
|
+
break;
|
|
50275
50582
|
case "no-context-file":
|
|
50276
|
-
|
|
50583
|
+
messages.push("\u2139\uFE0F No .swarm/context.md found \u2014 nothing to migrate.");
|
|
50584
|
+
break;
|
|
50277
50585
|
case "empty-context":
|
|
50278
|
-
|
|
50279
|
-
|
|
50280
|
-
return "\u26A0\uFE0F Migration skipped for an unknown reason.";
|
|
50586
|
+
messages.push("\u2139\uFE0F .swarm/context.md is empty \u2014 nothing to migrate.");
|
|
50587
|
+
break;
|
|
50281
50588
|
}
|
|
50589
|
+
} else {
|
|
50590
|
+
messages.push(`\u2705 Context migration: ${contextResult.entriesMigrated} entries added, ${contextResult.entriesDropped} dropped`);
|
|
50282
50591
|
}
|
|
50283
|
-
|
|
50592
|
+
if (hiveResult.skippedReason) {
|
|
50593
|
+
switch (hiveResult.skippedReason) {
|
|
50594
|
+
case "sentinel-exists":
|
|
50595
|
+
messages.push("\u23ED Hive legacy migration already completed. Delete the sentinel in the hive data dir to re-run.");
|
|
50596
|
+
break;
|
|
50597
|
+
case "no-context-file":
|
|
50598
|
+
messages.push("\u2139\uFE0F No legacy hive-knowledge.jsonl found \u2014 nothing to migrate.");
|
|
50599
|
+
break;
|
|
50600
|
+
}
|
|
50601
|
+
} else if (hiveResult.migrated) {
|
|
50602
|
+
messages.push(`\u2705 Hive legacy migration: ${hiveResult.entriesMigrated} entries added, ${hiveResult.entriesDropped} dropped`);
|
|
50603
|
+
}
|
|
50604
|
+
return messages.join(`
|
|
50605
|
+
`);
|
|
50284
50606
|
} catch (error93) {
|
|
50285
|
-
console.warn("[knowledge-command]
|
|
50286
|
-
return "\u274C Migration failed. Check
|
|
50607
|
+
console.warn("[knowledge-command] migration error:", error93 instanceof Error ? error93.message : String(error93));
|
|
50608
|
+
return "\u274C Migration failed. Check that knowledge source files are readable.";
|
|
50287
50609
|
}
|
|
50288
50610
|
}
|
|
50289
50611
|
async function handleKnowledgeListCommand(directory, _args) {
|
|
@@ -52836,7 +53158,7 @@ var init_gateway = __esm(() => {
|
|
|
52836
53158
|
|
|
52837
53159
|
// src/memory/evaluation.ts
|
|
52838
53160
|
import * as fs16 from "fs/promises";
|
|
52839
|
-
import * as
|
|
53161
|
+
import * as os9 from "os";
|
|
52840
53162
|
import * as path41 from "path";
|
|
52841
53163
|
async function evaluateMemoryRecallFixtures(options) {
|
|
52842
53164
|
const fixtureDirectory = path41.resolve(options.fixtureDirectory);
|
|
@@ -52848,7 +53170,7 @@ async function evaluateMemoryRecallFixtures(options) {
|
|
|
52848
53170
|
for (const fixture of fixtures) {
|
|
52849
53171
|
const materialized = materializeFixture(fixture);
|
|
52850
53172
|
for (const providerName of providers) {
|
|
52851
|
-
const tempRoot = await fs16.realpath(await fs16.mkdtemp(path41.join(
|
|
53173
|
+
const tempRoot = await fs16.realpath(await fs16.mkdtemp(path41.join(os9.tmpdir(), "swarm-memory-eval-")));
|
|
52852
53174
|
const provider = createEvaluationProvider(providerName, tempRoot);
|
|
52853
53175
|
try {
|
|
52854
53176
|
await provider.initialize?.();
|
|
@@ -53680,9 +54002,9 @@ var init_memory2 = __esm(() => {
|
|
|
53680
54002
|
|
|
53681
54003
|
// src/services/plan-service.ts
|
|
53682
54004
|
async function getPlanData(directory, phaseArg) {
|
|
53683
|
-
const plan = await
|
|
54005
|
+
const plan = await _internals25.loadPlanJsonOnly(directory);
|
|
53684
54006
|
if (plan) {
|
|
53685
|
-
const fullMarkdown =
|
|
54007
|
+
const fullMarkdown = _internals25.derivePlanMarkdown(plan);
|
|
53686
54008
|
if (phaseArg === undefined || phaseArg === null || phaseArg === "") {
|
|
53687
54009
|
return {
|
|
53688
54010
|
hasPlan: true,
|
|
@@ -53725,7 +54047,7 @@ async function getPlanData(directory, phaseArg) {
|
|
|
53725
54047
|
isLegacy: false
|
|
53726
54048
|
};
|
|
53727
54049
|
}
|
|
53728
|
-
const planContent = await
|
|
54050
|
+
const planContent = await _internals25.readSwarmFileAsync(directory, "plan.md");
|
|
53729
54051
|
if (!planContent) {
|
|
53730
54052
|
return {
|
|
53731
54053
|
hasPlan: false,
|
|
@@ -53821,11 +54143,11 @@ async function handlePlanCommand(directory, args) {
|
|
|
53821
54143
|
const planData = await getPlanData(directory, phaseArg);
|
|
53822
54144
|
return formatPlanMarkdown(planData);
|
|
53823
54145
|
}
|
|
53824
|
-
var
|
|
54146
|
+
var _internals25;
|
|
53825
54147
|
var init_plan_service = __esm(() => {
|
|
53826
54148
|
init_utils2();
|
|
53827
54149
|
init_manager();
|
|
53828
|
-
|
|
54150
|
+
_internals25 = {
|
|
53829
54151
|
loadPlanJsonOnly,
|
|
53830
54152
|
derivePlanMarkdown,
|
|
53831
54153
|
readSwarmFileAsync
|
|
@@ -53837,191 +54159,6 @@ var init_plan = __esm(() => {
|
|
|
53837
54159
|
init_plan_service();
|
|
53838
54160
|
});
|
|
53839
54161
|
|
|
53840
|
-
// src/commands/pr-ref.ts
|
|
53841
|
-
import { execSync as execSync3 } from "child_process";
|
|
53842
|
-
function sanitizeUrl2(raw) {
|
|
53843
|
-
let urlStr = raw.trim();
|
|
53844
|
-
urlStr = urlStr.replace(/\[\s*MODE\s*:[^\]]*\]/gi, "");
|
|
53845
|
-
const fragmentIdx = urlStr.indexOf("#");
|
|
53846
|
-
if (fragmentIdx !== -1) {
|
|
53847
|
-
urlStr = urlStr.slice(0, fragmentIdx);
|
|
53848
|
-
}
|
|
53849
|
-
const queryIdx = urlStr.indexOf("?");
|
|
53850
|
-
if (queryIdx !== -1) {
|
|
53851
|
-
urlStr = urlStr.slice(0, queryIdx);
|
|
53852
|
-
}
|
|
53853
|
-
urlStr = urlStr.replace(/^[A-Za-z][A-Za-z0-9+.-]*:\/\/[^@/]+@/, "https://");
|
|
53854
|
-
if (urlStr.length > MAX_URL_LEN2) {
|
|
53855
|
-
urlStr = urlStr.slice(0, MAX_URL_LEN2);
|
|
53856
|
-
}
|
|
53857
|
-
return urlStr.trim();
|
|
53858
|
-
}
|
|
53859
|
-
function sanitizeInstructions(raw) {
|
|
53860
|
-
const collapsed = raw.replace(/\s+/g, " ").trim();
|
|
53861
|
-
const stripped = collapsed.replace(/\[\s*MODE\s*:[^\]]*\]/gi, "");
|
|
53862
|
-
const normalized = stripped.replace(/\s+/g, " ").trim();
|
|
53863
|
-
if (normalized.length <= MAX_INSTRUCTIONS_LEN)
|
|
53864
|
-
return normalized;
|
|
53865
|
-
return `${normalized.slice(0, MAX_INSTRUCTIONS_LEN)}\u2026`;
|
|
53866
|
-
}
|
|
53867
|
-
function hasNonAsciiHostname(hostname5) {
|
|
53868
|
-
for (const ch of hostname5) {
|
|
53869
|
-
const cp = ch.codePointAt(0);
|
|
53870
|
-
if (cp !== undefined && cp > 127)
|
|
53871
|
-
return true;
|
|
53872
|
-
}
|
|
53873
|
-
return false;
|
|
53874
|
-
}
|
|
53875
|
-
function isPrivateHost2(url3) {
|
|
53876
|
-
const host = url3.hostname.toLowerCase();
|
|
53877
|
-
if (host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "0.0.0.0") {
|
|
53878
|
-
return true;
|
|
53879
|
-
}
|
|
53880
|
-
if (host.startsWith("localhost") || host === "localhost.com") {
|
|
53881
|
-
return true;
|
|
53882
|
-
}
|
|
53883
|
-
const ipv4Private = /^10\./;
|
|
53884
|
-
const ipv4172 = /^172\.(1[6-9]|2\d|3[0-1])\./;
|
|
53885
|
-
const ipv4192 = /^192\.168\./;
|
|
53886
|
-
const ipv6Private = /^fe80:/i;
|
|
53887
|
-
const ipv6Unique = /^f[cd][0-9a-f]{2}:/i;
|
|
53888
|
-
if (ipv4Private.test(host) || ipv4172.test(host) || ipv4192.test(host) || ipv6Private.test(host) || ipv6Unique.test(host)) {
|
|
53889
|
-
return true;
|
|
53890
|
-
}
|
|
53891
|
-
if (host.startsWith("::ffff:")) {
|
|
53892
|
-
const inner = host.slice(7);
|
|
53893
|
-
if (ipv4Private.test(inner) || ipv4172.test(inner) || ipv4192.test(inner)) {
|
|
53894
|
-
return true;
|
|
53895
|
-
}
|
|
53896
|
-
}
|
|
53897
|
-
return false;
|
|
53898
|
-
}
|
|
53899
|
-
function validateAndSanitizeUrl2(rawUrl) {
|
|
53900
|
-
const sanitized = sanitizeUrl2(rawUrl);
|
|
53901
|
-
if (!sanitized) {
|
|
53902
|
-
return { error: "Empty URL" };
|
|
53903
|
-
}
|
|
53904
|
-
if (!sanitized.startsWith("https://")) {
|
|
53905
|
-
return { error: "URL must use HTTPS scheme" };
|
|
53906
|
-
}
|
|
53907
|
-
try {
|
|
53908
|
-
const url3 = new URL(sanitized);
|
|
53909
|
-
if (hasNonAsciiHostname(url3.hostname)) {
|
|
53910
|
-
return { error: "Non-ASCII hostnames are not allowed" };
|
|
53911
|
-
}
|
|
53912
|
-
if (isPrivateHost2(url3)) {
|
|
53913
|
-
return { error: "Private or localhost URLs are not allowed" };
|
|
53914
|
-
}
|
|
53915
|
-
const githubPrPattern = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/pull\/([0-9]+)\/?$/;
|
|
53916
|
-
if (!githubPrPattern.test(sanitized)) {
|
|
53917
|
-
return {
|
|
53918
|
-
error: "URL must be a GitHub pull request URL (https://github.com/owner/repo/pull/N)"
|
|
53919
|
-
};
|
|
53920
|
-
}
|
|
53921
|
-
return { sanitized };
|
|
53922
|
-
} catch {
|
|
53923
|
-
return { error: "Invalid URL format" };
|
|
53924
|
-
}
|
|
53925
|
-
}
|
|
53926
|
-
function parsePrRef(input, cwd) {
|
|
53927
|
-
const urlMatch = input.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)\/?$/i);
|
|
53928
|
-
if (urlMatch) {
|
|
53929
|
-
return {
|
|
53930
|
-
owner: urlMatch[1],
|
|
53931
|
-
repo: urlMatch[2],
|
|
53932
|
-
number: parseInt(urlMatch[3], 10)
|
|
53933
|
-
};
|
|
53934
|
-
}
|
|
53935
|
-
const shorthandMatch = input.match(/^([^/]+)\/([^#]+)#(\d+)$/);
|
|
53936
|
-
if (shorthandMatch) {
|
|
53937
|
-
return {
|
|
53938
|
-
owner: shorthandMatch[1],
|
|
53939
|
-
repo: shorthandMatch[2],
|
|
53940
|
-
number: parseInt(shorthandMatch[3], 10)
|
|
53941
|
-
};
|
|
53942
|
-
}
|
|
53943
|
-
const bareMatch = input.match(/^(\d+)$/);
|
|
53944
|
-
if (bareMatch) {
|
|
53945
|
-
const prNumber = parseInt(bareMatch[1], 10);
|
|
53946
|
-
const remoteUrl = detectGitRemote2(cwd);
|
|
53947
|
-
if (!remoteUrl) {
|
|
53948
|
-
return null;
|
|
53949
|
-
}
|
|
53950
|
-
const parsed = parseGitRemoteUrl2(remoteUrl);
|
|
53951
|
-
if (!parsed) {
|
|
53952
|
-
return null;
|
|
53953
|
-
}
|
|
53954
|
-
return {
|
|
53955
|
-
owner: parsed.owner,
|
|
53956
|
-
repo: parsed.repo,
|
|
53957
|
-
number: prNumber
|
|
53958
|
-
};
|
|
53959
|
-
}
|
|
53960
|
-
return null;
|
|
53961
|
-
}
|
|
53962
|
-
function detectGitRemote2(cwd) {
|
|
53963
|
-
try {
|
|
53964
|
-
const remoteUrl = _internals25.execSync("git remote get-url origin", {
|
|
53965
|
-
encoding: "utf-8",
|
|
53966
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
53967
|
-
timeout: 5000,
|
|
53968
|
-
...cwd ? { cwd } : {}
|
|
53969
|
-
}).trim();
|
|
53970
|
-
return remoteUrl || null;
|
|
53971
|
-
} catch {
|
|
53972
|
-
return null;
|
|
53973
|
-
}
|
|
53974
|
-
}
|
|
53975
|
-
function parseGitRemoteUrl2(remoteUrl) {
|
|
53976
|
-
const httpsMatch = remoteUrl.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/i);
|
|
53977
|
-
if (httpsMatch) {
|
|
53978
|
-
return {
|
|
53979
|
-
owner: httpsMatch[1],
|
|
53980
|
-
repo: httpsMatch[2].replace(/\.git$/, "")
|
|
53981
|
-
};
|
|
53982
|
-
}
|
|
53983
|
-
const sshMatch = remoteUrl.match(/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/i);
|
|
53984
|
-
if (sshMatch) {
|
|
53985
|
-
return {
|
|
53986
|
-
owner: sshMatch[1],
|
|
53987
|
-
repo: sshMatch[2].replace(/\.git$/, "")
|
|
53988
|
-
};
|
|
53989
|
-
}
|
|
53990
|
-
const pathMatch = remoteUrl.match(/\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
|
|
53991
|
-
if (pathMatch) {
|
|
53992
|
-
return {
|
|
53993
|
-
owner: pathMatch[1],
|
|
53994
|
-
repo: pathMatch[2].replace(/\.git$/, "")
|
|
53995
|
-
};
|
|
53996
|
-
}
|
|
53997
|
-
return null;
|
|
53998
|
-
}
|
|
53999
|
-
function looksLikePrRef(token) {
|
|
54000
|
-
return /^https?:\/\//i.test(token) || /^[^/]+\/[^#]+#\d+$/.test(token) || /^\d+$/.test(token);
|
|
54001
|
-
}
|
|
54002
|
-
function resolvePrCommandInput(rest, cwd) {
|
|
54003
|
-
if (rest.length === 0) {
|
|
54004
|
-
return null;
|
|
54005
|
-
}
|
|
54006
|
-
const refToken = rest[0];
|
|
54007
|
-
const instructions = sanitizeInstructions(rest.slice(1).join(" "));
|
|
54008
|
-
const isFullUrl = /^https?:\/\//i.test(refToken);
|
|
54009
|
-
const prInfo = parsePrRef(isFullUrl ? sanitizeUrl2(refToken) : refToken, cwd);
|
|
54010
|
-
if (!prInfo) {
|
|
54011
|
-
return { error: `Could not parse PR reference from "${refToken}"` };
|
|
54012
|
-
}
|
|
54013
|
-
const prUrl = `https://github.com/${prInfo.owner}/${prInfo.repo}/pull/${prInfo.number}`;
|
|
54014
|
-
const result = validateAndSanitizeUrl2(prUrl);
|
|
54015
|
-
if ("error" in result) {
|
|
54016
|
-
return { error: result.error };
|
|
54017
|
-
}
|
|
54018
|
-
return { prUrl: result.sanitized, instructions };
|
|
54019
|
-
}
|
|
54020
|
-
var _internals25, MAX_URL_LEN2 = 2048, MAX_INSTRUCTIONS_LEN = 1000;
|
|
54021
|
-
var init_pr_ref = __esm(() => {
|
|
54022
|
-
_internals25 = { execSync: execSync3 };
|
|
54023
|
-
});
|
|
54024
|
-
|
|
54025
54162
|
// src/commands/pr-feedback.ts
|
|
54026
54163
|
function handlePrFeedbackCommand(directory, args) {
|
|
54027
54164
|
const rest = args.filter((t) => t.trim().length > 0);
|
|
@@ -63980,7 +64117,7 @@ init_registry();
|
|
|
63980
64117
|
init_cache_paths();
|
|
63981
64118
|
init_constants();
|
|
63982
64119
|
import * as fs36 from "fs";
|
|
63983
|
-
import * as
|
|
64120
|
+
import * as os10 from "os";
|
|
63984
64121
|
import * as path64 from "path";
|
|
63985
64122
|
var { version: version5 } = package_default;
|
|
63986
64123
|
var CONFIG_DIR = getPluginConfigDir();
|
|
@@ -63991,7 +64128,7 @@ var OPENCODE_PLUGIN_CACHE_PATHS = getPluginCachePaths();
|
|
|
63991
64128
|
var OPENCODE_PLUGIN_LOCK_FILE_PATHS = getPluginLockFilePaths();
|
|
63992
64129
|
function isSafeCachePath(p) {
|
|
63993
64130
|
const resolved = path64.resolve(p);
|
|
63994
|
-
const home = path64.resolve(
|
|
64131
|
+
const home = path64.resolve(os10.homedir());
|
|
63995
64132
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
63996
64133
|
return false;
|
|
63997
64134
|
}
|
|
@@ -64015,7 +64152,7 @@ function isSafeCachePath(p) {
|
|
|
64015
64152
|
}
|
|
64016
64153
|
function isSafeLockFilePath(p) {
|
|
64017
64154
|
const resolved = path64.resolve(p);
|
|
64018
|
-
const home = path64.resolve(
|
|
64155
|
+
const home = path64.resolve(os10.homedir());
|
|
64019
64156
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
64020
64157
|
return false;
|
|
64021
64158
|
}
|