@wrongstack/core 0.89.1 → 0.104.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/{agent-bridge-B8F2ORwg.d.ts → agent-bridge-mOxbpFcg.d.ts} +1 -1
- package/dist/{agent-subagent-runner-CQaLFNnA.d.ts → agent-subagent-runner-DukQLUcS.d.ts} +433 -433
- package/dist/{events-DzyLtja6.d.ts → brain-Dfv4Y82E.d.ts} +179 -92
- package/dist/{compactor-CJq7LQev.d.ts → compactor-DXLxLcmU.d.ts} +2 -2
- package/dist/{config-_DZ7dN-T.d.ts → config-BSU-6vah.d.ts} +45 -38
- package/dist/{context-ToHAp4-U.d.ts → context-CNRYfhUv.d.ts} +1 -1
- package/dist/coordination/index.d.ts +16 -17
- package/dist/coordination/index.js +128 -37
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +34 -35
- package/dist/defaults/index.js +752 -218
- package/dist/defaults/index.js.map +1 -1
- package/dist/{director-state-CgIc30qi.d.ts → director-state-BfeCUbmk.d.ts} +1 -1
- package/dist/execution/index.d.ts +65 -370
- package/dist/execution/index.js +446 -53
- package/dist/execution/index.js.map +1 -1
- package/dist/extension/index.d.ts +9 -10
- package/dist/extension/index.js +8 -6
- package/dist/extension/index.js.map +1 -1
- package/dist/goal-preamble-CI8lxeY1.d.ts +378 -0
- package/dist/{goal-store-DvWLNu52.d.ts → goal-store-ht0VmR1A.d.ts} +63 -21
- package/dist/{index-Ca_lOmKl.d.ts → index-BWRN6wOb.d.ts} +13 -15
- package/dist/{index-Dx-CnrDN.d.ts → index-DIKEcfgC.d.ts} +9 -10
- package/dist/index.d.ts +188 -176
- package/dist/index.js +1508 -407
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +9 -9
- package/dist/infrastructure/index.js +4 -2
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +14 -16
- package/dist/kernel/index.js.map +1 -1
- package/dist/{logger-B72yyPc6.d.ts → logger-B63L5bTg.d.ts} +1 -1
- package/dist/{logger-C_27pj9i.d.ts → logger-B9J5puGM.d.ts} +1 -1
- package/dist/{mcp-servers-Dck3T85_.d.ts → mcp-servers-CXCsANdY.d.ts} +3 -3
- package/dist/{mode-CHo2XtHs.d.ts → mode-ARA3HrkY.d.ts} +1 -1
- package/dist/models/index.d.ts +5 -5
- package/dist/models/index.js +8 -6
- package/dist/models/index.js.map +1 -1
- package/dist/{models-registry-Be3osGt5.d.ts → models-registry-B6_KfS65.d.ts} +1 -1
- package/dist/{models-registry-Boz639EI.d.ts → models-registry-DU64QxQa.d.ts} +1 -1
- package/dist/{multi-agent-coordinator-Da9nd8Ic.d.ts → multi-agent-coordinator-51LvnXkD.d.ts} +2 -2
- package/dist/{null-fleet-bus-CHJOXv3t.d.ts → null-fleet-bus-D09hMzFQ.d.ts} +32 -31
- package/dist/observability/index.d.ts +3 -3
- package/dist/{observability-CoSNZdhX.d.ts → observability-D-HZN_mF.d.ts} +1 -1
- package/dist/{parallel-eternal-engine-DyMCj2Pw.d.ts → parallel-eternal-engine-CUtmM_0V.d.ts} +54 -35
- package/dist/{path-resolver-TjBlRKyH.d.ts → path-resolver-DDJiMAtX.d.ts} +3 -3
- package/dist/{permission-14CChMmO.d.ts → permission-BDv7z0mk.d.ts} +7 -2
- package/dist/{permission-policy-gW5htOo1.d.ts → permission-policy-dF74EpDp.d.ts} +2 -2
- package/dist/{system-prompt-C0rLCeyn.d.ts → pipeline-BqiA_UMr.d.ts} +73 -73
- package/dist/{plan-templates-D9UhwoGh.d.ts → plan-templates-BdDxl9cI.d.ts} +79 -11
- package/dist/{provider-runner-BEPWwkxH.d.ts → provider-runner-BUunikwY.d.ts} +5 -5
- package/dist/{retry-policy-DSu6O6rD.d.ts → retry-policy-BcmuT_V0.d.ts} +2 -2
- package/dist/sdd/index.d.ts +17 -33
- package/dist/sdd/index.js +145 -36
- package/dist/sdd/index.js.map +1 -1
- package/dist/{secret-scrubber-yGBFQYju.d.ts → secret-vault-DrOhc2i5.d.ts} +7 -7
- package/dist/security/index.d.ts +4 -5
- package/dist/security/index.js +4 -2
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-11-fm95U.d.ts → selector-C7wcdqMA.d.ts} +1 -1
- package/dist/{session-event-bridge-D0u-x576.d.ts → session-event-bridge-BpJ5trO9.d.ts} +2 -2
- package/dist/{session-reader-BQU-toaN.d.ts → session-reader-DDz1Ek4V.d.ts} +2 -2
- package/dist/{skill-BJeF2DwY.d.ts → skill-Bj6Ezqb8.d.ts} +1 -1
- package/dist/skills/index.d.ts +1 -1
- package/dist/skills/index.js +3 -9
- package/dist/skills/index.js.map +1 -1
- package/dist/spec-TBi3Jr6T.d.ts +78 -0
- package/dist/storage/index.d.ts +145 -13
- package/dist/storage/index.js +990 -172
- package/dist/storage/index.js.map +1 -1
- package/dist/task-format-vGOIftmK.d.ts +23 -0
- package/dist/task-graph-u1q9Jkyk.d.ts +84 -0
- package/dist/types/index.d.ts +27 -28
- package/dist/types/index.js +19 -31
- package/dist/types/index.js.map +1 -1
- package/dist/utils/expect-defined.d.ts +7 -0
- package/dist/utils/expect-defined.js +11 -0
- package/dist/utils/expect-defined.js.map +1 -0
- package/dist/utils/index.d.ts +8 -20
- package/dist/utils/index.js +120 -41
- package/dist/utils/index.js.map +1 -1
- package/dist/{wstack-paths-BQMvEllz.d.ts → wstack-paths-_lqjzErq.d.ts} +1 -1
- package/package.json +5 -1
- package/skills/tech-stack/SKILL.md +177 -0
- package/dist/memory-CEXuo7sz.d.ts +0 -16
- package/dist/secret-scrubber-3MHDDAtm.d.ts +0 -6
- package/dist/task-graph-CikNdRTG.d.ts +0 -161
package/dist/execution/index.js
CHANGED
|
@@ -6,13 +6,15 @@ import { randomUUID, createHash, randomBytes } from 'crypto';
|
|
|
6
6
|
import * as os from 'os';
|
|
7
7
|
import { EventEmitter } from 'events';
|
|
8
8
|
|
|
9
|
-
// src/utils/
|
|
10
|
-
function expectDefined(value) {
|
|
9
|
+
// src/utils/expect-defined.ts
|
|
10
|
+
function expectDefined(value, label) {
|
|
11
11
|
if (value === null || value === void 0) {
|
|
12
12
|
throw new Error("Expected value to be defined");
|
|
13
13
|
}
|
|
14
14
|
return value;
|
|
15
15
|
}
|
|
16
|
+
|
|
17
|
+
// src/utils/token-estimate.ts
|
|
16
18
|
var RoughTokenEstimate = (text, charsPerToken = 3.5) => Math.max(1, Math.ceil(text.length / charsPerToken));
|
|
17
19
|
var ESTIMATE_CACHE = /* @__PURE__ */ new Map();
|
|
18
20
|
var ESTIMATE_CACHE_MAX_SIZE = 1e4;
|
|
@@ -100,12 +102,6 @@ function estimateRequestTokensCalibrated(messages, systemPrompt, tools) {
|
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
// src/utils/message-invariants.ts
|
|
103
|
-
function expectDefined2(value) {
|
|
104
|
-
if (value === null || value === void 0) {
|
|
105
|
-
throw new Error("Expected value to be defined");
|
|
106
|
-
}
|
|
107
|
-
return value;
|
|
108
|
-
}
|
|
109
105
|
function repairToolUseAdjacency(messages) {
|
|
110
106
|
const removedToolUses = [];
|
|
111
107
|
const removedToolResults = [];
|
|
@@ -113,7 +109,7 @@ function repairToolUseAdjacency(messages) {
|
|
|
113
109
|
let changed = false;
|
|
114
110
|
const out = [];
|
|
115
111
|
for (let i = 0; i < messages.length; i++) {
|
|
116
|
-
const original =
|
|
112
|
+
const original = expectDefined(messages[i]);
|
|
117
113
|
let msg = original;
|
|
118
114
|
if (hasToolUse(msg)) {
|
|
119
115
|
const nextIds = toolResultIds(messages[i + 1]);
|
|
@@ -613,12 +609,6 @@ var IntelligentCompactor = class {
|
|
|
613
609
|
};
|
|
614
610
|
|
|
615
611
|
// src/models/llm-selector.ts
|
|
616
|
-
function expectDefined3(value) {
|
|
617
|
-
if (value === null || value === void 0) {
|
|
618
|
-
throw new Error("Expected value to be defined");
|
|
619
|
-
}
|
|
620
|
-
return value;
|
|
621
|
-
}
|
|
622
612
|
var DEFAULT_SYSTEM_PROMPT = `You are a context pruning assistant. Given a conversation history and a token budget, decide which message ranges are worth keeping verbatim and which should be collapsed into summaries.
|
|
623
613
|
|
|
624
614
|
Output a JSON object with this structure:
|
|
@@ -659,7 +649,7 @@ function formatMessages(messages, maxChars = 8e3) {
|
|
|
659
649
|
const lines = [];
|
|
660
650
|
let used = 0;
|
|
661
651
|
for (let i = 0; i < messages.length; i++) {
|
|
662
|
-
const m =
|
|
652
|
+
const m = expectDefined(messages[i]);
|
|
663
653
|
const role = m.role.padEnd(10, " ");
|
|
664
654
|
let text;
|
|
665
655
|
if (typeof m.content === "string") {
|
|
@@ -724,7 +714,7 @@ IMPORTANT: Total conversation (${totalTokens} tokens) exceeds budget (${effectiv
|
|
|
724
714
|
let tokenCount = 0;
|
|
725
715
|
let startIdx = 0;
|
|
726
716
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
727
|
-
const m =
|
|
717
|
+
const m = expectDefined(messages[i]);
|
|
728
718
|
const cost = typeof m.content === "string" ? Math.ceil(m.content.length / 4) : m.content.reduce(
|
|
729
719
|
(acc, b) => acc + (b.type === "text" ? Math.ceil(b.text.length / 4) : Math.ceil(JSON.stringify(b).length / 4)),
|
|
730
720
|
0
|
|
@@ -1457,12 +1447,6 @@ function createToolOutputSerializer(opts = {}) {
|
|
|
1457
1447
|
}
|
|
1458
1448
|
|
|
1459
1449
|
// src/execution/tool-executor.ts
|
|
1460
|
-
function expectDefined4(value) {
|
|
1461
|
-
if (value === null || value === void 0) {
|
|
1462
|
-
throw new Error("Expected value to be defined");
|
|
1463
|
-
}
|
|
1464
|
-
return value;
|
|
1465
|
-
}
|
|
1466
1450
|
var ToolExecutor = class {
|
|
1467
1451
|
constructor(registry, opts) {
|
|
1468
1452
|
this.registry = registry;
|
|
@@ -1869,7 +1853,7 @@ function hasMalformedArguments(input) {
|
|
|
1869
1853
|
function extractMalformedRaw(input) {
|
|
1870
1854
|
if (!hasMalformedArguments(input)) return void 0;
|
|
1871
1855
|
const obj = input;
|
|
1872
|
-
const value = obj[
|
|
1856
|
+
const value = obj[expectDefined(Object.keys(obj)[0])];
|
|
1873
1857
|
if (value === void 0 || value === null) return void 0;
|
|
1874
1858
|
if (typeof value === "string") return value;
|
|
1875
1859
|
try {
|
|
@@ -2189,12 +2173,225 @@ function appendJournal(goal, entry) {
|
|
|
2189
2173
|
journal: trimmed
|
|
2190
2174
|
};
|
|
2191
2175
|
}
|
|
2176
|
+
function parseProgressFromText(text) {
|
|
2177
|
+
const re = /\[progress:\s*(\d{1,3})%\]\s*(?:[—\-]\s*(.+))?/i;
|
|
2178
|
+
const m = text.match(re);
|
|
2179
|
+
if (!m) return null;
|
|
2180
|
+
const progress = Math.min(100, Math.max(0, Number.parseInt(m[1], 10)));
|
|
2181
|
+
const note = m[2]?.trim() || void 0;
|
|
2182
|
+
return { progress, note };
|
|
2183
|
+
}
|
|
2184
|
+
function recordProgress(goal, progress, note) {
|
|
2185
|
+
const clamped = Math.min(100, Math.max(0, progress));
|
|
2186
|
+
const history = [...goal.progressHistory ?? [], { at: (/* @__PURE__ */ new Date()).toISOString(), progress: clamped, note }];
|
|
2187
|
+
const trimmed = history.length > 200 ? history.slice(-200) : history;
|
|
2188
|
+
return {
|
|
2189
|
+
...goal,
|
|
2190
|
+
progress: clamped,
|
|
2191
|
+
progressNote: note ?? `${clamped}% complete`,
|
|
2192
|
+
progressHistory: trimmed,
|
|
2193
|
+
progressTrend: computeTrend(trimmed)
|
|
2194
|
+
};
|
|
2195
|
+
}
|
|
2196
|
+
function computeTrend(history) {
|
|
2197
|
+
if (history.length < 3) return void 0;
|
|
2198
|
+
const recent = history.slice(-5);
|
|
2199
|
+
const deltas = [];
|
|
2200
|
+
for (let i = 1; i < recent.length; i++) {
|
|
2201
|
+
deltas.push(recent[i].progress - recent[i - 1].progress);
|
|
2202
|
+
}
|
|
2203
|
+
if (deltas.length < 2) return void 0;
|
|
2204
|
+
const avgDelta = deltas.reduce((a, b) => a + b, 0) / deltas.length;
|
|
2205
|
+
if (avgDelta > 2) return "accelerating";
|
|
2206
|
+
if (avgDelta < -1) return "stalling";
|
|
2207
|
+
return "steady";
|
|
2208
|
+
}
|
|
2192
2209
|
|
|
2193
2210
|
// src/utils/sleep.ts
|
|
2194
2211
|
function sleep(ms) {
|
|
2195
2212
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
2196
2213
|
}
|
|
2197
2214
|
|
|
2215
|
+
// src/execution/autonomy-brain.ts
|
|
2216
|
+
var RISK_LEVELS = {
|
|
2217
|
+
low: 0,
|
|
2218
|
+
medium: 1,
|
|
2219
|
+
high: 2,
|
|
2220
|
+
critical: 3
|
|
2221
|
+
};
|
|
2222
|
+
function createAutonomyBrain(opts) {
|
|
2223
|
+
const maxRisk = opts.maxAutoRisk ?? "high";
|
|
2224
|
+
const maxRiskLevel = RISK_LEVELS[maxRisk] ?? 2;
|
|
2225
|
+
const timeoutMs = opts.decisionTimeoutMs ?? 15e3;
|
|
2226
|
+
return {
|
|
2227
|
+
async decide(request) {
|
|
2228
|
+
const requestLevel = RISK_LEVELS[request.risk] ?? 2;
|
|
2229
|
+
if (requestLevel > maxRiskLevel) {
|
|
2230
|
+
const reason = `Auto-denied: risk "${request.risk}" exceeds max "${maxRisk}"`;
|
|
2231
|
+
const decision = { type: "deny", reason };
|
|
2232
|
+
opts.onDecision?.(
|
|
2233
|
+
`\u{1F9E0} Brain: DENIED \u2014 ${request.question.slice(0, 80)} (risk: ${request.risk} > ${maxRisk})`,
|
|
2234
|
+
decision,
|
|
2235
|
+
request
|
|
2236
|
+
);
|
|
2237
|
+
return decision;
|
|
2238
|
+
}
|
|
2239
|
+
const heuristic = quickDecide(request);
|
|
2240
|
+
if (heuristic) {
|
|
2241
|
+
opts.onDecision?.(formatDecisionSummary(heuristic, request), heuristic, request);
|
|
2242
|
+
return heuristic;
|
|
2243
|
+
}
|
|
2244
|
+
const llmDecision = await llmDecide(request, opts.provider, opts.model, timeoutMs);
|
|
2245
|
+
opts.onDecision?.(formatDecisionSummary(llmDecision, request), llmDecision, request);
|
|
2246
|
+
return llmDecision;
|
|
2247
|
+
}
|
|
2248
|
+
};
|
|
2249
|
+
}
|
|
2250
|
+
function formatDecisionSummary(decision, request) {
|
|
2251
|
+
const question = request.question.length > 80 ? request.question.slice(0, 77) + "\u2026" : request.question;
|
|
2252
|
+
if (decision.type === "deny") {
|
|
2253
|
+
return `\u{1F9E0} Brain: DENIED \u2014 "${question}" \u2192 ${decision.reason}`;
|
|
2254
|
+
}
|
|
2255
|
+
if (decision.type === "answer") {
|
|
2256
|
+
const action = decision.optionId ? `chose [${decision.optionId}]` : decision.text.length > 60 ? decision.text.slice(0, 57) + "\u2026" : decision.text;
|
|
2257
|
+
return `\u{1F9E0} Brain: DECIDED \u2014 "${question}" \u2192 ${action}`;
|
|
2258
|
+
}
|
|
2259
|
+
return `\u{1F9E0} Brain: ASKED HUMAN \u2014 "${question}"`;
|
|
2260
|
+
}
|
|
2261
|
+
function quickDecide(request) {
|
|
2262
|
+
const q = request.question.toLowerCase();
|
|
2263
|
+
const ctx = request.context?.toLowerCase() ?? "";
|
|
2264
|
+
if (q.includes("deadlock") && ctx.includes("failed")) {
|
|
2265
|
+
return {
|
|
2266
|
+
type: "answer",
|
|
2267
|
+
text: "Skip deadlocked tasks and continue with remaining work. Failed tasks will be reported in the final summary.",
|
|
2268
|
+
rationale: "Heuristic: deadlocked tasks blocked by failed dependencies \u2014 skipping unblocks remaining work."
|
|
2269
|
+
};
|
|
2270
|
+
}
|
|
2271
|
+
if ((q.includes("failed") || q.includes("retry")) && (ctx.includes("3") || ctx.includes("exhausted"))) {
|
|
2272
|
+
return {
|
|
2273
|
+
type: "answer",
|
|
2274
|
+
text: "Mark as failed and move on. Note the failure for the final report.",
|
|
2275
|
+
rationale: "Heuristic: retries exhausted \u2014 continuing would waste resources."
|
|
2276
|
+
};
|
|
2277
|
+
}
|
|
2278
|
+
if (q.includes("goal complete") || q.includes("mission complete")) {
|
|
2279
|
+
return null;
|
|
2280
|
+
}
|
|
2281
|
+
if (q.includes("continue") || q.includes("proceed")) {
|
|
2282
|
+
return {
|
|
2283
|
+
type: "answer",
|
|
2284
|
+
text: "Continue execution. Do not stop.",
|
|
2285
|
+
rationale: "Heuristic: autonomy mode \u2014 continue until all work is complete."
|
|
2286
|
+
};
|
|
2287
|
+
}
|
|
2288
|
+
return null;
|
|
2289
|
+
}
|
|
2290
|
+
async function llmDecide(request, provider, model, timeoutMs) {
|
|
2291
|
+
const optionsText = request.options?.length ? "\nOptions:\n" + request.options.map(
|
|
2292
|
+
(o) => ` [${o.id}] ${o.label}${o.consequence ? ` \u2014 ${o.consequence}` : ""}${o.recommended ? " \u2605 recommended" : ""}`
|
|
2293
|
+
).join("\n") : "";
|
|
2294
|
+
const systemPrompt = [
|
|
2295
|
+
"IDENTITY:",
|
|
2296
|
+
"You are the Autonomy Brain \u2014 a dedicated decision engine inside an",
|
|
2297
|
+
"autonomous AI coding agent called WrongStack. Your SOLE purpose is to",
|
|
2298
|
+
"evaluate situations where the autonomous workflow is blocked, stuck, or",
|
|
2299
|
+
"uncertain, and decide the best course of action to keep the system",
|
|
2300
|
+
"running and making progress toward its goal.",
|
|
2301
|
+
"",
|
|
2302
|
+
"WHAT YOU DO:",
|
|
2303
|
+
"- You receive a question + context from an autonomy subsystem (goal",
|
|
2304
|
+
" engine, phase orchestrator, task decomposer).",
|
|
2305
|
+
"- You evaluate whether the system should continue, pivot, retry, skip,",
|
|
2306
|
+
" or stop.",
|
|
2307
|
+
"- You output exactly ONE decision. No preamble, no markdown, no",
|
|
2308
|
+
" elaboration beyond what is needed to justify the decision.",
|
|
2309
|
+
"",
|
|
2310
|
+
"HOW YOU DECIDE:",
|
|
2311
|
+
'1. PREFER CONTINUATION. The default answer is always "continue" unless',
|
|
2312
|
+
" there is clear evidence that stopping is safer or more productive.",
|
|
2313
|
+
"2. BE SPECIFIC. If options are provided, pick one by its [id]. If not,",
|
|
2314
|
+
" describe the exact action in 1-2 sentences.",
|
|
2315
|
+
"3. VERIFY COMPLETION. If the question is about whether the goal is done,",
|
|
2316
|
+
" check deliverables and progress before saying yes. A progress bar at",
|
|
2317
|
+
" 80% with open deliverables means NOT done.",
|
|
2318
|
+
"4. AVOID WASTE. If a task has failed 3+ times with the same approach,",
|
|
2319
|
+
" recommend a different approach or skipping it \u2014 do not recommend",
|
|
2320
|
+
" retrying the same thing.",
|
|
2321
|
+
"5. CONSIDER COST. If the question mentions spent budget or token counts,",
|
|
2322
|
+
" factor that into your decision. A goal that has already spent $50",
|
|
2323
|
+
" with 90% progress is worth finishing; one at 15% with $100 spent",
|
|
2324
|
+
" may need re-evaluation.",
|
|
2325
|
+
"",
|
|
2326
|
+
"OUTPUT FORMAT:",
|
|
2327
|
+
"- With options: output the option [id] and a 1-sentence justification.",
|
|
2328
|
+
' Example: "[resolve] \u2014 conflict is in test files only, safe to auto-resolve."',
|
|
2329
|
+
"- Without options: output the decision as a 1-2 sentence action.",
|
|
2330
|
+
' Example: "Continue execution. Progress is steady at 60% with 3/5',
|
|
2331
|
+
' deliverables done. No reason to stop."',
|
|
2332
|
+
"",
|
|
2333
|
+
"CRITICAL RULE:",
|
|
2334
|
+
"You are NOT the main agent. Do not suggest code changes, tool calls,",
|
|
2335
|
+
"or implementation details. Your output is a DECISION, not a plan."
|
|
2336
|
+
].join("\n");
|
|
2337
|
+
const userMessage = [
|
|
2338
|
+
`Question: ${request.question}`,
|
|
2339
|
+
request.context ? `
|
|
2340
|
+
Context:
|
|
2341
|
+
${request.context}` : "",
|
|
2342
|
+
optionsText
|
|
2343
|
+
].filter(Boolean).join("\n");
|
|
2344
|
+
try {
|
|
2345
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
2346
|
+
const response = await provider.complete(
|
|
2347
|
+
{
|
|
2348
|
+
model,
|
|
2349
|
+
system: [{ type: "text", text: systemPrompt }],
|
|
2350
|
+
messages: [{ role: "user", content: userMessage || "Decide." }],
|
|
2351
|
+
maxTokens: 200
|
|
2352
|
+
},
|
|
2353
|
+
{ signal }
|
|
2354
|
+
);
|
|
2355
|
+
const text = extractText(response).trim();
|
|
2356
|
+
if (request.options?.length) {
|
|
2357
|
+
for (const opt of request.options) {
|
|
2358
|
+
if (text.toLowerCase().includes(opt.id.toLowerCase())) {
|
|
2359
|
+
return {
|
|
2360
|
+
type: "answer",
|
|
2361
|
+
optionId: opt.id,
|
|
2362
|
+
text: opt.label,
|
|
2363
|
+
rationale: text
|
|
2364
|
+
};
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
return {
|
|
2369
|
+
type: "answer",
|
|
2370
|
+
text: text || (request.fallback === "continue" ? "Continue execution." : "Denied by autonomy policy."),
|
|
2371
|
+
rationale: text || void 0
|
|
2372
|
+
};
|
|
2373
|
+
} catch {
|
|
2374
|
+
if (request.fallback === "continue") {
|
|
2375
|
+
return {
|
|
2376
|
+
type: "answer",
|
|
2377
|
+
text: "Continue (Autonomy Brain LLM unavailable \u2014 using fallback)."
|
|
2378
|
+
};
|
|
2379
|
+
}
|
|
2380
|
+
return { type: "deny", reason: "Autonomy Brain LLM unavailable for decision." };
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
function extractText(result) {
|
|
2384
|
+
if (!result || typeof result !== "object") return "";
|
|
2385
|
+
const r = result;
|
|
2386
|
+
if (Array.isArray(r.content)) {
|
|
2387
|
+
return r.content.filter((b) => b.type === "text").map((b) => b.text ?? "").join("");
|
|
2388
|
+
}
|
|
2389
|
+
if (Array.isArray(r.choices)) {
|
|
2390
|
+
return r.choices[0]?.message?.content ?? "";
|
|
2391
|
+
}
|
|
2392
|
+
return typeof r.text === "string" ? r.text : "";
|
|
2393
|
+
}
|
|
2394
|
+
|
|
2198
2395
|
// src/execution/eternal-autonomy.ts
|
|
2199
2396
|
var execFileP = promisify(execFile);
|
|
2200
2397
|
var BRAINSTORM_DONE = /* @__PURE__ */ Symbol("brainstorm-done");
|
|
@@ -2264,7 +2461,7 @@ var EternalAutonomyEngine = class {
|
|
|
2264
2461
|
this.consecutiveFailures = 0;
|
|
2265
2462
|
}
|
|
2266
2463
|
if (this.stopRequested) break;
|
|
2267
|
-
await sleep(this.opts.cycleGapMs ??
|
|
2464
|
+
await sleep(this.opts.cycleGapMs ?? 0);
|
|
2268
2465
|
}
|
|
2269
2466
|
} finally {
|
|
2270
2467
|
this.state = "stopped";
|
|
@@ -2434,6 +2631,18 @@ var EternalAutonomyEngine = class {
|
|
|
2434
2631
|
this.stopRequested = true;
|
|
2435
2632
|
return true;
|
|
2436
2633
|
}
|
|
2634
|
+
const parsed = parseProgressFromText(finalText);
|
|
2635
|
+
if (parsed) {
|
|
2636
|
+
await this.updateProgress(parsed.progress, parsed.note);
|
|
2637
|
+
if (parsed.progress >= 100) {
|
|
2638
|
+
await this.markGoalCompleted(
|
|
2639
|
+
{ source: action.source, task: action.task, directive: action.directive },
|
|
2640
|
+
`progress reached 100%: ${parsed.note ?? "goal complete"}`
|
|
2641
|
+
);
|
|
2642
|
+
this.stopRequested = true;
|
|
2643
|
+
return true;
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2437
2646
|
this.iterationsSinceCompact++;
|
|
2438
2647
|
await this.maybeCompact().catch((err) => {
|
|
2439
2648
|
this.opts.onError?.(
|
|
@@ -2520,11 +2729,16 @@ var EternalAutonomyEngine = class {
|
|
|
2520
2729
|
this.consecutiveBrainstormDone++;
|
|
2521
2730
|
const threshold = this.opts.brainstormDoneStopThreshold ?? 3;
|
|
2522
2731
|
if (this.consecutiveBrainstormDone >= threshold) {
|
|
2523
|
-
await this.
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2732
|
+
const shouldStop = await this.consultBrainForDone(goal);
|
|
2733
|
+
if (shouldStop) {
|
|
2734
|
+
await this.markGoalCompleted(
|
|
2735
|
+
{ source: "brainstorm", task: "no further work", directive: "" },
|
|
2736
|
+
`brainstorm returned DONE ${this.consecutiveBrainstormDone}x in a row${this.opts.brain ? ", brain confirmed" : ""}`
|
|
2737
|
+
);
|
|
2738
|
+
this.stopRequested = true;
|
|
2739
|
+
} else {
|
|
2740
|
+
this.consecutiveBrainstormDone = 0;
|
|
2741
|
+
}
|
|
2528
2742
|
}
|
|
2529
2743
|
return null;
|
|
2530
2744
|
}
|
|
@@ -2758,6 +2972,69 @@ ${recentJournal}` : "No prior iterations.",
|
|
|
2758
2972
|
async appendFailure(task, note) {
|
|
2759
2973
|
await this.appendIterationEntry({ source: "manual", task, status: "failure", note });
|
|
2760
2974
|
}
|
|
2975
|
+
/**
|
|
2976
|
+
* Consult the brain on whether the goal is truly complete.
|
|
2977
|
+
* Without a brain, always returns true (use heuristic: DONE threshold met = done).
|
|
2978
|
+
*/
|
|
2979
|
+
async consultBrainForDone(goal) {
|
|
2980
|
+
if (!this.opts.brain) return true;
|
|
2981
|
+
const deliverablesStatus = goal.deliverables?.length ? `
|
|
2982
|
+
Deliverables: ${goal.deliverables.length} total, progress ${goal.progress ?? "unknown"}%` : "";
|
|
2983
|
+
const recentJournal = goal.journal.slice(-5).map(
|
|
2984
|
+
(e) => ` #${e.iteration} [${e.status}] ${e.task}`
|
|
2985
|
+
).join("\n");
|
|
2986
|
+
try {
|
|
2987
|
+
const decision = await this.opts.brain.decide({
|
|
2988
|
+
id: `goal-done-${goal.iterations}`,
|
|
2989
|
+
source: "system",
|
|
2990
|
+
question: `Brainstorm returned DONE ${this.consecutiveBrainstormDone}x. Is the goal truly complete?`,
|
|
2991
|
+
context: [
|
|
2992
|
+
`Goal: ${goal.goal}`,
|
|
2993
|
+
`Iterations: ${goal.iterations}`,
|
|
2994
|
+
`Progress: ${goal.progress ?? "unknown"}%`,
|
|
2995
|
+
deliverablesStatus,
|
|
2996
|
+
recentJournal ? `
|
|
2997
|
+
Recent work:
|
|
2998
|
+
${recentJournal}` : ""
|
|
2999
|
+
].join("\n"),
|
|
3000
|
+
risk: "high",
|
|
3001
|
+
fallback: "continue"
|
|
3002
|
+
});
|
|
3003
|
+
const summary = formatDecisionSummary(decision, {
|
|
3004
|
+
id: `goal-done-${goal.iterations}`,
|
|
3005
|
+
source: "system",
|
|
3006
|
+
question: "Is the goal complete?",
|
|
3007
|
+
risk: "high",
|
|
3008
|
+
fallback: "continue"
|
|
3009
|
+
});
|
|
3010
|
+
const rationale = "rationale" in decision ? decision.rationale : void 0;
|
|
3011
|
+
await this.appendIterationEntry({
|
|
3012
|
+
source: "brainstorm",
|
|
3013
|
+
task: summary,
|
|
3014
|
+
status: "success",
|
|
3015
|
+
note: rationale
|
|
3016
|
+
});
|
|
3017
|
+
if (decision.type === "deny") {
|
|
3018
|
+
return false;
|
|
3019
|
+
}
|
|
3020
|
+
if (decision.type === "answer") {
|
|
3021
|
+
const text = decision.text.toLowerCase();
|
|
3022
|
+
return text.includes("complete") || text.includes("done") || text.includes("yes");
|
|
3023
|
+
}
|
|
3024
|
+
return true;
|
|
3025
|
+
} catch {
|
|
3026
|
+
return true;
|
|
3027
|
+
}
|
|
3028
|
+
}
|
|
3029
|
+
/**
|
|
3030
|
+
* Persist a progress update from the agent's [PROGRESS: N%] output.
|
|
3031
|
+
*/
|
|
3032
|
+
async updateProgress(progress, note) {
|
|
3033
|
+
const current = await loadGoal(this.goalPath);
|
|
3034
|
+
if (!current) return;
|
|
3035
|
+
const updated = recordProgress(current, progress, note);
|
|
3036
|
+
await saveGoal(this.goalPath, updated);
|
|
3037
|
+
}
|
|
2761
3038
|
async persistEngineState(state) {
|
|
2762
3039
|
const current = await loadGoal(this.goalPath);
|
|
2763
3040
|
if (!current) return;
|
|
@@ -3123,15 +3400,7 @@ function makeAgentSubagentRunner(opts) {
|
|
|
3123
3400
|
let budgetError = null;
|
|
3124
3401
|
const onBudgetError = (err) => {
|
|
3125
3402
|
if (err instanceof BudgetThresholdSignal) {
|
|
3126
|
-
|
|
3127
|
-
if (decision === "stop") {
|
|
3128
|
-
budgetError = new BudgetExceededError(err.kind, err.limit, err.used);
|
|
3129
|
-
aborter.abort();
|
|
3130
|
-
}
|
|
3131
|
-
}).catch(() => {
|
|
3132
|
-
budgetError = new BudgetExceededError(err.kind, err.limit, err.used);
|
|
3133
|
-
aborter.abort();
|
|
3134
|
-
});
|
|
3403
|
+
budgetError = err;
|
|
3135
3404
|
return;
|
|
3136
3405
|
}
|
|
3137
3406
|
aborter.abort();
|
|
@@ -3239,15 +3508,23 @@ function makeAgentSubagentRunner(opts) {
|
|
|
3239
3508
|
}
|
|
3240
3509
|
if (budgetError) {
|
|
3241
3510
|
if ("decision" in budgetError) {
|
|
3242
|
-
|
|
3243
|
-
|
|
3511
|
+
try {
|
|
3512
|
+
const decision = await budgetError.decision;
|
|
3513
|
+
if (decision === "stop") {
|
|
3514
|
+
budgetError = new BudgetExceededError(
|
|
3515
|
+
budgetError.kind,
|
|
3516
|
+
budgetError.limit,
|
|
3517
|
+
budgetError.used
|
|
3518
|
+
);
|
|
3519
|
+
} else {
|
|
3520
|
+
budgetError = null;
|
|
3521
|
+
}
|
|
3522
|
+
} catch {
|
|
3244
3523
|
budgetError = new BudgetExceededError(
|
|
3245
3524
|
budgetError.kind,
|
|
3246
3525
|
budgetError.limit,
|
|
3247
3526
|
budgetError.used
|
|
3248
3527
|
);
|
|
3249
|
-
} else {
|
|
3250
|
-
budgetError = null;
|
|
3251
3528
|
}
|
|
3252
3529
|
}
|
|
3253
3530
|
if (budgetError) throw budgetError;
|
|
@@ -5411,6 +5688,109 @@ Working rules:
|
|
|
5411
5688
|
"cloud cost"
|
|
5412
5689
|
]
|
|
5413
5690
|
}
|
|
5691
|
+
},
|
|
5692
|
+
{
|
|
5693
|
+
config: {
|
|
5694
|
+
id: "tech-stack",
|
|
5695
|
+
name: "Tech Stack Validator",
|
|
5696
|
+
role: "tech-stack",
|
|
5697
|
+
tools: ["search", "fetch", "read", "grep", "glob", "outdated", "audit", "json"],
|
|
5698
|
+
prompt: `You are the Tech Stack Validator \u2014 a single-shot validation agent that fires
|
|
5699
|
+
before any package, library, or framework choice is committed.
|
|
5700
|
+
|
|
5701
|
+
Your ONLY job: verify that a technology choice is current, real, and not obsolete.
|
|
5702
|
+
You are the "this isn't code, this is 10-year-old technology" agent. Intervene
|
|
5703
|
+
hard when the LLM hallucinates a version number or suggests dead tech.
|
|
5704
|
+
|
|
5705
|
+
## Critical rules
|
|
5706
|
+
|
|
5707
|
+
1. **Verify existence.** Search npm registry (fetch https://registry.npmjs.org/<pkg>/latest)
|
|
5708
|
+
or web search. A package that doesn't exist = hallucination.
|
|
5709
|
+
|
|
5710
|
+
2. **Check latest version.** Never trust any version number from the model. Always
|
|
5711
|
+
fetch the actual latest stable version from npm or the project's release page.
|
|
5712
|
+
|
|
5713
|
+
3. **Reject dead packages.** No release in >2 years + unresolved critical issues =
|
|
5714
|
+
dead. Suggest a maintained replacement.
|
|
5715
|
+
|
|
5716
|
+
4. **Reject prehistoric tech.** Any package/pattern superseded \u22655 years ago is
|
|
5717
|
+
REJECTED. Key blocklist:
|
|
5718
|
+
- axios / node-fetch / got / request \u2192 native fetch (Node 18+)
|
|
5719
|
+
- moment \u2192 date-fns / luxon / Temporal
|
|
5720
|
+
- jQuery (new projects) \u2192 vanilla DOM / React
|
|
5721
|
+
- Gulp / Grunt \u2192 tsup / esbuild / vite
|
|
5722
|
+
- CoffeeScript / Flow \u2192 TypeScript
|
|
5723
|
+
- Bluebird \u2192 native Promises
|
|
5724
|
+
- crypto-js \u2192 node:crypto / Web Crypto
|
|
5725
|
+
- Bower \u2192 npm/pnpm
|
|
5726
|
+
- underscore \u2192 lodash or native ES2020+
|
|
5727
|
+
|
|
5728
|
+
5. **The intervention phrase.** When rejecting on age grounds, you MUST output
|
|
5729
|
+
exactly: "This isn't code, this is X-year-old technology." where X =
|
|
5730
|
+
current year \u2212 the year the technology was made obsolete. Follow with
|
|
5731
|
+
what replaced it and a one-step migration path.
|
|
5732
|
+
|
|
5733
|
+
6. **Prefer built-in over third-party.** Check Node 22+ native APIs first:
|
|
5734
|
+
node:test, node:sqlite, fetch, WebSocket, Web Crypto \u2014 all built-in.
|
|
5735
|
+
|
|
5736
|
+
## Workflow (single-shot \u2014 do NOT loop)
|
|
5737
|
+
|
|
5738
|
+
1. Receive the proposed package + version
|
|
5739
|
+
2. Search npm registry or web for the latest version
|
|
5740
|
+
3. Check age, maintenance status, deprecation
|
|
5741
|
+
4. Output verdict: APPROVED (with exact version) or REJECTED (with replacement)
|
|
5742
|
+
|
|
5743
|
+
## Output format
|
|
5744
|
+
|
|
5745
|
+
### Tech Stack Validation \u2014 <package>
|
|
5746
|
+
|
|
5747
|
+
**Status**: APPROVED | REJECTED
|
|
5748
|
+
|
|
5749
|
+
**Package**: <name>@<version>
|
|
5750
|
+
**Source**: <URL you checked \u2014 npm registry, GitHub, web search>
|
|
5751
|
+
**Age**: <first release> \u2014 <last release date>
|
|
5752
|
+
**Verdict**: 1\u20132 sentence explanation.
|
|
5753
|
+
|
|
5754
|
+
When REJECTED on age:
|
|
5755
|
+
**"This isn't code, this is X-year-old technology."**
|
|
5756
|
+
**Replaced by**: <modern alternative>
|
|
5757
|
+
**Migration**: <one concrete step>
|
|
5758
|
+
|
|
5759
|
+
When APPROVED:
|
|
5760
|
+
**Install**: pnpm add <name>@^<major>.<minor>.0`
|
|
5761
|
+
},
|
|
5762
|
+
budget: {
|
|
5763
|
+
timeoutMs: 6e4,
|
|
5764
|
+
maxIterations: 5,
|
|
5765
|
+
maxToolCalls: 20,
|
|
5766
|
+
maxTokens: 4e4,
|
|
5767
|
+
maxCostUsd: 0.1
|
|
5768
|
+
},
|
|
5769
|
+
capability: {
|
|
5770
|
+
phase: "meta",
|
|
5771
|
+
summary: "Single-shot tech stack validator: checks npm for latest versions, rejects dead/obsolete packages, enforces modern alternatives.",
|
|
5772
|
+
keywords: [
|
|
5773
|
+
"tech stack",
|
|
5774
|
+
"version",
|
|
5775
|
+
"package",
|
|
5776
|
+
"library",
|
|
5777
|
+
"framework",
|
|
5778
|
+
"dependency",
|
|
5779
|
+
"install",
|
|
5780
|
+
"upgrade",
|
|
5781
|
+
"latest",
|
|
5782
|
+
"npm",
|
|
5783
|
+
"pnpm add",
|
|
5784
|
+
"outdated",
|
|
5785
|
+
"obsolete",
|
|
5786
|
+
"deprecated",
|
|
5787
|
+
"what version",
|
|
5788
|
+
"which package",
|
|
5789
|
+
"check version",
|
|
5790
|
+
"verify version",
|
|
5791
|
+
"is this current"
|
|
5792
|
+
]
|
|
5793
|
+
}
|
|
5414
5794
|
}
|
|
5415
5795
|
];
|
|
5416
5796
|
|
|
@@ -6557,12 +6937,6 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
6557
6937
|
};
|
|
6558
6938
|
|
|
6559
6939
|
// src/execution/parallel-eternal-engine.ts
|
|
6560
|
-
function expectDefined5(value) {
|
|
6561
|
-
if (value === null || value === void 0) {
|
|
6562
|
-
throw new Error("Expected value to be defined");
|
|
6563
|
-
}
|
|
6564
|
-
return value;
|
|
6565
|
-
}
|
|
6566
6940
|
var GOAL_COMPLETE_MARKER2 = /^\s*\[goal[_\s-]?complete\]\s*$/im;
|
|
6567
6941
|
var ParallelEternalEngine = class {
|
|
6568
6942
|
constructor(opts) {
|
|
@@ -6718,7 +7092,7 @@ var ParallelEternalEngine = class {
|
|
|
6718
7092
|
// Fan-out
|
|
6719
7093
|
// -------------------------------------------------------------------------
|
|
6720
7094
|
async fanOut(goal, tasks) {
|
|
6721
|
-
const coordinator =
|
|
7095
|
+
const coordinator = expectDefined(this.coordinator);
|
|
6722
7096
|
const slotCount = Math.min(this.slots, tasks.length);
|
|
6723
7097
|
const routes = this.dispatchEnabled ? await Promise.all(
|
|
6724
7098
|
tasks.slice(0, slotCount).map(
|
|
@@ -6750,7 +7124,7 @@ ${recentJournal}` : "No prior iterations.",
|
|
|
6750
7124
|
const routeInfo = [];
|
|
6751
7125
|
const spawnPromises = [];
|
|
6752
7126
|
for (let i = 0; i < slotCount; i++) {
|
|
6753
|
-
const task =
|
|
7127
|
+
const task = expectDefined(tasks[i]);
|
|
6754
7128
|
const route = routes[i] ?? null;
|
|
6755
7129
|
const subagentId = `parallel-${this.iterations}-${i}`;
|
|
6756
7130
|
const taskId = randomUUID();
|
|
@@ -7023,7 +7397,17 @@ ${journalTail.join("\n")}` : "Recent journal: (none \u2014 this is the first ite
|
|
|
7023
7397
|
}
|
|
7024
7398
|
|
|
7025
7399
|
// src/execution/goal-preamble.ts
|
|
7026
|
-
function buildGoalPreamble(goal) {
|
|
7400
|
+
function buildGoalPreamble(goal, deliverables) {
|
|
7401
|
+
const deliverableBlock = deliverables && deliverables.length > 0 ? [
|
|
7402
|
+
"",
|
|
7403
|
+
"CONCRETE DELIVERABLES (check these off as you go):",
|
|
7404
|
+
...deliverables.map((d, i) => ` ${i + 1}. ${d}`),
|
|
7405
|
+
"",
|
|
7406
|
+
"After EACH iteration, estimate your completion percentage (0\u2013100)",
|
|
7407
|
+
"against this deliverable list. Output it as:",
|
|
7408
|
+
" [PROGRESS: N%] \u2014 <1-sentence status>",
|
|
7409
|
+
"The eternal engine reads this to update the progress bar."
|
|
7410
|
+
].join("\n") : "";
|
|
7027
7411
|
return [
|
|
7028
7412
|
"[GOAL \u2014 LOCKED IN. You will work on this until it is verifiably done.",
|
|
7029
7413
|
"The user granted you full autonomy. Read these constraints once, then act.",
|
|
@@ -7032,6 +7416,7 @@ function buildGoalPreamble(goal) {
|
|
|
7032
7416
|
"---",
|
|
7033
7417
|
goal,
|
|
7034
7418
|
"---",
|
|
7419
|
+
deliverableBlock,
|
|
7035
7420
|
"",
|
|
7036
7421
|
"AUTHORITY YOU HAVE:",
|
|
7037
7422
|
"- Spawn as many subagents as the work needs (delegate / spawn_subagent).",
|
|
@@ -7053,6 +7438,7 @@ function buildGoalPreamble(goal) {
|
|
|
7053
7438
|
"- You can tell the user HOW to verify it themselves in 10 seconds.",
|
|
7054
7439
|
'- You have NOT hedged. None of: "looks like it should work", "I',
|
|
7055
7440
|
' believe this fixes it", "the changes appear correct".',
|
|
7441
|
+
`- Progress bar shows 100%. All deliverables checked off.`,
|
|
7056
7442
|
"",
|
|
7057
7443
|
"WHAT IS NOT DONE \u2014 never report any of these as completion:",
|
|
7058
7444
|
"- An error message you didn't recover from.",
|
|
@@ -7067,6 +7453,13 @@ function buildGoalPreamble(goal) {
|
|
|
7067
7453
|
" respond to with a fresh attempt (different role, different model,",
|
|
7068
7454
|
" tighter prompt).",
|
|
7069
7455
|
"",
|
|
7456
|
+
"PROGRESS REPORTING \u2014 MANDATORY every iteration:",
|
|
7457
|
+
"- End every response with exactly: [PROGRESS: N%] \u2014 <status note>",
|
|
7458
|
+
" where N is your honest estimate (0-100) of how much of the goal",
|
|
7459
|
+
" is done. The engine tracks this and shows a live progress bar.",
|
|
7460
|
+
"- Example: [PROGRESS: 45%] \u2014 Auth module refactored, 3/5 tests pass,",
|
|
7461
|
+
" remaining: test coverage + docs update.",
|
|
7462
|
+
"",
|
|
7070
7463
|
"PERSISTENCE PROTOCOL:",
|
|
7071
7464
|
"- If blocked, try at least 3 different angles before reporting the",
|
|
7072
7465
|
" problem to the user. Different tool inputs, different subagent",
|
|
@@ -7342,6 +7735,6 @@ function parseDescription(raw) {
|
|
|
7342
7735
|
return { trigger, scope };
|
|
7343
7736
|
}
|
|
7344
7737
|
|
|
7345
|
-
export { AutoCompactionMiddleware, AutonomousRunner, DefaultErrorHandler, DefaultRetryPolicy, DefaultSkillLoader, DoneConditionChecker, EternalAutonomyEngine, HybridCompactor, IntelligentCompactor, ParallelEternalEngine, SelectiveCompactor, ToolExecutor, buildGoalPreamble, makeAutonomyPromptContributor };
|
|
7738
|
+
export { AutoCompactionMiddleware, AutonomousRunner, DefaultErrorHandler, DefaultRetryPolicy, DefaultSkillLoader, DoneConditionChecker, EternalAutonomyEngine, HybridCompactor, IntelligentCompactor, ParallelEternalEngine, SelectiveCompactor, ToolExecutor, buildGoalPreamble, createAutonomyBrain, formatDecisionSummary, makeAutonomyPromptContributor };
|
|
7346
7739
|
//# sourceMappingURL=index.js.map
|
|
7347
7740
|
//# sourceMappingURL=index.js.map
|