pi-crew 0.9.62 → 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 +105 -0
- package/README.md +47 -1
- package/agents/critic.md +1 -1
- package/agents/explorer.md +1 -1
- package/agents/planner.md +1 -1
- package/agents/reviewer.md +1 -1
- package/agents/security-reviewer.md +1 -1
- package/agents/test-engineer.md +1 -1
- package/agents/writer.md +1 -1
- package/dist/index.mjs +478 -366
- package/package.json +7 -3
- 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/agents/agent-config.ts +4 -0
- package/src/agents/agent-serializer.ts +1 -0
- package/src/agents/discover-agents.ts +8 -0
- package/src/config/role-tools.ts +49 -1
- package/src/observability/event-to-metric.ts +29 -0
- package/src/observability/metrics-primitives.ts +41 -3
- package/src/prompt/prompt-runtime.ts +6 -0
- package/src/prompt/scratchpad-lifecycle.ts +605 -0
- package/src/runtime/README.md +1 -1
- package/src/runtime/broker/crew-broker.ts +0 -16
- package/src/runtime/child-pi/child-pi-spawn.ts +42 -1
- package/src/runtime/child-pi/child-pi.ts +5 -0
- 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/pi-args.ts +1 -1
- package/src/runtime/model/provider-extensions.ts +31 -12
- package/src/runtime/output/progress-tracker.ts +3 -33
- package/src/runtime/recovery/crash-recovery.ts +1 -1
- package/src/runtime/scratchpad/README.md +184 -0
- package/src/runtime/scratchpad/engine.ts +648 -0
- package/src/runtime/scratchpad/guest.ts +360 -0
- package/src/runtime/scratchpad/index.ts +22 -0
- package/src/runtime/scratchpad/protocol.ts +88 -0
- package/src/runtime/scratchpad/snapshot-hmac.ts +161 -0
- package/src/runtime/scratchpad/snapshot-lookup.ts +74 -0
- package/src/runtime/scratchpad/transform.ts +363 -0
- package/src/runtime/task-runner/child-executor.ts +48 -31
- 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
|
}
|
|
@@ -11602,15 +11608,51 @@ var init_frontmatter = __esm({
|
|
|
11602
11608
|
}
|
|
11603
11609
|
});
|
|
11604
11610
|
|
|
11611
|
+
// src/runtime/role-permission.ts
|
|
11612
|
+
function permissionForRole(role) {
|
|
11613
|
+
if (READ_ONLY_ROLES.has(role)) return "read_only";
|
|
11614
|
+
if (WRITE_ROLES.has(role)) return "workspace_write";
|
|
11615
|
+
return "read_only";
|
|
11616
|
+
}
|
|
11617
|
+
function currentCrewRole(env = process.env) {
|
|
11618
|
+
return env.PI_CREW_ROLE?.trim() || env.PI_TEAMS_ROLE?.trim() || void 0;
|
|
11619
|
+
}
|
|
11620
|
+
function checkSubagentSpawnPermission(role) {
|
|
11621
|
+
if (!role) return { allowed: true, mode: "workspace_write" };
|
|
11622
|
+
const mode = permissionForRole(role);
|
|
11623
|
+
if (mode === "read_only")
|
|
11624
|
+
return {
|
|
11625
|
+
allowed: false,
|
|
11626
|
+
mode,
|
|
11627
|
+
reason: `Role '${role}' is read-only and cannot spawn additional subagents.`
|
|
11628
|
+
};
|
|
11629
|
+
return { allowed: true, mode };
|
|
11630
|
+
}
|
|
11631
|
+
var READ_ONLY_ROLES, WRITE_ROLES;
|
|
11632
|
+
var init_role_permission = __esm({
|
|
11633
|
+
"src/runtime/role-permission.ts"() {
|
|
11634
|
+
"use strict";
|
|
11635
|
+
READ_ONLY_ROLES = /* @__PURE__ */ new Set(["explorer", "reviewer", "security-reviewer", "analyst", "critic", "planner"]);
|
|
11636
|
+
WRITE_ROLES = /* @__PURE__ */ new Set(["executor", "test-engineer", "writer", "verifier", "agent", "cold-verifier", "chain-executor", "worker"]);
|
|
11637
|
+
}
|
|
11638
|
+
});
|
|
11639
|
+
|
|
11605
11640
|
// src/config/role-tools.ts
|
|
11606
11641
|
function getToolConfig(role) {
|
|
11607
11642
|
const key = role.includes("_") ? role.replaceAll("_", "-") : role;
|
|
11608
11643
|
return ROLE_TOOL_CONFIGS[key] ?? ROLE_TOOL_CONFIGS[role] ?? {};
|
|
11609
11644
|
}
|
|
11645
|
+
function isScratchpadEnabledForRole(role, agent) {
|
|
11646
|
+
const normalized = role.includes("_") ? role.replaceAll("_", "-") : role;
|
|
11647
|
+
if (permissionForRole(normalized) === "read_only") return false;
|
|
11648
|
+
if (agent?.scratchpad === false) return false;
|
|
11649
|
+
return agent?.scratchpad === true || getToolConfig(normalized).scratchpad === true;
|
|
11650
|
+
}
|
|
11610
11651
|
var ROLE_TOOL_CONFIGS;
|
|
11611
11652
|
var init_role_tools = __esm({
|
|
11612
11653
|
"src/config/role-tools.ts"() {
|
|
11613
11654
|
"use strict";
|
|
11655
|
+
init_role_permission();
|
|
11614
11656
|
ROLE_TOOL_CONFIGS = {
|
|
11615
11657
|
// Explorer - Read-only exploration; bash is included for git log/show
|
|
11616
11658
|
// (decisions stream needs commit-history mining) but edit/write stay
|
|
@@ -11641,9 +11683,11 @@ var init_role_tools = __esm({
|
|
|
11641
11683
|
tools: ["read", "grep", "find", "ls", "glob"],
|
|
11642
11684
|
excludeTools: ["edit", "write", "bash", "web"]
|
|
11643
11685
|
},
|
|
11644
|
-
// Executor - Full access (default)
|
|
11686
|
+
// Executor - Full access (default). Phase 1 scratchpad-enabled (stateful
|
|
11687
|
+
// evaluator compounds intermediate results across execute calls).
|
|
11645
11688
|
executor: {
|
|
11646
11689
|
// No restrictions - full tool access
|
|
11690
|
+
scratchpad: true
|
|
11647
11691
|
},
|
|
11648
11692
|
// Reviewer - Read and review, no write
|
|
11649
11693
|
reviewer: {
|
|
@@ -11670,12 +11714,16 @@ var init_role_tools = __esm({
|
|
|
11670
11714
|
// integrity is preserved during verification. Mirrors cold-verifier behavior.
|
|
11671
11715
|
verifier: {
|
|
11672
11716
|
tools: ["read", "grep", "find", "ls", "bash"],
|
|
11673
|
-
excludeTools: ["edit", "write", "web"]
|
|
11717
|
+
excludeTools: ["edit", "write", "web"],
|
|
11718
|
+
// Phase 1 scratchpad: multi-cell test/verify flows reuse parsed state.
|
|
11719
|
+
scratchpad: true
|
|
11674
11720
|
},
|
|
11675
11721
|
// Test Engineer - Can write tests (F1: hyphenated key)
|
|
11676
11722
|
"test-engineer": {
|
|
11677
11723
|
tools: ["read", "edit", "write", "bash", "ls"],
|
|
11678
|
-
excludeTools: ["web"]
|
|
11724
|
+
excludeTools: ["web"],
|
|
11725
|
+
// Phase 1 scratchpad: build/run test suites with state across cells.
|
|
11726
|
+
scratchpad: true
|
|
11679
11727
|
}
|
|
11680
11728
|
};
|
|
11681
11729
|
}
|
|
@@ -11891,6 +11939,14 @@ function parseAgentFile(filePath, source) {
|
|
|
11891
11939
|
fallbackModels: parseCsv(frontmatter.fallbackModels),
|
|
11892
11940
|
thinking: frontmatter.thinking === "false" ? void 0 : frontmatter.thinking || void 0,
|
|
11893
11941
|
tools: parseToolsField(frontmatter.tools),
|
|
11942
|
+
// Phase 1 scratchpad opt-in (Q3: pi ignores unknown frontmatter keys; pi-crew
|
|
11943
|
+
// is the sole consumer in the worker path — task arrives via -p, agent file
|
|
11944
|
+
// is not re-read by pi). 3-STATE parse (NOT `=== "true"` like
|
|
11945
|
+
// inheritProjectContext): omitted/malformed → undefined so the F6 kill-switch
|
|
11946
|
+
// (`agent.scratchpad === false`) only fires on an EXPLICIT `scratchpad: false`,
|
|
11947
|
+
// not on every agent without the key (which would wrongly kill role
|
|
11948
|
+
// default-on). Only the literal "true"/"false" are honored.
|
|
11949
|
+
scratchpad: frontmatter.scratchpad === "true" ? true : frontmatter.scratchpad === "false" ? false : void 0,
|
|
11894
11950
|
// SEC-1: Strip extensions/excludeExtensions for untrusted project-sourced
|
|
11895
11951
|
// agents (RCE prevention). Both `project` (.crew/agents/) and
|
|
11896
11952
|
// `project-pi` (.pi/agents/) are repo-adjacent / untrusted sources —
|
|
@@ -12392,6 +12448,8 @@ function parseTeamFile(filePath, source) {
|
|
|
12392
12448
|
defaultWorkflow: frontmatter.defaultWorkflow || frontmatter.workflow || void 0,
|
|
12393
12449
|
workspaceMode: frontmatter.workspaceMode?.trim() === "worktree" ? "worktree" : "single",
|
|
12394
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",
|
|
12395
12453
|
routing: triggers || useWhen || avoidWhen || cost || category ? { triggers, useWhen, avoidWhen, cost, category } : void 0
|
|
12396
12454
|
};
|
|
12397
12455
|
} catch {
|
|
@@ -14860,6 +14918,55 @@ var init_env_filter = __esm({
|
|
|
14860
14918
|
}
|
|
14861
14919
|
});
|
|
14862
14920
|
|
|
14921
|
+
// src/runtime/scratchpad/snapshot-lookup.ts
|
|
14922
|
+
import { lstatSync as lstatSync5, readdirSync as readdirSync8 } from "node:fs";
|
|
14923
|
+
import { join as join18 } from "node:path";
|
|
14924
|
+
function findLatestScratchpadSnapshot(artifactsRoot, agentId) {
|
|
14925
|
+
const scratchpadDir = join18(artifactsRoot, "scratchpad");
|
|
14926
|
+
let dirStat;
|
|
14927
|
+
try {
|
|
14928
|
+
dirStat = lstatSync5(scratchpadDir);
|
|
14929
|
+
} catch {
|
|
14930
|
+
return null;
|
|
14931
|
+
}
|
|
14932
|
+
if (dirStat.isSymbolicLink() || !dirStat.isDirectory()) return null;
|
|
14933
|
+
let entries;
|
|
14934
|
+
try {
|
|
14935
|
+
entries = readdirSync8(scratchpadDir, { withFileTypes: true });
|
|
14936
|
+
} catch {
|
|
14937
|
+
return null;
|
|
14938
|
+
}
|
|
14939
|
+
const prefix = `${agentId}.attempt-`;
|
|
14940
|
+
let best = null;
|
|
14941
|
+
for (const dirent of entries) {
|
|
14942
|
+
if (dirent.isSymbolicLink() || !dirent.isFile()) continue;
|
|
14943
|
+
const name = dirent.name;
|
|
14944
|
+
if (!name.startsWith(prefix) || !name.endsWith(SNAPSHOT_SUFFIX)) continue;
|
|
14945
|
+
const attemptPart = name.slice(prefix.length, name.length - SNAPSHOT_SUFFIX.length);
|
|
14946
|
+
if (!/^\d+$/.test(attemptPart)) continue;
|
|
14947
|
+
const attempt = Number.parseInt(attemptPart, 10);
|
|
14948
|
+
let stat2;
|
|
14949
|
+
try {
|
|
14950
|
+
stat2 = lstatSync5(join18(scratchpadDir, name));
|
|
14951
|
+
} catch {
|
|
14952
|
+
continue;
|
|
14953
|
+
}
|
|
14954
|
+
if (!stat2.isFile()) continue;
|
|
14955
|
+
const hit = { path: join18(scratchpadDir, name), attempt, mtimeMs: stat2.mtimeMs };
|
|
14956
|
+
if (best === null || hit.mtimeMs > best.mtimeMs || hit.mtimeMs === best.mtimeMs && hit.attempt < best.attempt) {
|
|
14957
|
+
best = hit;
|
|
14958
|
+
}
|
|
14959
|
+
}
|
|
14960
|
+
return best;
|
|
14961
|
+
}
|
|
14962
|
+
var SNAPSHOT_SUFFIX;
|
|
14963
|
+
var init_snapshot_lookup = __esm({
|
|
14964
|
+
"src/runtime/scratchpad/snapshot-lookup.ts"() {
|
|
14965
|
+
"use strict";
|
|
14966
|
+
SNAPSHOT_SUFFIX = ".snapshot.json";
|
|
14967
|
+
}
|
|
14968
|
+
});
|
|
14969
|
+
|
|
14863
14970
|
// src/runtime/child-pi/child-pi-spawn.ts
|
|
14864
14971
|
import * as fs18 from "node:fs";
|
|
14865
14972
|
import * as path18 from "node:path";
|
|
@@ -14956,6 +15063,21 @@ function prepareSpawnContext(input, effectiveTask) {
|
|
|
14956
15063
|
if (input.runId) built.env.PI_CREW_BROKER_RUN_ID = input.runId;
|
|
14957
15064
|
if (input.agentId) built.env.PI_CREW_BROKER_TASK_ID = input.agentId;
|
|
14958
15065
|
}
|
|
15066
|
+
if (input.agentId && isScratchpadEnabledForRole(input.role ?? input.agent.name, input.agent)) {
|
|
15067
|
+
built.env.PI_CREW_SCRATCHPAD = "1";
|
|
15068
|
+
built.env.PI_CREW_TASK_ID = input.agentId;
|
|
15069
|
+
built.env.PI_CREW_ATTEMPT = String(input.attempt ?? 0);
|
|
15070
|
+
if (input.artifactsRoot) {
|
|
15071
|
+
built.env.PI_CREW_ARTIFACTS_ROOT = input.artifactsRoot;
|
|
15072
|
+
}
|
|
15073
|
+
const scratchTempDir = built.tempDir ?? createSafeTempDir(getPiTempBase(), "pi-crew-scratchpad-");
|
|
15074
|
+
built.env.PI_CREW_SCRATCHPAD_SNAPSHOT = resolveRealContainedPath(scratchTempDir, `${input.agentId}.snapshot.json`);
|
|
15075
|
+
const restoreHit = input.artifactsRoot ? findLatestScratchpadSnapshot(input.artifactsRoot, input.agentId) : null;
|
|
15076
|
+
if (restoreHit) {
|
|
15077
|
+
built.env.PI_CREW_SCRATCHPAD_RESTORE = restoreHit.path;
|
|
15078
|
+
built.env.PI_CREW_SCRATCHPAD_RESTORE_MTIME = String(restoreHit.mtimeMs);
|
|
15079
|
+
}
|
|
15080
|
+
}
|
|
14959
15081
|
if (input.signal?.aborted) {
|
|
14960
15082
|
return {
|
|
14961
15083
|
kind: "aborted",
|
|
@@ -14983,11 +15105,14 @@ var BASE_ALLOWLIST;
|
|
|
14983
15105
|
var init_child_pi_spawn = __esm({
|
|
14984
15106
|
"src/runtime/child-pi/child-pi-spawn.ts"() {
|
|
14985
15107
|
"use strict";
|
|
15108
|
+
init_role_tools();
|
|
14986
15109
|
init_env_allowlist();
|
|
14987
15110
|
init_env_filter();
|
|
14988
15111
|
init_internal_error();
|
|
15112
|
+
init_safe_paths();
|
|
14989
15113
|
init_pi_args();
|
|
14990
15114
|
init_pi_spawn();
|
|
15115
|
+
init_snapshot_lookup();
|
|
14991
15116
|
BASE_ALLOWLIST = [
|
|
14992
15117
|
"PATH",
|
|
14993
15118
|
"HOME",
|
|
@@ -22287,7 +22412,18 @@ var init_model_fallback = __esm({
|
|
|
22287
22412
|
/context[_ ]?length[_ ]?exceeded/i,
|
|
22288
22413
|
/safety/i,
|
|
22289
22414
|
/is[_ ]?overloaded/i,
|
|
22290
|
-
/\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
|
|
22291
22427
|
];
|
|
22292
22428
|
NON_RETRYABLE_MODEL_FAILURE_PATTERNS = [
|
|
22293
22429
|
/auth(?:entication)?/i,
|
|
@@ -23005,12 +23141,12 @@ var init_crew_hooks = __esm({
|
|
|
23005
23141
|
|
|
23006
23142
|
// src/runtime/skill-effectiveness.ts
|
|
23007
23143
|
import { existsSync as existsSync23, mkdirSync as mkdirSync14, readFileSync as readFileSync23, writeFileSync as writeFileSync4 } from "node:fs";
|
|
23008
|
-
import { dirname as dirname16, join as
|
|
23144
|
+
import { dirname as dirname16, join as join30 } from "node:path";
|
|
23009
23145
|
function getSkillMetricsPath(cwd, runId) {
|
|
23010
|
-
return
|
|
23146
|
+
return join30(projectCrewRoot(cwd), `state/runs/${runId}/skill-metrics.jsonl`);
|
|
23011
23147
|
}
|
|
23012
23148
|
function getSkillActivationsPath(cwd, runId) {
|
|
23013
|
-
return
|
|
23149
|
+
return join30(projectCrewRoot(cwd), `state/runs/${runId}/skill-activations.jsonl`);
|
|
23014
23150
|
}
|
|
23015
23151
|
function ensureSkillMetricsDir(cwd, runId) {
|
|
23016
23152
|
const dir = dirname16(getSkillMetricsPath(cwd, runId));
|
|
@@ -23725,10 +23861,12 @@ var init_team_tool_schema = __esm({
|
|
|
23725
23861
|
})
|
|
23726
23862
|
),
|
|
23727
23863
|
budgetTotal: Type.Optional(
|
|
23864
|
+
// Empty-string unset marker accepted (Tier-9: models emit "" when unset).
|
|
23728
23865
|
// 0 accepted as "unset/disabled" (models emit 0 for off); still rejects 1-999
|
|
23729
23866
|
// as the MISCONFIGURATION GUARD against typo'd silent-abort configs.
|
|
23730
23867
|
Type.Union(
|
|
23731
23868
|
[
|
|
23869
|
+
Type.Literal(""),
|
|
23732
23870
|
Type.Literal(0),
|
|
23733
23871
|
Type.Number({
|
|
23734
23872
|
minimum: 1e3
|
|
@@ -33743,35 +33881,6 @@ var init_live_session_runtime = __esm({
|
|
|
33743
33881
|
}
|
|
33744
33882
|
});
|
|
33745
33883
|
|
|
33746
|
-
// src/runtime/role-permission.ts
|
|
33747
|
-
function permissionForRole(role) {
|
|
33748
|
-
if (READ_ONLY_ROLES.has(role)) return "read_only";
|
|
33749
|
-
if (WRITE_ROLES.has(role)) return "workspace_write";
|
|
33750
|
-
return "read_only";
|
|
33751
|
-
}
|
|
33752
|
-
function currentCrewRole(env = process.env) {
|
|
33753
|
-
return env.PI_CREW_ROLE?.trim() || env.PI_TEAMS_ROLE?.trim() || void 0;
|
|
33754
|
-
}
|
|
33755
|
-
function checkSubagentSpawnPermission(role) {
|
|
33756
|
-
if (!role) return { allowed: true, mode: "workspace_write" };
|
|
33757
|
-
const mode = permissionForRole(role);
|
|
33758
|
-
if (mode === "read_only")
|
|
33759
|
-
return {
|
|
33760
|
-
allowed: false,
|
|
33761
|
-
mode,
|
|
33762
|
-
reason: `Role '${role}' is read-only and cannot spawn additional subagents.`
|
|
33763
|
-
};
|
|
33764
|
-
return { allowed: true, mode };
|
|
33765
|
-
}
|
|
33766
|
-
var READ_ONLY_ROLES, WRITE_ROLES;
|
|
33767
|
-
var init_role_permission = __esm({
|
|
33768
|
-
"src/runtime/role-permission.ts"() {
|
|
33769
|
-
"use strict";
|
|
33770
|
-
READ_ONLY_ROLES = /* @__PURE__ */ new Set(["explorer", "reviewer", "security-reviewer", "analyst", "critic", "planner"]);
|
|
33771
|
-
WRITE_ROLES = /* @__PURE__ */ new Set(["executor", "test-engineer", "writer", "verifier", "agent", "cold-verifier", "chain-executor", "worker"]);
|
|
33772
|
-
}
|
|
33773
|
-
});
|
|
33774
|
-
|
|
33775
33884
|
// src/state/coordination/task-claims.ts
|
|
33776
33885
|
import { randomUUID as randomUUID4, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
33777
33886
|
function createTaskClaim(owner, leaseMs = 5 * 6e4, now = /* @__PURE__ */ new Date()) {
|
|
@@ -39426,6 +39535,7 @@ function serializeAgent(agent) {
|
|
|
39426
39535
|
line("fallbackModels", agent.fallbackModels),
|
|
39427
39536
|
line("thinking", agent.thinking),
|
|
39428
39537
|
line("tools", agent.tools),
|
|
39538
|
+
line("scratchpad", agent.scratchpad),
|
|
39429
39539
|
agent.extensions !== void 0 ? line("extensions", agent.extensions) ?? "extensions:" : void 0,
|
|
39430
39540
|
line("skills", agent.skills),
|
|
39431
39541
|
line("systemPromptMode", agent.systemPromptMode),
|
|
@@ -39476,6 +39586,7 @@ function serializeTeam(team) {
|
|
|
39476
39586
|
team.defaultWorkflow ? `defaultWorkflow: ${team.defaultWorkflow}` : void 0,
|
|
39477
39587
|
team.workspaceMode ? `workspaceMode: ${team.workspaceMode}` : void 0,
|
|
39478
39588
|
team.maxConcurrency !== void 0 ? `maxConcurrency: ${team.maxConcurrency}` : void 0,
|
|
39589
|
+
team.observability !== void 0 ? `observability: ${team.observability}` : void 0,
|
|
39479
39590
|
line2("triggers", team.routing?.triggers),
|
|
39480
39591
|
line2("useWhen", team.routing?.useWhen),
|
|
39481
39592
|
line2("avoidWhen", team.routing?.avoidWhen),
|
|
@@ -40772,9 +40883,9 @@ var init_handle_settings = __esm({
|
|
|
40772
40883
|
|
|
40773
40884
|
// src/extension/team-tool/workflow-manage.ts
|
|
40774
40885
|
import { existsSync as existsSync41, readFileSync as readFileSync40, rmSync as rmSync14, writeFileSync as writeFileSync7 } from "node:fs";
|
|
40775
|
-
import { dirname as dirname29, join as
|
|
40886
|
+
import { dirname as dirname29, join as join46 } from "node:path";
|
|
40776
40887
|
function allowedWorkflowDirs(cwd) {
|
|
40777
|
-
return [
|
|
40888
|
+
return [join46(projectCrewRoot(cwd), "workflows"), join46(userPiRoot(), "workflows"), join46(packageRoot(), "workflows")];
|
|
40778
40889
|
}
|
|
40779
40890
|
function validateScriptContent(content) {
|
|
40780
40891
|
for (const pattern of FORBIDDEN_PATTERNS) {
|
|
@@ -40786,7 +40897,7 @@ function validateScriptContent(content) {
|
|
|
40786
40897
|
}
|
|
40787
40898
|
function resolveWorkflowWritePath(cwd, name, scope = "project") {
|
|
40788
40899
|
assertSafePathId("workflowName", name);
|
|
40789
|
-
const base = scope === "user" ?
|
|
40900
|
+
const base = scope === "user" ? join46(userPiRoot(), "workflows") : join46(projectCrewRoot(cwd), "workflows");
|
|
40790
40901
|
return resolveRealContainedPath(base, `${name}.dwf.ts`);
|
|
40791
40902
|
}
|
|
40792
40903
|
function handleWorkflowCreate(params, ctx) {
|
|
@@ -41640,7 +41751,7 @@ var init_async_runner = __esm({
|
|
|
41640
41751
|
});
|
|
41641
41752
|
|
|
41642
41753
|
// src/runtime/goal-workflow/goal-state-store.ts
|
|
41643
|
-
import { closeSync as closeSync10, existsSync as existsSync44, mkdirSync as mkdirSync26, openSync as openSync10, readdirSync as
|
|
41754
|
+
import { closeSync as closeSync10, existsSync as existsSync44, mkdirSync as mkdirSync26, openSync as openSync10, readdirSync as readdirSync21, readFileSync as readFileSync42, statSync as statSync33, unlinkSync as unlinkSync7 } from "node:fs";
|
|
41644
41755
|
import { dirname as dirname32 } from "node:path";
|
|
41645
41756
|
function resolveGoalsRoot(cwd) {
|
|
41646
41757
|
const crewRoot = projectCrewRoot(cwd) ?? userCrewRoot();
|
|
@@ -41800,7 +41911,7 @@ var init_goal_state_store = __esm({
|
|
|
41800
41911
|
try {
|
|
41801
41912
|
const root = resolveGoalsRoot(this.cwd);
|
|
41802
41913
|
if (!existsSync44(root)) return [];
|
|
41803
|
-
const entries =
|
|
41914
|
+
const entries = readdirSync21(root);
|
|
41804
41915
|
const goals = [];
|
|
41805
41916
|
for (const entry of entries) {
|
|
41806
41917
|
if (!entry.endsWith(".json")) continue;
|
|
@@ -41864,7 +41975,7 @@ var init_verification_integrity = __esm({
|
|
|
41864
41975
|
|
|
41865
41976
|
// src/runtime/workspace-lock.ts
|
|
41866
41977
|
import { createHash as createHash7 } from "node:crypto";
|
|
41867
|
-
import { closeSync as closeSync11, existsSync as existsSync45, mkdirSync as mkdirSync27, openSync as openSync11, readdirSync as
|
|
41978
|
+
import { closeSync as closeSync11, existsSync as existsSync45, mkdirSync as mkdirSync27, openSync as openSync11, readdirSync as readdirSync22, readFileSync as readFileSync44, statSync as statSync35, unlinkSync as unlinkSync8, writeFileSync as writeFileSync8 } from "node:fs";
|
|
41868
41979
|
import * as path50 from "node:path";
|
|
41869
41980
|
function workspaceLockPath(cwd) {
|
|
41870
41981
|
const absCwd = path50.resolve(cwd);
|
|
@@ -45069,7 +45180,8 @@ __export(crash_recovery_exports, {
|
|
|
45069
45180
|
detectInterruptedRuns: () => detectInterruptedRuns,
|
|
45070
45181
|
purgeStaleActiveRunIndex: () => purgeStaleActiveRunIndex,
|
|
45071
45182
|
readManifestWithTransientRetry: () => readManifestWithTransientRetry,
|
|
45072
|
-
reconcileAllStaleRuns: () => reconcileAllStaleRuns
|
|
45183
|
+
reconcileAllStaleRuns: () => reconcileAllStaleRuns,
|
|
45184
|
+
shouldRecoverTask: () => shouldRecoverTask
|
|
45073
45185
|
});
|
|
45074
45186
|
import * as fs63 from "node:fs";
|
|
45075
45187
|
import * as path52 from "node:path";
|
|
@@ -48365,6 +48477,9 @@ function taskHasObservableWorkerActivity(task) {
|
|
|
48365
48477
|
(task.agentProgress?.toolCount ?? 0) > 0 || task.usage || task.transcriptArtifact || task.modelAttempts?.some((attempt) => attempt.success) || task.jsonEvents
|
|
48366
48478
|
);
|
|
48367
48479
|
}
|
|
48480
|
+
function taskHasEmptyResult(task) {
|
|
48481
|
+
return Boolean(task.resultArtifact && task.resultArtifact.sizeBytes === 0);
|
|
48482
|
+
}
|
|
48368
48483
|
function resolveEffectivenessGuardMode(runtimeConfig, manifest) {
|
|
48369
48484
|
const configured = runtimeConfig?.effectivenessGuard;
|
|
48370
48485
|
if (configured === "off" || configured === "warn" || configured === "block" || configured === "fail") return configured;
|
|
@@ -48373,7 +48488,7 @@ function resolveEffectivenessGuardMode(runtimeConfig, manifest) {
|
|
|
48373
48488
|
}
|
|
48374
48489
|
function evaluateRunEffectiveness(input) {
|
|
48375
48490
|
const completedTasks = input.tasks.filter((task) => task.status === "completed");
|
|
48376
|
-
const noObservedWorkTasks = completedTasks.filter((task) => !taskHasObservableWorkerActivity(task));
|
|
48491
|
+
const noObservedWorkTasks = completedTasks.filter((task) => !taskHasObservableWorkerActivity(task) || taskHasEmptyResult(task));
|
|
48377
48492
|
const needsAttentionTasks = input.tasks.filter((task) => task.agentProgress?.activityState === "needs_attention");
|
|
48378
48493
|
const workerExecution = input.executeWorkers ? "enabled" : "disabled/scaffold";
|
|
48379
48494
|
const guardMode = resolveEffectivenessGuardMode(input.runtimeConfig, input.manifest);
|
|
@@ -49235,112 +49350,6 @@ var init_correlation = __esm({
|
|
|
49235
49350
|
}
|
|
49236
49351
|
});
|
|
49237
49352
|
|
|
49238
|
-
// src/plugins/plugin-registry.ts
|
|
49239
|
-
var PluginRegistry;
|
|
49240
|
-
var init_plugin_registry = __esm({
|
|
49241
|
-
"src/plugins/plugin-registry.ts"() {
|
|
49242
|
-
"use strict";
|
|
49243
|
-
PluginRegistry = class {
|
|
49244
|
-
plugins = [];
|
|
49245
|
-
register(plugin) {
|
|
49246
|
-
this.plugins.push(plugin);
|
|
49247
|
-
}
|
|
49248
|
-
activePlugins(allDeps) {
|
|
49249
|
-
return this.plugins.filter(
|
|
49250
|
-
(p) => p.enablers.some((enabler) => {
|
|
49251
|
-
if (enabler.endsWith("/")) {
|
|
49252
|
-
return allDeps.some((d) => d.startsWith(enabler));
|
|
49253
|
-
}
|
|
49254
|
-
return allDeps.includes(enabler);
|
|
49255
|
-
})
|
|
49256
|
-
);
|
|
49257
|
-
}
|
|
49258
|
-
allPlugins() {
|
|
49259
|
-
return [...this.plugins];
|
|
49260
|
-
}
|
|
49261
|
-
};
|
|
49262
|
-
}
|
|
49263
|
-
});
|
|
49264
|
-
|
|
49265
|
-
// src/plugins/plugin-define.ts
|
|
49266
|
-
function definePlugin(spec) {
|
|
49267
|
-
return spec;
|
|
49268
|
-
}
|
|
49269
|
-
var init_plugin_define = __esm({
|
|
49270
|
-
"src/plugins/plugin-define.ts"() {
|
|
49271
|
-
"use strict";
|
|
49272
|
-
}
|
|
49273
|
-
});
|
|
49274
|
-
|
|
49275
|
-
// src/plugins/plugins/nextjs.ts
|
|
49276
|
-
var NextJsPlugin;
|
|
49277
|
-
var init_nextjs = __esm({
|
|
49278
|
-
"src/plugins/plugins/nextjs.ts"() {
|
|
49279
|
-
"use strict";
|
|
49280
|
-
init_plugin_define();
|
|
49281
|
-
NextJsPlugin = definePlugin({
|
|
49282
|
-
name: "nextjs",
|
|
49283
|
-
enablers: ["next"],
|
|
49284
|
-
entryPatterns: [
|
|
49285
|
-
"src/app/**/*.{ts,tsx}",
|
|
49286
|
-
"src/pages/**/*.{ts,tsx}",
|
|
49287
|
-
"src/app/**/page.{ts,tsx}",
|
|
49288
|
-
"src/app/**/layout.{ts,tsx}",
|
|
49289
|
-
"src/app/**/route.{ts,tsx}",
|
|
49290
|
-
"middleware.{ts,js}",
|
|
49291
|
-
"next.config.{ts,js,mjs}"
|
|
49292
|
-
],
|
|
49293
|
-
configPatterns: ["next.config.{ts,js,mjs}"],
|
|
49294
|
-
toolingDependencies: ["next", "@next/font", "@next/mdx"],
|
|
49295
|
-
pathAliases: [["~", "src"]],
|
|
49296
|
-
virtualModulePrefixes: ["next:"]
|
|
49297
|
-
});
|
|
49298
|
-
}
|
|
49299
|
-
});
|
|
49300
|
-
|
|
49301
|
-
// src/plugins/plugins/vite.ts
|
|
49302
|
-
var VitePlugin;
|
|
49303
|
-
var init_vite = __esm({
|
|
49304
|
-
"src/plugins/plugins/vite.ts"() {
|
|
49305
|
-
"use strict";
|
|
49306
|
-
init_plugin_define();
|
|
49307
|
-
VitePlugin = definePlugin({
|
|
49308
|
-
name: "vite",
|
|
49309
|
-
enablers: ["vite", "rolldown-vite"],
|
|
49310
|
-
entryPatterns: ["src/main.{ts,tsx,js,jsx}", "src/index.{ts,tsx,js,jsx}", "index.html"],
|
|
49311
|
-
configPatterns: ["vite.config.{ts,js,mts,mjs}"],
|
|
49312
|
-
toolingDependencies: ["vite"],
|
|
49313
|
-
virtualModulePrefixes: ["virtual:"]
|
|
49314
|
-
});
|
|
49315
|
-
}
|
|
49316
|
-
});
|
|
49317
|
-
|
|
49318
|
-
// src/plugins/plugins/vitest.ts
|
|
49319
|
-
var VitestPlugin;
|
|
49320
|
-
var init_vitest = __esm({
|
|
49321
|
-
"src/plugins/plugins/vitest.ts"() {
|
|
49322
|
-
"use strict";
|
|
49323
|
-
init_plugin_define();
|
|
49324
|
-
VitestPlugin = definePlugin({
|
|
49325
|
-
name: "vitest",
|
|
49326
|
-
enablers: ["vitest"],
|
|
49327
|
-
entryPatterns: ["**/*.test.{ts,tsx}", "**/*.spec.{ts,tsx}", "src/**/*.test.{ts,tsx}", "src/**/*.spec.{ts,tsx}"],
|
|
49328
|
-
configPatterns: ["vitest.config.{ts,js,mjs}", "vite.config.ts"],
|
|
49329
|
-
toolingDependencies: ["vitest"]
|
|
49330
|
-
});
|
|
49331
|
-
}
|
|
49332
|
-
});
|
|
49333
|
-
|
|
49334
|
-
// src/plugins/plugins/index.ts
|
|
49335
|
-
var init_plugins = __esm({
|
|
49336
|
-
"src/plugins/plugins/index.ts"() {
|
|
49337
|
-
"use strict";
|
|
49338
|
-
init_nextjs();
|
|
49339
|
-
init_vite();
|
|
49340
|
-
init_vitest();
|
|
49341
|
-
}
|
|
49342
|
-
});
|
|
49343
|
-
|
|
49344
49353
|
// src/runtime/task-health.ts
|
|
49345
49354
|
function scoreToGrade(score) {
|
|
49346
49355
|
if (score >= 90) return "A";
|
|
@@ -50380,6 +50389,166 @@ var init_group_join = __esm({
|
|
|
50380
50389
|
}
|
|
50381
50390
|
});
|
|
50382
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
|
+
|
|
50383
50552
|
// src/runtime/model/runtime-policy.ts
|
|
50384
50553
|
function resolveTaskRuntimeKind(globalKind, role, isolationPolicy, env = process.env) {
|
|
50385
50554
|
if (globalKind === "scaffold") return "scaffold";
|
|
@@ -51732,75 +51901,6 @@ var init_task_graph = __esm({
|
|
|
51732
51901
|
}
|
|
51733
51902
|
});
|
|
51734
51903
|
|
|
51735
|
-
// src/runtime/scheduling/task-graph-scheduler.ts
|
|
51736
|
-
function buildTaskGraphIndex(tasks) {
|
|
51737
|
-
const cached2 = taskGraphIndexCache.get(tasks);
|
|
51738
|
-
if (cached2) return cached2;
|
|
51739
|
-
const fresh = {
|
|
51740
|
-
doneSteps: new Set(
|
|
51741
|
-
tasks.filter((task) => task.status === "completed").map((task) => task.stepId).filter((id) => id !== void 0)
|
|
51742
|
-
),
|
|
51743
|
-
idMap: new Map(tasks.map((task) => [task.id, task])),
|
|
51744
|
-
stepToTaskId: new Map(
|
|
51745
|
-
tasks.map((task) => [task.stepId, task.id]).filter((entry) => entry[0] !== void 0)
|
|
51746
|
-
)
|
|
51747
|
-
};
|
|
51748
|
-
taskGraphIndexCache.set(tasks, fresh);
|
|
51749
|
-
return fresh;
|
|
51750
|
-
}
|
|
51751
|
-
function dependencySatisfied(task, doneStepIds, idMap, stepMap) {
|
|
51752
|
-
return task.dependsOn.every((dependency) => {
|
|
51753
|
-
if (doneStepIds.has(dependency)) return true;
|
|
51754
|
-
const taskId = stepMap.get(dependency) ?? dependency;
|
|
51755
|
-
return idMap.get(taskId)?.status === "completed";
|
|
51756
|
-
});
|
|
51757
|
-
}
|
|
51758
|
-
function withQueue(task, index) {
|
|
51759
|
-
let resolvedQueue;
|
|
51760
|
-
if (task.status === "queued") {
|
|
51761
|
-
const isReady = dependencySatisfied(task, index.doneSteps, index.idMap, index.stepToTaskId);
|
|
51762
|
-
resolvedQueue = isReady ? "ready" : "blocked";
|
|
51763
|
-
} else if (task.status === "running") {
|
|
51764
|
-
resolvedQueue = "running";
|
|
51765
|
-
} else if (task.status === "completed" || task.status === "skipped" || task.status === "needs_attention") {
|
|
51766
|
-
resolvedQueue = "done";
|
|
51767
|
-
} else {
|
|
51768
|
-
resolvedQueue = "blocked";
|
|
51769
|
-
}
|
|
51770
|
-
if (task.graph && task.graph.queue === resolvedQueue) {
|
|
51771
|
-
return task;
|
|
51772
|
-
}
|
|
51773
|
-
return {
|
|
51774
|
-
...task,
|
|
51775
|
-
graph: task.graph ? { ...task.graph, queue: resolvedQueue } : task.graph
|
|
51776
|
-
};
|
|
51777
|
-
}
|
|
51778
|
-
function ensureIndex(tasks, index) {
|
|
51779
|
-
return index ?? buildTaskGraphIndex(tasks);
|
|
51780
|
-
}
|
|
51781
|
-
function refreshTaskGraphQueues(tasks, index) {
|
|
51782
|
-
const resolved = ensureIndex(tasks, index);
|
|
51783
|
-
return tasks.map((task) => withQueue(task, resolved));
|
|
51784
|
-
}
|
|
51785
|
-
function taskGraphSnapshot(tasks, index) {
|
|
51786
|
-
const refreshed = refreshTaskGraphQueues(tasks, index);
|
|
51787
|
-
return {
|
|
51788
|
-
ready: refreshed.filter((task) => task.status === "queued" && task.graph?.queue === "ready").map((task) => task.id),
|
|
51789
|
-
blocked: refreshed.filter((task) => task.status === "queued" && task.graph?.queue === "blocked").map((task) => task.id),
|
|
51790
|
-
running: refreshed.filter((task) => task.status === "running").map((task) => task.id),
|
|
51791
|
-
done: refreshed.filter((task) => task.status === "completed" || task.status === "skipped").map((task) => task.id),
|
|
51792
|
-
failed: refreshed.filter((task) => task.status === "failed").map((task) => task.id),
|
|
51793
|
-
cancelled: refreshed.filter((task) => task.status === "cancelled").map((task) => task.id)
|
|
51794
|
-
};
|
|
51795
|
-
}
|
|
51796
|
-
var taskGraphIndexCache;
|
|
51797
|
-
var init_task_graph_scheduler = __esm({
|
|
51798
|
-
"src/runtime/scheduling/task-graph-scheduler.ts"() {
|
|
51799
|
-
"use strict";
|
|
51800
|
-
taskGraphIndexCache = /* @__PURE__ */ new WeakMap();
|
|
51801
|
-
}
|
|
51802
|
-
});
|
|
51803
|
-
|
|
51804
51904
|
// src/extension/knowledge-injection.ts
|
|
51805
51905
|
import * as fs75 from "node:fs";
|
|
51806
51906
|
import * as path65 from "node:path";
|
|
@@ -53188,6 +53288,20 @@ function detectRetryableModelFailureFromOutput(parsed) {
|
|
|
53188
53288
|
}
|
|
53189
53289
|
return void 0;
|
|
53190
53290
|
}
|
|
53291
|
+
function evidenceStatusFor(childResult) {
|
|
53292
|
+
return childResult.exitStatus?.cancelled ? "cancelled" : childResult.error || childResult.exitCode && childResult.exitCode !== 0 ? "failed" : "completed";
|
|
53293
|
+
}
|
|
53294
|
+
function attemptErrorFor(childResult, parsedOutput, taskId) {
|
|
53295
|
+
let err2 = childResult.error || (childResult.exitCode && childResult.exitCode !== 0 ? childResult.stderr || `Child Pi exited with ${childResult.exitCode}` : void 0);
|
|
53296
|
+
if (childResult.exitStatus?.timedOut) {
|
|
53297
|
+
err2 = errors.childTimeout({ taskId, stderr: childResult.stderr }).message;
|
|
53298
|
+
}
|
|
53299
|
+
if (!err2 && parsedOutput) {
|
|
53300
|
+
const rateLimitErr = detectRetryableModelFailureFromOutput(parsedOutput);
|
|
53301
|
+
if (rateLimitErr) err2 = rateLimitErr;
|
|
53302
|
+
}
|
|
53303
|
+
return err2;
|
|
53304
|
+
}
|
|
53191
53305
|
async function runChildProcessTask(ctx) {
|
|
53192
53306
|
const input = ctx.input;
|
|
53193
53307
|
const manifest = ctx.manifest;
|
|
@@ -53371,6 +53485,7 @@ async function runChildProcessTask(ctx) {
|
|
|
53371
53485
|
runId: manifest.runId,
|
|
53372
53486
|
agentId: task.id,
|
|
53373
53487
|
artifactsRoot: manifest.artifactsRoot,
|
|
53488
|
+
attempt: i,
|
|
53374
53489
|
steeringFile: resolveRealContainedPath(`${manifest.artifactsRoot}/steering`, `${task.id}.jsonl`),
|
|
53375
53490
|
onSpawn: (pid) => {
|
|
53376
53491
|
try {
|
|
@@ -53459,7 +53574,7 @@ async function runChildProcessTask(ctx) {
|
|
|
53459
53574
|
input.signal.removeEventListener("abort", externalAbortListener);
|
|
53460
53575
|
}
|
|
53461
53576
|
}
|
|
53462
|
-
const evidenceStatus = childResult
|
|
53577
|
+
const evidenceStatus = evidenceStatusFor(childResult);
|
|
53463
53578
|
terminalEvidence = [
|
|
53464
53579
|
...terminalEvidence,
|
|
53465
53580
|
{
|
|
@@ -53505,17 +53620,7 @@ async function runChildProcessTask(ctx) {
|
|
|
53505
53620
|
parsedOutput = parsePiJsonOutput(transcriptText2);
|
|
53506
53621
|
rawFinalText = childResult.rawFinalText;
|
|
53507
53622
|
intermediateFindings = childResult.intermediateFindings;
|
|
53508
|
-
error =
|
|
53509
|
-
if (childResult.exitStatus?.timedOut) {
|
|
53510
|
-
error = errors.childTimeout({
|
|
53511
|
-
taskId: task.id,
|
|
53512
|
-
stderr: childResult.stderr
|
|
53513
|
-
}).message;
|
|
53514
|
-
}
|
|
53515
|
-
if (!error && parsedOutput) {
|
|
53516
|
-
const rateLimitErr = detectRetryableModelFailureFromOutput(parsedOutput);
|
|
53517
|
-
if (rateLimitErr) error = rateLimitErr;
|
|
53518
|
-
}
|
|
53623
|
+
error = attemptErrorFor(childResult, parsedOutput, task.id);
|
|
53519
53624
|
persistHeartbeat(true);
|
|
53520
53625
|
persistChildProgress({ type: "attempt_finished" }, true);
|
|
53521
53626
|
const attempt = {
|
|
@@ -56692,12 +56797,13 @@ __export(team_runner_exports, {
|
|
|
56692
56797
|
drainPendingUnits: () => drainPendingUnits,
|
|
56693
56798
|
executeTeamRun: () => executeTeamRun,
|
|
56694
56799
|
hasPendingMutatingTaskAtBoundary: () => hasPendingMutatingTaskAtBoundary,
|
|
56695
|
-
mergeTaskUpdatesPreservingTerminal: () => mergeTaskUpdatesPreservingTerminal,
|
|
56696
56800
|
setRunStatusRunning: () => setRunStatusRunning,
|
|
56697
56801
|
shouldUseRetry: () => shouldUseRetry
|
|
56698
56802
|
});
|
|
56803
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
56699
56804
|
import * as fs86 from "node:fs";
|
|
56700
56805
|
import * as path72 from "node:path";
|
|
56806
|
+
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
56701
56807
|
function startTeamRunHeartbeat(stateRoot, runId) {
|
|
56702
56808
|
const heartbeatPath = path72.join(stateRoot, "heartbeat.json");
|
|
56703
56809
|
const writeHeartbeat = () => {
|
|
@@ -56721,6 +56827,87 @@ function startTeamRunHeartbeat(stateRoot, runId) {
|
|
|
56721
56827
|
const interval = setInterval(writeHeartbeat, 6e4);
|
|
56722
56828
|
return () => clearInterval(interval);
|
|
56723
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
|
+
}
|
|
56724
56911
|
function checkPerTaskBudget(tasks, budgetTotal, budgetWarning, budgetAbort, fairShareFraction = 0.5) {
|
|
56725
56912
|
const usage = aggregateUsage(tasks);
|
|
56726
56913
|
const totalUsed = (usage?.input ?? 0) + (usage?.output ?? 0) + (usage?.cacheWrite ?? 0);
|
|
@@ -56764,9 +56951,6 @@ function markBlocked(tasks, reason) {
|
|
|
56764
56951
|
} : task
|
|
56765
56952
|
);
|
|
56766
56953
|
}
|
|
56767
|
-
function isNonTerminalTaskStatus(status) {
|
|
56768
|
-
return status === "queued" || status === "running" || status === "waiting";
|
|
56769
|
-
}
|
|
56770
56954
|
function cancelNonTerminalTasks(tasks, status, reason, filter, transform) {
|
|
56771
56955
|
const predicate = filter ?? ((task) => isNonTerminalTaskStatus(task.status));
|
|
56772
56956
|
return tasks.map((task) => {
|
|
@@ -56775,63 +56959,6 @@ function cancelNonTerminalTasks(tasks, status, reason, filter, transform) {
|
|
|
56775
56959
|
return transform ? transform(task, terminalised) : terminalised;
|
|
56776
56960
|
});
|
|
56777
56961
|
}
|
|
56778
|
-
function safeFinishedAt(task) {
|
|
56779
|
-
if (!task.finishedAt) return -Infinity;
|
|
56780
|
-
const ms = new Date(task.finishedAt).getTime();
|
|
56781
|
-
return Number.isNaN(ms) ? Infinity : ms;
|
|
56782
|
-
}
|
|
56783
|
-
function isMalformedFinishedAtReplacement(currentTime, updatedTime) {
|
|
56784
|
-
return !Number.isFinite(currentTime) && Number.isFinite(updatedTime);
|
|
56785
|
-
}
|
|
56786
|
-
function statusMergeKey(from, to) {
|
|
56787
|
-
return `${from}->${to}`;
|
|
56788
|
-
}
|
|
56789
|
-
function shouldMergeTaskUpdate(current, updated) {
|
|
56790
|
-
if (REJECTED_STATUS_MERGE_TRANSITIONS.has(statusMergeKey(current.status, updated.status))) return false;
|
|
56791
|
-
if (current.status === updated.status && updated.status === "running" && current.resultArtifact && !updated.resultArtifact)
|
|
56792
|
-
return false;
|
|
56793
|
-
if (current.status === updated.status && current.status === "completed" && current.resultArtifact && !updated.resultArtifact)
|
|
56794
|
-
return false;
|
|
56795
|
-
if (current.finishedAt !== void 0 && updated.finishedAt !== void 0) {
|
|
56796
|
-
const currentTime = safeFinishedAt(current);
|
|
56797
|
-
const updatedTime = safeFinishedAt(updated);
|
|
56798
|
-
if (!Number.isFinite(currentTime)) {
|
|
56799
|
-
console.warn(`[team-runner] Task ${current.id} has malformed finishedAt: ${current.finishedAt}`);
|
|
56800
|
-
}
|
|
56801
|
-
if (isMalformedFinishedAtReplacement(currentTime, updatedTime)) {
|
|
56802
|
-
return true;
|
|
56803
|
-
}
|
|
56804
|
-
if (updatedTime < currentTime) return false;
|
|
56805
|
-
}
|
|
56806
|
-
if (!updated.finishedAt && !isNonTerminalTaskStatus(updated.status)) return false;
|
|
56807
|
-
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;
|
|
56808
|
-
return hasMeaningfulUpdate;
|
|
56809
|
-
}
|
|
56810
|
-
function mergeTaskUpdatesPreservingTerminal(base, results) {
|
|
56811
|
-
const indexById = /* @__PURE__ */ new Map();
|
|
56812
|
-
for (const task of base) indexById.set(task.id, task);
|
|
56813
|
-
let skipped = 0;
|
|
56814
|
-
for (const result4 of results) {
|
|
56815
|
-
for (const updated of result4.tasks) {
|
|
56816
|
-
const current = indexById.get(updated.id);
|
|
56817
|
-
if (!current) continue;
|
|
56818
|
-
if (!shouldMergeTaskUpdate(current, updated)) {
|
|
56819
|
-
console.debug("[team-runner] Skipping stale merge for task", updated.id, {
|
|
56820
|
-
currentStatus: current.status,
|
|
56821
|
-
updatedStatus: updated.status,
|
|
56822
|
-
currentFinishedAt: current.finishedAt,
|
|
56823
|
-
updatedFinishedAt: updated.finishedAt
|
|
56824
|
-
});
|
|
56825
|
-
skipped += 1;
|
|
56826
|
-
continue;
|
|
56827
|
-
}
|
|
56828
|
-
indexById.set(updated.id, updated);
|
|
56829
|
-
}
|
|
56830
|
-
}
|
|
56831
|
-
const merged = base.map((task) => indexById.get(task.id) ?? task);
|
|
56832
|
-
void skipped;
|
|
56833
|
-
return refreshTaskGraphQueues(merged);
|
|
56834
|
-
}
|
|
56835
56962
|
function formatTaskProgress(task) {
|
|
56836
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}` : ""}`;
|
|
56837
56964
|
}
|
|
@@ -57093,6 +57220,7 @@ async function executeTeamRun(input) {
|
|
|
57093
57220
|
}
|
|
57094
57221
|
void registerRunPromise(manifest.runId);
|
|
57095
57222
|
const stopTeamHeartbeat = startTeamRunHeartbeat(manifest.stateRoot, manifest.runId);
|
|
57223
|
+
startPerfSampler(manifest, input.team);
|
|
57096
57224
|
const cleanupUsage = () => {
|
|
57097
57225
|
for (const task of input.tasks) clearTrackedTaskUsage(task.id);
|
|
57098
57226
|
};
|
|
@@ -57158,6 +57286,7 @@ async function executeTeamRun(input) {
|
|
|
57158
57286
|
);
|
|
57159
57287
|
}
|
|
57160
57288
|
await flushEventLogBuffer();
|
|
57289
|
+
schedulePerfAnalyze(manifest, input.team);
|
|
57161
57290
|
return result4;
|
|
57162
57291
|
} catch (error) {
|
|
57163
57292
|
stopTeamHeartbeat();
|
|
@@ -58245,15 +58374,13 @@ async function executeTeamRunCore(input, manifest, workflow) {
|
|
|
58245
58374
|
await drainPendingUnits(pendingUnits, runController);
|
|
58246
58375
|
}
|
|
58247
58376
|
}
|
|
58248
|
-
var
|
|
58377
|
+
var OBSERVABILITY_INTERVAL_MS, OBSERVABILITY_ANALYZE_DELAY_MS, lastProgressContentHash, __test__lastProgressContentHash, __test__writeProgress, __test__cancelPlanTasks;
|
|
58249
58378
|
var init_team_runner = __esm({
|
|
58250
58379
|
"src/runtime/team-runner.ts"() {
|
|
58251
58380
|
"use strict";
|
|
58252
58381
|
init_errors3();
|
|
58253
58382
|
init_registry2();
|
|
58254
58383
|
init_correlation();
|
|
58255
|
-
init_plugin_registry();
|
|
58256
|
-
init_plugins();
|
|
58257
58384
|
init_atomic_write();
|
|
58258
58385
|
init_contracts();
|
|
58259
58386
|
init_locks();
|
|
@@ -58271,6 +58398,7 @@ var init_team_runner = __esm({
|
|
|
58271
58398
|
init_goal_achievement();
|
|
58272
58399
|
init_group_join();
|
|
58273
58400
|
init_live_agent_manager();
|
|
58401
|
+
init_merge_gate();
|
|
58274
58402
|
init_runtime_policy();
|
|
58275
58403
|
init_path_overlap();
|
|
58276
58404
|
init_policy_engine();
|
|
@@ -58292,32 +58420,10 @@ var init_team_runner = __esm({
|
|
|
58292
58420
|
init_usage_tracker();
|
|
58293
58421
|
init_workflow_state();
|
|
58294
58422
|
init_adaptive_plan();
|
|
58423
|
+
init_merge_gate();
|
|
58295
58424
|
init_adaptive_plan();
|
|
58296
|
-
|
|
58297
|
-
|
|
58298
|
-
builtInRegistry.register(VitestPlugin);
|
|
58299
|
-
builtInRegistry.register(VitePlugin);
|
|
58300
|
-
REJECTED_STATUS_MERGE_TRANSITIONS = (() => {
|
|
58301
|
-
const rejected = /* @__PURE__ */ new Set();
|
|
58302
|
-
for (const from of TEAM_TASK_STATUSES) {
|
|
58303
|
-
if (!TEAM_TERMINAL_TASK_STATUSES.has(from)) continue;
|
|
58304
|
-
for (const to of TEAM_TASK_STATUSES) {
|
|
58305
|
-
if (!TEAM_TERMINAL_TASK_STATUSES.has(to)) rejected.add(statusMergeKey(from, to));
|
|
58306
|
-
}
|
|
58307
|
-
}
|
|
58308
|
-
rejected.add(statusMergeKey("waiting", "running"));
|
|
58309
|
-
const completedIntegrityFlips = [
|
|
58310
|
-
["completed", "failed"],
|
|
58311
|
-
["completed", "needs_attention"],
|
|
58312
|
-
["failed", "completed"],
|
|
58313
|
-
["cancelled", "completed"],
|
|
58314
|
-
["needs_attention", "completed"]
|
|
58315
|
-
];
|
|
58316
|
-
for (const [from, to] of completedIntegrityFlips) rejected.add(statusMergeKey(from, to));
|
|
58317
|
-
return rejected;
|
|
58318
|
-
})();
|
|
58319
|
-
__test__shouldMergeTaskUpdate = shouldMergeTaskUpdate;
|
|
58320
|
-
__test__mergeTaskUpdates = mergeTaskUpdatesPreservingTerminal;
|
|
58425
|
+
OBSERVABILITY_INTERVAL_MS = 2e3;
|
|
58426
|
+
OBSERVABILITY_ANALYZE_DELAY_MS = 3e3;
|
|
58321
58427
|
lastProgressContentHash = /* @__PURE__ */ new Map();
|
|
58322
58428
|
__test__lastProgressContentHash = lastProgressContentHash;
|
|
58323
58429
|
__test__writeProgress = writeProgress;
|
|
@@ -61073,7 +61179,7 @@ __export(dynamic_workflow_runner_exports, {
|
|
|
61073
61179
|
runDynamicWorkflow: () => runDynamicWorkflow
|
|
61074
61180
|
});
|
|
61075
61181
|
import { readFileSync as readFileSync67 } from "node:fs";
|
|
61076
|
-
import { join as
|
|
61182
|
+
import { join as join72 } from "node:path";
|
|
61077
61183
|
import { transformSync } from "esbuild";
|
|
61078
61184
|
function assertStructuredCloneable(value, name) {
|
|
61079
61185
|
try {
|
|
@@ -61085,7 +61191,7 @@ function assertStructuredCloneable(value, name) {
|
|
|
61085
61191
|
}
|
|
61086
61192
|
function resolveScriptPath(workflow, cwd) {
|
|
61087
61193
|
const crewRoot = projectCrewRoot(cwd);
|
|
61088
|
-
const allowedBases = [
|
|
61194
|
+
const allowedBases = [join72(projectCrewRoot(cwd), "workflows"), join72(userPiRoot(), "workflows"), join72(packageRoot(), "workflows")];
|
|
61089
61195
|
for (const base of allowedBases) {
|
|
61090
61196
|
try {
|
|
61091
61197
|
const real = resolveRealContainedPath(base, workflow.filePath);
|
|
@@ -66166,7 +66272,6 @@ var init_mascot = __esm({
|
|
|
66166
66272
|
currentArminGrid;
|
|
66167
66273
|
effectState = {};
|
|
66168
66274
|
effectDone = false;
|
|
66169
|
-
visible = true;
|
|
66170
66275
|
frame = 0;
|
|
66171
66276
|
effectPhase = 0;
|
|
66172
66277
|
gridVersion = 0;
|
|
@@ -66262,7 +66367,7 @@ var init_mascot = __esm({
|
|
|
66262
66367
|
this.gridVersion++;
|
|
66263
66368
|
}
|
|
66264
66369
|
this.invalidate();
|
|
66265
|
-
|
|
66370
|
+
this.requestRender?.();
|
|
66266
66371
|
}
|
|
66267
66372
|
tickArminEffect() {
|
|
66268
66373
|
switch (this.effect) {
|
|
@@ -66469,14 +66574,6 @@ var init_mascot = __esm({
|
|
|
66469
66574
|
this.close();
|
|
66470
66575
|
}
|
|
66471
66576
|
}
|
|
66472
|
-
/**
|
|
66473
|
-
* Set whether the mascot is currently visible (not obscured by another
|
|
66474
|
-
* overlay). When invisible, tick() skips requestRender so the animation
|
|
66475
|
-
* does not trigger needless repaints while hidden.
|
|
66476
|
-
*/
|
|
66477
|
-
setVisible(visible) {
|
|
66478
|
-
this.visible = visible;
|
|
66479
|
-
}
|
|
66480
66577
|
dispose() {
|
|
66481
66578
|
this.doneGuard.called = true;
|
|
66482
66579
|
if (this.interval) clearInterval(this.interval);
|
|
@@ -70525,10 +70622,18 @@ var init_otlp_exporter = __esm({
|
|
|
70525
70622
|
});
|
|
70526
70623
|
|
|
70527
70624
|
// src/observability/metrics-primitives.ts
|
|
70528
|
-
function
|
|
70625
|
+
function getCardinalityEvictions() {
|
|
70626
|
+
return cardinalityEvictions;
|
|
70627
|
+
}
|
|
70628
|
+
function enforceLabelCap(map3, _metricName) {
|
|
70529
70629
|
while (map3.size > MAX_LABEL_COMBINATIONS) {
|
|
70530
70630
|
const firstKey = map3.keys().next().value;
|
|
70531
|
-
if (firstKey !== void 0)
|
|
70631
|
+
if (firstKey !== void 0) {
|
|
70632
|
+
map3.delete(firstKey);
|
|
70633
|
+
cardinalityEvictions++;
|
|
70634
|
+
} else {
|
|
70635
|
+
break;
|
|
70636
|
+
}
|
|
70532
70637
|
}
|
|
70533
70638
|
}
|
|
70534
70639
|
function normalizeLabels(labels = {}) {
|
|
@@ -70542,12 +70647,13 @@ function labelKey(labels = {}) {
|
|
|
70542
70647
|
function cloneLabels(labels) {
|
|
70543
70648
|
return { ...labels };
|
|
70544
70649
|
}
|
|
70545
|
-
var DEFAULT_HISTOGRAM_BUCKETS, MAX_LABEL_COMBINATIONS, Metric, Counter, Gauge, Histogram;
|
|
70650
|
+
var DEFAULT_HISTOGRAM_BUCKETS, MAX_LABEL_COMBINATIONS, cardinalityEvictions, Metric, Counter, Gauge, Histogram;
|
|
70546
70651
|
var init_metrics_primitives = __esm({
|
|
70547
70652
|
"src/observability/metrics-primitives.ts"() {
|
|
70548
70653
|
"use strict";
|
|
70549
70654
|
DEFAULT_HISTOGRAM_BUCKETS = [1, 2, 5, 10, 25, 50, 100, 250, 500, 1e3, 2500, 5e3, 1e4];
|
|
70550
70655
|
MAX_LABEL_COMBINATIONS = 1e4;
|
|
70656
|
+
cardinalityEvictions = 0;
|
|
70551
70657
|
Metric = class {
|
|
70552
70658
|
name;
|
|
70553
70659
|
description;
|
|
@@ -70812,6 +70918,14 @@ function wireEventToMetrics(events, registry2) {
|
|
|
70812
70918
|
const deadletterCount = registry2.counter("crew.task.deadletter_total", "Deadletter triggers by reason");
|
|
70813
70919
|
const overflowCount = registry2.counter("crew.task.overflow_phase_total", "Overflow recovery phase transitions");
|
|
70814
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
|
+
);
|
|
70815
70929
|
registry2.gauge("crew.heartbeat.staleness_ms", "Heartbeat elapsed since last seen, milliseconds");
|
|
70816
70930
|
const runDuration = registry2.histogram(
|
|
70817
70931
|
"crew.run.duration_ms",
|
|
@@ -70911,11 +71025,21 @@ function wireEventToMetrics(events, registry2) {
|
|
|
70911
71025
|
direction: stringValue(item.direction, "unknown")
|
|
70912
71026
|
});
|
|
70913
71027
|
}
|
|
71028
|
+
],
|
|
71029
|
+
[
|
|
71030
|
+
"crew.limits.unbounded",
|
|
71031
|
+
() => {
|
|
71032
|
+
unboundedConcurrencyCount.inc({});
|
|
71033
|
+
}
|
|
70914
71034
|
]
|
|
70915
71035
|
];
|
|
70916
71036
|
const unsubscribers = [];
|
|
70917
71037
|
for (const [event, handler] of handlers) {
|
|
70918
71038
|
const unsubscribe = events?.on?.(event, (data) => {
|
|
71039
|
+
try {
|
|
71040
|
+
cardinalityEvictedGauge.set({}, getCardinalityEvictions());
|
|
71041
|
+
} catch {
|
|
71042
|
+
}
|
|
70919
71043
|
try {
|
|
70920
71044
|
handler(data);
|
|
70921
71045
|
} catch {
|
|
@@ -70936,6 +71060,7 @@ var CANCELLATION_REASON_LABELS;
|
|
|
70936
71060
|
var init_event_to_metric = __esm({
|
|
70937
71061
|
"src/observability/event-to-metric.ts"() {
|
|
70938
71062
|
"use strict";
|
|
71063
|
+
init_metrics_primitives();
|
|
70939
71064
|
CANCELLATION_REASON_LABELS = /* @__PURE__ */ new Set([
|
|
70940
71065
|
"caller_cancelled",
|
|
70941
71066
|
"leader_interrupted",
|
|
@@ -72238,20 +72363,20 @@ init_internal_error();
|
|
|
72238
72363
|
|
|
72239
72364
|
// src/extension/crew-vibes/config.ts
|
|
72240
72365
|
import { existsSync as existsSync75, mkdirSync as mkdirSync42, readFileSync as readFileSync74, writeFileSync as writeFileSync9 } from "node:fs";
|
|
72241
|
-
import { dirname as dirname39, join as
|
|
72366
|
+
import { dirname as dirname39, join as join78 } from "node:path";
|
|
72242
72367
|
|
|
72243
72368
|
// src/extension/crew-vibes/font-detect.ts
|
|
72244
72369
|
import { existsSync as existsSync74, readFileSync as readFileSync73 } from "node:fs";
|
|
72245
72370
|
import { homedir as homedir11, platform } from "node:os";
|
|
72246
|
-
import { join as
|
|
72371
|
+
import { join as join77 } from "node:path";
|
|
72247
72372
|
function fontPath() {
|
|
72248
72373
|
const os18 = platform();
|
|
72249
72374
|
const home = homedir11();
|
|
72250
|
-
if (os18 === "darwin") return
|
|
72251
|
-
if (os18 === "linux") return
|
|
72375
|
+
if (os18 === "darwin") return join77(home, "Library", "Fonts", "crew-vibes.ttf");
|
|
72376
|
+
if (os18 === "linux") return join77(home, ".local", "share", "fonts", "crew-vibes.ttf");
|
|
72252
72377
|
if (os18 === "win32") {
|
|
72253
|
-
const local = process.env.LOCALAPPDATA ??
|
|
72254
|
-
return
|
|
72378
|
+
const local = process.env.LOCALAPPDATA ?? join77(home, "AppData", "Local");
|
|
72379
|
+
return join77(local, "Microsoft", "Windows", "Fonts", "crew-vibes.ttf");
|
|
72255
72380
|
}
|
|
72256
72381
|
return "";
|
|
72257
72382
|
}
|
|
@@ -72300,7 +72425,7 @@ function resolveHome() {
|
|
|
72300
72425
|
return (process.env.PI_TEAMS_HOME ?? process.env.PI_CREW_HOME)?.trim() || process.env.HOME || process.env.USERPROFILE || "";
|
|
72301
72426
|
}
|
|
72302
72427
|
function configPath2() {
|
|
72303
|
-
return
|
|
72428
|
+
return join78(resolveHome(), ".pi", "agent", "pi-crew-vibes.json");
|
|
72304
72429
|
}
|
|
72305
72430
|
var DEFAULT_CONFIG2 = {
|
|
72306
72431
|
enabled: true,
|
|
@@ -72488,7 +72613,7 @@ function isDangerStage(index, levels) {
|
|
|
72488
72613
|
init_pi_ui_compat();
|
|
72489
72614
|
init_theme_adapter();
|
|
72490
72615
|
init_visual();
|
|
72491
|
-
import { isAbsolute as
|
|
72616
|
+
import { isAbsolute as isAbsolute11, relative as relative8, resolve as resolve21, sep as sep9 } from "node:path";
|
|
72492
72617
|
|
|
72493
72618
|
// src/extension/crew-vibes/render.ts
|
|
72494
72619
|
function formatCount(value) {
|
|
@@ -72625,7 +72750,7 @@ function formatCwdForFooter(cwd, home) {
|
|
|
72625
72750
|
const resolvedCwd = resolve21(cwd);
|
|
72626
72751
|
const resolvedHome = resolve21(home);
|
|
72627
72752
|
const rel = relative8(resolvedHome, resolvedCwd);
|
|
72628
|
-
const inside = rel === "" || rel !== ".." && !rel.startsWith(`..${sep9}`) && !
|
|
72753
|
+
const inside = rel === "" || rel !== ".." && !rel.startsWith(`..${sep9}`) && !isAbsolute11(rel);
|
|
72629
72754
|
if (!inside) return cwd;
|
|
72630
72755
|
return rel === "" ? "~" : `~${sep9}${rel}`;
|
|
72631
72756
|
}
|
|
@@ -72800,14 +72925,14 @@ function createCrewVibesFooter(deps) {
|
|
|
72800
72925
|
// src/extension/crew-vibes/provider-usage.ts
|
|
72801
72926
|
import { readFileSync as readFileSync75 } from "node:fs";
|
|
72802
72927
|
import { homedir as homedir12 } from "node:os";
|
|
72803
|
-
import { join as
|
|
72928
|
+
import { join as join79 } from "node:path";
|
|
72804
72929
|
function withTimeout(ms, fn) {
|
|
72805
72930
|
const controller = new AbortController();
|
|
72806
72931
|
const timeoutId = setTimeout(() => controller.abort(), ms);
|
|
72807
72932
|
return fn(controller.signal).finally(() => clearTimeout(timeoutId));
|
|
72808
72933
|
}
|
|
72809
72934
|
function piAuthPath() {
|
|
72810
|
-
return
|
|
72935
|
+
return join79(homedir12(), ".pi", "agent", "auth.json");
|
|
72811
72936
|
}
|
|
72812
72937
|
function loadAnthropicToken() {
|
|
72813
72938
|
const envToken = process.env.ANTHROPIC_OAUTH_TOKEN?.trim();
|
|
@@ -72852,8 +72977,8 @@ function tokenFromHostEntry(entry) {
|
|
|
72852
72977
|
return void 0;
|
|
72853
72978
|
}
|
|
72854
72979
|
function loadLegacyCopilotToken() {
|
|
72855
|
-
const configHome = process.env.XDG_CONFIG_HOME?.trim() ||
|
|
72856
|
-
const candidates = [
|
|
72980
|
+
const configHome = process.env.XDG_CONFIG_HOME?.trim() || join79(homedir12(), ".config");
|
|
72981
|
+
const candidates = [join79(configHome, "github-copilot", "hosts.json"), join79(homedir12(), ".github-copilot", "hosts.json")];
|
|
72857
72982
|
for (const hostsPath of candidates) {
|
|
72858
72983
|
try {
|
|
72859
72984
|
const data = JSON.parse(readFileSync75(hostsPath, "utf8"));
|
|
@@ -75190,7 +75315,7 @@ function startForegroundRunImpl(pi, ctx, extensionCtx, runner, runId) {
|
|
|
75190
75315
|
init_config();
|
|
75191
75316
|
import * as fs103 from "node:fs";
|
|
75192
75317
|
import * as path82 from "node:path";
|
|
75193
|
-
import { fileURLToPath as
|
|
75318
|
+
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
75194
75319
|
|
|
75195
75320
|
// src/runtime/per-write-validator.ts
|
|
75196
75321
|
import { readFileSync as readFileSync81 } from "node:fs";
|
|
@@ -75293,7 +75418,7 @@ function installResourcesDiscoverHook(pi, ctx) {
|
|
|
75293
75418
|
pi.on("resources_discover", () => {
|
|
75294
75419
|
const sessionCwd = ctx.currentCtx?.cwd ?? process.cwd();
|
|
75295
75420
|
const skillDir = path82.resolve(sessionCwd, "skills");
|
|
75296
|
-
const extSkillDir = path82.resolve(path82.dirname(
|
|
75421
|
+
const extSkillDir = path82.resolve(path82.dirname(fileURLToPath8(import.meta.url)), "..", "..", "skills");
|
|
75297
75422
|
const paths = [];
|
|
75298
75423
|
if (fs103.existsSync(extSkillDir)) paths.push(extSkillDir);
|
|
75299
75424
|
if (skillDir !== extSkillDir && fs103.existsSync(skillDir)) {
|
|
@@ -75916,19 +76041,6 @@ var CrewBroker = class {
|
|
|
75916
76041
|
}
|
|
75917
76042
|
this.resolvedSocketPath = null;
|
|
75918
76043
|
}
|
|
75919
|
-
/**
|
|
75920
|
-
* Non-throwing enqueue entry point for the post-append mailbox observer
|
|
75921
|
-
* (Phase 1) or any other in-process producer. Phase 0 accepts `notifyMessage`
|
|
75922
|
-
* as a no-op shape so the lifecycle controller can install a single
|
|
75923
|
-
* observer regardless of broker state.
|
|
75924
|
-
*
|
|
75925
|
-
* Fanout goes ONLY to authenticated connections matching the recipient.
|
|
75926
|
-
* Phase 0 keeps this as a typed no-op (`not-implemented` would be
|
|
75927
|
-
* inappropriate here — the caller is in-process and shouldn't be
|
|
75928
|
-
* punished for testing the broker skeleton).
|
|
75929
|
-
*/
|
|
75930
|
-
notifyMessage(_message) {
|
|
75931
|
-
}
|
|
75932
76044
|
// ------------------------------------------------------------------------
|
|
75933
76045
|
// Connection lifecycle
|
|
75934
76046
|
// ------------------------------------------------------------------------
|