@wrongstack/core 0.306.0 → 0.306.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/chronicle/index.js +6 -1
- package/dist/chronicle/project-server.js +13 -3
- package/dist/coordination/index.d.ts +1 -0
- package/dist/coordination/index.js +210 -103
- package/dist/coordination/mailbox-codecs.d.ts +29 -10
- package/dist/coordination/mailbox-constants.d.ts +30 -16
- package/dist/coordination/mailbox-health.d.ts +16 -0
- package/dist/coordination/mailbox-http-validation.d.ts +2 -1
- package/dist/coordination/mailbox-parse-state.d.ts +28 -10
- package/dist/coordination/mailbox-project-server.js +136 -20
- package/dist/coordination/mailbox-types.d.ts +44 -6
- package/dist/coordination/package-outdated-watcher.d.ts +15 -1
- package/dist/coordination/sqlite-mailbox-credentials.d.ts +26 -0
- package/dist/coordination/sqlite-mailbox.d.ts +26 -0
- package/dist/coordination/techstack-mailbox-consumer.d.ts +17 -0
- package/dist/core/index.js +39 -12
- package/dist/defaults/index.js +58 -87
- package/dist/execution/index.js +10 -3
- package/dist/hq/index.js +6 -39
- package/dist/index.js +239 -153
- package/dist/infrastructure/index.js +6 -39
- package/dist/plugin/index.js +6 -2
- package/dist/security/file-permissions.d.ts +12 -35
- package/dist/security/index.js +8 -51
- package/dist/security/kanban-boundary.d.ts +3 -1
- package/dist/session-catalog/project-server.js +6 -39
- package/dist/storage/index.js +56 -49
- package/dist/types/blocks.d.ts +9 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +22 -0
- package/dist/utils/memory-evidence-fence.d.ts +47 -0
- package/instructions/agents/code-reviewer.md +3 -0
- package/instructions/coordination/subagent-baseline.md +10 -1
- package/instructions/system-lite.md +8 -5
- package/instructions/system-pro.md +26 -0
- package/instructions/system.md +21 -0
- package/package.json +3 -3
|
@@ -24,6 +24,23 @@ export interface TechStackConsumerOptions {
|
|
|
24
24
|
}>;
|
|
25
25
|
/** Agent id that the consumer watches for. Default: 'tech-stack'. */
|
|
26
26
|
targetAgent?: string | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* The only sender whose `assign` messages may spawn an agent. Default:
|
|
29
|
+
* `'dep-watcher'` — the `watcherAgentId` default of
|
|
30
|
+
* {@link attachDepWatcherBridge}, which is the pipeline this consumer exists
|
|
31
|
+
* to serve. Matched on the base identity, so a session-qualified
|
|
32
|
+
* `dep-watcher@<tag>` also passes.
|
|
33
|
+
*
|
|
34
|
+
* Without this the consumer acted on an `assign` addressed to `tech-stack`
|
|
35
|
+
* from ANY sender. The mailbox is a shared bus: every agent on the project
|
|
36
|
+
* can send one with `mail_send`, and so can any external credential holding
|
|
37
|
+
* `mail.send.actionable` when the HTTP bridge is enabled. The message body
|
|
38
|
+
* then chose a file path and was pasted verbatim into the task of a freshly
|
|
39
|
+
* spawned subagent holding `read`, `fetch` and `mailbox` — a peer-writable
|
|
40
|
+
* path into an agent that can read files, reach the network, and broadcast
|
|
41
|
+
* to everyone. Restricting the sender is what makes the spawn intentional.
|
|
42
|
+
*/
|
|
43
|
+
senderAgentId?: string | undefined;
|
|
27
44
|
/** Agent id that sends the completion ack. Default: 'tech-stack-consumer'. */
|
|
28
45
|
consumerAgentId?: string | undefined;
|
|
29
46
|
/** Polling interval in ms. Default: 5000. */
|
package/dist/core/index.js
CHANGED
|
@@ -1505,24 +1505,34 @@ var RemoteMailbox = class {
|
|
|
1505
1505
|
}
|
|
1506
1506
|
publishHqRegistryEvent(event, payload) {
|
|
1507
1507
|
const publisher = this.hqPublisher;
|
|
1508
|
-
if (!publisher || !event.startsWith("mailbox.agent_") && !event.startsWith("mailbox.client_")) {
|
|
1508
|
+
if (!publisher || this.closed || !event.startsWith("mailbox.agent_") && !event.startsWith("mailbox.client_")) {
|
|
1509
1509
|
return;
|
|
1510
1510
|
}
|
|
1511
1511
|
const mailboxId = `${path5.basename(this.projectDir)}:mailbox`;
|
|
1512
1512
|
const record = typeof payload === "object" && payload !== null ? payload : {};
|
|
1513
1513
|
const agentId = typeof record["agentId"] === "string" ? record["agentId"] : void 0;
|
|
1514
1514
|
const action = event === "mailbox.agent_registered" ? "agent.registered" : event === "mailbox.agent_heartbeat" ? "agent.heartbeat" : event === "mailbox.agent_deregistered" ? "agent.deregistered" : void 0;
|
|
1515
|
-
|
|
1516
|
-
const agent = agentId ? statuses.find((candidate) => candidate.agentId === agentId) : void 0;
|
|
1515
|
+
if (action !== "agent.registered") {
|
|
1517
1516
|
if (action) {
|
|
1518
1517
|
publisher.publishMailboxEvent({
|
|
1519
1518
|
mailboxId,
|
|
1520
1519
|
action,
|
|
1521
|
-
...agent ? { agent } : {},
|
|
1522
1520
|
...agentId ? { summary: agentId } : {}
|
|
1523
1521
|
});
|
|
1524
1522
|
}
|
|
1525
1523
|
if (action !== "agent.heartbeat") this.scheduleHqSnapshot(mailboxId);
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1526
|
+
void this.getAgentStatuses().then((statuses) => {
|
|
1527
|
+
if (this.closed) return;
|
|
1528
|
+
const agent = agentId ? statuses.find((candidate) => candidate.agentId === agentId) : void 0;
|
|
1529
|
+
publisher.publishMailboxEvent({
|
|
1530
|
+
mailboxId,
|
|
1531
|
+
action,
|
|
1532
|
+
...agent ? { agent } : {},
|
|
1533
|
+
...agentId ? { summary: agentId } : {}
|
|
1534
|
+
});
|
|
1535
|
+
this.scheduleHqSnapshot(mailboxId);
|
|
1526
1536
|
}).catch(() => {
|
|
1527
1537
|
});
|
|
1528
1538
|
}
|
|
@@ -1654,7 +1664,12 @@ import * as syncFs from "node:fs";
|
|
|
1654
1664
|
import * as path7 from "node:path";
|
|
1655
1665
|
|
|
1656
1666
|
// src/security/file-permissions.ts
|
|
1657
|
-
|
|
1667
|
+
import {
|
|
1668
|
+
restrictDirPermissions,
|
|
1669
|
+
restrictFilePermissions,
|
|
1670
|
+
SECRET_DIR_MODE,
|
|
1671
|
+
SECRET_FILE_MODE
|
|
1672
|
+
} from "@wrongstack/persistence";
|
|
1658
1673
|
|
|
1659
1674
|
// src/utils/pid.ts
|
|
1660
1675
|
function isPidAlive(pid) {
|
|
@@ -7389,6 +7404,24 @@ function deriveCachePrefixKey(systemPrompt) {
|
|
|
7389
7404
|
return key;
|
|
7390
7405
|
}
|
|
7391
7406
|
|
|
7407
|
+
// src/utils/memory-evidence-fence.ts
|
|
7408
|
+
var MEMORY_EVIDENCE_TAG = "memory_evidence";
|
|
7409
|
+
var FENCE_DELIMITER = /\[[ \t]*\/?[ \t]*memory_evidence\b[^\]\n]*\]/gi;
|
|
7410
|
+
function sanitizeMemoryEvidenceBody(text) {
|
|
7411
|
+
return text.replace(FENCE_DELIMITER, (match) => `(${match.slice(1, -1)})`);
|
|
7412
|
+
}
|
|
7413
|
+
function sanitizeMemoryEvidenceSource(source) {
|
|
7414
|
+
const collapsed = source.replace(/[^a-z0-9_.-]+/gi, "-").replace(/^-+|-+$/g, "").slice(0, 80).replace(/-+$/, "");
|
|
7415
|
+
return collapsed || "memory";
|
|
7416
|
+
}
|
|
7417
|
+
function formatMemoryEvidenceBlock(source, body) {
|
|
7418
|
+
const label = sanitizeMemoryEvidenceSource(source);
|
|
7419
|
+
const safe = sanitizeMemoryEvidenceBody(body);
|
|
7420
|
+
return `[${MEMORY_EVIDENCE_TAG} source="${label}"]
|
|
7421
|
+
${safe}
|
|
7422
|
+
[/${MEMORY_EVIDENCE_TAG}]`;
|
|
7423
|
+
}
|
|
7424
|
+
|
|
7392
7425
|
// src/utils/message-invariants.ts
|
|
7393
7426
|
function repairToolUseAdjacency(messages) {
|
|
7394
7427
|
const removedToolUses = [];
|
|
@@ -8014,15 +8047,9 @@ function buildMemoryEvidenceBlocks(ctx) {
|
|
|
8014
8047
|
if (remaining <= 0) break;
|
|
8015
8048
|
const text = entry.text.trim();
|
|
8016
8049
|
if (!text) continue;
|
|
8017
|
-
const source = entry.source.replace(/[^a-z0-9_.-]+/gi, "-").slice(0, 80) || "memory";
|
|
8018
8050
|
const bounded = text.slice(0, remaining);
|
|
8019
8051
|
remaining -= bounded.length;
|
|
8020
|
-
blocks.push({
|
|
8021
|
-
type: "text",
|
|
8022
|
-
text: `[memory_evidence source="${source}"]
|
|
8023
|
-
${bounded}
|
|
8024
|
-
[/memory_evidence]`
|
|
8025
|
-
});
|
|
8052
|
+
blocks.push({ type: "text", text: formatMemoryEvidenceBlock(entry.source, bounded) });
|
|
8026
8053
|
}
|
|
8027
8054
|
return blocks;
|
|
8028
8055
|
}
|
package/dist/defaults/index.js
CHANGED
|
@@ -9820,45 +9820,12 @@ import * as fsp17 from "node:fs/promises";
|
|
|
9820
9820
|
import * as path23 from "node:path";
|
|
9821
9821
|
|
|
9822
9822
|
// src/security/file-permissions.ts
|
|
9823
|
-
import {
|
|
9824
|
-
|
|
9825
|
-
|
|
9826
|
-
|
|
9827
|
-
|
|
9828
|
-
|
|
9829
|
-
try {
|
|
9830
|
-
const { execFile: execFile2 } = await import("node:child_process");
|
|
9831
|
-
const { promisify: promisify2 } = await import("node:util");
|
|
9832
|
-
const execFileAsync = promisify2(execFile2);
|
|
9833
|
-
const user = windowsAccountName();
|
|
9834
|
-
if (!user) {
|
|
9835
|
-
warn(
|
|
9836
|
-
`[${label}] Could not determine the current Windows user for ${filePath}; skipping icacls hardening.`
|
|
9837
|
-
);
|
|
9838
|
-
return;
|
|
9839
|
-
}
|
|
9840
|
-
await execFileAsync("icacls", [filePath, "/inheritance:r", "/grant:r", `${user}:(F)`], {
|
|
9841
|
-
windowsHide: true
|
|
9842
|
-
});
|
|
9843
|
-
} catch {
|
|
9844
|
-
warn(
|
|
9845
|
-
`[${label}] Could not restrict permissions on ${filePath} \u2014 it may be readable by other users on this system.`
|
|
9846
|
-
);
|
|
9847
|
-
}
|
|
9848
|
-
} else {
|
|
9849
|
-
try {
|
|
9850
|
-
await chmod(filePath, SECRET_FILE_MODE);
|
|
9851
|
-
} catch {
|
|
9852
|
-
}
|
|
9853
|
-
}
|
|
9854
|
-
}
|
|
9855
|
-
function windowsAccountName() {
|
|
9856
|
-
const username = process.env.USERNAME || process.env.USER;
|
|
9857
|
-
if (!username || username.includes("\0")) return void 0;
|
|
9858
|
-
const domain = process.env.USERDOMAIN;
|
|
9859
|
-
if (domain && !domain.includes("\0")) return `${domain}\\${username}`;
|
|
9860
|
-
return username;
|
|
9861
|
-
}
|
|
9823
|
+
import {
|
|
9824
|
+
restrictDirPermissions,
|
|
9825
|
+
restrictFilePermissions,
|
|
9826
|
+
SECRET_DIR_MODE,
|
|
9827
|
+
SECRET_FILE_MODE
|
|
9828
|
+
} from "@wrongstack/persistence";
|
|
9862
9829
|
|
|
9863
9830
|
// src/security/secret-scrubber.ts
|
|
9864
9831
|
var PATTERNS = [
|
|
@@ -14038,6 +14005,44 @@ function userInputTitle(content) {
|
|
|
14038
14005
|
return sessionContentPreview(content, 60);
|
|
14039
14006
|
}
|
|
14040
14007
|
|
|
14008
|
+
// src/storage/session-writer-scrubber.ts
|
|
14009
|
+
function scrubSessionWriterEvent(event, secretScrubber) {
|
|
14010
|
+
const persistMessage = (message) => {
|
|
14011
|
+
const { _estTokens: _ignored, ...persisted } = message;
|
|
14012
|
+
return {
|
|
14013
|
+
...persisted,
|
|
14014
|
+
content: typeof persisted.content === "string" ? secretScrubber?.scrub(persisted.content) ?? persisted.content : secretScrubber?.scrubObject(persisted.content) ?? persisted.content
|
|
14015
|
+
};
|
|
14016
|
+
};
|
|
14017
|
+
if (event.type === "context_snapshot" || event.type === "messages_replaced") {
|
|
14018
|
+
return { ...event, messages: event.messages.map(persistMessage) };
|
|
14019
|
+
}
|
|
14020
|
+
if (event.type === "message_appended" || event.type === "message_updated") {
|
|
14021
|
+
return { ...event, message: persistMessage(event.message) };
|
|
14022
|
+
}
|
|
14023
|
+
if (!secretScrubber) return event;
|
|
14024
|
+
if (event.type === "user_input") {
|
|
14025
|
+
return {
|
|
14026
|
+
...event,
|
|
14027
|
+
content: typeof event.content === "string" ? secretScrubber.scrub(event.content) : secretScrubber.scrubObject(event.content)
|
|
14028
|
+
};
|
|
14029
|
+
}
|
|
14030
|
+
if (event.type === "llm_response") {
|
|
14031
|
+
return { ...event, content: secretScrubber.scrubObject(event.content) };
|
|
14032
|
+
}
|
|
14033
|
+
if (event.type === "file_snapshot") {
|
|
14034
|
+
return {
|
|
14035
|
+
...event,
|
|
14036
|
+
files: event.files.map((f) => ({
|
|
14037
|
+
...f,
|
|
14038
|
+
before: f.before !== null ? secretScrubber.scrub(f.before) : null,
|
|
14039
|
+
after: f.after !== null ? secretScrubber.scrub(f.after) : null
|
|
14040
|
+
}))
|
|
14041
|
+
};
|
|
14042
|
+
}
|
|
14043
|
+
return event;
|
|
14044
|
+
}
|
|
14045
|
+
|
|
14041
14046
|
// src/storage/session-writer-truncate.ts
|
|
14042
14047
|
import * as fsp6 from "node:fs/promises";
|
|
14043
14048
|
var CHUNK_SIZE = 65536;
|
|
@@ -14182,45 +14187,11 @@ async function rewriteSessionToCheckpoint(filePath, checkpointByteOffset) {
|
|
|
14182
14187
|
}
|
|
14183
14188
|
}
|
|
14184
14189
|
|
|
14185
|
-
// src/storage/session-writer-scrubber.ts
|
|
14186
|
-
function scrubSessionWriterEvent(event, secretScrubber) {
|
|
14187
|
-
const persistMessage = (message) => {
|
|
14188
|
-
const { _estTokens: _ignored, ...persisted } = message;
|
|
14189
|
-
return {
|
|
14190
|
-
...persisted,
|
|
14191
|
-
content: typeof persisted.content === "string" ? secretScrubber?.scrub(persisted.content) ?? persisted.content : secretScrubber?.scrubObject(persisted.content) ?? persisted.content
|
|
14192
|
-
};
|
|
14193
|
-
};
|
|
14194
|
-
if (event.type === "context_snapshot" || event.type === "messages_replaced") {
|
|
14195
|
-
return { ...event, messages: event.messages.map(persistMessage) };
|
|
14196
|
-
}
|
|
14197
|
-
if (event.type === "message_appended" || event.type === "message_updated") {
|
|
14198
|
-
return { ...event, message: persistMessage(event.message) };
|
|
14199
|
-
}
|
|
14200
|
-
if (!secretScrubber) return event;
|
|
14201
|
-
if (event.type === "user_input") {
|
|
14202
|
-
return {
|
|
14203
|
-
...event,
|
|
14204
|
-
content: typeof event.content === "string" ? secretScrubber.scrub(event.content) : secretScrubber.scrubObject(event.content)
|
|
14205
|
-
};
|
|
14206
|
-
}
|
|
14207
|
-
if (event.type === "llm_response") {
|
|
14208
|
-
return { ...event, content: secretScrubber.scrubObject(event.content) };
|
|
14209
|
-
}
|
|
14210
|
-
if (event.type === "file_snapshot") {
|
|
14211
|
-
return {
|
|
14212
|
-
...event,
|
|
14213
|
-
files: event.files.map((f) => ({
|
|
14214
|
-
...f,
|
|
14215
|
-
before: f.before !== null ? secretScrubber.scrub(f.before) : null,
|
|
14216
|
-
after: f.after !== null ? secretScrubber.scrub(f.after) : null
|
|
14217
|
-
}))
|
|
14218
|
-
};
|
|
14219
|
-
}
|
|
14220
|
-
return event;
|
|
14221
|
-
}
|
|
14222
|
-
|
|
14223
14190
|
// src/storage/file-session-writer.ts
|
|
14191
|
+
function isClosedHandleError(err) {
|
|
14192
|
+
const code = err?.code;
|
|
14193
|
+
return code === "EBADF" || code === "ERR_CLOSED_RESOURCE" || code === "ERR_INVALID_HANDLE";
|
|
14194
|
+
}
|
|
14224
14195
|
var FileSessionWriter = class _FileSessionWriter {
|
|
14225
14196
|
constructor(id, handle, startedAt, meta, events, opts = {}, traceId) {
|
|
14226
14197
|
this.id = id;
|
|
@@ -14392,8 +14363,7 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
14392
14363
|
try {
|
|
14393
14364
|
return await this.handle.appendFile(data, "utf8");
|
|
14394
14365
|
} catch (err) {
|
|
14395
|
-
|
|
14396
|
-
if (nodeErr?.code === "EBADF") {
|
|
14366
|
+
if (isClosedHandleError(err)) {
|
|
14397
14367
|
this.handle = await fsp7.open(this.filePath, "a", 384);
|
|
14398
14368
|
return await this.handle.appendFile(data, "utf8");
|
|
14399
14369
|
}
|
|
@@ -14433,8 +14403,8 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
14433
14403
|
bufferSynchronousEvent(event) {
|
|
14434
14404
|
if (this.closed) return;
|
|
14435
14405
|
void this.ensureInit();
|
|
14436
|
-
this.
|
|
14437
|
-
|
|
14406
|
+
const appendEvent = scrubSessionWriterEvent(event, this.secretScrubber);
|
|
14407
|
+
this.observeForSummary(appendEvent);
|
|
14438
14408
|
try {
|
|
14439
14409
|
this._onAppend?.(appendEvent);
|
|
14440
14410
|
} catch {
|
|
@@ -14587,8 +14557,7 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
14587
14557
|
try {
|
|
14588
14558
|
await this.handle.datasync();
|
|
14589
14559
|
} catch (err) {
|
|
14590
|
-
|
|
14591
|
-
if (nodeErr?.code === "EBADF") {
|
|
14560
|
+
if (isClosedHandleError(err)) {
|
|
14592
14561
|
this.handle = await fsp7.open(this.filePath, "a", 384);
|
|
14593
14562
|
return;
|
|
14594
14563
|
}
|
|
@@ -14825,6 +14794,7 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
14825
14794
|
return this.closePromise;
|
|
14826
14795
|
}
|
|
14827
14796
|
async doClose() {
|
|
14797
|
+
await this.ensureInit();
|
|
14828
14798
|
if (this.pendingFileSnapshots.length > 0) {
|
|
14829
14799
|
await this.writeFileSnapshot(this.activePromptIndex ?? 0, [...this.pendingFileSnapshots]);
|
|
14830
14800
|
this.pendingFileSnapshots = [];
|
|
@@ -14840,8 +14810,7 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
14840
14810
|
try {
|
|
14841
14811
|
await this.handle.datasync();
|
|
14842
14812
|
} catch (err) {
|
|
14843
|
-
|
|
14844
|
-
if (nodeErr?.code !== "EBADF") throw err;
|
|
14813
|
+
if (!isClosedHandleError(err)) throw err;
|
|
14845
14814
|
}
|
|
14846
14815
|
const endedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
14847
14816
|
const observedActivityMs = Date.parse(this.lastActivityAt);
|
|
@@ -28277,7 +28246,8 @@ async function evaluateToolKanbanBoundary(tool, input, ctx, options = {}) {
|
|
|
28277
28246
|
decision: "block",
|
|
28278
28247
|
reason: "Active card is not implementation-ready: " + readiness.issues.map((issue) => issue.message).join(" | "),
|
|
28279
28248
|
boardId: board.id,
|
|
28280
|
-
taskId: task.id
|
|
28249
|
+
taskId: task.id,
|
|
28250
|
+
readinessIssues: readiness.issues
|
|
28281
28251
|
};
|
|
28282
28252
|
}
|
|
28283
28253
|
if (task.lifecycle?.currentStage !== "running" || task.assignment?.status !== "running") {
|
|
@@ -29068,7 +29038,8 @@ ${errorDetails}`,
|
|
|
29068
29038
|
type: "tool_result",
|
|
29069
29039
|
tool_use_id: use.id,
|
|
29070
29040
|
content: `Tool "${tool.name}" blocked by Kanban boundary. ${boundary.reason ?? ""}`.trim(),
|
|
29071
|
-
is_error: true
|
|
29041
|
+
is_error: true,
|
|
29042
|
+
_kanbanBoundary: boundary
|
|
29072
29043
|
};
|
|
29073
29044
|
budget = this.budgetForString(result.content, budget);
|
|
29074
29045
|
return { result, tool, durationMs: Date.now() - start };
|
package/dist/execution/index.js
CHANGED
|
@@ -7270,7 +7270,12 @@ import { dirname as dirname3 } from "node:path";
|
|
|
7270
7270
|
import { createInterface } from "node:readline";
|
|
7271
7271
|
|
|
7272
7272
|
// src/security/file-permissions.ts
|
|
7273
|
-
|
|
7273
|
+
import {
|
|
7274
|
+
restrictDirPermissions,
|
|
7275
|
+
restrictFilePermissions,
|
|
7276
|
+
SECRET_DIR_MODE,
|
|
7277
|
+
SECRET_FILE_MODE
|
|
7278
|
+
} from "@wrongstack/persistence";
|
|
7274
7279
|
|
|
7275
7280
|
// src/coordination/brain-ledger.ts
|
|
7276
7281
|
var QUESTION_MAX = 200;
|
|
@@ -21401,7 +21406,8 @@ async function evaluateToolKanbanBoundary(tool, input, ctx, options = {}) {
|
|
|
21401
21406
|
decision: "block",
|
|
21402
21407
|
reason: "Active card is not implementation-ready: " + readiness.issues.map((issue) => issue.message).join(" | "),
|
|
21403
21408
|
boardId: board.id,
|
|
21404
|
-
taskId: task.id
|
|
21409
|
+
taskId: task.id,
|
|
21410
|
+
readinessIssues: readiness.issues
|
|
21405
21411
|
};
|
|
21406
21412
|
}
|
|
21407
21413
|
if (task.lifecycle?.currentStage !== "running" || task.assignment?.status !== "running") {
|
|
@@ -22192,7 +22198,8 @@ ${errorDetails}`,
|
|
|
22192
22198
|
type: "tool_result",
|
|
22193
22199
|
tool_use_id: use.id,
|
|
22194
22200
|
content: `Tool "${tool.name}" blocked by Kanban boundary. ${boundary.reason ?? ""}`.trim(),
|
|
22195
|
-
is_error: true
|
|
22201
|
+
is_error: true,
|
|
22202
|
+
_kanbanBoundary: boundary
|
|
22196
22203
|
};
|
|
22197
22204
|
budget = this.budgetForString(result.content, budget);
|
|
22198
22205
|
return { result, tool, durationMs: Date.now() - start };
|
package/dist/hq/index.js
CHANGED
|
@@ -2050,45 +2050,12 @@ import * as fs3 from "node:fs/promises";
|
|
|
2050
2050
|
import * as path4 from "node:path";
|
|
2051
2051
|
|
|
2052
2052
|
// src/security/file-permissions.ts
|
|
2053
|
-
import {
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
try {
|
|
2060
|
-
const { execFile } = await import("node:child_process");
|
|
2061
|
-
const { promisify } = await import("node:util");
|
|
2062
|
-
const execFileAsync = promisify(execFile);
|
|
2063
|
-
const user = windowsAccountName();
|
|
2064
|
-
if (!user) {
|
|
2065
|
-
warn(
|
|
2066
|
-
`[${label}] Could not determine the current Windows user for ${filePath}; skipping icacls hardening.`
|
|
2067
|
-
);
|
|
2068
|
-
return;
|
|
2069
|
-
}
|
|
2070
|
-
await execFileAsync("icacls", [filePath, "/inheritance:r", "/grant:r", `${user}:(F)`], {
|
|
2071
|
-
windowsHide: true
|
|
2072
|
-
});
|
|
2073
|
-
} catch {
|
|
2074
|
-
warn(
|
|
2075
|
-
`[${label}] Could not restrict permissions on ${filePath} \u2014 it may be readable by other users on this system.`
|
|
2076
|
-
);
|
|
2077
|
-
}
|
|
2078
|
-
} else {
|
|
2079
|
-
try {
|
|
2080
|
-
await chmod(filePath, SECRET_FILE_MODE);
|
|
2081
|
-
} catch {
|
|
2082
|
-
}
|
|
2083
|
-
}
|
|
2084
|
-
}
|
|
2085
|
-
function windowsAccountName() {
|
|
2086
|
-
const username = process.env.USERNAME || process.env.USER;
|
|
2087
|
-
if (!username || username.includes("\0")) return void 0;
|
|
2088
|
-
const domain = process.env.USERDOMAIN;
|
|
2089
|
-
if (domain && !domain.includes("\0")) return `${domain}\\${username}`;
|
|
2090
|
-
return username;
|
|
2091
|
-
}
|
|
2053
|
+
import {
|
|
2054
|
+
restrictDirPermissions,
|
|
2055
|
+
restrictFilePermissions,
|
|
2056
|
+
SECRET_DIR_MODE,
|
|
2057
|
+
SECRET_FILE_MODE
|
|
2058
|
+
} from "@wrongstack/persistence";
|
|
2092
2059
|
|
|
2093
2060
|
// src/utils/pid.ts
|
|
2094
2061
|
function isPidAlive(pid) {
|