@voybio/ace-swarm 0.2.5 → 2.4.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/CHANGELOG.md +11 -1
- package/README.md +20 -13
- package/assets/agent-state/EVIDENCE_LOG.md +1 -1
- package/assets/agent-state/MODULES/roles/capability-framework.json +41 -0
- package/assets/agent-state/MODULES/roles/capability-git.json +33 -0
- package/assets/agent-state/MODULES/roles/capability-safety.json +37 -0
- package/assets/agent-state/MODULES/schemas/ACE_RUNTIME_PROFILE.schema.json +21 -0
- package/assets/agent-state/MODULES/schemas/RUNTIME_EXECUTOR_SESSION_REGISTRY.schema.json +43 -0
- package/assets/agent-state/MODULES/schemas/WORKSPACE_SESSION_REGISTRY.schema.json +11 -0
- package/assets/agent-state/STATUS.md +2 -2
- package/assets/scripts/ace-hook-dispatch.mjs +70 -6
- package/assets/scripts/render-mcp-configs.sh +19 -5
- package/dist/ace-context.js +22 -1
- package/dist/ace-server-instructions.js +3 -3
- package/dist/ace-state-resolver.js +5 -3
- package/dist/astgrep-index.d.ts +9 -1
- package/dist/astgrep-index.js +14 -3
- package/dist/cli.js +27 -20
- package/dist/handoff-registry.js +5 -5
- package/dist/helpers/artifacts.d.ts +19 -0
- package/dist/helpers/artifacts.js +152 -0
- package/dist/helpers/bootstrap.d.ts +24 -0
- package/dist/helpers/bootstrap.js +894 -0
- package/dist/helpers/constants.d.ts +53 -0
- package/dist/helpers/constants.js +288 -0
- package/dist/helpers/drift.d.ts +13 -0
- package/dist/helpers/drift.js +45 -0
- package/dist/helpers/path-utils.d.ts +17 -0
- package/dist/helpers/path-utils.js +104 -0
- package/dist/helpers/store-resolution.d.ts +19 -0
- package/dist/helpers/store-resolution.js +301 -0
- package/dist/helpers/workspace-root.d.ts +3 -0
- package/dist/helpers/workspace-root.js +80 -0
- package/dist/helpers.d.ts +8 -125
- package/dist/helpers.js +8 -1768
- package/dist/job-scheduler.js +3 -3
- package/dist/local-model-runtime.js +12 -1
- package/dist/model-bridge.d.ts +7 -0
- package/dist/model-bridge.js +75 -5
- package/dist/orchestrator-supervisor.d.ts +14 -0
- package/dist/orchestrator-supervisor.js +72 -1
- package/dist/run-ledger.js +3 -3
- package/dist/runtime-command.d.ts +8 -0
- package/dist/runtime-command.js +38 -6
- package/dist/runtime-executor.d.ts +14 -0
- package/dist/runtime-executor.js +669 -171
- package/dist/runtime-profile.d.ts +32 -0
- package/dist/runtime-profile.js +89 -13
- package/dist/runtime-tool-specs.d.ts +21 -0
- package/dist/runtime-tool-specs.js +78 -3
- package/dist/safe-edit.d.ts +7 -0
- package/dist/safe-edit.js +163 -37
- package/dist/schemas.js +19 -0
- package/dist/shared.d.ts +2 -2
- package/dist/status-events.js +9 -6
- package/dist/store/ace-packed-store.d.ts +3 -2
- package/dist/store/ace-packed-store.js +188 -110
- package/dist/store/bootstrap-store.d.ts +1 -1
- package/dist/store/bootstrap-store.js +94 -81
- package/dist/store/cache-workspace.js +11 -5
- package/dist/store/materializers/context-snapshot-materializer.js +6 -2
- package/dist/store/materializers/hook-context-materializer.d.ts +6 -9
- package/dist/store/materializers/hook-context-materializer.js +11 -21
- package/dist/store/materializers/host-file-materializer.js +6 -0
- package/dist/store/materializers/projection-manager.d.ts +0 -1
- package/dist/store/materializers/projection-manager.js +5 -13
- package/dist/store/materializers/scheduler-projection-materializer.js +1 -1
- package/dist/store/materializers/vericify-projector.d.ts +7 -7
- package/dist/store/materializers/vericify-projector.js +11 -11
- package/dist/store/repositories/local-model-runtime-repository.d.ts +120 -3
- package/dist/store/repositories/local-model-runtime-repository.js +242 -6
- package/dist/store/skills-install.d.ts +4 -0
- package/dist/store/skills-install.js +21 -12
- package/dist/store/state-reader.d.ts +2 -0
- package/dist/store/state-reader.js +20 -0
- package/dist/store/store-artifacts.d.ts +7 -0
- package/dist/store/store-artifacts.js +27 -1
- package/dist/store/store-authority-audit.d.ts +18 -1
- package/dist/store/store-authority-audit.js +115 -5
- package/dist/store/store-snapshot.d.ts +3 -0
- package/dist/store/store-snapshot.js +22 -2
- package/dist/store/workspace-store-paths.d.ts +39 -0
- package/dist/store/workspace-store-paths.js +94 -0
- package/dist/store/write-coordinator.d.ts +65 -0
- package/dist/store/write-coordinator.js +386 -0
- package/dist/todo-state.js +5 -5
- package/dist/tools-agent.js +268 -14
- package/dist/tools-discovery.js +1 -1
- package/dist/tools-files.d.ts +7 -0
- package/dist/tools-files.js +299 -10
- package/dist/tools-framework.js +25 -5
- package/dist/tools-handoff.js +2 -2
- package/dist/tools-lifecycle.js +4 -4
- package/dist/tools-memory.js +6 -6
- package/dist/tools-todo.js +2 -2
- package/dist/tracker-adapters.d.ts +1 -1
- package/dist/tracker-adapters.js +13 -18
- package/dist/tracker-sync.js +5 -3
- package/dist/tui/agent-runner.js +3 -1
- package/dist/tui/chat.js +103 -7
- package/dist/tui/dashboard.d.ts +1 -0
- package/dist/tui/dashboard.js +43 -0
- package/dist/tui/layout.d.ts +20 -0
- package/dist/tui/layout.js +31 -1
- package/dist/tui/local-model-contract.d.ts +6 -2
- package/dist/tui/local-model-contract.js +16 -3
- package/dist/vericify-bridge.d.ts +5 -0
- package/dist/vericify-bridge.js +27 -3
- package/dist/workspace-manager.d.ts +30 -3
- package/dist/workspace-manager.js +257 -27
- package/package.json +1 -2
- package/dist/internal-tool-runtime.d.ts +0 -21
- package/dist/internal-tool-runtime.js +0 -136
- package/dist/store/workspace-snapshot.d.ts +0 -26
- package/dist/store/workspace-snapshot.js +0 -107
|
@@ -8,6 +8,31 @@ export declare const DEFAULT_RUNTIME_TOOL_REGISTRY_REL_PATH = "agent-state/runti
|
|
|
8
8
|
export declare const DEFAULT_EXECUTOR_MAX_TURNS = 6;
|
|
9
9
|
export declare const DEFAULT_EXECUTOR_TURN_TIMEOUT_MS = 300000;
|
|
10
10
|
export declare const DEFAULT_VERICIFY_BRIDGE_REL_PATH = "agent-state/vericify/ace-bridge.json";
|
|
11
|
+
export type RuntimeModelClass = "frontier" | "mid" | "small_local";
|
|
12
|
+
export declare const DEFAULT_STALL_WINDOW_MS = 300000;
|
|
13
|
+
export declare const DEFAULT_TURN_BUDGET_MS = 1800000;
|
|
14
|
+
export declare const DEFAULT_MAX_STALL_RESTARTS = 3;
|
|
15
|
+
export declare const DEFAULT_INITIAL_BACKOFF_MS = 5000;
|
|
16
|
+
export declare const DEFAULT_MAX_RETRY_BACKOFF_MS = 300000;
|
|
17
|
+
export interface ModelClassLivenessDefaults {
|
|
18
|
+
turn_budget_ms: number;
|
|
19
|
+
stall_window_ms: number;
|
|
20
|
+
max_stall_restarts: number;
|
|
21
|
+
initial_backoff_ms: number;
|
|
22
|
+
max_retry_backoff_ms: number;
|
|
23
|
+
}
|
|
24
|
+
export interface SurgicalReadBudgets {
|
|
25
|
+
small_local: number;
|
|
26
|
+
mid: number;
|
|
27
|
+
frontier: number | null;
|
|
28
|
+
}
|
|
29
|
+
export interface ResolvedSurgicalReadBudget {
|
|
30
|
+
model_class: RuntimeModelClass;
|
|
31
|
+
read_file_lines_max_lines: number | null;
|
|
32
|
+
}
|
|
33
|
+
export declare const DEFAULT_SURGICAL_READ_BUDGETS: SurgicalReadBudgets;
|
|
34
|
+
export declare function getLivenessDefaults(modelClass?: RuntimeModelClass): ModelClassLivenessDefaults;
|
|
35
|
+
export declare function resolveEffectiveSurgicalReadBudget(profile: RuntimeProfile | undefined, modelClass?: RuntimeModelClass): ResolvedSurgicalReadBudget;
|
|
11
36
|
export declare const DEFAULT_VERICIFY_PROCESS_POST_LOG_REL_PATH = "agent-state/vericify/process-posts.json";
|
|
12
37
|
declare const runtimeProfileSchema: z.ZodObject<{
|
|
13
38
|
ace_runtime_version: z.ZodLiteral<"1.0.0">;
|
|
@@ -41,6 +66,11 @@ declare const runtimeProfileSchema: z.ZodObject<{
|
|
|
41
66
|
}, z.core.$strict>;
|
|
42
67
|
tools: z.ZodDefault<z.ZodOptional<z.ZodObject<{
|
|
43
68
|
registry_path: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
69
|
+
surgical_read_budgets: z.ZodDefault<z.ZodOptional<z.ZodObject<{
|
|
70
|
+
small_local: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
71
|
+
mid: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
72
|
+
frontier: z.ZodDefault<z.ZodOptional<z.ZodNullable<z.ZodNumber>>>;
|
|
73
|
+
}, z.core.$strict>>>;
|
|
44
74
|
}, z.core.$strict>>>;
|
|
45
75
|
autonomy: z.ZodDefault<z.ZodOptional<z.ZodObject<{
|
|
46
76
|
orchestrator_preflight: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
@@ -110,7 +140,9 @@ export declare function readRuntimeProfile(): RuntimeProfile;
|
|
|
110
140
|
export declare function readRuntimePromptTemplate(): string;
|
|
111
141
|
export declare function readRuntimeProfileState(): RuntimeProfileSnapshot;
|
|
112
142
|
export declare function renderRuntimePrompt(templateContext: Record<string, unknown>): string;
|
|
143
|
+
export declare function renderRuntimePromptFromSnapshot(snapshot: RuntimeProfileSnapshot, templateContext: Record<string, unknown>): string;
|
|
113
144
|
export declare function getRuntimeProfilePath(): string;
|
|
114
145
|
export declare function getRuntimeProfileSchemaPath(): string;
|
|
146
|
+
export declare function getSurgicalReadBudget(modelClass: "frontier" | "mid" | "small_local" | undefined, profile?: RuntimeProfile): number | null;
|
|
115
147
|
export {};
|
|
116
148
|
//# sourceMappingURL=runtime-profile.d.ts.map
|
package/dist/runtime-profile.js
CHANGED
|
@@ -4,7 +4,7 @@ import { resolve } from "node:path";
|
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { DEFAULTS_ROOT, resolveWorkspaceArtifactPath, resolveWorkspaceRoot, } from "./helpers.js";
|
|
6
6
|
import { getStoreStatSync, getWorkspaceStorePath, parseVirtualStorePath, readStoreBlobSync, readStoreBlobByPathSync, toVirtualStorePath, } from "./store/store-snapshot.js";
|
|
7
|
-
import {
|
|
7
|
+
import { appendStatusEventSafe } from "./status-events.js";
|
|
8
8
|
import { DEFAULT_AUTONOMY_POLICY, DEFAULT_CONTINUITY_POLICY, } from "./ace-autonomy.js";
|
|
9
9
|
export const RUNTIME_PROFILE_REL_PATH = "agent-state/ACE_WORKFLOW.md";
|
|
10
10
|
export const RUNTIME_PROFILE_SCHEMA_REL_PATH = "agent-state/MODULES/schemas/ACE_RUNTIME_PROFILE.schema.json";
|
|
@@ -13,6 +13,57 @@ export const DEFAULT_RUNTIME_TOOL_REGISTRY_REL_PATH = "agent-state/runtime-tool-
|
|
|
13
13
|
export const DEFAULT_EXECUTOR_MAX_TURNS = 6;
|
|
14
14
|
export const DEFAULT_EXECUTOR_TURN_TIMEOUT_MS = 300_000;
|
|
15
15
|
export const DEFAULT_VERICIFY_BRIDGE_REL_PATH = "agent-state/vericify/ace-bridge.json";
|
|
16
|
+
// Liveness defaults per model class
|
|
17
|
+
export const DEFAULT_STALL_WINDOW_MS = 300_000; // 5 min — inter-progress cap
|
|
18
|
+
export const DEFAULT_TURN_BUDGET_MS = 1_800_000; // 30 min — per-turn soft cap
|
|
19
|
+
export const DEFAULT_MAX_STALL_RESTARTS = 3;
|
|
20
|
+
export const DEFAULT_INITIAL_BACKOFF_MS = 5_000;
|
|
21
|
+
export const DEFAULT_MAX_RETRY_BACKOFF_MS = 300_000;
|
|
22
|
+
export const DEFAULT_SURGICAL_READ_BUDGETS = {
|
|
23
|
+
small_local: 200,
|
|
24
|
+
mid: 800,
|
|
25
|
+
frontier: null,
|
|
26
|
+
};
|
|
27
|
+
export function getLivenessDefaults(modelClass) {
|
|
28
|
+
switch (modelClass) {
|
|
29
|
+
case "small_local":
|
|
30
|
+
return {
|
|
31
|
+
turn_budget_ms: 3_600_000, // 60 min — slow models need generous cap
|
|
32
|
+
stall_window_ms: 180_000, // 3 min stall window
|
|
33
|
+
max_stall_restarts: 3,
|
|
34
|
+
initial_backoff_ms: 10_000,
|
|
35
|
+
max_retry_backoff_ms: 300_000,
|
|
36
|
+
};
|
|
37
|
+
case "mid":
|
|
38
|
+
return {
|
|
39
|
+
turn_budget_ms: 1_800_000, // 30 min
|
|
40
|
+
stall_window_ms: 300_000, // 5 min
|
|
41
|
+
max_stall_restarts: 3,
|
|
42
|
+
initial_backoff_ms: 5_000,
|
|
43
|
+
max_retry_backoff_ms: 180_000,
|
|
44
|
+
};
|
|
45
|
+
case "frontier":
|
|
46
|
+
default:
|
|
47
|
+
return {
|
|
48
|
+
turn_budget_ms: DEFAULT_TURN_BUDGET_MS,
|
|
49
|
+
stall_window_ms: DEFAULT_STALL_WINDOW_MS,
|
|
50
|
+
max_stall_restarts: DEFAULT_MAX_STALL_RESTARTS,
|
|
51
|
+
initial_backoff_ms: DEFAULT_INITIAL_BACKOFF_MS,
|
|
52
|
+
max_retry_backoff_ms: DEFAULT_MAX_RETRY_BACKOFF_MS,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function resolveSurgicalReadBudgetValue(budgets, modelClass) {
|
|
57
|
+
const resolved = budgets ?? DEFAULT_SURGICAL_READ_BUDGETS;
|
|
58
|
+
return resolved[modelClass] ?? null;
|
|
59
|
+
}
|
|
60
|
+
export function resolveEffectiveSurgicalReadBudget(profile, modelClass) {
|
|
61
|
+
const effectiveModelClass = modelClass ?? "frontier";
|
|
62
|
+
return {
|
|
63
|
+
model_class: effectiveModelClass,
|
|
64
|
+
read_file_lines_max_lines: resolveSurgicalReadBudgetValue(profile?.tools?.surgical_read_budgets, effectiveModelClass),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
16
67
|
export const DEFAULT_VERICIFY_PROCESS_POST_LOG_REL_PATH = "agent-state/vericify/process-posts.json";
|
|
17
68
|
const DEFAULT_RUNTIME_PROFILE_PATH = resolve(DEFAULTS_ROOT, RUNTIME_PROFILE_REL_PATH);
|
|
18
69
|
const DEFAULT_RUNTIME_PROFILE_SCHEMA_PATH = resolve(DEFAULTS_ROOT, RUNTIME_PROFILE_SCHEMA_REL_PATH);
|
|
@@ -63,10 +114,22 @@ const runtimeProfileSchema = z
|
|
|
63
114
|
.min(1)
|
|
64
115
|
.optional()
|
|
65
116
|
.default(DEFAULT_RUNTIME_TOOL_REGISTRY_REL_PATH),
|
|
117
|
+
surgical_read_budgets: z
|
|
118
|
+
.object({
|
|
119
|
+
small_local: z.number().int().positive().optional().default(DEFAULT_SURGICAL_READ_BUDGETS.small_local),
|
|
120
|
+
mid: z.number().int().positive().optional().default(DEFAULT_SURGICAL_READ_BUDGETS.mid),
|
|
121
|
+
frontier: z.number().int().positive().nullable().optional().default(DEFAULT_SURGICAL_READ_BUDGETS.frontier),
|
|
122
|
+
})
|
|
123
|
+
.strict()
|
|
124
|
+
.optional()
|
|
125
|
+
.default(DEFAULT_SURGICAL_READ_BUDGETS),
|
|
66
126
|
})
|
|
67
127
|
.strict()
|
|
68
128
|
.optional()
|
|
69
|
-
.default({
|
|
129
|
+
.default({
|
|
130
|
+
registry_path: DEFAULT_RUNTIME_TOOL_REGISTRY_REL_PATH,
|
|
131
|
+
surgical_read_budgets: DEFAULT_SURGICAL_READ_BUDGETS,
|
|
132
|
+
}),
|
|
70
133
|
autonomy: z
|
|
71
134
|
.object({
|
|
72
135
|
orchestrator_preflight: z.boolean().optional().default(true),
|
|
@@ -336,7 +399,7 @@ function parseRuntimeProfileContent(raw) {
|
|
|
336
399
|
}
|
|
337
400
|
function emitRuntimeProfileEvent(eventType, input) {
|
|
338
401
|
try {
|
|
339
|
-
|
|
402
|
+
void appendStatusEventSafe({
|
|
340
403
|
source_module: "capability-framework",
|
|
341
404
|
event_type: eventType,
|
|
342
405
|
status: eventType === "RUNTIME_PROFILE_INVALID" ? "fail" : "pass",
|
|
@@ -349,6 +412,8 @@ function emitRuntimeProfileEvent(eventType, input) {
|
|
|
349
412
|
signature: input.signature,
|
|
350
413
|
errors: input.errors,
|
|
351
414
|
},
|
|
415
|
+
}).catch(() => {
|
|
416
|
+
// Runtime profile reads must not fail due to observability side effects.
|
|
352
417
|
});
|
|
353
418
|
}
|
|
354
419
|
catch {
|
|
@@ -357,13 +422,16 @@ function emitRuntimeProfileEvent(eventType, input) {
|
|
|
357
422
|
}
|
|
358
423
|
function ensureLastGoodSnapshot() {
|
|
359
424
|
const current = loadRuntimeProfile();
|
|
360
|
-
if (current.ok
|
|
361
|
-
return
|
|
362
|
-
if (lastGoodSnapshot
|
|
425
|
+
if (current.ok)
|
|
426
|
+
return current;
|
|
427
|
+
if (lastGoodSnapshot &&
|
|
428
|
+
lastGoodSnapshot.path === current.path &&
|
|
429
|
+
lastGoodSnapshot.source === current.source) {
|
|
363
430
|
return lastGoodSnapshot;
|
|
431
|
+
}
|
|
364
432
|
const packaged = loadRuntimeProfile(DEFAULT_RUNTIME_PROFILE_PATH);
|
|
365
|
-
if (packaged.ok
|
|
366
|
-
return
|
|
433
|
+
if (packaged.ok)
|
|
434
|
+
return packaged;
|
|
367
435
|
throw new Error(`Packaged ACE runtime profile is invalid: ${(packaged.ok ? [] : packaged.errors).join("; ")}`);
|
|
368
436
|
}
|
|
369
437
|
function resolveTemplatePath(context, path) {
|
|
@@ -511,14 +579,17 @@ export function readRuntimeProfileState() {
|
|
|
511
579
|
}
|
|
512
580
|
export function renderRuntimePrompt(templateContext) {
|
|
513
581
|
const active = ensureLastGoodSnapshot();
|
|
582
|
+
return renderRuntimePromptFromSnapshot(active, templateContext);
|
|
583
|
+
}
|
|
584
|
+
export function renderRuntimePromptFromSnapshot(snapshot, templateContext) {
|
|
514
585
|
const renderContext = {
|
|
515
|
-
...
|
|
516
|
-
runtime_profile_path:
|
|
517
|
-
runtime_profile_source:
|
|
518
|
-
prompt_template:
|
|
586
|
+
...snapshot.profile,
|
|
587
|
+
runtime_profile_path: snapshot.path,
|
|
588
|
+
runtime_profile_source: snapshot.source,
|
|
589
|
+
prompt_template: snapshot.prompt_template,
|
|
519
590
|
...templateContext,
|
|
520
591
|
};
|
|
521
|
-
return
|
|
592
|
+
return snapshot.prompt_template.replace(/{{\s*([A-Za-z0-9_.-]+)\s*}}/g, (match, token) => {
|
|
522
593
|
const value = resolveTemplatePath(renderContext, token);
|
|
523
594
|
return value === undefined ? match : stringifyTemplateValue(value);
|
|
524
595
|
});
|
|
@@ -529,4 +600,9 @@ export function getRuntimeProfilePath() {
|
|
|
529
600
|
export function getRuntimeProfileSchemaPath() {
|
|
530
601
|
return DEFAULT_RUNTIME_PROFILE_SCHEMA_PATH;
|
|
531
602
|
}
|
|
603
|
+
export function getSurgicalReadBudget(modelClass, profile) {
|
|
604
|
+
const effectiveProfile = profile ?? readRuntimeProfile();
|
|
605
|
+
const budgets = effectiveProfile.tools?.surgical_read_budgets ?? DEFAULT_SURGICAL_READ_BUDGETS;
|
|
606
|
+
return budgets[modelClass ?? "frontier"] ?? null;
|
|
607
|
+
}
|
|
532
608
|
//# sourceMappingURL=runtime-profile.js.map
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { ToolCostClass } from "./store/repositories/local-model-runtime-repository.js";
|
|
1
2
|
import { type ArtifactSource } from "./helpers.js";
|
|
3
|
+
import { type RuntimeModelClass } from "./runtime-profile.js";
|
|
2
4
|
import { type ValidationResult } from "./schemas.js";
|
|
3
5
|
export declare const RUNTIME_TOOL_SPEC_REGISTRY_REL_PATH = "agent-state/runtime-tool-specs.json";
|
|
4
6
|
export declare const RUNTIME_TOOL_SPEC_SCHEMA_REL_PATH = "agent-state/MODULES/schemas/RUNTIME_TOOL_SPEC_REGISTRY.schema.json";
|
|
@@ -64,5 +66,24 @@ export declare function readRuntimeToolRegistry(): RuntimeToolSpecRegistry;
|
|
|
64
66
|
export declare function listRuntimeToolSpecs(): RuntimeToolSpec[];
|
|
65
67
|
export declare function getRuntimeToolRegistryPath(): string;
|
|
66
68
|
export declare function executeRuntimeTool(name: string, input: unknown, context?: RuntimeToolExecutionContext): Promise<RuntimeToolExecutionResult>;
|
|
69
|
+
export type ModelClass = RuntimeModelClass;
|
|
70
|
+
export declare const SMALL_LOCAL_PRIORITY_TOOL_NAMES: readonly ["outline_file", "astgrep_query", "list_workspace", "read_file_lines", "recall_context", "validate_framework", "run_orchestrator"];
|
|
71
|
+
export interface FilteredToolCatalogEntry {
|
|
72
|
+
name: string;
|
|
73
|
+
description: string;
|
|
74
|
+
input_schema: RuntimeToolSchema;
|
|
75
|
+
cost_class: ToolCostClass;
|
|
76
|
+
}
|
|
77
|
+
export interface FilteredToolCatalog {
|
|
78
|
+
entries: FilteredToolCatalogEntry[];
|
|
79
|
+
model_class: ModelClass;
|
|
80
|
+
unavailable_tools: {
|
|
81
|
+
name: string;
|
|
82
|
+
reason: string;
|
|
83
|
+
reason_code: string;
|
|
84
|
+
}[];
|
|
85
|
+
tool_cost_class: Record<string, ToolCostClass>;
|
|
86
|
+
}
|
|
87
|
+
export declare function buildFilteredToolCatalog(modelClass: ModelClass | undefined, allowedTools?: string[]): FilteredToolCatalog;
|
|
67
88
|
export {};
|
|
68
89
|
//# sourceMappingURL=runtime-tool-specs.d.ts.map
|
|
@@ -12,7 +12,7 @@ import { appendStatusEventSafe } from "./status-events.js";
|
|
|
12
12
|
import { openStore } from "./store/ace-packed-store.js";
|
|
13
13
|
import { getWorkspaceStorePath, readStoreBlobSync, storeExistsSync, toVirtualStorePath, } from "./store/store-snapshot.js";
|
|
14
14
|
import { operationalArtifactKey, } from "./store/store-artifacts.js";
|
|
15
|
-
import {
|
|
15
|
+
import { withStoreWriteCoordinator } from "./store/write-coordinator.js";
|
|
16
16
|
export const RUNTIME_TOOL_SPEC_REGISTRY_REL_PATH = "agent-state/runtime-tool-specs.json";
|
|
17
17
|
export const RUNTIME_TOOL_SPEC_SCHEMA_REL_PATH = "agent-state/MODULES/schemas/RUNTIME_TOOL_SPEC_REGISTRY.schema.json";
|
|
18
18
|
export const RUNTIME_TOOL_SPEC_SCHEMA_NAME = "runtime-tool-spec-registry@1.0.0";
|
|
@@ -113,7 +113,7 @@ async function persistToolInvocationArtifacts(callId, requestContent, responseCo
|
|
|
113
113
|
return { requestPath, responsePath };
|
|
114
114
|
}
|
|
115
115
|
const storePath = getWorkspaceStorePath(workspaceRoot);
|
|
116
|
-
await
|
|
116
|
+
await withStoreWriteCoordinator(storePath, async () => {
|
|
117
117
|
const store = await openStore(storePath);
|
|
118
118
|
try {
|
|
119
119
|
await store.setBlob(runtimeToolArtifactKey(callId, "request"), requestContent);
|
|
@@ -123,7 +123,7 @@ async function persistToolInvocationArtifacts(callId, requestContent, responseCo
|
|
|
123
123
|
finally {
|
|
124
124
|
await store.close();
|
|
125
125
|
}
|
|
126
|
-
});
|
|
126
|
+
}, { operation_label: "persistToolInvocationArtifacts" });
|
|
127
127
|
return {
|
|
128
128
|
requestPath: runtimeToolArtifactVirtualPath(callId, "request"),
|
|
129
129
|
responsePath: runtimeToolArtifactVirtualPath(callId, "response"),
|
|
@@ -524,4 +524,79 @@ export async function executeRuntimeTool(name, input, context = {}) {
|
|
|
524
524
|
});
|
|
525
525
|
return result;
|
|
526
526
|
}
|
|
527
|
+
export const SMALL_LOCAL_PRIORITY_TOOL_NAMES = [
|
|
528
|
+
"outline_file",
|
|
529
|
+
"astgrep_query",
|
|
530
|
+
"list_workspace",
|
|
531
|
+
"read_file_lines",
|
|
532
|
+
"recall_context",
|
|
533
|
+
"validate_framework",
|
|
534
|
+
"run_orchestrator",
|
|
535
|
+
];
|
|
536
|
+
const HEAVY_TOOL_NAMES = new Set([
|
|
537
|
+
"read_workspace_file",
|
|
538
|
+
"write_workspace_file",
|
|
539
|
+
"safe_edit_file",
|
|
540
|
+
"astgrep_rewrite",
|
|
541
|
+
]);
|
|
542
|
+
function extractCostClass(tool) {
|
|
543
|
+
const desc = (tool.description ?? "").toLowerCase();
|
|
544
|
+
if (desc.includes("cost: cheap"))
|
|
545
|
+
return "cheap";
|
|
546
|
+
if (desc.includes("cost: moderate"))
|
|
547
|
+
return "moderate";
|
|
548
|
+
if (desc.includes("cost: heavy"))
|
|
549
|
+
return "heavy";
|
|
550
|
+
if (HEAVY_TOOL_NAMES.has(tool.name))
|
|
551
|
+
return "heavy";
|
|
552
|
+
if (["read_file_lines", "apply_patch", "diff_files"].includes(tool.name))
|
|
553
|
+
return "moderate";
|
|
554
|
+
return "cheap";
|
|
555
|
+
}
|
|
556
|
+
export function buildFilteredToolCatalog(modelClass, allowedTools) {
|
|
557
|
+
const allTools = listRuntimeToolSpecs();
|
|
558
|
+
const effectiveModelClass = modelClass ?? "frontier";
|
|
559
|
+
const allowed = allowedTools ? new Set(allowedTools) : null;
|
|
560
|
+
const unavailable = [];
|
|
561
|
+
let entries = [];
|
|
562
|
+
for (const tool of allTools) {
|
|
563
|
+
if (allowed !== null && !allowed.has(tool.name)) {
|
|
564
|
+
unavailable.push({
|
|
565
|
+
name: tool.name,
|
|
566
|
+
reason: "Not in allowed_tools for this session",
|
|
567
|
+
reason_code: "workspace_disabled",
|
|
568
|
+
});
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
const costClass = extractCostClass(tool);
|
|
572
|
+
let description = tool.description;
|
|
573
|
+
if (effectiveModelClass === "small_local" && costClass === "heavy") {
|
|
574
|
+
description = `[cost: heavy — prefer surgical alternatives] ${description}`;
|
|
575
|
+
}
|
|
576
|
+
entries.push({
|
|
577
|
+
name: tool.name,
|
|
578
|
+
description,
|
|
579
|
+
input_schema: tool.input_schema,
|
|
580
|
+
cost_class: costClass,
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
if (effectiveModelClass === "small_local" || effectiveModelClass === "mid") {
|
|
584
|
+
const priority = new Map(SMALL_LOCAL_PRIORITY_TOOL_NAMES.map((name, idx) => [name, idx]));
|
|
585
|
+
entries.sort((a, b) => {
|
|
586
|
+
const pa = priority.get(a.name) ?? 999;
|
|
587
|
+
const pb = priority.get(b.name) ?? 999;
|
|
588
|
+
return pa - pb;
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
const toolCostClass = {};
|
|
592
|
+
for (const e of entries) {
|
|
593
|
+
toolCostClass[e.name] = e.cost_class;
|
|
594
|
+
}
|
|
595
|
+
return {
|
|
596
|
+
entries,
|
|
597
|
+
model_class: effectiveModelClass,
|
|
598
|
+
unavailable_tools: unavailable,
|
|
599
|
+
tool_cost_class: toolCostClass,
|
|
600
|
+
};
|
|
601
|
+
}
|
|
527
602
|
//# sourceMappingURL=runtime-tool-specs.js.map
|
package/dist/safe-edit.d.ts
CHANGED
|
@@ -49,4 +49,11 @@ export declare function diffContents(original: string, updated: string): DiffRes
|
|
|
49
49
|
export declare function diffFiles(pathA: string, pathB: string): DiffResult & {
|
|
50
50
|
error?: string;
|
|
51
51
|
};
|
|
52
|
+
export interface ApplyPatchInput {
|
|
53
|
+
path: string;
|
|
54
|
+
patch: string;
|
|
55
|
+
validation_command?: string;
|
|
56
|
+
test_command?: string;
|
|
57
|
+
}
|
|
58
|
+
export declare function applyPatch(input: ApplyPatchInput): SafeEditResult;
|
|
52
59
|
//# sourceMappingURL=safe-edit.d.ts.map
|
package/dist/safe-edit.js
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
* Safe-edit module: copy → modify → validate → swap pattern.
|
|
3
3
|
* Prevents bricking by never leaving core files in a broken state.
|
|
4
4
|
*/
|
|
5
|
-
import { copyFileSync, existsSync, mkdirSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
5
|
+
import { copyFileSync, cpSync, existsSync, mkdtempSync, mkdirSync, readFileSync, renameSync, rmSync, symlinkSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
7
|
-
import { dirname, resolve } from "node:path";
|
|
7
|
+
import { basename, dirname, relative, resolve } from "node:path";
|
|
8
8
|
import { spawnSync } from "node:child_process";
|
|
9
|
+
import { tmpdir } from "node:os";
|
|
9
10
|
import { WORKSPACE_ROOT, safeRead, wsPath } from "./helpers.js";
|
|
10
11
|
import { isInside, isReadError, normalizeRelPath } from "./shared.js";
|
|
11
12
|
const STAGING_DIR = ".ace-staging";
|
|
@@ -19,14 +20,56 @@ function ensureDir(dirPath) {
|
|
|
19
20
|
if (!existsSync(dirPath))
|
|
20
21
|
mkdirSync(dirPath, { recursive: true });
|
|
21
22
|
}
|
|
22
|
-
function
|
|
23
|
+
function resolveWorkspaceTarget(inputPath) {
|
|
24
|
+
const absPath = resolve(WORKSPACE_ROOT, inputPath);
|
|
25
|
+
if (!isInside(WORKSPACE_ROOT, absPath)) {
|
|
26
|
+
return { error: `Path escapes workspace root: ${inputPath}`, absPath };
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
absPath,
|
|
30
|
+
relPath: normalizeRelPath(relative(WORKSPACE_ROOT, absPath)),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function shouldCopyIntoStaging(src) {
|
|
34
|
+
const rel = normalizeRelPath(relative(WORKSPACE_ROOT, src));
|
|
35
|
+
if (!rel || rel === ".")
|
|
36
|
+
return true;
|
|
37
|
+
const first = rel.split("/")[0];
|
|
38
|
+
return !new Set([".ace-staging", ".git", "node_modules", ".npm-cache"]).has(first);
|
|
39
|
+
}
|
|
40
|
+
function prepareStagedWorkspace(stagingDir) {
|
|
41
|
+
const stagedWorkspace = mkdtempSync(resolve(tmpdir(), "ace-staged-workspace-"));
|
|
42
|
+
rmSync(stagedWorkspace, { recursive: true, force: true });
|
|
43
|
+
mkdirSync(stagedWorkspace, { recursive: true });
|
|
44
|
+
cpSync(WORKSPACE_ROOT, stagedWorkspace, {
|
|
45
|
+
recursive: true,
|
|
46
|
+
dereference: false,
|
|
47
|
+
filter: (src) => shouldCopyIntoStaging(src),
|
|
48
|
+
});
|
|
49
|
+
const rootNodeModules = resolve(WORKSPACE_ROOT, "node_modules");
|
|
50
|
+
if (existsSync(rootNodeModules)) {
|
|
51
|
+
symlinkSync(rootNodeModules, resolve(stagedWorkspace, "node_modules"), "dir");
|
|
52
|
+
}
|
|
53
|
+
writeFileSync(resolve(stagingDir, "workspace-path.txt"), stagedWorkspace, "utf-8");
|
|
54
|
+
return stagedWorkspace;
|
|
55
|
+
}
|
|
56
|
+
function workspacePathIn(root, relPath) {
|
|
57
|
+
return resolve(root, relPath);
|
|
58
|
+
}
|
|
59
|
+
function swapTargetContent(absPath, content) {
|
|
60
|
+
ensureDir(dirname(absPath));
|
|
61
|
+
const swapPath = `${absPath}.ace-swap.${process.pid}.${Date.now()}`;
|
|
62
|
+
writeFileSync(swapPath, content, "utf-8");
|
|
63
|
+
renameSync(swapPath, absPath);
|
|
64
|
+
}
|
|
65
|
+
function runValidation(validationCmd, testCmd, cwd = WORKSPACE_ROOT) {
|
|
23
66
|
let validation_passed;
|
|
24
67
|
let validation_output;
|
|
25
68
|
let test_passed;
|
|
26
69
|
let test_output;
|
|
27
70
|
if (validationCmd) {
|
|
28
71
|
const res = spawnSync("sh", ["-c", validationCmd], {
|
|
29
|
-
cwd
|
|
72
|
+
cwd,
|
|
30
73
|
encoding: "utf-8",
|
|
31
74
|
timeout: 60_000,
|
|
32
75
|
maxBuffer: 4 * 1024 * 1024,
|
|
@@ -36,7 +79,7 @@ function runValidation(validationCmd, testCmd) {
|
|
|
36
79
|
}
|
|
37
80
|
if (testCmd && (validation_passed === undefined || validation_passed)) {
|
|
38
81
|
const res = spawnSync("sh", ["-c", testCmd], {
|
|
39
|
-
cwd
|
|
82
|
+
cwd,
|
|
40
83
|
encoding: "utf-8",
|
|
41
84
|
timeout: 120_000,
|
|
42
85
|
maxBuffer: 4 * 1024 * 1024,
|
|
@@ -51,84 +94,80 @@ function runValidation(validationCmd, testCmd) {
|
|
|
51
94
|
// Safe edit (copy → modify → validate → swap)
|
|
52
95
|
// ────────────────────────────────────────────────────────────────────
|
|
53
96
|
export function safeEditFile(input) {
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
if (!isInside(WORKSPACE_ROOT, absPath)) {
|
|
97
|
+
const target = resolveWorkspaceTarget(input.path);
|
|
98
|
+
if ("error" in target) {
|
|
57
99
|
return {
|
|
58
100
|
ok: false,
|
|
59
|
-
original_path: absPath,
|
|
101
|
+
original_path: target.absPath,
|
|
60
102
|
staging_path: "",
|
|
61
103
|
original_hash: "none",
|
|
62
104
|
new_hash: "none",
|
|
63
|
-
error:
|
|
105
|
+
error: target.error,
|
|
64
106
|
restored: false,
|
|
65
107
|
};
|
|
66
108
|
}
|
|
67
|
-
const relPath =
|
|
109
|
+
const { absPath, relPath } = target;
|
|
68
110
|
const timestamp = Date.now();
|
|
69
111
|
const originalContent = safeRead(input.path);
|
|
70
112
|
const isNew = isReadError(originalContent);
|
|
71
113
|
const originalHash = isNew ? "none" : fileHash(originalContent);
|
|
72
|
-
const
|
|
114
|
+
const stagedNewHash = fileHash(input.content);
|
|
73
115
|
// Step 1: Create staging directory
|
|
74
116
|
const stagingDir = wsPath(STAGING_DIR, `${timestamp}-${isNew ? "new" : originalHash.slice(0, 8)}`);
|
|
75
117
|
ensureDir(stagingDir);
|
|
76
118
|
const flatName = relPath.replace(/\//g, "__");
|
|
77
119
|
const stagingNew = resolve(stagingDir, `new__${flatName}`);
|
|
78
120
|
writeFileSync(stagingNew, input.content, "utf-8");
|
|
121
|
+
const stagedWorkspace = prepareStagedWorkspace(stagingDir);
|
|
122
|
+
const stagedTarget = workspacePathIn(stagedWorkspace, relPath);
|
|
123
|
+
ensureDir(dirname(stagedTarget));
|
|
124
|
+
writeFileSync(stagedTarget, input.content, "utf-8");
|
|
79
125
|
// Step 2: If file exists, copy original to staging + backup
|
|
80
126
|
let backupPath;
|
|
81
127
|
if (!isNew) {
|
|
82
128
|
const stagingOriginal = resolve(stagingDir, `original__${flatName}`);
|
|
83
129
|
writeFileSync(stagingOriginal, originalContent, "utf-8");
|
|
84
|
-
if (input.backup !== false) {
|
|
85
|
-
backupPath = `${absPath}.ace-backup.${originalHash.slice(0, 8)}`;
|
|
86
|
-
copyFileSync(absPath, backupPath);
|
|
87
|
-
}
|
|
88
130
|
}
|
|
89
|
-
// Step 3:
|
|
90
|
-
|
|
91
|
-
writeFileSync(absPath, input.content, "utf-8");
|
|
92
|
-
// Step 4: Run validation/tests
|
|
131
|
+
// Step 3: Run validation/tests against the staged workspace.
|
|
132
|
+
let check;
|
|
93
133
|
if (input.validation_command || input.test_command) {
|
|
94
|
-
|
|
134
|
+
check = runValidation(input.validation_command, input.test_command, stagedWorkspace);
|
|
95
135
|
if (!check.passed) {
|
|
96
|
-
// ROLLBACK: restore original content
|
|
97
|
-
if (!isNew) {
|
|
98
|
-
writeFileSync(absPath, originalContent, "utf-8");
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
// Remove newly created file
|
|
102
|
-
try {
|
|
103
|
-
unlinkSync(absPath);
|
|
104
|
-
}
|
|
105
|
-
catch {
|
|
106
|
-
/* best effort */
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
136
|
return {
|
|
110
137
|
ok: false,
|
|
111
138
|
original_path: absPath,
|
|
112
139
|
staging_path: stagingDir,
|
|
113
140
|
backup_path: backupPath,
|
|
114
141
|
original_hash: originalHash,
|
|
115
|
-
new_hash:
|
|
142
|
+
new_hash: stagedNewHash,
|
|
116
143
|
validation_passed: check.validation_passed,
|
|
117
144
|
validation_output: check.validation_output,
|
|
118
145
|
test_passed: check.test_passed,
|
|
119
146
|
test_output: check.test_output,
|
|
120
|
-
error: "Validation/test failed —
|
|
147
|
+
error: "Validation/test failed — staged change not promoted",
|
|
121
148
|
restored: true,
|
|
122
149
|
};
|
|
123
150
|
}
|
|
124
151
|
}
|
|
152
|
+
// Step 4: Promote staged content to the real target only after checks pass.
|
|
153
|
+
if (!isNew && input.backup !== false) {
|
|
154
|
+
backupPath = `${absPath}.ace-backup.${originalHash.slice(0, 8)}`;
|
|
155
|
+
copyFileSync(absPath, backupPath);
|
|
156
|
+
}
|
|
157
|
+
const promotedContent = readFileSync(stagedTarget, "utf-8");
|
|
158
|
+
const promotedHash = fileHash(promotedContent);
|
|
159
|
+
swapTargetContent(absPath, promotedContent);
|
|
125
160
|
return {
|
|
126
161
|
ok: true,
|
|
127
162
|
original_path: absPath,
|
|
128
163
|
staging_path: stagingDir,
|
|
129
164
|
backup_path: backupPath,
|
|
130
165
|
original_hash: originalHash,
|
|
131
|
-
new_hash:
|
|
166
|
+
new_hash: promotedHash,
|
|
167
|
+
validation_passed: check?.validation_passed,
|
|
168
|
+
validation_output: check?.validation_output,
|
|
169
|
+
test_passed: check?.test_passed,
|
|
170
|
+
test_output: check?.test_output,
|
|
132
171
|
};
|
|
133
172
|
}
|
|
134
173
|
// ────────────────────────────────────────────────────────────────────
|
|
@@ -252,4 +291,91 @@ export function diffFiles(pathA, pathB) {
|
|
|
252
291
|
}
|
|
253
292
|
return diffContents(contentA, contentB);
|
|
254
293
|
}
|
|
294
|
+
export function applyPatch(input) {
|
|
295
|
+
const target = resolveWorkspaceTarget(input.path);
|
|
296
|
+
if ("error" in target) {
|
|
297
|
+
return {
|
|
298
|
+
ok: false,
|
|
299
|
+
original_path: target.absPath,
|
|
300
|
+
staging_path: "",
|
|
301
|
+
original_hash: "none",
|
|
302
|
+
new_hash: "none",
|
|
303
|
+
error: target.error,
|
|
304
|
+
restored: false,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
const { absPath, relPath } = target;
|
|
308
|
+
const originalContent = safeRead(input.path);
|
|
309
|
+
const isNew = isReadError(originalContent);
|
|
310
|
+
const originalHash = isNew ? "none" : fileHash(originalContent);
|
|
311
|
+
const timestamp = Date.now();
|
|
312
|
+
const stagingDir = wsPath(STAGING_DIR, `${timestamp}-patch-${isNew ? "new" : originalHash.slice(0, 8)}`);
|
|
313
|
+
ensureDir(stagingDir);
|
|
314
|
+
const stagedWorkspace = prepareStagedWorkspace(stagingDir);
|
|
315
|
+
const stagedTarget = workspacePathIn(stagedWorkspace, relPath);
|
|
316
|
+
ensureDir(dirname(stagedTarget));
|
|
317
|
+
if (isNew && !existsSync(stagedTarget))
|
|
318
|
+
writeFileSync(stagedTarget, "", "utf-8");
|
|
319
|
+
const tmpPatch = resolve(stagingDir, `${basename(relPath)}.${timestamp}.patch`);
|
|
320
|
+
try {
|
|
321
|
+
writeFileSync(tmpPatch, input.patch, "utf8");
|
|
322
|
+
const patchResult = spawnSync("patch", [stagedTarget, tmpPatch], {
|
|
323
|
+
encoding: "utf8",
|
|
324
|
+
cwd: stagedWorkspace,
|
|
325
|
+
});
|
|
326
|
+
if (patchResult.status !== 0) {
|
|
327
|
+
return {
|
|
328
|
+
ok: false,
|
|
329
|
+
original_path: absPath,
|
|
330
|
+
staging_path: stagingDir,
|
|
331
|
+
original_hash: originalHash,
|
|
332
|
+
new_hash: "none",
|
|
333
|
+
error: `patch command failed: ${patchResult.stderr || patchResult.stdout}`,
|
|
334
|
+
restored: true,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
const patchedContent = readFileSync(stagedTarget, "utf-8");
|
|
338
|
+
const newHash = fileHash(patchedContent);
|
|
339
|
+
const check = runValidation(input.validation_command, input.test_command, stagedWorkspace);
|
|
340
|
+
if (!check.passed) {
|
|
341
|
+
return {
|
|
342
|
+
ok: false,
|
|
343
|
+
original_path: absPath,
|
|
344
|
+
staging_path: stagingDir,
|
|
345
|
+
original_hash: originalHash,
|
|
346
|
+
new_hash: newHash,
|
|
347
|
+
validation_passed: check.validation_passed,
|
|
348
|
+
validation_output: check.validation_output,
|
|
349
|
+
test_passed: check.test_passed,
|
|
350
|
+
test_output: check.test_output,
|
|
351
|
+
error: "Validation/test failed — staged patch not promoted",
|
|
352
|
+
restored: true,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
let backupPath;
|
|
356
|
+
if (!isNew) {
|
|
357
|
+
backupPath = `${absPath}.ace-backup.${originalHash.slice(0, 8)}`;
|
|
358
|
+
copyFileSync(absPath, backupPath);
|
|
359
|
+
}
|
|
360
|
+
swapTargetContent(absPath, patchedContent);
|
|
361
|
+
return {
|
|
362
|
+
ok: true,
|
|
363
|
+
original_path: absPath,
|
|
364
|
+
staging_path: stagingDir,
|
|
365
|
+
backup_path: backupPath,
|
|
366
|
+
original_hash: originalHash,
|
|
367
|
+
new_hash: newHash,
|
|
368
|
+
validation_passed: check.validation_passed,
|
|
369
|
+
validation_output: check.validation_output,
|
|
370
|
+
test_passed: check.test_passed,
|
|
371
|
+
test_output: check.test_output,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
finally {
|
|
375
|
+
try {
|
|
376
|
+
unlinkSync(tmpPatch);
|
|
377
|
+
}
|
|
378
|
+
catch { /* ignore */ }
|
|
379
|
+
}
|
|
380
|
+
}
|
|
255
381
|
//# sourceMappingURL=safe-edit.js.map
|