replicas-engine 0.1.567 → 0.1.569
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 +128 -42
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -2114,7 +2114,7 @@ LENGTH=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE")
|
|
|
2114
2114
|
|
|
2115
2115
|
# 1. Reserve an upload URL + file ID.
|
|
2116
2116
|
RESERVE=$(curl -s -G "https://slack.com/api/files.getUploadURLExternal" \\
|
|
2117
|
-
-H "Authorization: Bearer $
|
|
2117
|
+
-H "Authorization: Bearer $REPLICAS_SLACK_BOT_TOKEN" \\
|
|
2118
2118
|
--data-urlencode "filename=$FILENAME" \\
|
|
2119
2119
|
--data-urlencode "length=$LENGTH")
|
|
2120
2120
|
UPLOAD_URL=$(echo "$RESERVE" | jq -r '.upload_url')
|
|
@@ -2129,7 +2129,7 @@ curl -s -X POST "$UPLOAD_URL" \\
|
|
|
2129
2129
|
|
|
2130
2130
|
# 3. Complete the upload, sharing it into the channel/thread with the dashboard link.
|
|
2131
2131
|
curl -s -X POST "https://slack.com/api/files.completeUploadExternal" \\
|
|
2132
|
-
-H "Authorization: Bearer $
|
|
2132
|
+
-H "Authorization: Bearer $REPLICAS_SLACK_BOT_TOKEN" \\
|
|
2133
2133
|
-H "Content-Type: application/json; charset=utf-8" \\
|
|
2134
2134
|
-d "{
|
|
2135
2135
|
\\"files\\": [{\\"id\\": \\"$FILE_ID\\", \\"title\\": \\"Screenshot\\"}],
|
|
@@ -2640,10 +2640,10 @@ This guide covers how to interact with Slack from within your Replicas workspace
|
|
|
2640
2640
|
|
|
2641
2641
|
## Prerequisites
|
|
2642
2642
|
|
|
2643
|
-
Check if the \`
|
|
2643
|
+
Check if the \`REPLICAS_SLACK_BOT_TOKEN\` environment variable is set:
|
|
2644
2644
|
|
|
2645
2645
|
\`\`\`bash
|
|
2646
|
-
echo "\${
|
|
2646
|
+
echo "\${REPLICAS_SLACK_BOT_TOKEN:+set}"
|
|
2647
2647
|
\`\`\`
|
|
2648
2648
|
|
|
2649
2649
|
- If **set**: Your workspace has Slack access. You can use the Slack Web API as described below.
|
|
@@ -2651,7 +2651,7 @@ echo "\${SLACK_BOT_TOKEN:+set}"
|
|
|
2651
2651
|
|
|
2652
2652
|
## Using the Slack API
|
|
2653
2653
|
|
|
2654
|
-
All requests use the \`$
|
|
2654
|
+
All requests use the \`$REPLICAS_SLACK_BOT_TOKEN\` for authentication via the Slack Web API.
|
|
2655
2655
|
|
|
2656
2656
|
### Fetching a Thread from a Slack Link
|
|
2657
2657
|
|
|
@@ -2662,14 +2662,14 @@ If you encounter a Slack message link (e.g. \`https://team.slack.com/archives/C0
|
|
|
2662
2662
|
|
|
2663
2663
|
\`\`\`bash
|
|
2664
2664
|
curl -s "https://slack.com/api/conversations.replies?channel=CHANNEL_ID&ts=THREAD_TS" \\
|
|
2665
|
-
-H "Authorization: Bearer $
|
|
2665
|
+
-H "Authorization: Bearer $REPLICAS_SLACK_BOT_TOKEN"
|
|
2666
2666
|
\`\`\`
|
|
2667
2667
|
|
|
2668
2668
|
### Sending a Message
|
|
2669
2669
|
|
|
2670
2670
|
\`\`\`bash
|
|
2671
2671
|
curl -s -X POST "https://slack.com/api/chat.postMessage" \\
|
|
2672
|
-
-H "Authorization: Bearer $
|
|
2672
|
+
-H "Authorization: Bearer $REPLICAS_SLACK_BOT_TOKEN" \\
|
|
2673
2673
|
-H "Content-Type: application/json" \\
|
|
2674
2674
|
-d '{
|
|
2675
2675
|
"channel": "CHANNEL_ID",
|
|
@@ -2708,7 +2708,7 @@ The channel and thread flags default to \`SLACK_CHANNEL_ID\` and \`SLACK_THREAD_
|
|
|
2708
2708
|
|
|
2709
2709
|
\`\`\`bash
|
|
2710
2710
|
curl -s "https://slack.com/api/search.messages?query=YOUR_SEARCH_QUERY" \\
|
|
2711
|
-
-H "Authorization: Bearer $
|
|
2711
|
+
-H "Authorization: Bearer $REPLICAS_SLACK_BOT_TOKEN"
|
|
2712
2712
|
\`\`\`
|
|
2713
2713
|
|
|
2714
2714
|
### Uploading Files
|
|
@@ -2722,7 +2722,7 @@ LENGTH=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE")
|
|
|
2722
2722
|
|
|
2723
2723
|
# 1. Reserve an upload URL + file ID.
|
|
2724
2724
|
RESERVE=$(curl -s -G "https://slack.com/api/files.getUploadURLExternal" \\
|
|
2725
|
-
-H "Authorization: Bearer $
|
|
2725
|
+
-H "Authorization: Bearer $REPLICAS_SLACK_BOT_TOKEN" \\
|
|
2726
2726
|
--data-urlencode "filename=$FILENAME" \\
|
|
2727
2727
|
--data-urlencode "length=$LENGTH")
|
|
2728
2728
|
UPLOAD_URL=$(echo "$RESERVE" | jq -r '.upload_url')
|
|
@@ -2737,7 +2737,7 @@ curl -s -X POST "$UPLOAD_URL" \\
|
|
|
2737
2737
|
|
|
2738
2738
|
# 3. Complete the upload and share into a channel (and optionally a thread).
|
|
2739
2739
|
curl -s -X POST "https://slack.com/api/files.completeUploadExternal" \\
|
|
2740
|
-
-H "Authorization: Bearer $
|
|
2740
|
+
-H "Authorization: Bearer $REPLICAS_SLACK_BOT_TOKEN" \\
|
|
2741
2741
|
-H "Content-Type: application/json; charset=utf-8" \\
|
|
2742
2742
|
-d "{
|
|
2743
2743
|
\\"files\\": [{\\"id\\": \\"$FILE_ID\\", \\"title\\": \\"File title\\"}],
|
|
@@ -4260,8 +4260,9 @@ function parseOpencodeEvents(events) {
|
|
|
4260
4260
|
if (event.type === "event_msg" && event.payload.type === "user_message") {
|
|
4261
4261
|
const message = event.payload.message;
|
|
4262
4262
|
if (typeof message === "string" && message.trim()) {
|
|
4263
|
+
const messageId = event.payload[USER_MESSAGE_ID_PAYLOAD_KEY];
|
|
4263
4264
|
messages.push({
|
|
4264
|
-
id: `opencode-user-${event.timestamp}
|
|
4265
|
+
id: typeof messageId === "string" ? messageId : `opencode-user-${event.timestamp}`,
|
|
4265
4266
|
type: "user",
|
|
4266
4267
|
content: message,
|
|
4267
4268
|
timestamp: event.timestamp
|
|
@@ -4273,7 +4274,7 @@ function parseOpencodeEvents(events) {
|
|
|
4273
4274
|
const error = assistantError(event.payload.info);
|
|
4274
4275
|
if (error) {
|
|
4275
4276
|
messages.push({
|
|
4276
|
-
id: `opencode
|
|
4277
|
+
id: `opencode-${event.type}-${event.timestamp}`,
|
|
4277
4278
|
type: "error",
|
|
4278
4279
|
message: error,
|
|
4279
4280
|
timestamp: event.timestamp
|
|
@@ -4284,7 +4285,7 @@ function parseOpencodeEvents(events) {
|
|
|
4284
4285
|
if (event.type === "opencode-error") {
|
|
4285
4286
|
const message = typeof event.payload.message === "string" ? event.payload.message : "Opencode run failed";
|
|
4286
4287
|
messages.push({
|
|
4287
|
-
id: `opencode
|
|
4288
|
+
id: `opencode-${event.type}-${event.timestamp}`,
|
|
4288
4289
|
type: "error",
|
|
4289
4290
|
message,
|
|
4290
4291
|
timestamp: event.timestamp
|
|
@@ -4295,7 +4296,7 @@ function parseOpencodeEvents(events) {
|
|
|
4295
4296
|
const tool2 = typeof event.payload.tool === "string" ? event.payload.tool : "tool";
|
|
4296
4297
|
const input = event.payload.input ?? event.payload.arguments;
|
|
4297
4298
|
const callId = typeof event.payload.callID === "string" ? event.payload.callID : null;
|
|
4298
|
-
const id2 = callId ? `opencode-${callId}` : `opencode-${event.
|
|
4299
|
+
const id2 = callId ? `opencode-${callId}` : `opencode-${event.type}-${event.timestamp}`;
|
|
4299
4300
|
upsertDisplayMessage(messages, createCallDisplayMessage({
|
|
4300
4301
|
id: id2,
|
|
4301
4302
|
server: "opencode",
|
|
@@ -4308,7 +4309,7 @@ function parseOpencodeEvents(events) {
|
|
|
4308
4309
|
}
|
|
4309
4310
|
const part = partFromEvent(event);
|
|
4310
4311
|
if (!part) continue;
|
|
4311
|
-
let id = `opencode-${event.
|
|
4312
|
+
let id = `opencode-${event.type}-${event.timestamp}`;
|
|
4312
4313
|
if (typeof part.callID === "string") id = `opencode-${part.callID}`;
|
|
4313
4314
|
else if (typeof part.id === "string") id = `opencode-${part.id}`;
|
|
4314
4315
|
const time = isRecord(part.time) ? part.time : null;
|
|
@@ -5252,38 +5253,81 @@ function stableString(value) {
|
|
|
5252
5253
|
return String(value);
|
|
5253
5254
|
}
|
|
5254
5255
|
}
|
|
5255
|
-
function
|
|
5256
|
-
if (
|
|
5257
|
-
|
|
5258
|
-
return false;
|
|
5256
|
+
function duplicateKey(message) {
|
|
5257
|
+
if (message.type === "user" || message.type === "agent" || message.type === "reasoning") {
|
|
5258
|
+
return JSON.stringify([message.type, message.content]);
|
|
5259
5259
|
}
|
|
5260
|
-
if (
|
|
5261
|
-
if (
|
|
5262
|
-
if (
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5260
|
+
if (message.type === "command") return JSON.stringify([message.type, message.command]);
|
|
5261
|
+
if (message.type === "web_search") return JSON.stringify([message.type, message.query]);
|
|
5262
|
+
if (message.type === "subagent") {
|
|
5263
|
+
return JSON.stringify([
|
|
5264
|
+
message.type,
|
|
5265
|
+
message.description,
|
|
5266
|
+
message.prompt,
|
|
5267
|
+
message.subagentType,
|
|
5268
|
+
message.model
|
|
5269
|
+
]);
|
|
5267
5270
|
}
|
|
5268
|
-
if (
|
|
5269
|
-
return
|
|
5271
|
+
if (message.type === "todo_list") {
|
|
5272
|
+
return JSON.stringify([message.type, stableString(message.items)]);
|
|
5270
5273
|
}
|
|
5271
|
-
if (
|
|
5272
|
-
return
|
|
5274
|
+
if (message.type === "patch") {
|
|
5275
|
+
return JSON.stringify([message.type, stableString(message.operations)]);
|
|
5273
5276
|
}
|
|
5274
|
-
if (
|
|
5275
|
-
return
|
|
5277
|
+
if (message.type === "tool_call") {
|
|
5278
|
+
return JSON.stringify([
|
|
5279
|
+
message.type,
|
|
5280
|
+
message.server,
|
|
5281
|
+
message.tool,
|
|
5282
|
+
stableString(message.input)
|
|
5283
|
+
]);
|
|
5276
5284
|
}
|
|
5277
|
-
return
|
|
5285
|
+
return null;
|
|
5286
|
+
}
|
|
5287
|
+
function duplicateBucketKey(message, bucketOffset = 0) {
|
|
5288
|
+
const key = duplicateKey(message);
|
|
5289
|
+
if (key === null) return null;
|
|
5290
|
+
const bucket = Math.floor(parseTimestampMs(message.timestamp) / DUPLICATE_WINDOW_MS) + bucketOffset;
|
|
5291
|
+
return JSON.stringify([bucket, key]);
|
|
5278
5292
|
}
|
|
5279
5293
|
function mergeCodexAspDisplayMessages(primary, supplemental) {
|
|
5280
5294
|
const merged = [...primary];
|
|
5295
|
+
const firstIndexById = /* @__PURE__ */ new Map();
|
|
5296
|
+
const indexesByDuplicateBucket = /* @__PURE__ */ new Map();
|
|
5297
|
+
const indexMessage = (message, index) => {
|
|
5298
|
+
if (!firstIndexById.has(message.id)) firstIndexById.set(message.id, index);
|
|
5299
|
+
const key = duplicateBucketKey(message);
|
|
5300
|
+
if (key === null) return;
|
|
5301
|
+
const indexes = indexesByDuplicateBucket.get(key) ?? /* @__PURE__ */ new Set();
|
|
5302
|
+
indexes.add(index);
|
|
5303
|
+
indexesByDuplicateBucket.set(key, indexes);
|
|
5304
|
+
};
|
|
5305
|
+
const unindexMessage = (message, index) => {
|
|
5306
|
+
const key = duplicateBucketKey(message);
|
|
5307
|
+
if (key === null) return;
|
|
5308
|
+
const indexes = indexesByDuplicateBucket.get(key);
|
|
5309
|
+
indexes?.delete(index);
|
|
5310
|
+
if (indexes?.size === 0) indexesByDuplicateBucket.delete(key);
|
|
5311
|
+
};
|
|
5312
|
+
merged.forEach(indexMessage);
|
|
5281
5313
|
for (const message of supplemental) {
|
|
5282
|
-
|
|
5283
|
-
if (duplicateIndex ===
|
|
5284
|
-
|
|
5314
|
+
let duplicateIndex = firstIndexById.get(message.id);
|
|
5315
|
+
if (duplicateIndex === void 0) {
|
|
5316
|
+
for (let bucketOffset = -1; bucketOffset <= 1; bucketOffset += 1) {
|
|
5317
|
+
const key = duplicateBucketKey(message, bucketOffset);
|
|
5318
|
+
for (const index of (key === null ? void 0 : indexesByDuplicateBucket.get(key)) ?? []) {
|
|
5319
|
+
if (nearTimestamp(merged[index].timestamp, message.timestamp) && (duplicateIndex === void 0 || index < duplicateIndex)) {
|
|
5320
|
+
duplicateIndex = index;
|
|
5321
|
+
}
|
|
5322
|
+
}
|
|
5323
|
+
}
|
|
5324
|
+
}
|
|
5325
|
+
if (duplicateIndex === void 0) {
|
|
5326
|
+
indexMessage(message, merged.push(message) - 1);
|
|
5285
5327
|
} else if (message.type === "user") {
|
|
5328
|
+
unindexMessage(merged[duplicateIndex], duplicateIndex);
|
|
5286
5329
|
merged[duplicateIndex] = { ...merged[duplicateIndex], timestamp: message.timestamp };
|
|
5330
|
+
indexMessage(merged[duplicateIndex], duplicateIndex);
|
|
5287
5331
|
}
|
|
5288
5332
|
}
|
|
5289
5333
|
return merged.map((message, index) => ({ message, index })).sort((a, b) => parseTimestampMs(a.message.timestamp) - parseTimestampMs(b.message.timestamp) || a.index - b.index).map(({ message }) => message);
|
|
@@ -5539,7 +5583,7 @@ function loadEngineEnv() {
|
|
|
5539
5583
|
WORKSPACE_ID: readEnv("WORKSPACE_ID"),
|
|
5540
5584
|
LINEAR_SESSION_ID: readEnv("LINEAR_SESSION_ID"),
|
|
5541
5585
|
LINEAR_ACCESS_TOKEN: readEnv("LINEAR_ACCESS_TOKEN"),
|
|
5542
|
-
|
|
5586
|
+
REPLICAS_SLACK_BOT_TOKEN: readEnv("REPLICAS_SLACK_BOT_TOKEN"),
|
|
5543
5587
|
SLACK_CHANNEL_ID: readEnv("SLACK_CHANNEL_ID"),
|
|
5544
5588
|
SLACK_THREAD_TS: readEnv("SLACK_THREAD_TS"),
|
|
5545
5589
|
ANTHROPIC_API_KEY: readEnv("ANTHROPIC_API_KEY"),
|
|
@@ -7174,7 +7218,7 @@ var EnvironmentDetailsService = class {
|
|
|
7174
7218
|
details.gitlabAccessConfigured = gitlabAccessConfigured;
|
|
7175
7219
|
details.gitlabCredentialsConfigured = gitlabAccessConfigured;
|
|
7176
7220
|
details.linearAccessConfigured = Boolean(ENGINE_ENV.LINEAR_SESSION_ID || ENGINE_ENV.LINEAR_ACCESS_TOKEN);
|
|
7177
|
-
details.slackAccessConfigured = Boolean(ENGINE_ENV.
|
|
7221
|
+
details.slackAccessConfigured = Boolean(ENGINE_ENV.REPLICAS_SLACK_BOT_TOKEN);
|
|
7178
7222
|
const freshRepos = repositories.map((repo) => ({
|
|
7179
7223
|
repositoryName: repo.name,
|
|
7180
7224
|
warmHookCompleted: "n/a",
|
|
@@ -8363,9 +8407,9 @@ async function fetchImageAsBase64(url, linearAccessToken) {
|
|
|
8363
8407
|
}
|
|
8364
8408
|
}
|
|
8365
8409
|
if (hostname === "files.slack.com") {
|
|
8366
|
-
const token = ENGINE_ENV.
|
|
8410
|
+
const token = ENGINE_ENV.REPLICAS_SLACK_BOT_TOKEN;
|
|
8367
8411
|
if (!token) {
|
|
8368
|
-
throw new Error(`Cannot fetch Slack file from ${url}:
|
|
8412
|
+
throw new Error(`Cannot fetch Slack file from ${url}: REPLICAS_SLACK_BOT_TOKEN is not configured`);
|
|
8369
8413
|
}
|
|
8370
8414
|
headers["Authorization"] = `Bearer ${token}`;
|
|
8371
8415
|
}
|
|
@@ -10732,7 +10776,7 @@ var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
|
|
|
10732
10776
|
var MIN_CODEX_CLI_VERSION = "0.144.6";
|
|
10733
10777
|
var CODEX_UPGRADE_TIMEOUT_MS = 12e4;
|
|
10734
10778
|
var codexCliVersionEnsured = null;
|
|
10735
|
-
var ENGINE_PACKAGE_VERSION = "0.1.
|
|
10779
|
+
var ENGINE_PACKAGE_VERSION = "0.1.569";
|
|
10736
10780
|
var INITIALIZE_METHOD = "initialize";
|
|
10737
10781
|
var INITIALIZED_NOTIFICATION = "initialized";
|
|
10738
10782
|
var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
|
|
@@ -11027,6 +11071,7 @@ var THREAD_GOAL_SET_METHOD = "thread/goal/set";
|
|
|
11027
11071
|
var THREAD_GOAL_GET_METHOD = "thread/goal/get";
|
|
11028
11072
|
var THREAD_GOAL_CLEAR_METHOD = "thread/goal/clear";
|
|
11029
11073
|
var THREAD_COMPACT_START_METHOD = "thread/compact/start";
|
|
11074
|
+
var THREAD_INJECT_ITEMS_METHOD = "thread/inject_items";
|
|
11030
11075
|
var THREAD_SETTINGS_UPDATE_METHOD = "thread/settings/update";
|
|
11031
11076
|
var TURN_START_METHOD = "turn/start";
|
|
11032
11077
|
var TURN_INTERRUPT_METHOD = "turn/interrupt";
|
|
@@ -11699,6 +11744,10 @@ var DuplicateDefaultChatError = class extends Error {
|
|
|
11699
11744
|
// src/managers/codex-asp/codex-asp-manager.ts
|
|
11700
11745
|
var GOAL_TURN_CONTINUATION_GRACE_MS = 5e3;
|
|
11701
11746
|
var CODEX_SLASH_COMMANDS_CACHE_MS = 3e4;
|
|
11747
|
+
var POLICY_REASON_INJECTION_TIMEOUT_MS = 5e3;
|
|
11748
|
+
function formatBlockedCommandReason(reason) {
|
|
11749
|
+
return reason?.includes("Blocked by organization policy") ? reason : `Blocked by organization policy: ${reason || "agents may not merge pull requests."}`;
|
|
11750
|
+
}
|
|
11702
11751
|
async function readCodexAspThreadHistory(threadId) {
|
|
11703
11752
|
let entries;
|
|
11704
11753
|
try {
|
|
@@ -12454,6 +12503,11 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
12454
12503
|
serverRequest.params.cwd,
|
|
12455
12504
|
serverRequest.params.commandActions
|
|
12456
12505
|
);
|
|
12506
|
+
await this.injectBlockedCommandReason(
|
|
12507
|
+
host,
|
|
12508
|
+
serverRequest.params.threadId,
|
|
12509
|
+
result.reason
|
|
12510
|
+
);
|
|
12457
12511
|
host.client.respond(requestId, { decision: "decline" });
|
|
12458
12512
|
return;
|
|
12459
12513
|
}
|
|
@@ -12490,6 +12544,11 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
12490
12544
|
serverRequest.params.cwd,
|
|
12491
12545
|
[{ type: "unknown", command }]
|
|
12492
12546
|
);
|
|
12547
|
+
await this.injectBlockedCommandReason(
|
|
12548
|
+
host,
|
|
12549
|
+
this.currentThreadId ?? serverRequest.params.conversationId,
|
|
12550
|
+
result.reason
|
|
12551
|
+
);
|
|
12493
12552
|
host.client.respond(requestId, { decision: "denied" });
|
|
12494
12553
|
return;
|
|
12495
12554
|
}
|
|
@@ -12540,11 +12599,38 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
12540
12599
|
}
|
|
12541
12600
|
host.client.reject(requestId, -32601, `Replicas does not support ASP server request ${method}`);
|
|
12542
12601
|
}
|
|
12602
|
+
async injectBlockedCommandReason(host, threadId, reason) {
|
|
12603
|
+
try {
|
|
12604
|
+
await host.client.request(
|
|
12605
|
+
THREAD_INJECT_ITEMS_METHOD,
|
|
12606
|
+
{
|
|
12607
|
+
threadId,
|
|
12608
|
+
items: [{
|
|
12609
|
+
type: "message",
|
|
12610
|
+
role: "developer",
|
|
12611
|
+
content: [{
|
|
12612
|
+
type: "input_text",
|
|
12613
|
+
text: [
|
|
12614
|
+
"<organization_policy>",
|
|
12615
|
+
"The command currently awaiting approval was rejected for this reason:",
|
|
12616
|
+
formatBlockedCommandReason(reason),
|
|
12617
|
+
"Do not retry the blocked command unchanged. Adjust your approach to comply with this policy.",
|
|
12618
|
+
"</organization_policy>"
|
|
12619
|
+
].join("\n")
|
|
12620
|
+
}]
|
|
12621
|
+
}]
|
|
12622
|
+
},
|
|
12623
|
+
{ timeoutMs: POLICY_REASON_INJECTION_TIMEOUT_MS }
|
|
12624
|
+
);
|
|
12625
|
+
} catch (error) {
|
|
12626
|
+
console.warn("[CodexAspManager] Failed to inject blocked command reason:", error);
|
|
12627
|
+
}
|
|
12628
|
+
}
|
|
12543
12629
|
nextTranscriptSequence() {
|
|
12544
12630
|
return this.codexAspSequence++;
|
|
12545
12631
|
}
|
|
12546
12632
|
recordBlockedCommand(threadId, turnId, itemId, command, reason, startedAtMs, cwd, commandActions) {
|
|
12547
|
-
const output = reason
|
|
12633
|
+
const output = formatBlockedCommandReason(reason);
|
|
12548
12634
|
const timestamp = timestampFromMilliseconds(startedAtMs);
|
|
12549
12635
|
const blockedItem = {
|
|
12550
12636
|
type: "commandExecution",
|