@wrongstack/core 0.309.0 → 0.310.0
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 +113 -41
- package/dist/chronicle/metrics-ingest.d.ts +7 -0
- package/dist/chronicle/metrics-schema.d.ts +4 -1
- package/dist/chronicle/project-server.js +94 -38
- package/dist/chronicle/query.d.ts +1 -0
- package/dist/chronicle/sqlite-journal-schema.d.ts +2 -1
- package/dist/chronicle/types.d.ts +2 -0
- package/dist/{agent-status-helpers.d.ts → coordination/agent-status-helpers.d.ts} +1 -1
- package/dist/{agent-status-tracker.d.ts → coordination/agent-status-tracker.d.ts} +2 -2
- package/dist/{middleware → coordination}/collab-pause.d.ts +1 -1
- package/dist/coordination/director-kanban-queue-helpers.d.ts +1 -1
- package/dist/coordination/director.d.ts +7 -0
- package/dist/coordination/explore-companion.d.ts +9 -6
- package/dist/coordination/fleet-status-tool.d.ts +1 -1
- package/dist/coordination/index.d.ts +5 -1
- package/dist/coordination/index.js +2392 -405
- package/dist/coordination/kanban-dispatch-port.d.ts +30 -0
- package/dist/coordination/kanban-ops-port.d.ts +21 -0
- package/dist/coordination/mailbox-hooks.d.ts +1 -1
- package/dist/coordination/mailbox-project-server.js +14 -9
- package/dist/coordination/mutation-engine.d.ts +5 -3
- package/dist/core/context.d.ts +35 -44
- package/dist/core/conversation-state.d.ts +16 -52
- package/dist/core/index.js +92 -25
- package/dist/core/provider-runner.d.ts +2 -2
- package/dist/core/run-env.d.ts +7 -28
- package/dist/core/streaming-response-builder.d.ts +2 -2
- package/dist/execution/index.js +138 -162
- package/dist/goal/index.js +100 -22
- package/dist/hq/auth-store.d.ts +9 -0
- package/dist/hq/cost-bridge.d.ts +1 -1
- package/dist/hq/index.js +69 -7
- package/dist/index.d.ts +12 -5
- package/dist/index.js +21185 -26807
- package/dist/infrastructure/index.js +232 -135
- package/dist/infrastructure/provider-cache-ledger.d.ts +1 -1
- package/dist/infrastructure/token-counter.d.ts +5 -1
- package/dist/kernel/events/file-events.d.ts +6 -0
- package/dist/kernel/events/provider-events.d.ts +10 -7
- package/dist/kernel/events/session-events.d.ts +4 -4
- package/dist/kernel/events/tool-events.d.ts +12 -2
- package/dist/observability/index.js +1 -1
- package/dist/plugin/index.js +218 -47
- package/dist/prompts/index.js +360 -3
- package/dist/security/auto-approve-policy.d.ts +2 -2
- package/dist/security/index.d.ts +1 -0
- package/dist/security/index.js +224 -68
- package/dist/security/kanban-boundary.d.ts +1 -1
- package/dist/security/kanban-governance-port.d.ts +28 -0
- package/dist/security/permission-helpers.d.ts +11 -0
- package/dist/security/permission-policy.d.ts +10 -1
- package/dist/security/yolo-risk.d.ts +17 -0
- package/dist/session-catalog/index.js +34 -5
- package/dist/session-catalog/project-server.js +34 -5
- package/dist/session-catalog/protocol.d.ts +1 -1
- package/dist/session-catalog/registry.d.ts +1 -1
- package/dist/session-catalog/store-schema.d.ts +1 -1
- package/dist/session-catalog/store.d.ts +1 -1
- package/dist/skills/index.js +39 -6
- package/dist/storage/annotations-store.d.ts +1 -1
- package/dist/storage/board-store-port.d.ts +45 -0
- package/dist/storage/completed-work-checkpoint.d.ts +1 -1
- package/dist/storage/config-loader/types.d.ts +1 -1
- package/dist/storage/event-bus-port.d.ts +27 -0
- package/dist/storage/file-session-writer.d.ts +47 -5
- package/dist/storage/goal-coordination.d.ts +1 -1
- package/dist/storage/goal-store.d.ts +1 -1
- package/dist/storage/index.d.ts +3 -4
- package/dist/storage/index.js +1107 -1462
- package/dist/storage/plan-store.d.ts +1 -1
- package/dist/storage/queue-store.d.ts +1 -1
- package/dist/storage/replay-log-store.d.ts +1 -1
- package/dist/storage/session-recovery.d.ts +10 -0
- package/dist/storage/session-resume-validation.d.ts +13 -1
- package/dist/storage/session-store/events.d.ts +1 -1
- package/dist/storage/session-store/load-session-data.d.ts +1 -1
- package/dist/storage/session-store/rename-session.d.ts +1 -1
- package/dist/storage/session-store/resume-session.d.ts +3 -1
- package/dist/storage/session-store/session-store-index.d.ts +2 -1
- package/dist/storage/session-store/types.d.ts +1 -1
- package/dist/storage/session-store.d.ts +70 -0
- package/dist/storage/session-summary-tracker.d.ts +8 -0
- package/dist/storage/session-write-buffer.d.ts +31 -2
- package/dist/storage/task-store.d.ts +1 -1
- package/dist/storage/todos-checkpoint.d.ts +1 -1
- package/dist/storage/tool-audit-log.d.ts +1 -1
- package/dist/tasking/index.js +100 -22
- package/dist/tasking/task-tracker.d.ts +24 -1
- package/dist/types/compactor.d.ts +2 -2
- package/dist/types/context.d.ts +212 -0
- package/dist/types/conversation-state.d.ts +109 -0
- package/dist/types/error-handler.d.ts +2 -2
- package/dist/types/file-event-record.d.ts +6 -0
- package/dist/types/index.d.ts +3 -3
- package/dist/types/index.js +17 -1
- package/dist/types/permission.d.ts +3 -3
- package/dist/types/plugin.d.ts +3 -3
- package/dist/types/provider-runner.d.ts +2 -2
- package/dist/types/provider.d.ts +10 -0
- package/dist/types/run-env.d.ts +32 -0
- package/dist/types/session.d.ts +3 -0
- package/dist/types/slash-command.d.ts +2 -2
- package/dist/types/token-counter.d.ts +30 -1
- package/dist/types/tool-executor.d.ts +2 -2
- package/dist/types/tool.d.ts +20 -5
- package/dist/utils/context-breakdown.d.ts +2 -2
- package/dist/utils/context-evidence.d.ts +12 -12
- package/dist/utils/crash-shield.d.ts +9 -0
- package/dist/utils/heap-watchdog.js +11 -3
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.js +126 -160
- package/dist/utils/regex-guard.d.ts +7 -30
- package/dist/utils/terminal-sanitize.d.ts +41 -0
- package/dist/utils/todos-format.d.ts +1 -1
- package/dist/utils/tool-subject.d.ts +1 -1
- package/dist/utils/tree-kill.d.ts +2 -0
- package/dist/utils/tree-kill.js +1 -0
- package/instructions/agents/chaos-monkey.md +5 -1
- package/instructions/coordination/subagent-baseline.md +10 -0
- package/instructions/system-lite.md +2 -0
- package/instructions/system-pro.md +40 -0
- package/instructions/system.md +15 -0
- package/package.json +7 -10
- package/dist/defaults/index.d.ts +0 -69
- package/dist/defaults/index.js +0 -37755
- /package/dist/{fleet-notifier.d.ts → coordination/fleet-notifier.d.ts} +0 -0
- /package/dist/{session-registry-atomic-file.d.ts → session-catalog/session-registry-atomic-file.d.ts} +0 -0
- /package/dist/{session-registry-types.d.ts → session-catalog/session-registry-types.d.ts} +0 -0
- /package/dist/{session-registry.d.ts → session-catalog/session-registry.d.ts} +0 -0
|
@@ -740,7 +740,7 @@ import * as fs5 from "node:fs";
|
|
|
740
740
|
import * as path5 from "node:path";
|
|
741
741
|
|
|
742
742
|
// src/coordination/sqlite-mailbox-schema.ts
|
|
743
|
-
import {
|
|
743
|
+
import { loadRuntimeDatabaseSync } from "@wrongstack/persistence";
|
|
744
744
|
|
|
745
745
|
// src/utils/sqlite-warning.ts
|
|
746
746
|
var SQLITE_EXPERIMENTAL_WARNING_RE = /sqlite is an experimental feature/i;
|
|
@@ -770,8 +770,7 @@ var DatabaseSyncCtor;
|
|
|
770
770
|
function loadDatabaseSync() {
|
|
771
771
|
if (DatabaseSyncCtor) return DatabaseSyncCtor;
|
|
772
772
|
return withSqliteExperimentalWarningSuppressed(() => {
|
|
773
|
-
|
|
774
|
-
DatabaseSyncCtor = require2("node:sqlite").DatabaseSync;
|
|
773
|
+
DatabaseSyncCtor = loadRuntimeDatabaseSync();
|
|
775
774
|
return DatabaseSyncCtor;
|
|
776
775
|
});
|
|
777
776
|
}
|
|
@@ -804,6 +803,14 @@ var PATTERNS = [
|
|
|
804
803
|
anchor: "sk-ant-"
|
|
805
804
|
},
|
|
806
805
|
{ type: "openai_key", regex: /(?<![A-Za-z0-9])sk-(?:proj-)?[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g, anchor: "sk-" },
|
|
806
|
+
{
|
|
807
|
+
// `xai` is a first-class provider in this codebase, but its key shape was
|
|
808
|
+
// absent here — so the one credential format WrongStack itself hands users
|
|
809
|
+
// was the one the scrubber could not recognize (audit 2026-08-20).
|
|
810
|
+
type: "xai_key",
|
|
811
|
+
regex: /(?<![A-Za-z0-9])xai-[A-Za-z0-9]{20,}(?![A-Za-z0-9])/g,
|
|
812
|
+
anchor: "xai-"
|
|
813
|
+
},
|
|
807
814
|
{ type: "github_pat", regex: /(?<![A-Za-z0-9])ghp_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g, anchor: "ghp_" },
|
|
808
815
|
{ type: "github_pat_v2", regex: /(?<![A-Za-z0-9])github_pat_[A-Za-z0-9_]{50,}(?![A-Za-z0-9])/g, anchor: "github_pat_" },
|
|
809
816
|
{ type: "aws_access_key", regex: /(?<![A-Za-z0-9])AKIA[0-9A-Z]{16}(?![A-Za-z0-9])/g, anchor: "AKIA" },
|
|
@@ -894,8 +901,8 @@ var PATTERNS = [
|
|
|
894
901
|
// replacement so the separator between adjacent secrets is preserved
|
|
895
902
|
// rather than collapsed. Capture groups are therefore: 1=leading
|
|
896
903
|
// delimiter, 2=key name, 3=value.
|
|
897
|
-
regex: /(^|\s)([A-Z_]{4,}(?:KEY|TOKEN|SECRET|PASSWORD|PWD))\s*[:=]\s*['"]?([A-Za-z0-9_/+=-]{20,512})['"]?(?=\s|$)/g,
|
|
898
|
-
anchor: ["KEY", "TOKEN", "SECRET", "PASSWORD", "PWD"]
|
|
904
|
+
regex: /(^|\s)([A-Z_]{4,}(?:KEY|TOKEN|SECRET|PASSWORD|PWD|PASSPHRASE))\s*[:=]\s*['"]?([A-Za-z0-9_/+=-]{20,512})['"]?(?=\s|$)/g,
|
|
905
|
+
anchor: ["KEY", "TOKEN", "SECRET", "PASSWORD", "PWD", "PASSPHRASE"]
|
|
899
906
|
},
|
|
900
907
|
{
|
|
901
908
|
type: "json_credential_key",
|
|
@@ -1012,6 +1019,27 @@ var JSON_CREDENTIAL_REGEX = PATTERNS.find((p) => p.type === "json_credential_key
|
|
|
1012
1019
|
var COMBINED_REPLACEMENTS = SIMPLE_PATTERNS.map((p) => `[REDACTED:${p.type}]`);
|
|
1013
1020
|
var SCRUB_CHUNK_BYTES = 64 * 1024;
|
|
1014
1021
|
var SCRUB_OVERLAP_BYTES = 1024;
|
|
1022
|
+
var PEM_PRIVATE_KEY_BEGIN_RE = /-----BEGIN (?:RSA|EC|OPENSSH|DSA|PGP)? ?PRIVATE KEY-----/;
|
|
1023
|
+
var PEM_END_MARKER = "-----END";
|
|
1024
|
+
var MAX_PEM_BLOCK_BYTES = 64 * 1024;
|
|
1025
|
+
var PEM_END_LINE_TOLERANCE = 64;
|
|
1026
|
+
function extendChunkBoundaryPastPem(text, chunkStart, proposedEnd) {
|
|
1027
|
+
const head = text.slice(chunkStart, proposedEnd);
|
|
1028
|
+
const lastBegin = head.lastIndexOf("-----BEGIN ");
|
|
1029
|
+
if (lastBegin === -1) return proposedEnd;
|
|
1030
|
+
const fromBegin = text.slice(chunkStart + lastBegin);
|
|
1031
|
+
const marker = PEM_PRIVATE_KEY_BEGIN_RE.exec(fromBegin);
|
|
1032
|
+
if (!marker || marker.index !== 0) return proposedEnd;
|
|
1033
|
+
const bodyStart = marker[0].length;
|
|
1034
|
+
const cap = Math.min(text.length, chunkStart + lastBegin + MAX_PEM_BLOCK_BYTES);
|
|
1035
|
+
const closeIdx = fromBegin.indexOf(PEM_END_MARKER, bodyStart);
|
|
1036
|
+
if (closeIdx === -1 || chunkStart + lastBegin + closeIdx >= cap + PEM_END_LINE_TOLERANCE) {
|
|
1037
|
+
return proposedEnd;
|
|
1038
|
+
}
|
|
1039
|
+
const lineEnd = fromBegin.indexOf("\n", closeIdx);
|
|
1040
|
+
const end = lineEnd === -1 ? text.length : chunkStart + lastBegin + lineEnd + 1;
|
|
1041
|
+
return Math.max(proposedEnd, end);
|
|
1042
|
+
}
|
|
1015
1043
|
var PATTERN_ANCHORS = [
|
|
1016
1044
|
...new Set(
|
|
1017
1045
|
PATTERNS.flatMap(
|
|
@@ -1048,6 +1076,7 @@ var DefaultSecretScrubber = class {
|
|
|
1048
1076
|
}
|
|
1049
1077
|
}
|
|
1050
1078
|
end = safe === -1 ? end : safe + 1;
|
|
1079
|
+
end = extendChunkBoundaryPastPem(text, i, end);
|
|
1051
1080
|
}
|
|
1052
1081
|
out.push(this.scrubOne(text.slice(i, end)));
|
|
1053
1082
|
i = end;
|
|
@@ -184,7 +184,7 @@ import * as fs2 from "node:fs";
|
|
|
184
184
|
import * as path3 from "node:path";
|
|
185
185
|
|
|
186
186
|
// src/coordination/sqlite-mailbox-schema.ts
|
|
187
|
-
import {
|
|
187
|
+
import { loadRuntimeDatabaseSync } from "@wrongstack/persistence";
|
|
188
188
|
|
|
189
189
|
// src/utils/sqlite-warning.ts
|
|
190
190
|
var SQLITE_EXPERIMENTAL_WARNING_RE = /sqlite is an experimental feature/i;
|
|
@@ -214,8 +214,7 @@ var DatabaseSyncCtor;
|
|
|
214
214
|
function loadDatabaseSync() {
|
|
215
215
|
if (DatabaseSyncCtor) return DatabaseSyncCtor;
|
|
216
216
|
return withSqliteExperimentalWarningSuppressed(() => {
|
|
217
|
-
|
|
218
|
-
DatabaseSyncCtor = require2("node:sqlite").DatabaseSync;
|
|
217
|
+
DatabaseSyncCtor = loadRuntimeDatabaseSync();
|
|
219
218
|
return DatabaseSyncCtor;
|
|
220
219
|
});
|
|
221
220
|
}
|
|
@@ -248,6 +247,14 @@ var PATTERNS = [
|
|
|
248
247
|
anchor: "sk-ant-"
|
|
249
248
|
},
|
|
250
249
|
{ type: "openai_key", regex: /(?<![A-Za-z0-9])sk-(?:proj-)?[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g, anchor: "sk-" },
|
|
250
|
+
{
|
|
251
|
+
// `xai` is a first-class provider in this codebase, but its key shape was
|
|
252
|
+
// absent here — so the one credential format WrongStack itself hands users
|
|
253
|
+
// was the one the scrubber could not recognize (audit 2026-08-20).
|
|
254
|
+
type: "xai_key",
|
|
255
|
+
regex: /(?<![A-Za-z0-9])xai-[A-Za-z0-9]{20,}(?![A-Za-z0-9])/g,
|
|
256
|
+
anchor: "xai-"
|
|
257
|
+
},
|
|
251
258
|
{ type: "github_pat", regex: /(?<![A-Za-z0-9])ghp_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g, anchor: "ghp_" },
|
|
252
259
|
{ type: "github_pat_v2", regex: /(?<![A-Za-z0-9])github_pat_[A-Za-z0-9_]{50,}(?![A-Za-z0-9])/g, anchor: "github_pat_" },
|
|
253
260
|
{ type: "aws_access_key", regex: /(?<![A-Za-z0-9])AKIA[0-9A-Z]{16}(?![A-Za-z0-9])/g, anchor: "AKIA" },
|
|
@@ -338,8 +345,8 @@ var PATTERNS = [
|
|
|
338
345
|
// replacement so the separator between adjacent secrets is preserved
|
|
339
346
|
// rather than collapsed. Capture groups are therefore: 1=leading
|
|
340
347
|
// delimiter, 2=key name, 3=value.
|
|
341
|
-
regex: /(^|\s)([A-Z_]{4,}(?:KEY|TOKEN|SECRET|PASSWORD|PWD))\s*[:=]\s*['"]?([A-Za-z0-9_/+=-]{20,512})['"]?(?=\s|$)/g,
|
|
342
|
-
anchor: ["KEY", "TOKEN", "SECRET", "PASSWORD", "PWD"]
|
|
348
|
+
regex: /(^|\s)([A-Z_]{4,}(?:KEY|TOKEN|SECRET|PASSWORD|PWD|PASSPHRASE))\s*[:=]\s*['"]?([A-Za-z0-9_/+=-]{20,512})['"]?(?=\s|$)/g,
|
|
349
|
+
anchor: ["KEY", "TOKEN", "SECRET", "PASSWORD", "PWD", "PASSPHRASE"]
|
|
343
350
|
},
|
|
344
351
|
{
|
|
345
352
|
type: "json_credential_key",
|
|
@@ -456,6 +463,27 @@ var JSON_CREDENTIAL_REGEX = PATTERNS.find((p) => p.type === "json_credential_key
|
|
|
456
463
|
var COMBINED_REPLACEMENTS = SIMPLE_PATTERNS.map((p) => `[REDACTED:${p.type}]`);
|
|
457
464
|
var SCRUB_CHUNK_BYTES = 64 * 1024;
|
|
458
465
|
var SCRUB_OVERLAP_BYTES = 1024;
|
|
466
|
+
var PEM_PRIVATE_KEY_BEGIN_RE = /-----BEGIN (?:RSA|EC|OPENSSH|DSA|PGP)? ?PRIVATE KEY-----/;
|
|
467
|
+
var PEM_END_MARKER = "-----END";
|
|
468
|
+
var MAX_PEM_BLOCK_BYTES = 64 * 1024;
|
|
469
|
+
var PEM_END_LINE_TOLERANCE = 64;
|
|
470
|
+
function extendChunkBoundaryPastPem(text, chunkStart, proposedEnd) {
|
|
471
|
+
const head = text.slice(chunkStart, proposedEnd);
|
|
472
|
+
const lastBegin = head.lastIndexOf("-----BEGIN ");
|
|
473
|
+
if (lastBegin === -1) return proposedEnd;
|
|
474
|
+
const fromBegin = text.slice(chunkStart + lastBegin);
|
|
475
|
+
const marker = PEM_PRIVATE_KEY_BEGIN_RE.exec(fromBegin);
|
|
476
|
+
if (!marker || marker.index !== 0) return proposedEnd;
|
|
477
|
+
const bodyStart = marker[0].length;
|
|
478
|
+
const cap = Math.min(text.length, chunkStart + lastBegin + MAX_PEM_BLOCK_BYTES);
|
|
479
|
+
const closeIdx = fromBegin.indexOf(PEM_END_MARKER, bodyStart);
|
|
480
|
+
if (closeIdx === -1 || chunkStart + lastBegin + closeIdx >= cap + PEM_END_LINE_TOLERANCE) {
|
|
481
|
+
return proposedEnd;
|
|
482
|
+
}
|
|
483
|
+
const lineEnd = fromBegin.indexOf("\n", closeIdx);
|
|
484
|
+
const end = lineEnd === -1 ? text.length : chunkStart + lastBegin + lineEnd + 1;
|
|
485
|
+
return Math.max(proposedEnd, end);
|
|
486
|
+
}
|
|
459
487
|
var PATTERN_ANCHORS = [
|
|
460
488
|
...new Set(
|
|
461
489
|
PATTERNS.flatMap(
|
|
@@ -492,6 +520,7 @@ var DefaultSecretScrubber = class {
|
|
|
492
520
|
}
|
|
493
521
|
}
|
|
494
522
|
end = safe === -1 ? end : safe + 1;
|
|
523
|
+
end = extendChunkBoundaryPastPem(text, i, end);
|
|
495
524
|
}
|
|
496
525
|
out.push(this.scrubOne(text.slice(i, end)));
|
|
497
526
|
i = end;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SessionRegistryEntry } from '
|
|
1
|
+
import type { SessionRegistryEntry } from './session-registry-types.js';
|
|
2
2
|
import type { SessionSummary } from '../types/session.js';
|
|
3
3
|
export declare const SESSION_CATALOG_PROTOCOL_VERSION = 1;
|
|
4
4
|
export declare const SESSION_CATALOG_MAX_FRAME_CHARS: number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentEntry, SessionRegistryEntry } from '
|
|
1
|
+
import type { AgentEntry, SessionRegistryEntry } from './session-registry-types.js';
|
|
2
2
|
import type { ResumeReservation, SessionCatalogEvent } from './protocol.js';
|
|
3
3
|
export interface SessionResumeClaim {
|
|
4
4
|
reservation: ResumeReservation;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
-
import type { SessionRegistryEntry } from '
|
|
2
|
+
import type { SessionRegistryEntry } from './session-registry-types.js';
|
|
3
3
|
export declare const SCHEMA_VERSION = 1;
|
|
4
4
|
export declare const MAX_LEASE_MS = 120000;
|
|
5
5
|
export declare const MAX_RESERVATION_MS = 60000;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SessionRegistryEntry } from '
|
|
1
|
+
import type { SessionRegistryEntry } from './session-registry-types.js';
|
|
2
2
|
import type { SessionSummary } from '../types/session.js';
|
|
3
3
|
import type { CatalogSessionRecord, MaintenanceLease, ResumeReservation, SessionCatalogHealth, SessionCatalogListArgs, SessionLeaseCredential } from './protocol.js';
|
|
4
4
|
export declare class SessionCatalogStore {
|
package/dist/skills/index.js
CHANGED
|
@@ -888,6 +888,32 @@ function numField(rec, key) {
|
|
|
888
888
|
import { spawn } from "node:child_process";
|
|
889
889
|
import * as fs3 from "node:fs/promises";
|
|
890
890
|
import * as path3 from "node:path";
|
|
891
|
+
|
|
892
|
+
// src/utils/win32-cmd.ts
|
|
893
|
+
var WIN32_CMD_META = /[&|<>"%\r\n\0]/;
|
|
894
|
+
function buildWin32CmdShimInvocation(command, args = []) {
|
|
895
|
+
assertSafeWin32CmdArgs([command, ...args]);
|
|
896
|
+
const line = ["call", quoteWin32CmdArg(command), ...args.map(quoteWin32CmdArg)].join(" ");
|
|
897
|
+
return {
|
|
898
|
+
command: process.env["COMSPEC"] ?? "cmd.exe",
|
|
899
|
+
args: ["/d", "/c", line],
|
|
900
|
+
windowsVerbatimArguments: true
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
function assertSafeWin32CmdArgs(args) {
|
|
904
|
+
for (const arg of args) {
|
|
905
|
+
if (typeof arg === "string" && WIN32_CMD_META.test(arg)) {
|
|
906
|
+
throw new Error(
|
|
907
|
+
'win32 cmd shim spawn: argument contains a shell metacharacter (one of & | < > ", or a newline) that could enable command injection through the .cmd/.bat wrapper - refusing to run. Offending argument: ' + JSON.stringify(arg)
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
function quoteWin32CmdArg(arg) {
|
|
913
|
+
return `"${arg}"`;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// src/skills/skill-generator.ts
|
|
891
917
|
async function validateSkillNameAvailable(name, loader) {
|
|
892
918
|
const formatViolations = validateSkillName(name);
|
|
893
919
|
const conflicts = loader ? (await loader.listEntries()).filter((e) => e.name === name) : [];
|
|
@@ -989,14 +1015,21 @@ async function openInEditor(filePath, env = process.env) {
|
|
|
989
1015
|
context: { filePath }
|
|
990
1016
|
});
|
|
991
1017
|
}
|
|
992
|
-
const
|
|
1018
|
+
const editorArgs = [...parts.slice(1), filePath];
|
|
1019
|
+
const child = shell ? (() => {
|
|
1020
|
+
const inv = buildWin32CmdShimInvocation(parts[0], editorArgs);
|
|
1021
|
+
return spawn(inv.command, inv.args, {
|
|
1022
|
+
stdio: "ignore",
|
|
1023
|
+
detached: true,
|
|
1024
|
+
windowsVerbatimArguments: inv.windowsVerbatimArguments,
|
|
1025
|
+
// Suppresses the console flash the cmd.exe wrapper would otherwise
|
|
1026
|
+
// show before the editor appears. Repo convention — see
|
|
1027
|
+
// `core/tests/architecture/spawn-convention.test.ts`.
|
|
1028
|
+
windowsHide: true
|
|
1029
|
+
});
|
|
1030
|
+
})() : spawn(parts[0], editorArgs, {
|
|
993
1031
|
stdio: "ignore",
|
|
994
1032
|
detached: true,
|
|
995
|
-
shell,
|
|
996
|
-
// `shell` routes through cmd.exe on win32, which flashes a console window
|
|
997
|
-
// before the editor appears. A GUI editor is unaffected by the flag; the
|
|
998
|
-
// shell wrapper is what it suppresses. Repo convention — see
|
|
999
|
-
// `core/tests/architecture/spawn-convention.test.ts`.
|
|
1000
1033
|
windowsHide: true
|
|
1001
1034
|
});
|
|
1002
1035
|
child.unref();
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kanban board-store port for the storage area (goal coordination).
|
|
3
|
+
*
|
|
4
|
+
* `goal-kanban.ts` and `goal-coordination.ts` previously imported the
|
|
5
|
+
* concrete functions from `@wrongstack/kanban` directly, keeping a
|
|
6
|
+
* core → kanban runtime edge (the layering inversion catalogued as
|
|
7
|
+
* roadmap #11 / report §2.1). This port is the leaf contract the storage
|
|
8
|
+
* area codes against; the CLI composition root registers the real
|
|
9
|
+
* implementation at boot (TOKENS-style dependency injection).
|
|
10
|
+
*
|
|
11
|
+
* Type-only imports of kanban's data shapes remain permitted — they erase
|
|
12
|
+
* at compile time and do not create a runtime edge. Only *callable*
|
|
13
|
+
* surface is ported.
|
|
14
|
+
*
|
|
15
|
+
* Un-registered default: goal features fail soft (board sync disabled)
|
|
16
|
+
* exactly as before the extraction, so embedding contexts without kanban
|
|
17
|
+
* keep working.
|
|
18
|
+
*/
|
|
19
|
+
import type { CreateKanbanBoardInput, CreateKanbanTaskInput, KanbanBoard, KanbanBoardSummary, KanbanEventContext, KanbanTask, UpdateKanbanTaskInput } from '@wrongstack/kanban';
|
|
20
|
+
export interface BoardStorePort {
|
|
21
|
+
createBoard(projectRoot: string, input: CreateKanbanBoardInput): Promise<KanbanBoard>;
|
|
22
|
+
listBoards(projectRoot: string): Promise<KanbanBoardSummary[]>;
|
|
23
|
+
getBoard(projectRoot: string, boardId: string): Promise<KanbanBoard | null>;
|
|
24
|
+
removeBoard(projectRoot: string, boardId: string): Promise<boolean>;
|
|
25
|
+
addTask(projectRoot: string, boardId: string, input: CreateKanbanTaskInput, eventContext?: KanbanEventContext): Promise<{
|
|
26
|
+
board: KanbanBoard;
|
|
27
|
+
task: KanbanTask;
|
|
28
|
+
} | null>;
|
|
29
|
+
updateTask(projectRoot: string, boardId: string, taskId: string, input: UpdateKanbanTaskInput, eventContext?: KanbanEventContext): Promise<KanbanBoard | null>;
|
|
30
|
+
}
|
|
31
|
+
/** Composition-root hook: register the real kanban-backed implementation. */
|
|
32
|
+
export declare function setBoardStorePort(impl: BoardStorePort): void;
|
|
33
|
+
/**
|
|
34
|
+
* Resolve the board-store port. Callers that must fail soft should catch
|
|
35
|
+
* the not-wired error, same semantics as kanban being absent.
|
|
36
|
+
*/
|
|
37
|
+
export declare function boardStore(): BoardStorePort;
|
|
38
|
+
/**
|
|
39
|
+
* Fail-soft resolver: the port when wired, otherwise `null`. For code paths
|
|
40
|
+
* whose documented behavior when kanban is absent is a no-op or empty
|
|
41
|
+
* result (goal sync, previews) — avoids the synchronous throw breaking
|
|
42
|
+
* `.catch()` fail-soft chains in non-CLI embeddings.
|
|
43
|
+
*/
|
|
44
|
+
export declare function tryBoardStore(): BoardStorePort | null;
|
|
45
|
+
//# sourceMappingURL=board-store-port.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EventBus } from '
|
|
1
|
+
import type { EventBus } from '../event-bus-port.js';
|
|
2
2
|
import type { Config } from '../../types/config.js';
|
|
3
3
|
import type { Logger } from '../../types/logger.js';
|
|
4
4
|
import type { SecretVault } from '../../types/secret-vault.js';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event-bus port for the storage area.
|
|
3
|
+
*
|
|
4
|
+
* Storage modules receive a bus instance from the composition root and use
|
|
5
|
+
* it only to *emit* `storage.*` events (verified: zero subscribe/logger/
|
|
6
|
+
* constructor calls across packages/core/src/storage). Importing the concrete
|
|
7
|
+
* `EventBus` class from `../kernel/events.js` kept a storage → kernel edge in
|
|
8
|
+
* the dependency graph; this port severs it.
|
|
9
|
+
*
|
|
10
|
+
* Structurally satisfied by the kernel `EventBus` class (its typed-generic
|
|
11
|
+
* `emit` is compatible with this loose signature via method-bivariance), so
|
|
12
|
+
* composition-root wiring needs no adapter.
|
|
13
|
+
*
|
|
14
|
+
* Surface policy: emit-only. If a storage consumer ever needs to subscribe,
|
|
15
|
+
* widen this port deliberately instead of re-importing the kernel type.
|
|
16
|
+
*/
|
|
17
|
+
export interface EventBus {
|
|
18
|
+
/**
|
|
19
|
+
* Emit a storage-domain event onto the bus.
|
|
20
|
+
*
|
|
21
|
+
* Loose parameter typing is deliberate: the concrete kernel bus carries the
|
|
22
|
+
* full `EventMap` typing; storage call sites pass literal `'storage.*'`
|
|
23
|
+
* names whose payloads the kernel map validates at the wiring boundary.
|
|
24
|
+
*/
|
|
25
|
+
emit(event: string, payload?: unknown): void;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=event-bus-port.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as fsp from 'node:fs/promises';
|
|
2
|
-
import type { EventBus } from '
|
|
2
|
+
import type { EventBus } from './event-bus-port.js';
|
|
3
3
|
import type { SecretScrubber } from '../types/secret-scrubber.js';
|
|
4
4
|
import type { FileSnapshot, SessionEvent, SessionMetadata, SessionSummary, SessionWriter } from '../types/session.js';
|
|
5
5
|
import type { SessionCheckpointCas } from './session-checkpoint-cas.js';
|
|
@@ -46,6 +46,15 @@ export declare class FileSessionWriter implements SessionWriter {
|
|
|
46
46
|
get onAppendBatch(): ((events: SessionEvent[]) => void) | undefined;
|
|
47
47
|
set onAppendBatch(cb: ((events: SessionEvent[]) => void) | undefined);
|
|
48
48
|
private readonly onCloseCb?;
|
|
49
|
+
/** Mid-session metadata checkpoint throttle. 0 disables checkpointing. */
|
|
50
|
+
private readonly metadataCheckpointMs;
|
|
51
|
+
/** One-shot guard for the "interval set but no sink" warning below. */
|
|
52
|
+
private _checkpointNoSinkWarned;
|
|
53
|
+
private readonly onMetadataCheckpointCb?;
|
|
54
|
+
/** Set whenever summary counters changed since the last metadata checkpoint. */
|
|
55
|
+
private metadataDirty;
|
|
56
|
+
private metadataTimer;
|
|
57
|
+
private metadataCheckpointInFlight;
|
|
49
58
|
/** Implements SessionWriter.traceId — propagated from ContextInit.traceId. */
|
|
50
59
|
traceId: string | undefined;
|
|
51
60
|
/**
|
|
@@ -104,15 +113,47 @@ export declare class FileSessionWriter implements SessionWriter {
|
|
|
104
113
|
onClose?: ((summary: SessionSummary) => void | Promise<void>) | undefined;
|
|
105
114
|
/** Reconcile an explicit name changed while this writer remained open. */
|
|
106
115
|
resolveName?: (() => Promise<Pick<SessionSummary, 'name'> | null>) | undefined;
|
|
116
|
+
/**
|
|
117
|
+
* Mid-session metadata checkpoint throttle (ms). While the session is
|
|
118
|
+
* live and dirty, the summary sidecar + index row are refreshed at most
|
|
119
|
+
* this often, so a SIGKILLed process still leaves accurate listing
|
|
120
|
+
* metadata instead of its create-time stub. 0 disables checkpointing —
|
|
121
|
+
* killed sessions then stay visible through the store's list()-union
|
|
122
|
+
* scan, but only with analyzer-derived metadata rather than tracked
|
|
123
|
+
* counters. Default 10_000.
|
|
124
|
+
*/
|
|
125
|
+
metadataCheckpointMs?: number | undefined;
|
|
126
|
+
/**
|
|
127
|
+
* Persists a mid-session summary snapshot (store-level index row /
|
|
128
|
+
* catalog upsert). The sidecar file itself is written by the writer
|
|
129
|
+
* under its manifest lock; this callback covers the index side.
|
|
130
|
+
*/
|
|
131
|
+
onMetadataCheckpoint?: ((summary: SessionSummary) => void | Promise<void>) | undefined;
|
|
107
132
|
}, traceId?: string | undefined);
|
|
108
133
|
get pendingToolUses(): string[];
|
|
109
134
|
private writeSessionStartLazy;
|
|
135
|
+
/**
|
|
136
|
+
* Arm the mid-session metadata checkpoint timer if it is not already armed.
|
|
137
|
+
* Called after every observed event; the timer itself is unref'd so an idle
|
|
138
|
+
* session never keeps the process alive for a cosmetic sidecar refresh.
|
|
139
|
+
*/
|
|
140
|
+
private scheduleMetadataCheckpoint;
|
|
141
|
+
/**
|
|
142
|
+
* Persist a mid-session summary snapshot: the `.summary.json` sidecar under
|
|
143
|
+
* the manifest lock, then the store-level index row / catalog upsert via
|
|
144
|
+
* `onMetadataCheckpoint`. Runs at most once per throttle interval and only
|
|
145
|
+
* when summary counters changed since the last checkpoint; a failed
|
|
146
|
+
* checkpoint stays dirty and retries on the next armed tick.
|
|
147
|
+
*/
|
|
148
|
+
private runMetadataCheckpoint;
|
|
110
149
|
append(event: SessionEvent): Promise<void>;
|
|
111
150
|
appendBatch(events: SessionEvent[]): Promise<void>;
|
|
112
151
|
/**
|
|
113
152
|
* Flush buffered events to disk immediately. Critical events
|
|
114
|
-
* (user_input, llm_response
|
|
115
|
-
*
|
|
153
|
+
* (user_input, llm_response, checkpoint, in_flight_*) already flush
|
|
154
|
+
* themselves inside append()/appendBatch(), so calling this matters for
|
|
155
|
+
* non-critical tails that would otherwise sit in the in-memory buffer
|
|
156
|
+
* for up to 500ms.
|
|
116
157
|
*
|
|
117
158
|
* Idempotent — cancels any pending timer, writes whatever has accumulated,
|
|
118
159
|
* then asks the OS to synchronize the file data before resolving. Even an
|
|
@@ -123,8 +164,9 @@ export declare class FileSessionWriter implements SessionWriter {
|
|
|
123
164
|
* Last-gasp synchronous drain for hard-exit paths (process.exit after
|
|
124
165
|
* rapid Ctrl+C). The async write chain cannot be awaited when the process
|
|
125
166
|
* is about to die, but whatever still sits in the in-memory buffer CAN be
|
|
126
|
-
* saved with a blocking append.
|
|
127
|
-
*
|
|
167
|
+
* saved with a blocking append. A failed sync append leaves the buffer
|
|
168
|
+
* intact so a subsequent close()/flush() can retry. An in-flight async
|
|
169
|
+
* write may still be cut off by a hard exit.
|
|
128
170
|
*/
|
|
129
171
|
flushSync(): void;
|
|
130
172
|
close(): Promise<void>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BrainArbiter } from '../coordination/brain.js';
|
|
2
|
-
import type { EventBus } from '
|
|
2
|
+
import type { EventBus } from './event-bus-port.js';
|
|
3
3
|
import { type GoalFile } from './goal-store.js';
|
|
4
4
|
export interface CompletedGoalDeliverable {
|
|
5
5
|
index: number;
|
package/dist/storage/index.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { FleetNotifier, type FleetNotifierOptions, } from '../fleet-notifier.js';
|
|
1
|
+
export { type BoardStorePort, boardStore, setBoardStorePort, } from './board-store-port.js';
|
|
3
2
|
export { type CatalogSessionRecord, type MaintenanceLease, type ResumeReservation, type SessionCatalogHealth, SessionCatalogProjectClient, type SessionCatalogProjectClientOptions, type SessionLeaseCredential, type SessionResumeClaim, } from '../session-catalog/index.js';
|
|
4
3
|
export { getProjectSessionRegistry as getSessionRegistry, hasProjectSessionRegistry as hasSessionRegistry, ProjectSessionRegistry as SessionRegistry, } from '../session-catalog/registry.js';
|
|
5
|
-
export type { AgentEntry, AgentLiveStatus, SessionLiveStatus, SessionRegistryEntry, SessionWebUIEndpointHint, } from '../session-registry.js';
|
|
4
|
+
export type { AgentEntry, AgentLiveStatus, SessionLiveStatus, SessionRegistryEntry, SessionWebUIEndpointHint, } from '../session-catalog/session-registry.js';
|
|
6
5
|
/** @deprecated Test/migration adapter; production ownership uses SessionRegistry above. */
|
|
7
|
-
export { SessionRegistry as LegacySessionRegistry } from '../session-registry.js';
|
|
6
|
+
export { SessionRegistry as LegacySessionRegistry } from '../session-catalog/session-registry.js';
|
|
8
7
|
export type { SyncCategory, SyncConfig } from '../types/config.js';
|
|
9
8
|
export type { DefaultSessionReaderOptions, SessionReader } from '../types/session-reader.js';
|
|
10
9
|
export { type Annotation, AnnotationsStore, type AnnotationsStoreOptions, } from './annotations-store.js';
|