replicas-engine 0.1.412 → 0.1.414
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/src/index.js +270 -45
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -481,7 +481,7 @@ var WORKSPACE_SIZES = ["small", "large"];
|
|
|
481
481
|
var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
|
|
482
482
|
|
|
483
483
|
// ../shared/src/e2b.ts
|
|
484
|
-
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-09-
|
|
484
|
+
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-09-v3";
|
|
485
485
|
|
|
486
486
|
// ../shared/src/runtime-env.ts
|
|
487
487
|
function parsePosixEnvFile(content) {
|
|
@@ -1418,59 +1418,26 @@ var GOOGLE_ABILITY = {
|
|
|
1418
1418
|
|
|
1419
1419
|
// ../shared/src/default-skills/replicas-agent/abilities/learnings.ts
|
|
1420
1420
|
var SECTION6 = `### Learnings
|
|
1421
|
-
|
|
1421
|
+
Propose additions, updates, or deletions to curated organization knowledge.
|
|
1422
1422
|
|
|
1423
|
-
**Reference:** \`references/LEARNINGS.md
|
|
1424
|
-
|
|
1425
|
-
Use this when:
|
|
1426
|
-
- You are starting a substantive task and have gathered enough context to write a meaningful query
|
|
1427
|
-
- A user corrects you about a durable fact, preference, or process worth keeping
|
|
1428
|
-
- You find an existing learning contradicted by the current code or docs`;
|
|
1423
|
+
**Reference:** \`references/LEARNINGS.md\``;
|
|
1429
1424
|
var REFERENCE6 = `# Learnings
|
|
1430
1425
|
|
|
1431
|
-
Learnings are curated, human-approved knowledge entries your organization maintains: conventions, gotchas, environment facts, and process rules.
|
|
1432
|
-
|
|
1433
|
-
## Reading Learnings
|
|
1434
|
-
|
|
1435
|
-
\`\`\`bash
|
|
1436
|
-
replicas learnings read --query "<enriched query>"
|
|
1437
|
-
\`\`\`
|
|
1438
|
-
|
|
1439
|
-
**When to read:** once you've collected enough context to write a meaningful query \u2014 typically after your first look at the relevant code. Don't wait until you're deep into execution; learnings are most valuable before you commit to an approach.
|
|
1440
|
-
|
|
1441
|
-
**Enrich the query.** Use codebase specifics (feature area, module/component names), not the raw user request. Triggers describe *situations*, so a query grounded in what the task actually touches matches far better.
|
|
1442
|
-
|
|
1443
|
-
Example: the user asks "remove the PRs chart projections". After locating the chart you know it lives in the platform admin dashboard, so query:
|
|
1444
|
-
|
|
1445
|
-
\`\`\`bash
|
|
1446
|
-
replicas learnings read --query "Remove the PRs chart in the platform admin dashboard"
|
|
1447
|
-
\`\`\`
|
|
1448
|
-
|
|
1449
|
-
This matches a learning triggered on "UI/UX work on the admin panel" that the raw request would have missed.
|
|
1450
|
-
|
|
1451
|
-
Output is a list of blocks \u2014 id, name, and content. Use the ids to propose updates or deletions.
|
|
1452
|
-
|
|
1453
|
-
## Proposing changes
|
|
1426
|
+
Learnings are curated, human-approved knowledge entries your organization maintains: conventions, gotchas, environment facts, and process rules.
|
|
1454
1427
|
|
|
1455
1428
|
All writes are proposals: a human reviews them in the dashboard, and nothing takes effect until approved.
|
|
1456
1429
|
|
|
1457
|
-
|
|
1458
|
-
replicas learnings add --name "<short name>" --content "<the knowledge>" [--trigger "<when to surface it>"] [--always] [--global]
|
|
1459
|
-
replicas learnings update <id> [--name "..."] [--content "..."] [--trigger "..."] [--always true|false]
|
|
1460
|
-
replicas learnings delete <id>
|
|
1461
|
-
\`\`\`
|
|
1462
|
-
|
|
1463
|
-
\`--always\` marks an entry as always-returned (no trigger needed); \`--global\` proposes org-wide scope instead of this workspace's environment.
|
|
1430
|
+
Use \`replicas learnings --help\` and subcommand help such as \`replicas learnings add --help\`, \`replicas learnings update --help\`, or \`replicas learnings delete --help\` for current command syntax.
|
|
1464
1431
|
|
|
1465
1432
|
**Be very conservative:**
|
|
1466
|
-
- Propose \`add\` only for
|
|
1433
|
+
- Propose \`add\` only for repeatable, org-useful facts likely to matter again: explicit user corrections, hard-won environment or process knowledge.
|
|
1467
1434
|
- Never store task-specific details, anything derivable by reading the repo, or secrets/credentials.
|
|
1468
|
-
- Propose \`update\` or \`delete\` when a learning is contradicted by the current code or docs
|
|
1435
|
+
- Propose \`update\` or \`delete\` when a learning is contradicted by the current code or docs, especially if the outdated guidance would affect future repeated work.
|
|
1469
1436
|
- Write narrow triggers describing when the entry should surface (e.g. "UI/UX work on the admin panel"), not vague topics.`;
|
|
1470
1437
|
var LEARNINGS_ABILITY = {
|
|
1471
1438
|
label: "Learnings",
|
|
1472
|
-
description: "
|
|
1473
|
-
bullet: "-
|
|
1439
|
+
description: "Propose changes to curated org knowledge for human review.",
|
|
1440
|
+
bullet: "- Proposing changes to organization Learnings (curated, human-approved knowledge)",
|
|
1474
1441
|
section: SECTION6,
|
|
1475
1442
|
referenceFile: { name: "LEARNINGS.md", content: REFERENCE6 }
|
|
1476
1443
|
};
|
|
@@ -2736,6 +2703,11 @@ function extractCommandProtectionCommandText(request, options = {}) {
|
|
|
2736
2703
|
for (const key of COMMAND_PROTECTION_COMMAND_KEYS) {
|
|
2737
2704
|
const value = input[key];
|
|
2738
2705
|
if (typeof value === "string" && value.trim()) return value;
|
|
2706
|
+
if (Array.isArray(value) && value.every((item) => typeof item === "string")) return value.join(" ");
|
|
2707
|
+
}
|
|
2708
|
+
if (isRecord(input.args)) {
|
|
2709
|
+
const nested = extractCommandProtectionCommandText({ toolInput: input.args }, options);
|
|
2710
|
+
if (nested) return nested;
|
|
2739
2711
|
}
|
|
2740
2712
|
}
|
|
2741
2713
|
if (typeof input === "string") return input;
|
|
@@ -6541,6 +6513,7 @@ var LinearEventForwarder = class {
|
|
|
6541
6513
|
};
|
|
6542
6514
|
|
|
6543
6515
|
// src/services/command-protection-service.ts
|
|
6516
|
+
var DEFAULT_COMMAND_PROTECTION_BLOCK_MESSAGE = "Blocked by organization policy: agents may not merge pull requests.";
|
|
6544
6517
|
function asCommandProtectionResponse(value) {
|
|
6545
6518
|
if (typeof value !== "object" || value === null) return null;
|
|
6546
6519
|
const candidate = value;
|
|
@@ -6585,6 +6558,17 @@ async function evaluateCommandProtection(request, signal) {
|
|
|
6585
6558
|
function extractToolCommand(input) {
|
|
6586
6559
|
return extractCommandProtectionCommandText({ toolInput: input }, { stringifyFallback: false });
|
|
6587
6560
|
}
|
|
6561
|
+
function reportCommandProtectionBlock(options) {
|
|
6562
|
+
const message = options.result.reason || DEFAULT_COMMAND_PROTECTION_BLOCK_MESSAGE;
|
|
6563
|
+
console.warn(`[${options.managerName}] blocked ${options.action} by PR merge policy: ${message}`);
|
|
6564
|
+
options.recordHistoryEvent(options.eventType, {
|
|
6565
|
+
type: "error",
|
|
6566
|
+
message,
|
|
6567
|
+
...options.context,
|
|
6568
|
+
command: options.command
|
|
6569
|
+
}, options.historyFile);
|
|
6570
|
+
return message;
|
|
6571
|
+
}
|
|
6588
6572
|
|
|
6589
6573
|
// src/services/skill-registry-service.ts
|
|
6590
6574
|
import { readFile as readFile8, readdir as readdir3, stat as stat2 } from "fs/promises";
|
|
@@ -8232,7 +8216,7 @@ var AspClient = class {
|
|
|
8232
8216
|
// src/managers/codex-asp/app-server-process.ts
|
|
8233
8217
|
var DEFAULT_CODEX_BINARY = "codex";
|
|
8234
8218
|
var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
|
|
8235
|
-
var ENGINE_PACKAGE_VERSION = "0.1.
|
|
8219
|
+
var ENGINE_PACKAGE_VERSION = "0.1.414";
|
|
8236
8220
|
var INITIALIZE_METHOD = "initialize";
|
|
8237
8221
|
var INITIALIZED_NOTIFICATION = "initialized";
|
|
8238
8222
|
var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
|
|
@@ -10348,6 +10332,24 @@ function extractCursorCommandDescription(content) {
|
|
|
10348
10332
|
}
|
|
10349
10333
|
return void 0;
|
|
10350
10334
|
}
|
|
10335
|
+
function cursorToolInputFromDelta(update) {
|
|
10336
|
+
if (update.type !== "tool-call-started") return null;
|
|
10337
|
+
const toolCall = update.toolCall;
|
|
10338
|
+
return {
|
|
10339
|
+
toolName: toolCall.type,
|
|
10340
|
+
toolInput: toolCall,
|
|
10341
|
+
command: extractToolCommand(toolCall),
|
|
10342
|
+
toolUseId: update.callId
|
|
10343
|
+
};
|
|
10344
|
+
}
|
|
10345
|
+
function cursorToolInputFromMessage(event) {
|
|
10346
|
+
return {
|
|
10347
|
+
toolName: event.name,
|
|
10348
|
+
toolInput: event.args ?? {},
|
|
10349
|
+
command: extractToolCommand(event.args),
|
|
10350
|
+
toolUseId: event.call_id
|
|
10351
|
+
};
|
|
10352
|
+
}
|
|
10351
10353
|
async function listCursorCommandsInDirectory(directory) {
|
|
10352
10354
|
let entries;
|
|
10353
10355
|
try {
|
|
@@ -10373,6 +10375,8 @@ var CursorManager = class extends CodingAgentManager {
|
|
|
10373
10375
|
agent = null;
|
|
10374
10376
|
activeRun = null;
|
|
10375
10377
|
activeModel = null;
|
|
10378
|
+
blockedToolCallIds = /* @__PURE__ */ new Set();
|
|
10379
|
+
pendingCursorBlockReason = null;
|
|
10376
10380
|
historyFilePath;
|
|
10377
10381
|
historyFile;
|
|
10378
10382
|
slashCommandsCache = null;
|
|
@@ -10451,12 +10455,22 @@ var CursorManager = class extends CodingAgentManager {
|
|
|
10451
10455
|
}, this.historyFile);
|
|
10452
10456
|
const run = await agent.send(message, {
|
|
10453
10457
|
model: { id: model },
|
|
10454
|
-
mode: request.planMode ? "plan" : "agent"
|
|
10458
|
+
mode: request.planMode ? "plan" : "agent",
|
|
10459
|
+
onDelta: async (args) => {
|
|
10460
|
+
await this.handleCursorToolCall(cursorToolInputFromDelta(args.update));
|
|
10461
|
+
}
|
|
10455
10462
|
});
|
|
10456
10463
|
this.activeRun = run;
|
|
10457
10464
|
this.activeModel = model;
|
|
10465
|
+
if (this.pendingCursorBlockReason) {
|
|
10466
|
+
await run.cancel();
|
|
10467
|
+
throw new Error(this.pendingCursorBlockReason);
|
|
10468
|
+
}
|
|
10458
10469
|
for await (const event of run.stream()) {
|
|
10459
10470
|
this.recordCursorEvent(event);
|
|
10471
|
+
if (event.type === "tool_call" && event.status === "running") {
|
|
10472
|
+
await this.handleCursorToolCall(cursorToolInputFromMessage(event));
|
|
10473
|
+
}
|
|
10460
10474
|
if (linearSessionId) {
|
|
10461
10475
|
linearForwarder.sendEvent(convertCursorEvent(event, linearSessionId));
|
|
10462
10476
|
}
|
|
@@ -10479,10 +10493,45 @@ var CursorManager = class extends CodingAgentManager {
|
|
|
10479
10493
|
} finally {
|
|
10480
10494
|
this.activeRun = null;
|
|
10481
10495
|
this.activeModel = null;
|
|
10496
|
+
this.blockedToolCallIds.clear();
|
|
10497
|
+
this.pendingCursorBlockReason = null;
|
|
10482
10498
|
await this.historyFile.flush();
|
|
10483
10499
|
await this.onTurnComplete();
|
|
10484
10500
|
}
|
|
10485
10501
|
}
|
|
10502
|
+
async handleCursorToolCall(toolCall) {
|
|
10503
|
+
if (!ENGINE_ENV.REPLICAS_DISABLE_GH_PR_MERGE || !toolCall) return;
|
|
10504
|
+
if (this.blockedToolCallIds.has(toolCall.toolUseId)) return;
|
|
10505
|
+
const result = await evaluateCommandProtection({
|
|
10506
|
+
provider: "cursor",
|
|
10507
|
+
source: "cursor_tool_call",
|
|
10508
|
+
toolName: toolCall.toolName,
|
|
10509
|
+
toolInput: toolCall.toolInput,
|
|
10510
|
+
command: toolCall.command,
|
|
10511
|
+
cwd: this.workingDirectory,
|
|
10512
|
+
toolUseId: toolCall.toolUseId
|
|
10513
|
+
});
|
|
10514
|
+
if (result.allowed) return;
|
|
10515
|
+
this.blockedToolCallIds.add(toolCall.toolUseId);
|
|
10516
|
+
const message = reportCommandProtectionBlock({
|
|
10517
|
+
managerName: "CursorManager",
|
|
10518
|
+
action: "tool call",
|
|
10519
|
+
eventType: "cursor-command-protection.blocked",
|
|
10520
|
+
result,
|
|
10521
|
+
command: toolCall.command,
|
|
10522
|
+
context: {
|
|
10523
|
+
toolName: toolCall.toolName,
|
|
10524
|
+
toolUseId: toolCall.toolUseId
|
|
10525
|
+
},
|
|
10526
|
+
historyFile: this.historyFile,
|
|
10527
|
+
recordHistoryEvent: this.recordHistoryEvent.bind(this)
|
|
10528
|
+
});
|
|
10529
|
+
if (this.activeRun) {
|
|
10530
|
+
await this.activeRun.cancel();
|
|
10531
|
+
throw new Error(message);
|
|
10532
|
+
}
|
|
10533
|
+
this.pendingCursorBlockReason = message;
|
|
10534
|
+
}
|
|
10486
10535
|
async toCursorMessage(request) {
|
|
10487
10536
|
if (!request.images || request.images.length === 0) {
|
|
10488
10537
|
return request.message;
|
|
@@ -10578,7 +10627,23 @@ var OPENCODE_SHIM_DIR = dirname6(fileURLToPath(new URL("../../scripts/opencode",
|
|
|
10578
10627
|
var OPENCODE_CONFIG_PATH = join18(ENGINE_ENV.HOME_DIR, ".config", "opencode", "opencode.json");
|
|
10579
10628
|
var OPENCODE_FETCH_DISPATCHER = new Agent({ headersTimeout: 0, bodyTimeout: 0 });
|
|
10580
10629
|
var OPENCODE_SERVER_STARTUP_TIMEOUT_MS = 3e4;
|
|
10581
|
-
var OPENCODE_WORKSPACE_PERMISSION =
|
|
10630
|
+
var OPENCODE_WORKSPACE_PERMISSION = {
|
|
10631
|
+
read: "allow",
|
|
10632
|
+
edit: "allow",
|
|
10633
|
+
glob: "allow",
|
|
10634
|
+
grep: "allow",
|
|
10635
|
+
list: "allow",
|
|
10636
|
+
bash: "ask",
|
|
10637
|
+
task: "allow",
|
|
10638
|
+
external_directory: "allow",
|
|
10639
|
+
todowrite: "allow",
|
|
10640
|
+
question: "allow",
|
|
10641
|
+
webfetch: "allow",
|
|
10642
|
+
websearch: "allow",
|
|
10643
|
+
lsp: "allow",
|
|
10644
|
+
doom_loop: "allow",
|
|
10645
|
+
skill: "allow"
|
|
10646
|
+
};
|
|
10582
10647
|
var OPENCODE_SLASH_COMMANDS_CACHE_MS = 3e4;
|
|
10583
10648
|
var OPENCODE_VARIANT_CANDIDATES_BY_THINKING_LEVEL = {
|
|
10584
10649
|
low: ["low"],
|
|
@@ -10710,6 +10775,27 @@ function opencodeErrorPayload(error) {
|
|
|
10710
10775
|
function opencodeFetch(input, init) {
|
|
10711
10776
|
return fetch(input, { ...init, dispatcher: OPENCODE_FETCH_DISPATCHER });
|
|
10712
10777
|
}
|
|
10778
|
+
function parseOpencodeToolInputText(text) {
|
|
10779
|
+
try {
|
|
10780
|
+
return JSON.parse(text);
|
|
10781
|
+
} catch {
|
|
10782
|
+
return { command: text };
|
|
10783
|
+
}
|
|
10784
|
+
}
|
|
10785
|
+
function opencodePermissionCommand(payload, toolInput) {
|
|
10786
|
+
const toolCommand = extractToolCommand(toolInput);
|
|
10787
|
+
if (toolCommand) return toolCommand;
|
|
10788
|
+
const payloadCommand = extractToolCommand(payload);
|
|
10789
|
+
if (payloadCommand) return payloadCommand;
|
|
10790
|
+
const resources = Array.isArray(payload.resources) ? payload.resources.filter((item) => typeof item === "string") : [];
|
|
10791
|
+
if (resources.length > 0) return resources.join(" ");
|
|
10792
|
+
const metadata = isRecord4(payload.metadata) ? payload.metadata : null;
|
|
10793
|
+
for (const key of ["command", "cmd", "pattern", "resource"]) {
|
|
10794
|
+
const value = metadata?.[key];
|
|
10795
|
+
if (typeof value === "string" && value.trim()) return value;
|
|
10796
|
+
}
|
|
10797
|
+
return null;
|
|
10798
|
+
}
|
|
10713
10799
|
var OpencodeManager = class extends CodingAgentManager {
|
|
10714
10800
|
client = null;
|
|
10715
10801
|
server = null;
|
|
@@ -10727,6 +10813,11 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
10727
10813
|
activeLinearForwarder = null;
|
|
10728
10814
|
forwardedLinearPartKeys = /* @__PURE__ */ new Set();
|
|
10729
10815
|
modelVariants = /* @__PURE__ */ new Map();
|
|
10816
|
+
handledPermissionRequestIds = /* @__PURE__ */ new Set();
|
|
10817
|
+
pendingPermissionRequestIds = /* @__PURE__ */ new Set();
|
|
10818
|
+
handledToolCallIds = /* @__PURE__ */ new Set();
|
|
10819
|
+
pendingToolCallIds = /* @__PURE__ */ new Set();
|
|
10820
|
+
opencodeToolInputs = /* @__PURE__ */ new Map();
|
|
10730
10821
|
slashCommandsCache = null;
|
|
10731
10822
|
slashCommandsRequest = null;
|
|
10732
10823
|
constructor(options) {
|
|
@@ -10931,6 +11022,11 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
10931
11022
|
this.activeAbortController = null;
|
|
10932
11023
|
this.activeLinearForwarder = null;
|
|
10933
11024
|
this.forwardedLinearPartKeys.clear();
|
|
11025
|
+
this.handledPermissionRequestIds.clear();
|
|
11026
|
+
this.pendingPermissionRequestIds.clear();
|
|
11027
|
+
this.handledToolCallIds.clear();
|
|
11028
|
+
this.pendingToolCallIds.clear();
|
|
11029
|
+
this.opencodeToolInputs.clear();
|
|
10934
11030
|
await this.historyFile.flush();
|
|
10935
11031
|
await this.onTurnComplete();
|
|
10936
11032
|
}
|
|
@@ -10968,12 +11064,141 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
10968
11064
|
if (typeof partSessionID === "string" && this.sessionId && partSessionID !== this.sessionId) return;
|
|
10969
11065
|
if (event.type === "message.part.updated" && isOpencodePart(part)) {
|
|
10970
11066
|
if (this.shouldRecordOpencodePart(part)) this.recordOpencodePart(part);
|
|
11067
|
+
this.handleOpencodePartProtection(part).catch((error) => {
|
|
11068
|
+
console.error("[OpencodeManager] Failed to evaluate Opencode tool part:", error);
|
|
11069
|
+
});
|
|
10971
11070
|
return;
|
|
10972
11071
|
}
|
|
10973
11072
|
if (event.type === "message.updated") this.recordOpencodeMessageRole(payload);
|
|
11073
|
+
if (event.type === "session.next.tool.input.ended") {
|
|
11074
|
+
const callId = typeof payload.callID === "string" ? payload.callID : void 0;
|
|
11075
|
+
if (callId && typeof payload.text === "string") {
|
|
11076
|
+
this.opencodeToolInputs.set(callId, parseOpencodeToolInputText(payload.text));
|
|
11077
|
+
}
|
|
11078
|
+
}
|
|
11079
|
+
if (event.type === "permission.v2.asked" || event.type === "permission.asked") {
|
|
11080
|
+
this.respondToOpencodePermission(event.type, payload).catch((error) => {
|
|
11081
|
+
console.error("[OpencodeManager] Failed to respond to Opencode permission:", error);
|
|
11082
|
+
});
|
|
11083
|
+
}
|
|
11084
|
+
if (event.type === "session.next.tool.called") {
|
|
11085
|
+
this.handleOpencodeToolCallProtection(payload).catch((error) => {
|
|
11086
|
+
console.error("[OpencodeManager] Failed to evaluate Opencode tool call:", error);
|
|
11087
|
+
});
|
|
11088
|
+
}
|
|
10974
11089
|
if (this.recordOpencodeNextPart(event.type, payload)) return;
|
|
10975
11090
|
this.recordHistoryEvent(`opencode-${event.type}`, payload, this.historyFile);
|
|
10976
11091
|
}
|
|
11092
|
+
async respondToOpencodePermission(type, payload) {
|
|
11093
|
+
if (!this.client) return;
|
|
11094
|
+
const requestId = typeof payload.id === "string" ? payload.id : void 0;
|
|
11095
|
+
const sessionId = typeof payload.sessionID === "string" ? payload.sessionID : this.sessionId ?? void 0;
|
|
11096
|
+
if (!requestId || !sessionId || this.handledPermissionRequestIds.has(requestId) || this.pendingPermissionRequestIds.has(requestId)) return;
|
|
11097
|
+
this.pendingPermissionRequestIds.add(requestId);
|
|
11098
|
+
try {
|
|
11099
|
+
const source = isRecord4(payload.source) ? payload.source : null;
|
|
11100
|
+
const callId = typeof source?.callID === "string" ? source.callID : isRecord4(payload.tool) && typeof payload.tool.callID === "string" ? payload.tool.callID : void 0;
|
|
11101
|
+
const toolInput = callId ? this.opencodeToolInputs.get(callId) ?? payload : payload;
|
|
11102
|
+
const command = opencodePermissionCommand(payload, toolInput);
|
|
11103
|
+
const result = ENGINE_ENV.REPLICAS_DISABLE_GH_PR_MERGE ? await evaluateCommandProtection({
|
|
11104
|
+
provider: "opencode",
|
|
11105
|
+
source: "opencode_permission_request",
|
|
11106
|
+
toolName: typeof payload.action === "string" ? payload.action : typeof payload.permission === "string" ? payload.permission : "permission",
|
|
11107
|
+
toolInput,
|
|
11108
|
+
command,
|
|
11109
|
+
cwd: this.workingDirectory,
|
|
11110
|
+
toolUseId: requestId
|
|
11111
|
+
}) : { allowed: true, enabled: false };
|
|
11112
|
+
const reply = result.allowed ? "once" : "reject";
|
|
11113
|
+
const message = result.allowed ? void 0 : reportCommandProtectionBlock({
|
|
11114
|
+
managerName: "OpencodeManager",
|
|
11115
|
+
action: "permission",
|
|
11116
|
+
eventType: "opencode-command-protection.blocked",
|
|
11117
|
+
result,
|
|
11118
|
+
command,
|
|
11119
|
+
context: {
|
|
11120
|
+
requestId
|
|
11121
|
+
},
|
|
11122
|
+
historyFile: this.historyFile,
|
|
11123
|
+
recordHistoryEvent: this.recordHistoryEvent.bind(this)
|
|
11124
|
+
});
|
|
11125
|
+
if (type === "permission.v2.asked") {
|
|
11126
|
+
await this.client.v2.session.permission.reply({
|
|
11127
|
+
sessionID: sessionId,
|
|
11128
|
+
requestID: requestId,
|
|
11129
|
+
reply,
|
|
11130
|
+
...message ? { message } : {}
|
|
11131
|
+
}, { throwOnError: true });
|
|
11132
|
+
} else {
|
|
11133
|
+
await this.client.permission.reply({
|
|
11134
|
+
requestID: requestId,
|
|
11135
|
+
directory: this.workingDirectory,
|
|
11136
|
+
reply,
|
|
11137
|
+
...message ? { message } : {}
|
|
11138
|
+
}, { throwOnError: true });
|
|
11139
|
+
}
|
|
11140
|
+
this.handledPermissionRequestIds.add(requestId);
|
|
11141
|
+
} finally {
|
|
11142
|
+
this.pendingPermissionRequestIds.delete(requestId);
|
|
11143
|
+
}
|
|
11144
|
+
}
|
|
11145
|
+
async handleOpencodeToolCallProtection(payload) {
|
|
11146
|
+
const callId = typeof payload.callID === "string" ? payload.callID : void 0;
|
|
11147
|
+
if (!callId || this.handledToolCallIds.has(callId)) return;
|
|
11148
|
+
const toolName = typeof payload.tool === "string" ? payload.tool : "tool";
|
|
11149
|
+
const input = isRecord4(payload.input) ? payload.input : {};
|
|
11150
|
+
this.opencodeToolInputs.set(callId, input);
|
|
11151
|
+
const command = extractToolCommand(input);
|
|
11152
|
+
await this.evaluateOpencodeToolProtection(toolName, input, command, callId);
|
|
11153
|
+
}
|
|
11154
|
+
async handleOpencodePartProtection(part) {
|
|
11155
|
+
if (part.type !== "tool") return;
|
|
11156
|
+
const state = part.state;
|
|
11157
|
+
if (state.status !== "running" && state.status !== "pending") return;
|
|
11158
|
+
await this.evaluateOpencodeToolProtection(part.tool, state.input, extractToolCommand(state.input), part.id);
|
|
11159
|
+
}
|
|
11160
|
+
async evaluateOpencodeToolProtection(toolName, toolInput, command, toolUseId) {
|
|
11161
|
+
if (!ENGINE_ENV.REPLICAS_DISABLE_GH_PR_MERGE || this.handledToolCallIds.has(toolUseId) || this.pendingToolCallIds.has(toolUseId)) return;
|
|
11162
|
+
this.pendingToolCallIds.add(toolUseId);
|
|
11163
|
+
try {
|
|
11164
|
+
const result = await evaluateCommandProtection({
|
|
11165
|
+
provider: "opencode",
|
|
11166
|
+
source: "opencode_tool_call",
|
|
11167
|
+
toolName,
|
|
11168
|
+
toolInput,
|
|
11169
|
+
command,
|
|
11170
|
+
cwd: this.workingDirectory,
|
|
11171
|
+
toolUseId
|
|
11172
|
+
});
|
|
11173
|
+
if (result.allowed) {
|
|
11174
|
+
this.handledToolCallIds.add(toolUseId);
|
|
11175
|
+
return;
|
|
11176
|
+
}
|
|
11177
|
+
const message = reportCommandProtectionBlock({
|
|
11178
|
+
managerName: "OpencodeManager",
|
|
11179
|
+
action: "tool call",
|
|
11180
|
+
eventType: "opencode-command-protection.blocked",
|
|
11181
|
+
result,
|
|
11182
|
+
command,
|
|
11183
|
+
context: {
|
|
11184
|
+
toolName,
|
|
11185
|
+
toolUseId
|
|
11186
|
+
},
|
|
11187
|
+
historyFile: this.historyFile,
|
|
11188
|
+
recordHistoryEvent: this.recordHistoryEvent.bind(this)
|
|
11189
|
+
});
|
|
11190
|
+
this.activeAbortController?.abort();
|
|
11191
|
+
if (this.client && this.sessionId) {
|
|
11192
|
+
await this.client.session.abort(
|
|
11193
|
+
{ sessionID: this.sessionId, directory: this.workingDirectory },
|
|
11194
|
+
{ throwOnError: true }
|
|
11195
|
+
);
|
|
11196
|
+
}
|
|
11197
|
+
this.handledToolCallIds.add(toolUseId);
|
|
11198
|
+
} finally {
|
|
11199
|
+
this.pendingToolCallIds.delete(toolUseId);
|
|
11200
|
+
}
|
|
11201
|
+
}
|
|
10977
11202
|
recordOpencodeMessageRole(payload) {
|
|
10978
11203
|
const info = isRecord4(payload.info) ? payload.info : null;
|
|
10979
11204
|
const id = typeof info?.id === "string" ? info.id : void 0;
|