pi-crew 0.9.64 → 0.9.65
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 +13 -0
- package/README.md +46 -1
- package/dist/index.mjs +316 -299
- package/package.json +3 -2
- package/scripts/analyze-run.mjs +1333 -0
- package/scripts/pty_probe.py +10 -8
- package/scripts/resource-sampler.mjs +482 -0
- package/skills/real-test-pi-crew/SKILL.md +6 -6
- package/src/observability/event-to-metric.ts +29 -0
- package/src/observability/metrics-primitives.ts +41 -3
- package/src/runtime/README.md +1 -1
- package/src/runtime/broker/crew-broker.ts +0 -16
- package/src/runtime/effectiveness.ts +23 -1
- package/src/runtime/merge-gate.ts +202 -0
- package/src/runtime/model/model-fallback.ts +11 -0
- package/src/runtime/model/provider-extensions.ts +31 -12
- package/src/runtime/output/progress-tracker.ts +3 -33
- package/src/runtime/scratchpad/engine.ts +40 -2
- package/src/runtime/scratchpad/snapshot-hmac.ts +161 -0
- package/src/runtime/team-runner.ts +128 -203
- package/src/schema/team-tool-schema.ts +2 -0
- package/src/teams/discover-teams.ts +2 -0
- package/src/teams/team-config.ts +7 -0
- package/src/teams/team-serializer.ts +1 -0
- package/src/ui/mascot.ts +1 -14
- package/teams/default.team.md +1 -0
- package/teams/fast-fix.team.md +1 -0
- package/src/observability/event-bus.ts +0 -86
- package/src/plugins/plugin-define.ts +0 -6
- package/src/plugins/plugin-registry.ts +0 -32
- package/src/plugins/plugins/index.ts +0 -3
- package/src/plugins/plugins/nextjs.ts +0 -19
- package/src/plugins/plugins/vite.ts +0 -10
- package/src/plugins/plugins/vitest.ts +0 -9
- package/src/runtime/child-pi/child-pi-pool.ts +0 -68
- package/src/runtime/iteration-hooks.ts +0 -305
package/dist/index.mjs
CHANGED
|
@@ -11513,10 +11513,16 @@ function discoverProviderExtensions(settingsPath2) {
|
|
|
11513
11513
|
const npmBase = path9.join(baseDir, "npm", "node_modules");
|
|
11514
11514
|
for (const spec of settings.packages ?? []) {
|
|
11515
11515
|
if (typeof spec !== "string") continue;
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11516
|
+
let pkgDir;
|
|
11517
|
+
if (spec.startsWith("npm:")) {
|
|
11518
|
+
pkgDir = path9.join(npmBase, spec.slice(4));
|
|
11519
|
+
} else if (spec.startsWith("./") || spec.startsWith("../") || path9.isAbsolute(spec)) {
|
|
11520
|
+
pkgDir = path9.resolve(baseDir, spec);
|
|
11521
|
+
} else {
|
|
11522
|
+
continue;
|
|
11523
|
+
}
|
|
11519
11524
|
if (!fs9.existsSync(pkgDir)) continue;
|
|
11525
|
+
if (path9.resolve(pkgDir) === path9.resolve(packageRoot())) continue;
|
|
11520
11526
|
const entryPath = resolvePackageEntry(pkgDir);
|
|
11521
11527
|
if (entryPath) out.push({ spec, entryPath });
|
|
11522
11528
|
}
|
|
@@ -12442,6 +12448,8 @@ function parseTeamFile(filePath, source) {
|
|
|
12442
12448
|
defaultWorkflow: frontmatter.defaultWorkflow || frontmatter.workflow || void 0,
|
|
12443
12449
|
workspaceMode: frontmatter.workspaceMode?.trim() === "worktree" ? "worktree" : "single",
|
|
12444
12450
|
maxConcurrency: frontmatter.maxConcurrency ? Number.parseInt(frontmatter.maxConcurrency, 10) : void 0,
|
|
12451
|
+
// observability defaults ON ("luôn hoạt động"); explicit `observability: false` disables.
|
|
12452
|
+
observability: frontmatter.observability === void 0 ? true : frontmatter.observability !== "false",
|
|
12445
12453
|
routing: triggers || useWhen || avoidWhen || cost || category ? { triggers, useWhen, avoidWhen, cost, category } : void 0
|
|
12446
12454
|
};
|
|
12447
12455
|
} catch {
|
|
@@ -22404,7 +22412,18 @@ var init_model_fallback = __esm({
|
|
|
22404
22412
|
/context[_ ]?length[_ ]?exceeded/i,
|
|
22405
22413
|
/safety/i,
|
|
22406
22414
|
/is[_ ]?overloaded/i,
|
|
22407
|
-
/\b408\b
|
|
22415
|
+
/\b408\b/,
|
|
22416
|
+
//
|
|
22417
|
+
// EPIPE / broken-pipe. In the child-pi worker path this typically means
|
|
22418
|
+
// the child `pi` process exited (crash or early exit) while the parent
|
|
22419
|
+
// was still writing to its stdin — spawning a fresh child on the next
|
|
22420
|
+
// model in the fallback chain usually recovers. In the network path it
|
|
22421
|
+
// is a transient pipe close. Both are retryable on a different model.
|
|
22422
|
+
// See docs/failure-mode-inventory.md EPIPE gap; NON_RETRYABLE patterns
|
|
22423
|
+
// (auth/billing) are checked first, so an auth error mentioning EPIPE
|
|
22424
|
+
// stays non-retryable.
|
|
22425
|
+
/epipe/i,
|
|
22426
|
+
/broken pipe/i
|
|
22408
22427
|
];
|
|
22409
22428
|
NON_RETRYABLE_MODEL_FAILURE_PATTERNS = [
|
|
22410
22429
|
/auth(?:entication)?/i,
|
|
@@ -23842,10 +23861,12 @@ var init_team_tool_schema = __esm({
|
|
|
23842
23861
|
})
|
|
23843
23862
|
),
|
|
23844
23863
|
budgetTotal: Type.Optional(
|
|
23864
|
+
// Empty-string unset marker accepted (Tier-9: models emit "" when unset).
|
|
23845
23865
|
// 0 accepted as "unset/disabled" (models emit 0 for off); still rejects 1-999
|
|
23846
23866
|
// as the MISCONFIGURATION GUARD against typo'd silent-abort configs.
|
|
23847
23867
|
Type.Union(
|
|
23848
23868
|
[
|
|
23869
|
+
Type.Literal(""),
|
|
23849
23870
|
Type.Literal(0),
|
|
23850
23871
|
Type.Number({
|
|
23851
23872
|
minimum: 1e3
|
|
@@ -39565,6 +39586,7 @@ function serializeTeam(team) {
|
|
|
39565
39586
|
team.defaultWorkflow ? `defaultWorkflow: ${team.defaultWorkflow}` : void 0,
|
|
39566
39587
|
team.workspaceMode ? `workspaceMode: ${team.workspaceMode}` : void 0,
|
|
39567
39588
|
team.maxConcurrency !== void 0 ? `maxConcurrency: ${team.maxConcurrency}` : void 0,
|
|
39589
|
+
team.observability !== void 0 ? `observability: ${team.observability}` : void 0,
|
|
39568
39590
|
line2("triggers", team.routing?.triggers),
|
|
39569
39591
|
line2("useWhen", team.routing?.useWhen),
|
|
39570
39592
|
line2("avoidWhen", team.routing?.avoidWhen),
|
|
@@ -48455,6 +48477,9 @@ function taskHasObservableWorkerActivity(task) {
|
|
|
48455
48477
|
(task.agentProgress?.toolCount ?? 0) > 0 || task.usage || task.transcriptArtifact || task.modelAttempts?.some((attempt) => attempt.success) || task.jsonEvents
|
|
48456
48478
|
);
|
|
48457
48479
|
}
|
|
48480
|
+
function taskHasEmptyResult(task) {
|
|
48481
|
+
return Boolean(task.resultArtifact && task.resultArtifact.sizeBytes === 0);
|
|
48482
|
+
}
|
|
48458
48483
|
function resolveEffectivenessGuardMode(runtimeConfig, manifest) {
|
|
48459
48484
|
const configured = runtimeConfig?.effectivenessGuard;
|
|
48460
48485
|
if (configured === "off" || configured === "warn" || configured === "block" || configured === "fail") return configured;
|
|
@@ -48463,7 +48488,7 @@ function resolveEffectivenessGuardMode(runtimeConfig, manifest) {
|
|
|
48463
48488
|
}
|
|
48464
48489
|
function evaluateRunEffectiveness(input) {
|
|
48465
48490
|
const completedTasks = input.tasks.filter((task) => task.status === "completed");
|
|
48466
|
-
const noObservedWorkTasks = completedTasks.filter((task) => !taskHasObservableWorkerActivity(task));
|
|
48491
|
+
const noObservedWorkTasks = completedTasks.filter((task) => !taskHasObservableWorkerActivity(task) || taskHasEmptyResult(task));
|
|
48467
48492
|
const needsAttentionTasks = input.tasks.filter((task) => task.agentProgress?.activityState === "needs_attention");
|
|
48468
48493
|
const workerExecution = input.executeWorkers ? "enabled" : "disabled/scaffold";
|
|
48469
48494
|
const guardMode = resolveEffectivenessGuardMode(input.runtimeConfig, input.manifest);
|
|
@@ -49325,112 +49350,6 @@ var init_correlation = __esm({
|
|
|
49325
49350
|
}
|
|
49326
49351
|
});
|
|
49327
49352
|
|
|
49328
|
-
// src/plugins/plugin-registry.ts
|
|
49329
|
-
var PluginRegistry;
|
|
49330
|
-
var init_plugin_registry = __esm({
|
|
49331
|
-
"src/plugins/plugin-registry.ts"() {
|
|
49332
|
-
"use strict";
|
|
49333
|
-
PluginRegistry = class {
|
|
49334
|
-
plugins = [];
|
|
49335
|
-
register(plugin) {
|
|
49336
|
-
this.plugins.push(plugin);
|
|
49337
|
-
}
|
|
49338
|
-
activePlugins(allDeps) {
|
|
49339
|
-
return this.plugins.filter(
|
|
49340
|
-
(p) => p.enablers.some((enabler) => {
|
|
49341
|
-
if (enabler.endsWith("/")) {
|
|
49342
|
-
return allDeps.some((d) => d.startsWith(enabler));
|
|
49343
|
-
}
|
|
49344
|
-
return allDeps.includes(enabler);
|
|
49345
|
-
})
|
|
49346
|
-
);
|
|
49347
|
-
}
|
|
49348
|
-
allPlugins() {
|
|
49349
|
-
return [...this.plugins];
|
|
49350
|
-
}
|
|
49351
|
-
};
|
|
49352
|
-
}
|
|
49353
|
-
});
|
|
49354
|
-
|
|
49355
|
-
// src/plugins/plugin-define.ts
|
|
49356
|
-
function definePlugin(spec) {
|
|
49357
|
-
return spec;
|
|
49358
|
-
}
|
|
49359
|
-
var init_plugin_define = __esm({
|
|
49360
|
-
"src/plugins/plugin-define.ts"() {
|
|
49361
|
-
"use strict";
|
|
49362
|
-
}
|
|
49363
|
-
});
|
|
49364
|
-
|
|
49365
|
-
// src/plugins/plugins/nextjs.ts
|
|
49366
|
-
var NextJsPlugin;
|
|
49367
|
-
var init_nextjs = __esm({
|
|
49368
|
-
"src/plugins/plugins/nextjs.ts"() {
|
|
49369
|
-
"use strict";
|
|
49370
|
-
init_plugin_define();
|
|
49371
|
-
NextJsPlugin = definePlugin({
|
|
49372
|
-
name: "nextjs",
|
|
49373
|
-
enablers: ["next"],
|
|
49374
|
-
entryPatterns: [
|
|
49375
|
-
"src/app/**/*.{ts,tsx}",
|
|
49376
|
-
"src/pages/**/*.{ts,tsx}",
|
|
49377
|
-
"src/app/**/page.{ts,tsx}",
|
|
49378
|
-
"src/app/**/layout.{ts,tsx}",
|
|
49379
|
-
"src/app/**/route.{ts,tsx}",
|
|
49380
|
-
"middleware.{ts,js}",
|
|
49381
|
-
"next.config.{ts,js,mjs}"
|
|
49382
|
-
],
|
|
49383
|
-
configPatterns: ["next.config.{ts,js,mjs}"],
|
|
49384
|
-
toolingDependencies: ["next", "@next/font", "@next/mdx"],
|
|
49385
|
-
pathAliases: [["~", "src"]],
|
|
49386
|
-
virtualModulePrefixes: ["next:"]
|
|
49387
|
-
});
|
|
49388
|
-
}
|
|
49389
|
-
});
|
|
49390
|
-
|
|
49391
|
-
// src/plugins/plugins/vite.ts
|
|
49392
|
-
var VitePlugin;
|
|
49393
|
-
var init_vite = __esm({
|
|
49394
|
-
"src/plugins/plugins/vite.ts"() {
|
|
49395
|
-
"use strict";
|
|
49396
|
-
init_plugin_define();
|
|
49397
|
-
VitePlugin = definePlugin({
|
|
49398
|
-
name: "vite",
|
|
49399
|
-
enablers: ["vite", "rolldown-vite"],
|
|
49400
|
-
entryPatterns: ["src/main.{ts,tsx,js,jsx}", "src/index.{ts,tsx,js,jsx}", "index.html"],
|
|
49401
|
-
configPatterns: ["vite.config.{ts,js,mts,mjs}"],
|
|
49402
|
-
toolingDependencies: ["vite"],
|
|
49403
|
-
virtualModulePrefixes: ["virtual:"]
|
|
49404
|
-
});
|
|
49405
|
-
}
|
|
49406
|
-
});
|
|
49407
|
-
|
|
49408
|
-
// src/plugins/plugins/vitest.ts
|
|
49409
|
-
var VitestPlugin;
|
|
49410
|
-
var init_vitest = __esm({
|
|
49411
|
-
"src/plugins/plugins/vitest.ts"() {
|
|
49412
|
-
"use strict";
|
|
49413
|
-
init_plugin_define();
|
|
49414
|
-
VitestPlugin = definePlugin({
|
|
49415
|
-
name: "vitest",
|
|
49416
|
-
enablers: ["vitest"],
|
|
49417
|
-
entryPatterns: ["**/*.test.{ts,tsx}", "**/*.spec.{ts,tsx}", "src/**/*.test.{ts,tsx}", "src/**/*.spec.{ts,tsx}"],
|
|
49418
|
-
configPatterns: ["vitest.config.{ts,js,mjs}", "vite.config.ts"],
|
|
49419
|
-
toolingDependencies: ["vitest"]
|
|
49420
|
-
});
|
|
49421
|
-
}
|
|
49422
|
-
});
|
|
49423
|
-
|
|
49424
|
-
// src/plugins/plugins/index.ts
|
|
49425
|
-
var init_plugins = __esm({
|
|
49426
|
-
"src/plugins/plugins/index.ts"() {
|
|
49427
|
-
"use strict";
|
|
49428
|
-
init_nextjs();
|
|
49429
|
-
init_vite();
|
|
49430
|
-
init_vitest();
|
|
49431
|
-
}
|
|
49432
|
-
});
|
|
49433
|
-
|
|
49434
49353
|
// src/runtime/task-health.ts
|
|
49435
49354
|
function scoreToGrade(score) {
|
|
49436
49355
|
if (score >= 90) return "A";
|
|
@@ -50470,6 +50389,166 @@ var init_group_join = __esm({
|
|
|
50470
50389
|
}
|
|
50471
50390
|
});
|
|
50472
50391
|
|
|
50392
|
+
// src/runtime/scheduling/task-graph-scheduler.ts
|
|
50393
|
+
function buildTaskGraphIndex(tasks) {
|
|
50394
|
+
const cached2 = taskGraphIndexCache.get(tasks);
|
|
50395
|
+
if (cached2) return cached2;
|
|
50396
|
+
const fresh = {
|
|
50397
|
+
doneSteps: new Set(
|
|
50398
|
+
tasks.filter((task) => task.status === "completed").map((task) => task.stepId).filter((id) => id !== void 0)
|
|
50399
|
+
),
|
|
50400
|
+
idMap: new Map(tasks.map((task) => [task.id, task])),
|
|
50401
|
+
stepToTaskId: new Map(
|
|
50402
|
+
tasks.map((task) => [task.stepId, task.id]).filter((entry) => entry[0] !== void 0)
|
|
50403
|
+
)
|
|
50404
|
+
};
|
|
50405
|
+
taskGraphIndexCache.set(tasks, fresh);
|
|
50406
|
+
return fresh;
|
|
50407
|
+
}
|
|
50408
|
+
function dependencySatisfied(task, doneStepIds, idMap, stepMap) {
|
|
50409
|
+
return task.dependsOn.every((dependency) => {
|
|
50410
|
+
if (doneStepIds.has(dependency)) return true;
|
|
50411
|
+
const taskId = stepMap.get(dependency) ?? dependency;
|
|
50412
|
+
return idMap.get(taskId)?.status === "completed";
|
|
50413
|
+
});
|
|
50414
|
+
}
|
|
50415
|
+
function withQueue(task, index) {
|
|
50416
|
+
let resolvedQueue;
|
|
50417
|
+
if (task.status === "queued") {
|
|
50418
|
+
const isReady = dependencySatisfied(task, index.doneSteps, index.idMap, index.stepToTaskId);
|
|
50419
|
+
resolvedQueue = isReady ? "ready" : "blocked";
|
|
50420
|
+
} else if (task.status === "running") {
|
|
50421
|
+
resolvedQueue = "running";
|
|
50422
|
+
} else if (task.status === "completed" || task.status === "skipped" || task.status === "needs_attention") {
|
|
50423
|
+
resolvedQueue = "done";
|
|
50424
|
+
} else {
|
|
50425
|
+
resolvedQueue = "blocked";
|
|
50426
|
+
}
|
|
50427
|
+
if (task.graph && task.graph.queue === resolvedQueue) {
|
|
50428
|
+
return task;
|
|
50429
|
+
}
|
|
50430
|
+
return {
|
|
50431
|
+
...task,
|
|
50432
|
+
graph: task.graph ? { ...task.graph, queue: resolvedQueue } : task.graph
|
|
50433
|
+
};
|
|
50434
|
+
}
|
|
50435
|
+
function ensureIndex(tasks, index) {
|
|
50436
|
+
return index ?? buildTaskGraphIndex(tasks);
|
|
50437
|
+
}
|
|
50438
|
+
function refreshTaskGraphQueues(tasks, index) {
|
|
50439
|
+
const resolved = ensureIndex(tasks, index);
|
|
50440
|
+
return tasks.map((task) => withQueue(task, resolved));
|
|
50441
|
+
}
|
|
50442
|
+
function taskGraphSnapshot(tasks, index) {
|
|
50443
|
+
const refreshed = refreshTaskGraphQueues(tasks, index);
|
|
50444
|
+
return {
|
|
50445
|
+
ready: refreshed.filter((task) => task.status === "queued" && task.graph?.queue === "ready").map((task) => task.id),
|
|
50446
|
+
blocked: refreshed.filter((task) => task.status === "queued" && task.graph?.queue === "blocked").map((task) => task.id),
|
|
50447
|
+
running: refreshed.filter((task) => task.status === "running").map((task) => task.id),
|
|
50448
|
+
done: refreshed.filter((task) => task.status === "completed" || task.status === "skipped").map((task) => task.id),
|
|
50449
|
+
failed: refreshed.filter((task) => task.status === "failed").map((task) => task.id),
|
|
50450
|
+
cancelled: refreshed.filter((task) => task.status === "cancelled").map((task) => task.id)
|
|
50451
|
+
};
|
|
50452
|
+
}
|
|
50453
|
+
var taskGraphIndexCache;
|
|
50454
|
+
var init_task_graph_scheduler = __esm({
|
|
50455
|
+
"src/runtime/scheduling/task-graph-scheduler.ts"() {
|
|
50456
|
+
"use strict";
|
|
50457
|
+
taskGraphIndexCache = /* @__PURE__ */ new WeakMap();
|
|
50458
|
+
}
|
|
50459
|
+
});
|
|
50460
|
+
|
|
50461
|
+
// src/runtime/merge-gate.ts
|
|
50462
|
+
function isNonTerminalTaskStatus(status) {
|
|
50463
|
+
return status === "queued" || status === "running" || status === "waiting";
|
|
50464
|
+
}
|
|
50465
|
+
function safeFinishedAt(task) {
|
|
50466
|
+
if (!task.finishedAt) return -Infinity;
|
|
50467
|
+
const ms = new Date(task.finishedAt).getTime();
|
|
50468
|
+
return Number.isNaN(ms) ? Infinity : ms;
|
|
50469
|
+
}
|
|
50470
|
+
function isMalformedFinishedAtReplacement(currentTime, updatedTime) {
|
|
50471
|
+
return !Number.isFinite(currentTime) && Number.isFinite(updatedTime);
|
|
50472
|
+
}
|
|
50473
|
+
function statusMergeKey(from, to) {
|
|
50474
|
+
return `${from}->${to}`;
|
|
50475
|
+
}
|
|
50476
|
+
function shouldMergeTaskUpdate(current, updated) {
|
|
50477
|
+
if (REJECTED_STATUS_MERGE_TRANSITIONS.has(statusMergeKey(current.status, updated.status))) return false;
|
|
50478
|
+
if (current.status === updated.status && updated.status === "running" && current.resultArtifact && !updated.resultArtifact)
|
|
50479
|
+
return false;
|
|
50480
|
+
if (current.status === updated.status && current.status === "completed" && current.resultArtifact && !updated.resultArtifact)
|
|
50481
|
+
return false;
|
|
50482
|
+
if (current.finishedAt !== void 0 && updated.finishedAt !== void 0) {
|
|
50483
|
+
const currentTime = safeFinishedAt(current);
|
|
50484
|
+
const updatedTime = safeFinishedAt(updated);
|
|
50485
|
+
if (!Number.isFinite(currentTime)) {
|
|
50486
|
+
console.warn(`[merge-gate] Task ${current.id} has malformed finishedAt: ${current.finishedAt}`);
|
|
50487
|
+
}
|
|
50488
|
+
if (isMalformedFinishedAtReplacement(currentTime, updatedTime)) {
|
|
50489
|
+
return true;
|
|
50490
|
+
}
|
|
50491
|
+
if (updatedTime < currentTime) return false;
|
|
50492
|
+
}
|
|
50493
|
+
if (!updated.finishedAt && !isNonTerminalTaskStatus(updated.status)) return false;
|
|
50494
|
+
const hasMeaningfulUpdate = updated.status !== current.status || updated.finishedAt !== current.finishedAt || updated.startedAt !== current.startedAt || Boolean(updated.resultArtifact) !== Boolean(current.resultArtifact) || Boolean(updated.resultArtifact) && updated.resultArtifact !== current.resultArtifact || Boolean(updated.error) || Boolean(updated.modelAttempts?.length) || Boolean(updated.usage) || Boolean(updated.attempts?.length) || updated.heartbeat?.lastSeenAt !== current.heartbeat?.lastSeenAt || updated.jsonEvents !== current.jsonEvents || updated.agentProgress?.lastActivityAt !== current.agentProgress?.lastActivityAt;
|
|
50495
|
+
return hasMeaningfulUpdate;
|
|
50496
|
+
}
|
|
50497
|
+
function mergeTaskUpdatesPreservingTerminal(base, results) {
|
|
50498
|
+
const indexById = /* @__PURE__ */ new Map();
|
|
50499
|
+
for (const task of base) indexById.set(task.id, task);
|
|
50500
|
+
let skipped = 0;
|
|
50501
|
+
for (const result4 of results) {
|
|
50502
|
+
for (const updated of result4.tasks) {
|
|
50503
|
+
const current = indexById.get(updated.id);
|
|
50504
|
+
if (!current) continue;
|
|
50505
|
+
if (!shouldMergeTaskUpdate(current, updated)) {
|
|
50506
|
+
console.debug("[merge-gate] Skipping stale merge for task", updated.id, {
|
|
50507
|
+
currentStatus: current.status,
|
|
50508
|
+
updatedStatus: updated.status,
|
|
50509
|
+
currentFinishedAt: current.finishedAt,
|
|
50510
|
+
updatedFinishedAt: updated.finishedAt
|
|
50511
|
+
});
|
|
50512
|
+
skipped += 1;
|
|
50513
|
+
continue;
|
|
50514
|
+
}
|
|
50515
|
+
indexById.set(updated.id, updated);
|
|
50516
|
+
}
|
|
50517
|
+
}
|
|
50518
|
+
const merged = base.map((task) => indexById.get(task.id) ?? task);
|
|
50519
|
+
void skipped;
|
|
50520
|
+
return refreshTaskGraphQueues(merged);
|
|
50521
|
+
}
|
|
50522
|
+
var REJECTED_STATUS_MERGE_TRANSITIONS, __test__shouldMergeTaskUpdate, __test__mergeTaskUpdates;
|
|
50523
|
+
var init_merge_gate = __esm({
|
|
50524
|
+
"src/runtime/merge-gate.ts"() {
|
|
50525
|
+
"use strict";
|
|
50526
|
+
init_contracts();
|
|
50527
|
+
init_task_graph_scheduler();
|
|
50528
|
+
REJECTED_STATUS_MERGE_TRANSITIONS = (() => {
|
|
50529
|
+
const rejected = /* @__PURE__ */ new Set();
|
|
50530
|
+
for (const from of TEAM_TASK_STATUSES) {
|
|
50531
|
+
if (!TEAM_TERMINAL_TASK_STATUSES.has(from)) continue;
|
|
50532
|
+
for (const to of TEAM_TASK_STATUSES) {
|
|
50533
|
+
if (!TEAM_TERMINAL_TASK_STATUSES.has(to)) rejected.add(statusMergeKey(from, to));
|
|
50534
|
+
}
|
|
50535
|
+
}
|
|
50536
|
+
rejected.add(statusMergeKey("waiting", "running"));
|
|
50537
|
+
const completedIntegrityFlips = [
|
|
50538
|
+
["completed", "failed"],
|
|
50539
|
+
["completed", "needs_attention"],
|
|
50540
|
+
["failed", "completed"],
|
|
50541
|
+
["cancelled", "completed"],
|
|
50542
|
+
["needs_attention", "completed"]
|
|
50543
|
+
];
|
|
50544
|
+
for (const [from, to] of completedIntegrityFlips) rejected.add(statusMergeKey(from, to));
|
|
50545
|
+
return rejected;
|
|
50546
|
+
})();
|
|
50547
|
+
__test__shouldMergeTaskUpdate = shouldMergeTaskUpdate;
|
|
50548
|
+
__test__mergeTaskUpdates = mergeTaskUpdatesPreservingTerminal;
|
|
50549
|
+
}
|
|
50550
|
+
});
|
|
50551
|
+
|
|
50473
50552
|
// src/runtime/model/runtime-policy.ts
|
|
50474
50553
|
function resolveTaskRuntimeKind(globalKind, role, isolationPolicy, env = process.env) {
|
|
50475
50554
|
if (globalKind === "scaffold") return "scaffold";
|
|
@@ -51822,75 +51901,6 @@ var init_task_graph = __esm({
|
|
|
51822
51901
|
}
|
|
51823
51902
|
});
|
|
51824
51903
|
|
|
51825
|
-
// src/runtime/scheduling/task-graph-scheduler.ts
|
|
51826
|
-
function buildTaskGraphIndex(tasks) {
|
|
51827
|
-
const cached2 = taskGraphIndexCache.get(tasks);
|
|
51828
|
-
if (cached2) return cached2;
|
|
51829
|
-
const fresh = {
|
|
51830
|
-
doneSteps: new Set(
|
|
51831
|
-
tasks.filter((task) => task.status === "completed").map((task) => task.stepId).filter((id) => id !== void 0)
|
|
51832
|
-
),
|
|
51833
|
-
idMap: new Map(tasks.map((task) => [task.id, task])),
|
|
51834
|
-
stepToTaskId: new Map(
|
|
51835
|
-
tasks.map((task) => [task.stepId, task.id]).filter((entry) => entry[0] !== void 0)
|
|
51836
|
-
)
|
|
51837
|
-
};
|
|
51838
|
-
taskGraphIndexCache.set(tasks, fresh);
|
|
51839
|
-
return fresh;
|
|
51840
|
-
}
|
|
51841
|
-
function dependencySatisfied(task, doneStepIds, idMap, stepMap) {
|
|
51842
|
-
return task.dependsOn.every((dependency) => {
|
|
51843
|
-
if (doneStepIds.has(dependency)) return true;
|
|
51844
|
-
const taskId = stepMap.get(dependency) ?? dependency;
|
|
51845
|
-
return idMap.get(taskId)?.status === "completed";
|
|
51846
|
-
});
|
|
51847
|
-
}
|
|
51848
|
-
function withQueue(task, index) {
|
|
51849
|
-
let resolvedQueue;
|
|
51850
|
-
if (task.status === "queued") {
|
|
51851
|
-
const isReady = dependencySatisfied(task, index.doneSteps, index.idMap, index.stepToTaskId);
|
|
51852
|
-
resolvedQueue = isReady ? "ready" : "blocked";
|
|
51853
|
-
} else if (task.status === "running") {
|
|
51854
|
-
resolvedQueue = "running";
|
|
51855
|
-
} else if (task.status === "completed" || task.status === "skipped" || task.status === "needs_attention") {
|
|
51856
|
-
resolvedQueue = "done";
|
|
51857
|
-
} else {
|
|
51858
|
-
resolvedQueue = "blocked";
|
|
51859
|
-
}
|
|
51860
|
-
if (task.graph && task.graph.queue === resolvedQueue) {
|
|
51861
|
-
return task;
|
|
51862
|
-
}
|
|
51863
|
-
return {
|
|
51864
|
-
...task,
|
|
51865
|
-
graph: task.graph ? { ...task.graph, queue: resolvedQueue } : task.graph
|
|
51866
|
-
};
|
|
51867
|
-
}
|
|
51868
|
-
function ensureIndex(tasks, index) {
|
|
51869
|
-
return index ?? buildTaskGraphIndex(tasks);
|
|
51870
|
-
}
|
|
51871
|
-
function refreshTaskGraphQueues(tasks, index) {
|
|
51872
|
-
const resolved = ensureIndex(tasks, index);
|
|
51873
|
-
return tasks.map((task) => withQueue(task, resolved));
|
|
51874
|
-
}
|
|
51875
|
-
function taskGraphSnapshot(tasks, index) {
|
|
51876
|
-
const refreshed = refreshTaskGraphQueues(tasks, index);
|
|
51877
|
-
return {
|
|
51878
|
-
ready: refreshed.filter((task) => task.status === "queued" && task.graph?.queue === "ready").map((task) => task.id),
|
|
51879
|
-
blocked: refreshed.filter((task) => task.status === "queued" && task.graph?.queue === "blocked").map((task) => task.id),
|
|
51880
|
-
running: refreshed.filter((task) => task.status === "running").map((task) => task.id),
|
|
51881
|
-
done: refreshed.filter((task) => task.status === "completed" || task.status === "skipped").map((task) => task.id),
|
|
51882
|
-
failed: refreshed.filter((task) => task.status === "failed").map((task) => task.id),
|
|
51883
|
-
cancelled: refreshed.filter((task) => task.status === "cancelled").map((task) => task.id)
|
|
51884
|
-
};
|
|
51885
|
-
}
|
|
51886
|
-
var taskGraphIndexCache;
|
|
51887
|
-
var init_task_graph_scheduler = __esm({
|
|
51888
|
-
"src/runtime/scheduling/task-graph-scheduler.ts"() {
|
|
51889
|
-
"use strict";
|
|
51890
|
-
taskGraphIndexCache = /* @__PURE__ */ new WeakMap();
|
|
51891
|
-
}
|
|
51892
|
-
});
|
|
51893
|
-
|
|
51894
51904
|
// src/extension/knowledge-injection.ts
|
|
51895
51905
|
import * as fs75 from "node:fs";
|
|
51896
51906
|
import * as path65 from "node:path";
|
|
@@ -56787,12 +56797,13 @@ __export(team_runner_exports, {
|
|
|
56787
56797
|
drainPendingUnits: () => drainPendingUnits,
|
|
56788
56798
|
executeTeamRun: () => executeTeamRun,
|
|
56789
56799
|
hasPendingMutatingTaskAtBoundary: () => hasPendingMutatingTaskAtBoundary,
|
|
56790
|
-
mergeTaskUpdatesPreservingTerminal: () => mergeTaskUpdatesPreservingTerminal,
|
|
56791
56800
|
setRunStatusRunning: () => setRunStatusRunning,
|
|
56792
56801
|
shouldUseRetry: () => shouldUseRetry
|
|
56793
56802
|
});
|
|
56803
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
56794
56804
|
import * as fs86 from "node:fs";
|
|
56795
56805
|
import * as path72 from "node:path";
|
|
56806
|
+
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
56796
56807
|
function startTeamRunHeartbeat(stateRoot, runId) {
|
|
56797
56808
|
const heartbeatPath = path72.join(stateRoot, "heartbeat.json");
|
|
56798
56809
|
const writeHeartbeat = () => {
|
|
@@ -56816,6 +56827,87 @@ function startTeamRunHeartbeat(stateRoot, runId) {
|
|
|
56816
56827
|
const interval = setInterval(writeHeartbeat, 6e4);
|
|
56817
56828
|
return () => clearInterval(interval);
|
|
56818
56829
|
}
|
|
56830
|
+
function perfScriptPath(scriptName) {
|
|
56831
|
+
try {
|
|
56832
|
+
const candidates = [
|
|
56833
|
+
fileURLToPath7(new URL(`../../scripts/${scriptName}`, import.meta.url)),
|
|
56834
|
+
fileURLToPath7(new URL(`../scripts/${scriptName}`, import.meta.url))
|
|
56835
|
+
];
|
|
56836
|
+
return candidates.find((p) => fs86.existsSync(p));
|
|
56837
|
+
} catch {
|
|
56838
|
+
return void 0;
|
|
56839
|
+
}
|
|
56840
|
+
}
|
|
56841
|
+
function startPerfSampler(manifest, team) {
|
|
56842
|
+
const marker = (msg) => {
|
|
56843
|
+
try {
|
|
56844
|
+
fs86.appendFileSync(path72.join(manifest.artifactsRoot, "perf-obs.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}
|
|
56845
|
+
`);
|
|
56846
|
+
} catch {
|
|
56847
|
+
}
|
|
56848
|
+
};
|
|
56849
|
+
marker(`startPerfSampler entered (team=${team.name} observability=${String(team.observability)} importMetaUrl=${import.meta.url})`);
|
|
56850
|
+
if (team.observability !== true) {
|
|
56851
|
+
marker(`SKIP: observability=${String(team.observability)} !== true`);
|
|
56852
|
+
return;
|
|
56853
|
+
}
|
|
56854
|
+
const samplerPath = perfScriptPath("resource-sampler.mjs");
|
|
56855
|
+
if (!samplerPath) {
|
|
56856
|
+
marker(`SKIP: resource-sampler.mjs not found (importMetaUrl=${import.meta.url})`);
|
|
56857
|
+
return;
|
|
56858
|
+
}
|
|
56859
|
+
marker(`spawning sampler from ${samplerPath}`);
|
|
56860
|
+
const crewRoot = path72.dirname(path72.dirname(path72.dirname(manifest.stateRoot)));
|
|
56861
|
+
const outPath = path72.join(manifest.artifactsRoot, "resources.jsonl");
|
|
56862
|
+
const logPath = path72.join(manifest.artifactsRoot, "perf-obs.log");
|
|
56863
|
+
try {
|
|
56864
|
+
const child = spawn6(
|
|
56865
|
+
process.execPath,
|
|
56866
|
+
[
|
|
56867
|
+
"--experimental-strip-types",
|
|
56868
|
+
samplerPath,
|
|
56869
|
+
"--watch-run",
|
|
56870
|
+
manifest.runId,
|
|
56871
|
+
"--crew-root",
|
|
56872
|
+
crewRoot,
|
|
56873
|
+
"--interval",
|
|
56874
|
+
String(OBSERVABILITY_INTERVAL_MS),
|
|
56875
|
+
"--out",
|
|
56876
|
+
outPath
|
|
56877
|
+
],
|
|
56878
|
+
{ detached: true, stdio: ["ignore", "ignore", "pipe"] }
|
|
56879
|
+
);
|
|
56880
|
+
child.stderr?.on("data", (d) => {
|
|
56881
|
+
try {
|
|
56882
|
+
fs86.appendFileSync(logPath, String(d));
|
|
56883
|
+
} catch {
|
|
56884
|
+
}
|
|
56885
|
+
});
|
|
56886
|
+
child.unref();
|
|
56887
|
+
} catch (err2) {
|
|
56888
|
+
console.warn(`[perf-obs] sampler spawn failed for ${manifest.runId}: ${String(err2)}`);
|
|
56889
|
+
}
|
|
56890
|
+
}
|
|
56891
|
+
function schedulePerfAnalyze(manifest, team) {
|
|
56892
|
+
if (team.observability !== true) return;
|
|
56893
|
+
const analyzePath = perfScriptPath("analyze-run.mjs");
|
|
56894
|
+
const resourcesPath = path72.join(manifest.artifactsRoot, "resources.jsonl");
|
|
56895
|
+
if (!analyzePath || !fs86.existsSync(resourcesPath)) return;
|
|
56896
|
+
const crewRoot = path72.dirname(path72.dirname(path72.dirname(manifest.stateRoot)));
|
|
56897
|
+
const timer = setTimeout(() => {
|
|
56898
|
+
try {
|
|
56899
|
+
const child = spawn6(
|
|
56900
|
+
process.execPath,
|
|
56901
|
+
["--experimental-strip-types", analyzePath, manifest.runId, "--crew-root", crewRoot, "--resources", resourcesPath],
|
|
56902
|
+
{ detached: true, stdio: "ignore" }
|
|
56903
|
+
);
|
|
56904
|
+
child.unref();
|
|
56905
|
+
} catch (err2) {
|
|
56906
|
+
console.warn(`[perf-obs] analyze spawn failed for ${manifest.runId}: ${String(err2)}`);
|
|
56907
|
+
}
|
|
56908
|
+
}, OBSERVABILITY_ANALYZE_DELAY_MS);
|
|
56909
|
+
timer.unref();
|
|
56910
|
+
}
|
|
56819
56911
|
function checkPerTaskBudget(tasks, budgetTotal, budgetWarning, budgetAbort, fairShareFraction = 0.5) {
|
|
56820
56912
|
const usage = aggregateUsage(tasks);
|
|
56821
56913
|
const totalUsed = (usage?.input ?? 0) + (usage?.output ?? 0) + (usage?.cacheWrite ?? 0);
|
|
@@ -56859,9 +56951,6 @@ function markBlocked(tasks, reason) {
|
|
|
56859
56951
|
} : task
|
|
56860
56952
|
);
|
|
56861
56953
|
}
|
|
56862
|
-
function isNonTerminalTaskStatus(status) {
|
|
56863
|
-
return status === "queued" || status === "running" || status === "waiting";
|
|
56864
|
-
}
|
|
56865
56954
|
function cancelNonTerminalTasks(tasks, status, reason, filter, transform) {
|
|
56866
56955
|
const predicate = filter ?? ((task) => isNonTerminalTaskStatus(task.status));
|
|
56867
56956
|
return tasks.map((task) => {
|
|
@@ -56870,63 +56959,6 @@ function cancelNonTerminalTasks(tasks, status, reason, filter, transform) {
|
|
|
56870
56959
|
return transform ? transform(task, terminalised) : terminalised;
|
|
56871
56960
|
});
|
|
56872
56961
|
}
|
|
56873
|
-
function safeFinishedAt(task) {
|
|
56874
|
-
if (!task.finishedAt) return -Infinity;
|
|
56875
|
-
const ms = new Date(task.finishedAt).getTime();
|
|
56876
|
-
return Number.isNaN(ms) ? Infinity : ms;
|
|
56877
|
-
}
|
|
56878
|
-
function isMalformedFinishedAtReplacement(currentTime, updatedTime) {
|
|
56879
|
-
return !Number.isFinite(currentTime) && Number.isFinite(updatedTime);
|
|
56880
|
-
}
|
|
56881
|
-
function statusMergeKey(from, to) {
|
|
56882
|
-
return `${from}->${to}`;
|
|
56883
|
-
}
|
|
56884
|
-
function shouldMergeTaskUpdate(current, updated) {
|
|
56885
|
-
if (REJECTED_STATUS_MERGE_TRANSITIONS.has(statusMergeKey(current.status, updated.status))) return false;
|
|
56886
|
-
if (current.status === updated.status && updated.status === "running" && current.resultArtifact && !updated.resultArtifact)
|
|
56887
|
-
return false;
|
|
56888
|
-
if (current.status === updated.status && current.status === "completed" && current.resultArtifact && !updated.resultArtifact)
|
|
56889
|
-
return false;
|
|
56890
|
-
if (current.finishedAt !== void 0 && updated.finishedAt !== void 0) {
|
|
56891
|
-
const currentTime = safeFinishedAt(current);
|
|
56892
|
-
const updatedTime = safeFinishedAt(updated);
|
|
56893
|
-
if (!Number.isFinite(currentTime)) {
|
|
56894
|
-
console.warn(`[team-runner] Task ${current.id} has malformed finishedAt: ${current.finishedAt}`);
|
|
56895
|
-
}
|
|
56896
|
-
if (isMalformedFinishedAtReplacement(currentTime, updatedTime)) {
|
|
56897
|
-
return true;
|
|
56898
|
-
}
|
|
56899
|
-
if (updatedTime < currentTime) return false;
|
|
56900
|
-
}
|
|
56901
|
-
if (!updated.finishedAt && !isNonTerminalTaskStatus(updated.status)) return false;
|
|
56902
|
-
const hasMeaningfulUpdate = updated.status !== current.status || updated.finishedAt !== current.finishedAt || updated.startedAt !== current.startedAt || Boolean(updated.resultArtifact) !== Boolean(current.resultArtifact) || Boolean(updated.resultArtifact) && updated.resultArtifact !== current.resultArtifact || Boolean(updated.error) || Boolean(updated.modelAttempts?.length) || Boolean(updated.usage) || Boolean(updated.attempts?.length) || updated.heartbeat?.lastSeenAt !== current.heartbeat?.lastSeenAt || updated.jsonEvents !== current.jsonEvents || updated.agentProgress?.lastActivityAt !== current.agentProgress?.lastActivityAt;
|
|
56903
|
-
return hasMeaningfulUpdate;
|
|
56904
|
-
}
|
|
56905
|
-
function mergeTaskUpdatesPreservingTerminal(base, results) {
|
|
56906
|
-
const indexById = /* @__PURE__ */ new Map();
|
|
56907
|
-
for (const task of base) indexById.set(task.id, task);
|
|
56908
|
-
let skipped = 0;
|
|
56909
|
-
for (const result4 of results) {
|
|
56910
|
-
for (const updated of result4.tasks) {
|
|
56911
|
-
const current = indexById.get(updated.id);
|
|
56912
|
-
if (!current) continue;
|
|
56913
|
-
if (!shouldMergeTaskUpdate(current, updated)) {
|
|
56914
|
-
console.debug("[team-runner] Skipping stale merge for task", updated.id, {
|
|
56915
|
-
currentStatus: current.status,
|
|
56916
|
-
updatedStatus: updated.status,
|
|
56917
|
-
currentFinishedAt: current.finishedAt,
|
|
56918
|
-
updatedFinishedAt: updated.finishedAt
|
|
56919
|
-
});
|
|
56920
|
-
skipped += 1;
|
|
56921
|
-
continue;
|
|
56922
|
-
}
|
|
56923
|
-
indexById.set(updated.id, updated);
|
|
56924
|
-
}
|
|
56925
|
-
}
|
|
56926
|
-
const merged = base.map((task) => indexById.get(task.id) ?? task);
|
|
56927
|
-
void skipped;
|
|
56928
|
-
return refreshTaskGraphQueues(merged);
|
|
56929
|
-
}
|
|
56930
56962
|
function formatTaskProgress(task) {
|
|
56931
56963
|
return `- ${task.id}: ${task.status} (${task.role} -> ${task.agent})${task.taskPacket ? ` scope=${task.taskPacket.scope}` : ""}${task.verification ? ` green=${task.verification.observedGreenLevel}/${task.verification.requiredGreenLevel}` : ""}${task.error ? ` - ${task.error}` : ""}`;
|
|
56932
56964
|
}
|
|
@@ -57188,6 +57220,7 @@ async function executeTeamRun(input) {
|
|
|
57188
57220
|
}
|
|
57189
57221
|
void registerRunPromise(manifest.runId);
|
|
57190
57222
|
const stopTeamHeartbeat = startTeamRunHeartbeat(manifest.stateRoot, manifest.runId);
|
|
57223
|
+
startPerfSampler(manifest, input.team);
|
|
57191
57224
|
const cleanupUsage = () => {
|
|
57192
57225
|
for (const task of input.tasks) clearTrackedTaskUsage(task.id);
|
|
57193
57226
|
};
|
|
@@ -57253,6 +57286,7 @@ async function executeTeamRun(input) {
|
|
|
57253
57286
|
);
|
|
57254
57287
|
}
|
|
57255
57288
|
await flushEventLogBuffer();
|
|
57289
|
+
schedulePerfAnalyze(manifest, input.team);
|
|
57256
57290
|
return result4;
|
|
57257
57291
|
} catch (error) {
|
|
57258
57292
|
stopTeamHeartbeat();
|
|
@@ -58340,15 +58374,13 @@ async function executeTeamRunCore(input, manifest, workflow) {
|
|
|
58340
58374
|
await drainPendingUnits(pendingUnits, runController);
|
|
58341
58375
|
}
|
|
58342
58376
|
}
|
|
58343
|
-
var
|
|
58377
|
+
var OBSERVABILITY_INTERVAL_MS, OBSERVABILITY_ANALYZE_DELAY_MS, lastProgressContentHash, __test__lastProgressContentHash, __test__writeProgress, __test__cancelPlanTasks;
|
|
58344
58378
|
var init_team_runner = __esm({
|
|
58345
58379
|
"src/runtime/team-runner.ts"() {
|
|
58346
58380
|
"use strict";
|
|
58347
58381
|
init_errors3();
|
|
58348
58382
|
init_registry2();
|
|
58349
58383
|
init_correlation();
|
|
58350
|
-
init_plugin_registry();
|
|
58351
|
-
init_plugins();
|
|
58352
58384
|
init_atomic_write();
|
|
58353
58385
|
init_contracts();
|
|
58354
58386
|
init_locks();
|
|
@@ -58366,6 +58398,7 @@ var init_team_runner = __esm({
|
|
|
58366
58398
|
init_goal_achievement();
|
|
58367
58399
|
init_group_join();
|
|
58368
58400
|
init_live_agent_manager();
|
|
58401
|
+
init_merge_gate();
|
|
58369
58402
|
init_runtime_policy();
|
|
58370
58403
|
init_path_overlap();
|
|
58371
58404
|
init_policy_engine();
|
|
@@ -58387,32 +58420,10 @@ var init_team_runner = __esm({
|
|
|
58387
58420
|
init_usage_tracker();
|
|
58388
58421
|
init_workflow_state();
|
|
58389
58422
|
init_adaptive_plan();
|
|
58423
|
+
init_merge_gate();
|
|
58390
58424
|
init_adaptive_plan();
|
|
58391
|
-
|
|
58392
|
-
|
|
58393
|
-
builtInRegistry.register(VitestPlugin);
|
|
58394
|
-
builtInRegistry.register(VitePlugin);
|
|
58395
|
-
REJECTED_STATUS_MERGE_TRANSITIONS = (() => {
|
|
58396
|
-
const rejected = /* @__PURE__ */ new Set();
|
|
58397
|
-
for (const from of TEAM_TASK_STATUSES) {
|
|
58398
|
-
if (!TEAM_TERMINAL_TASK_STATUSES.has(from)) continue;
|
|
58399
|
-
for (const to of TEAM_TASK_STATUSES) {
|
|
58400
|
-
if (!TEAM_TERMINAL_TASK_STATUSES.has(to)) rejected.add(statusMergeKey(from, to));
|
|
58401
|
-
}
|
|
58402
|
-
}
|
|
58403
|
-
rejected.add(statusMergeKey("waiting", "running"));
|
|
58404
|
-
const completedIntegrityFlips = [
|
|
58405
|
-
["completed", "failed"],
|
|
58406
|
-
["completed", "needs_attention"],
|
|
58407
|
-
["failed", "completed"],
|
|
58408
|
-
["cancelled", "completed"],
|
|
58409
|
-
["needs_attention", "completed"]
|
|
58410
|
-
];
|
|
58411
|
-
for (const [from, to] of completedIntegrityFlips) rejected.add(statusMergeKey(from, to));
|
|
58412
|
-
return rejected;
|
|
58413
|
-
})();
|
|
58414
|
-
__test__shouldMergeTaskUpdate = shouldMergeTaskUpdate;
|
|
58415
|
-
__test__mergeTaskUpdates = mergeTaskUpdatesPreservingTerminal;
|
|
58425
|
+
OBSERVABILITY_INTERVAL_MS = 2e3;
|
|
58426
|
+
OBSERVABILITY_ANALYZE_DELAY_MS = 3e3;
|
|
58416
58427
|
lastProgressContentHash = /* @__PURE__ */ new Map();
|
|
58417
58428
|
__test__lastProgressContentHash = lastProgressContentHash;
|
|
58418
58429
|
__test__writeProgress = writeProgress;
|
|
@@ -66261,7 +66272,6 @@ var init_mascot = __esm({
|
|
|
66261
66272
|
currentArminGrid;
|
|
66262
66273
|
effectState = {};
|
|
66263
66274
|
effectDone = false;
|
|
66264
|
-
visible = true;
|
|
66265
66275
|
frame = 0;
|
|
66266
66276
|
effectPhase = 0;
|
|
66267
66277
|
gridVersion = 0;
|
|
@@ -66357,7 +66367,7 @@ var init_mascot = __esm({
|
|
|
66357
66367
|
this.gridVersion++;
|
|
66358
66368
|
}
|
|
66359
66369
|
this.invalidate();
|
|
66360
|
-
|
|
66370
|
+
this.requestRender?.();
|
|
66361
66371
|
}
|
|
66362
66372
|
tickArminEffect() {
|
|
66363
66373
|
switch (this.effect) {
|
|
@@ -66564,14 +66574,6 @@ var init_mascot = __esm({
|
|
|
66564
66574
|
this.close();
|
|
66565
66575
|
}
|
|
66566
66576
|
}
|
|
66567
|
-
/**
|
|
66568
|
-
* Set whether the mascot is currently visible (not obscured by another
|
|
66569
|
-
* overlay). When invisible, tick() skips requestRender so the animation
|
|
66570
|
-
* does not trigger needless repaints while hidden.
|
|
66571
|
-
*/
|
|
66572
|
-
setVisible(visible) {
|
|
66573
|
-
this.visible = visible;
|
|
66574
|
-
}
|
|
66575
66577
|
dispose() {
|
|
66576
66578
|
this.doneGuard.called = true;
|
|
66577
66579
|
if (this.interval) clearInterval(this.interval);
|
|
@@ -70620,10 +70622,18 @@ var init_otlp_exporter = __esm({
|
|
|
70620
70622
|
});
|
|
70621
70623
|
|
|
70622
70624
|
// src/observability/metrics-primitives.ts
|
|
70623
|
-
function
|
|
70625
|
+
function getCardinalityEvictions() {
|
|
70626
|
+
return cardinalityEvictions;
|
|
70627
|
+
}
|
|
70628
|
+
function enforceLabelCap(map3, _metricName) {
|
|
70624
70629
|
while (map3.size > MAX_LABEL_COMBINATIONS) {
|
|
70625
70630
|
const firstKey = map3.keys().next().value;
|
|
70626
|
-
if (firstKey !== void 0)
|
|
70631
|
+
if (firstKey !== void 0) {
|
|
70632
|
+
map3.delete(firstKey);
|
|
70633
|
+
cardinalityEvictions++;
|
|
70634
|
+
} else {
|
|
70635
|
+
break;
|
|
70636
|
+
}
|
|
70627
70637
|
}
|
|
70628
70638
|
}
|
|
70629
70639
|
function normalizeLabels(labels = {}) {
|
|
@@ -70637,12 +70647,13 @@ function labelKey(labels = {}) {
|
|
|
70637
70647
|
function cloneLabels(labels) {
|
|
70638
70648
|
return { ...labels };
|
|
70639
70649
|
}
|
|
70640
|
-
var DEFAULT_HISTOGRAM_BUCKETS, MAX_LABEL_COMBINATIONS, Metric, Counter, Gauge, Histogram;
|
|
70650
|
+
var DEFAULT_HISTOGRAM_BUCKETS, MAX_LABEL_COMBINATIONS, cardinalityEvictions, Metric, Counter, Gauge, Histogram;
|
|
70641
70651
|
var init_metrics_primitives = __esm({
|
|
70642
70652
|
"src/observability/metrics-primitives.ts"() {
|
|
70643
70653
|
"use strict";
|
|
70644
70654
|
DEFAULT_HISTOGRAM_BUCKETS = [1, 2, 5, 10, 25, 50, 100, 250, 500, 1e3, 2500, 5e3, 1e4];
|
|
70645
70655
|
MAX_LABEL_COMBINATIONS = 1e4;
|
|
70656
|
+
cardinalityEvictions = 0;
|
|
70646
70657
|
Metric = class {
|
|
70647
70658
|
name;
|
|
70648
70659
|
description;
|
|
@@ -70907,6 +70918,14 @@ function wireEventToMetrics(events, registry2) {
|
|
|
70907
70918
|
const deadletterCount = registry2.counter("crew.task.deadletter_total", "Deadletter triggers by reason");
|
|
70908
70919
|
const overflowCount = registry2.counter("crew.task.overflow_phase_total", "Overflow recovery phase transitions");
|
|
70909
70920
|
const supervisorContactCount = registry2.counter("crew.task.supervisor_contact_total", "Supervisor contact requests by reason");
|
|
70921
|
+
const unboundedConcurrencyCount = registry2.counter(
|
|
70922
|
+
"crew.limits.unbounded_total",
|
|
70923
|
+
"Runs that enabled allowUnboundedConcurrency (advisory; bypasses hard cap)"
|
|
70924
|
+
);
|
|
70925
|
+
const cardinalityEvictedGauge = registry2.gauge(
|
|
70926
|
+
"crew.metrics.cardinality_evicted",
|
|
70927
|
+
"Cumulative label-combination evictions (non-zero = unreliable aggregation)"
|
|
70928
|
+
);
|
|
70910
70929
|
registry2.gauge("crew.heartbeat.staleness_ms", "Heartbeat elapsed since last seen, milliseconds");
|
|
70911
70930
|
const runDuration = registry2.histogram(
|
|
70912
70931
|
"crew.run.duration_ms",
|
|
@@ -71006,11 +71025,21 @@ function wireEventToMetrics(events, registry2) {
|
|
|
71006
71025
|
direction: stringValue(item.direction, "unknown")
|
|
71007
71026
|
});
|
|
71008
71027
|
}
|
|
71028
|
+
],
|
|
71029
|
+
[
|
|
71030
|
+
"crew.limits.unbounded",
|
|
71031
|
+
() => {
|
|
71032
|
+
unboundedConcurrencyCount.inc({});
|
|
71033
|
+
}
|
|
71009
71034
|
]
|
|
71010
71035
|
];
|
|
71011
71036
|
const unsubscribers = [];
|
|
71012
71037
|
for (const [event, handler] of handlers) {
|
|
71013
71038
|
const unsubscribe = events?.on?.(event, (data) => {
|
|
71039
|
+
try {
|
|
71040
|
+
cardinalityEvictedGauge.set({}, getCardinalityEvictions());
|
|
71041
|
+
} catch {
|
|
71042
|
+
}
|
|
71014
71043
|
try {
|
|
71015
71044
|
handler(data);
|
|
71016
71045
|
} catch {
|
|
@@ -71031,6 +71060,7 @@ var CANCELLATION_REASON_LABELS;
|
|
|
71031
71060
|
var init_event_to_metric = __esm({
|
|
71032
71061
|
"src/observability/event-to-metric.ts"() {
|
|
71033
71062
|
"use strict";
|
|
71063
|
+
init_metrics_primitives();
|
|
71034
71064
|
CANCELLATION_REASON_LABELS = /* @__PURE__ */ new Set([
|
|
71035
71065
|
"caller_cancelled",
|
|
71036
71066
|
"leader_interrupted",
|
|
@@ -72583,7 +72613,7 @@ function isDangerStage(index, levels) {
|
|
|
72583
72613
|
init_pi_ui_compat();
|
|
72584
72614
|
init_theme_adapter();
|
|
72585
72615
|
init_visual();
|
|
72586
|
-
import { isAbsolute as
|
|
72616
|
+
import { isAbsolute as isAbsolute11, relative as relative8, resolve as resolve21, sep as sep9 } from "node:path";
|
|
72587
72617
|
|
|
72588
72618
|
// src/extension/crew-vibes/render.ts
|
|
72589
72619
|
function formatCount(value) {
|
|
@@ -72720,7 +72750,7 @@ function formatCwdForFooter(cwd, home) {
|
|
|
72720
72750
|
const resolvedCwd = resolve21(cwd);
|
|
72721
72751
|
const resolvedHome = resolve21(home);
|
|
72722
72752
|
const rel = relative8(resolvedHome, resolvedCwd);
|
|
72723
|
-
const inside = rel === "" || rel !== ".." && !rel.startsWith(`..${sep9}`) && !
|
|
72753
|
+
const inside = rel === "" || rel !== ".." && !rel.startsWith(`..${sep9}`) && !isAbsolute11(rel);
|
|
72724
72754
|
if (!inside) return cwd;
|
|
72725
72755
|
return rel === "" ? "~" : `~${sep9}${rel}`;
|
|
72726
72756
|
}
|
|
@@ -75285,7 +75315,7 @@ function startForegroundRunImpl(pi, ctx, extensionCtx, runner, runId) {
|
|
|
75285
75315
|
init_config();
|
|
75286
75316
|
import * as fs103 from "node:fs";
|
|
75287
75317
|
import * as path82 from "node:path";
|
|
75288
|
-
import { fileURLToPath as
|
|
75318
|
+
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
75289
75319
|
|
|
75290
75320
|
// src/runtime/per-write-validator.ts
|
|
75291
75321
|
import { readFileSync as readFileSync81 } from "node:fs";
|
|
@@ -75388,7 +75418,7 @@ function installResourcesDiscoverHook(pi, ctx) {
|
|
|
75388
75418
|
pi.on("resources_discover", () => {
|
|
75389
75419
|
const sessionCwd = ctx.currentCtx?.cwd ?? process.cwd();
|
|
75390
75420
|
const skillDir = path82.resolve(sessionCwd, "skills");
|
|
75391
|
-
const extSkillDir = path82.resolve(path82.dirname(
|
|
75421
|
+
const extSkillDir = path82.resolve(path82.dirname(fileURLToPath8(import.meta.url)), "..", "..", "skills");
|
|
75392
75422
|
const paths = [];
|
|
75393
75423
|
if (fs103.existsSync(extSkillDir)) paths.push(extSkillDir);
|
|
75394
75424
|
if (skillDir !== extSkillDir && fs103.existsSync(skillDir)) {
|
|
@@ -76011,19 +76041,6 @@ var CrewBroker = class {
|
|
|
76011
76041
|
}
|
|
76012
76042
|
this.resolvedSocketPath = null;
|
|
76013
76043
|
}
|
|
76014
|
-
/**
|
|
76015
|
-
* Non-throwing enqueue entry point for the post-append mailbox observer
|
|
76016
|
-
* (Phase 1) or any other in-process producer. Phase 0 accepts `notifyMessage`
|
|
76017
|
-
* as a no-op shape so the lifecycle controller can install a single
|
|
76018
|
-
* observer regardless of broker state.
|
|
76019
|
-
*
|
|
76020
|
-
* Fanout goes ONLY to authenticated connections matching the recipient.
|
|
76021
|
-
* Phase 0 keeps this as a typed no-op (`not-implemented` would be
|
|
76022
|
-
* inappropriate here — the caller is in-process and shouldn't be
|
|
76023
|
-
* punished for testing the broker skeleton).
|
|
76024
|
-
*/
|
|
76025
|
-
notifyMessage(_message) {
|
|
76026
|
-
}
|
|
76027
76044
|
// ------------------------------------------------------------------------
|
|
76028
76045
|
// Connection lifecycle
|
|
76029
76046
|
// ------------------------------------------------------------------------
|