@pennixrv/trellis 0.7.1 → 0.7.2-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -7
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +6 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/ablate.d.ts.map +1 -1
- package/dist/commands/ablate.js +2 -0
- package/dist/commands/ablate.js.map +1 -1
- package/dist/commands/backup.d.ts +4 -0
- package/dist/commands/backup.d.ts.map +1 -0
- package/dist/commands/backup.js +75 -0
- package/dist/commands/backup.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +705 -681
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mem.d.ts.map +1 -1
- package/dist/commands/mem.js +49 -7
- package/dist/commands/mem.js.map +1 -1
- package/dist/commands/task-progress.d.ts +1 -0
- package/dist/commands/task-progress.d.ts.map +1 -1
- package/dist/commands/task-progress.js +67 -25
- package/dist/commands/task-progress.js.map +1 -1
- package/dist/commands/teamwork/adapters/acp.d.ts +20 -0
- package/dist/commands/teamwork/adapters/acp.d.ts.map +1 -0
- package/dist/commands/teamwork/adapters/acp.js +268 -0
- package/dist/commands/teamwork/adapters/acp.js.map +1 -0
- package/dist/commands/teamwork/adapters/claude.d.ts +1 -0
- package/dist/commands/teamwork/adapters/claude.d.ts.map +1 -1
- package/dist/commands/teamwork/adapters/claude.js +5 -0
- package/dist/commands/teamwork/adapters/claude.js.map +1 -1
- package/dist/commands/teamwork/adapters/codex.d.ts +3 -2
- package/dist/commands/teamwork/adapters/codex.d.ts.map +1 -1
- package/dist/commands/teamwork/adapters/codex.js +14 -15
- package/dist/commands/teamwork/adapters/codex.js.map +1 -1
- package/dist/commands/teamwork/adapters/index.d.ts +23 -1
- package/dist/commands/teamwork/adapters/index.d.ts.map +1 -1
- package/dist/commands/teamwork/adapters/index.js +163 -24
- package/dist/commands/teamwork/adapters/index.js.map +1 -1
- package/dist/commands/teamwork/agent-loader.d.ts +2 -1
- package/dist/commands/teamwork/agent-loader.d.ts.map +1 -1
- package/dist/commands/teamwork/agent-loader.js +2 -1
- package/dist/commands/teamwork/agent-loader.js.map +1 -1
- package/dist/commands/teamwork/artifact.d.ts +33 -10
- package/dist/commands/teamwork/artifact.d.ts.map +1 -1
- package/dist/commands/teamwork/artifact.js +182 -50
- package/dist/commands/teamwork/artifact.js.map +1 -1
- package/dist/commands/teamwork/batch-reservation.d.ts +16 -0
- package/dist/commands/teamwork/batch-reservation.d.ts.map +1 -0
- package/dist/commands/teamwork/batch-reservation.js +43 -0
- package/dist/commands/teamwork/batch-reservation.js.map +1 -0
- package/dist/commands/teamwork/batch.d.ts +22 -0
- package/dist/commands/teamwork/batch.d.ts.map +1 -0
- package/dist/commands/teamwork/batch.js +394 -0
- package/dist/commands/teamwork/batch.js.map +1 -0
- package/dist/commands/teamwork/context-loader.d.ts +1 -1
- package/dist/commands/teamwork/context-loader.d.ts.map +1 -1
- package/dist/commands/teamwork/context-loader.js +19 -6
- package/dist/commands/teamwork/context-loader.js.map +1 -1
- package/dist/commands/teamwork/coordination.d.ts +88 -0
- package/dist/commands/teamwork/coordination.d.ts.map +1 -0
- package/dist/commands/teamwork/coordination.js +153 -0
- package/dist/commands/teamwork/coordination.js.map +1 -0
- package/dist/commands/teamwork/coordinator.d.ts +17 -3
- package/dist/commands/teamwork/coordinator.d.ts.map +1 -1
- package/dist/commands/teamwork/coordinator.js +772 -289
- package/dist/commands/teamwork/coordinator.js.map +1 -1
- package/dist/commands/teamwork/create.d.ts +1 -0
- package/dist/commands/teamwork/create.d.ts.map +1 -1
- package/dist/commands/teamwork/create.js +2 -1
- package/dist/commands/teamwork/create.js.map +1 -1
- package/dist/commands/teamwork/dev-parse-trace.d.ts +2 -1
- package/dist/commands/teamwork/dev-parse-trace.d.ts.map +1 -1
- package/dist/commands/teamwork/dev-parse-trace.js +2 -0
- package/dist/commands/teamwork/dev-parse-trace.js.map +1 -1
- package/dist/commands/teamwork/foreground-wait.d.ts +6 -0
- package/dist/commands/teamwork/foreground-wait.d.ts.map +1 -0
- package/dist/commands/teamwork/foreground-wait.js +65 -0
- package/dist/commands/teamwork/foreground-wait.js.map +1 -0
- package/dist/commands/teamwork/guard.d.ts +2 -2
- package/dist/commands/teamwork/guard.d.ts.map +1 -1
- package/dist/commands/teamwork/guard.js +23 -5
- package/dist/commands/teamwork/guard.js.map +1 -1
- package/dist/commands/teamwork/index.d.ts.map +1 -1
- package/dist/commands/teamwork/index.js +139 -10
- package/dist/commands/teamwork/index.js.map +1 -1
- package/dist/commands/teamwork/kill.d.ts +2 -0
- package/dist/commands/teamwork/kill.d.ts.map +1 -1
- package/dist/commands/teamwork/kill.js +79 -38
- package/dist/commands/teamwork/kill.js.map +1 -1
- package/dist/commands/teamwork/messages.d.ts.map +1 -1
- package/dist/commands/teamwork/messages.js +3 -0
- package/dist/commands/teamwork/messages.js.map +1 -1
- package/dist/commands/teamwork/plan.d.ts +22 -0
- package/dist/commands/teamwork/plan.d.ts.map +1 -0
- package/dist/commands/teamwork/plan.js +288 -0
- package/dist/commands/teamwork/plan.js.map +1 -0
- package/dist/commands/teamwork/process-identity.d.ts +3 -0
- package/dist/commands/teamwork/process-identity.d.ts.map +1 -0
- package/dist/commands/teamwork/process-identity.js +24 -0
- package/dist/commands/teamwork/process-identity.js.map +1 -0
- package/dist/commands/teamwork/profiles.d.ts +43 -6
- package/dist/commands/teamwork/profiles.d.ts.map +1 -1
- package/dist/commands/teamwork/profiles.js +138 -110
- package/dist/commands/teamwork/profiles.js.map +1 -1
- package/dist/commands/teamwork/prompt.d.ts +4 -0
- package/dist/commands/teamwork/prompt.d.ts.map +1 -0
- package/dist/commands/teamwork/prompt.js +33 -0
- package/dist/commands/teamwork/prompt.js.map +1 -0
- package/dist/commands/teamwork/result.d.ts +54 -0
- package/dist/commands/teamwork/result.d.ts.map +1 -0
- package/dist/commands/teamwork/result.js +94 -0
- package/dist/commands/teamwork/result.js.map +1 -0
- package/dist/commands/teamwork/rm.d.ts.map +1 -1
- package/dist/commands/teamwork/rm.js +64 -64
- package/dist/commands/teamwork/rm.js.map +1 -1
- package/dist/commands/teamwork/run.d.ts +5 -0
- package/dist/commands/teamwork/run.d.ts.map +1 -1
- package/dist/commands/teamwork/run.js +120 -24
- package/dist/commands/teamwork/run.js.map +1 -1
- package/dist/commands/teamwork/runtime.d.ts +9 -0
- package/dist/commands/teamwork/runtime.d.ts.map +1 -0
- package/dist/commands/teamwork/runtime.js +372 -0
- package/dist/commands/teamwork/runtime.js.map +1 -0
- package/dist/commands/teamwork/send.d.ts +1 -0
- package/dist/commands/teamwork/send.d.ts.map +1 -1
- package/dist/commands/teamwork/send.js +2 -1
- package/dist/commands/teamwork/send.js.map +1 -1
- package/dist/commands/teamwork/spawn.d.ts +10 -3
- package/dist/commands/teamwork/spawn.d.ts.map +1 -1
- package/dist/commands/teamwork/spawn.js +42 -27
- package/dist/commands/teamwork/spawn.js.map +1 -1
- package/dist/commands/teamwork/store/lock.js +28 -4
- package/dist/commands/teamwork/store/lock.js.map +1 -1
- package/dist/commands/teamwork/supervisor/inbox.d.ts +1 -0
- package/dist/commands/teamwork/supervisor/inbox.d.ts.map +1 -1
- package/dist/commands/teamwork/supervisor/inbox.js +28 -9
- package/dist/commands/teamwork/supervisor/inbox.js.map +1 -1
- package/dist/commands/teamwork/supervisor/stdout.d.ts.map +1 -1
- package/dist/commands/teamwork/supervisor/stdout.js +2 -3
- package/dist/commands/teamwork/supervisor/stdout.js.map +1 -1
- package/dist/commands/teamwork/supervisor/warning.d.ts.map +1 -1
- package/dist/commands/teamwork/supervisor/warning.js +2 -3
- package/dist/commands/teamwork/supervisor/warning.js.map +1 -1
- package/dist/commands/teamwork/supervisor.d.ts +5 -0
- package/dist/commands/teamwork/supervisor.d.ts.map +1 -1
- package/dist/commands/teamwork/supervisor.js +21 -12
- package/dist/commands/teamwork/supervisor.js.map +1 -1
- package/dist/commands/teamwork/teammate-adapters.d.ts +0 -5
- package/dist/commands/teamwork/teammate-adapters.d.ts.map +1 -1
- package/dist/commands/teamwork/teammate-adapters.js +9 -56
- package/dist/commands/teamwork/teammate-adapters.js.map +1 -1
- package/dist/commands/teamwork/teammate-config.d.ts +5 -1
- package/dist/commands/teamwork/teammate-config.d.ts.map +1 -1
- package/dist/commands/teamwork/teammate-config.js +62 -19
- package/dist/commands/teamwork/teammate-config.js.map +1 -1
- package/dist/commands/teamwork/teammate-launch.d.ts +15 -6
- package/dist/commands/teamwork/teammate-launch.d.ts.map +1 -1
- package/dist/commands/teamwork/teammate-launch.js +129 -22
- package/dist/commands/teamwork/teammate-launch.js.map +1 -1
- package/dist/commands/teamwork/wait.d.ts +2 -0
- package/dist/commands/teamwork/wait.d.ts.map +1 -1
- package/dist/commands/teamwork/wait.js +44 -3
- package/dist/commands/teamwork/wait.js.map +1 -1
- package/dist/commands/uninstall.d.ts.map +1 -1
- package/dist/commands/uninstall.js +92 -84
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +635 -592
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +94 -89
- package/dist/commands/workflow.js.map +1 -1
- package/dist/configurators/shared.js +2 -2
- package/dist/configurators/shared.js.map +1 -1
- package/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +14 -32
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/constants/paths.d.ts +3 -10
- package/dist/constants/paths.d.ts.map +1 -1
- package/dist/constants/paths.js +4 -13
- package/dist/constants/paths.js.map +1 -1
- package/dist/migrations/manifests/0.7.1-beta.0.json +9 -0
- package/dist/migrations/manifests/0.7.1-beta.1.json +186 -0
- package/dist/migrations/manifests/0.7.1-beta.10.json +9 -0
- package/dist/migrations/manifests/0.7.1-beta.11.json +9 -0
- package/dist/migrations/manifests/0.7.1-beta.12.json +9 -0
- package/dist/migrations/manifests/0.7.1-beta.13.json +9 -0
- package/dist/migrations/manifests/0.7.1-beta.14.json +11 -0
- package/dist/migrations/manifests/0.7.1-beta.15.json +9 -0
- package/dist/migrations/manifests/0.7.1-beta.16.json +9 -0
- package/dist/migrations/manifests/0.7.1-beta.17.json +9 -0
- package/dist/migrations/manifests/0.7.1-beta.18.json +9 -0
- package/dist/migrations/manifests/0.7.1-beta.19.json +9 -0
- package/dist/migrations/manifests/0.7.1-beta.2.json +522 -0
- package/dist/migrations/manifests/0.7.1-beta.3.json +9 -0
- package/dist/migrations/manifests/0.7.1-beta.4.json +9 -0
- package/dist/migrations/manifests/0.7.1-beta.5.json +9 -0
- package/dist/migrations/manifests/0.7.1-beta.6.json +10 -0
- package/dist/migrations/manifests/0.7.1-beta.7.json +8 -0
- package/dist/migrations/manifests/0.7.1-beta.8.json +481 -0
- package/dist/migrations/manifests/0.7.1-beta.9.json +191 -0
- package/dist/migrations/manifests/0.7.2-beta.0.json +11 -0
- package/dist/templates/claude/hooks/statusline.py +9 -4
- package/dist/templates/codex/hooks/session-start.py +14 -11
- package/dist/templates/codex/hooks.json +10 -0
- package/dist/templates/common/bundled-skills/trellis-decision-space-construction-and-merging/workflow.md +2 -0
- package/dist/templates/common/bundled-skills/trellis-goal-exploration-and-requirements/workflow.md +2 -0
- package/dist/templates/common/bundled-skills/trellis-meta/SKILL.md +1 -1
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/add-project-local-conventions.md +1 -1
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-context-loading.md +5 -5
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-task-lifecycle.md +3 -2
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/overview.md +1 -1
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/context-injection.md +1 -1
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/multi-agent-teamwork.md +14 -2
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/task-system.md +8 -2
- package/dist/templates/common/bundled-skills/trellis-session-insight/references/cli-quick-reference.md +2 -1
- package/dist/templates/common/bundled-skills/trellis-session-insight/references/triggering-patterns.md +2 -2
- package/dist/templates/common/bundled-skills/trellis-solution-design-and-convergence/workflow.md +8 -0
- package/dist/templates/common/bundled-skills/trellis-spec-bootstrap/references/mcp-setup.md +4 -2
- package/dist/templates/common/bundled-skills/trellis-spec-bootstrap/references/spec-task-planning.md +2 -2
- package/dist/templates/common/bundled-skills/trellis-task-implementation/workflow.md +6 -0
- package/dist/templates/common/bundled-skills/trellis-teamwork/SKILL.md +18 -3
- package/dist/templates/common/bundled-skills/trellis-teamwork/references/coordination-modes.md +34 -3
- package/dist/templates/common/bundled-skills/trellis-teamwork/references/teammate-configuration-matrix.md +37 -26
- package/dist/templates/common/bundled-skills/trellis-teamwork/references/teammate-processes.md +128 -14
- package/dist/templates/common/bundled-skills/trellis-teamwork/references/teamwork-plan-construction.md +152 -20
- package/dist/templates/common/commands/start.md +2 -2
- package/dist/templates/common/skills/before-dev.md +1 -4
- package/dist/templates/common/skills/break-loop.md +7 -18
- package/dist/templates/common/skills/check.md +7 -11
- package/dist/templates/common/skills/{brainstorm.md → request-intake.md} +5 -3
- package/dist/templates/common/skills/update-spec.md +5 -7
- package/dist/templates/copilot/hooks/session-start.py +14 -11
- package/dist/templates/copilot/index.d.ts +1 -6
- package/dist/templates/copilot/index.d.ts.map +1 -1
- package/dist/templates/copilot/index.js +1 -14
- package/dist/templates/copilot/index.js.map +1 -1
- package/dist/templates/extract.js +4 -0
- package/dist/templates/extract.js.map +1 -1
- package/dist/templates/markdown/spec/backend/index.md.txt +4 -35
- package/dist/templates/markdown/spec/frontend/index.md.txt +4 -36
- package/dist/templates/omp/extensions/trellis/index.ts.txt +2 -2
- package/dist/templates/opencode/lib/session-utils.js +301 -209
- package/dist/templates/pi/extensions/trellis/index.ts.txt +17 -1
- package/dist/templates/shared-hooks/guard-teamwork-wait.py +53 -0
- package/dist/templates/shared-hooks/index.d.ts +1 -1
- package/dist/templates/shared-hooks/index.d.ts.map +1 -1
- package/dist/templates/shared-hooks/index.js +1 -0
- package/dist/templates/shared-hooks/index.js.map +1 -1
- package/dist/templates/shared-hooks/inject-workflow-state.py +8 -3
- package/dist/templates/shared-hooks/session-start.py +16 -12
- package/dist/templates/snow/SNOW.md +1 -1
- package/dist/templates/trellis/agents/delegated-worktree-primary-agent.md +9 -0
- package/dist/templates/trellis/agents/profiles/architecture.md +9 -0
- package/dist/templates/trellis/agents/profiles/diagnosis.md +9 -0
- package/dist/templates/trellis/agents/profiles/exploration.md +9 -0
- package/dist/templates/trellis/agents/profiles/research.md +9 -0
- package/dist/templates/trellis/agents/profiles/review.md +9 -0
- package/dist/templates/trellis/agents/profiles/verification.md +9 -0
- package/dist/templates/trellis/agents/teammate-profiles.json +56 -4
- package/dist/templates/trellis/agents/teammate.md +4 -52
- package/dist/templates/trellis/config.yaml +2 -5
- package/dist/templates/trellis/index.d.ts +4 -0
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js +22 -4
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/scripts/add_session.py +1 -1
- package/dist/templates/trellis/scripts/common/active_task.py +3 -47
- package/dist/templates/trellis/scripts/common/paths.py +9 -25
- package/dist/templates/trellis/scripts/common/safe_commit.py +8 -8
- package/dist/templates/trellis/scripts/common/task_context.py +11 -51
- package/dist/templates/trellis/scripts/common/task_continuity.py +129 -60
- package/dist/templates/trellis/scripts/common/task_layout.py +80 -0
- package/dist/templates/trellis/scripts/common/task_move.py +345 -0
- package/dist/templates/trellis/scripts/common/task_store.py +35 -57
- package/dist/templates/trellis/scripts/common/task_utils.py +23 -19
- package/dist/templates/trellis/scripts/common/task_workflow.py +339 -46
- package/dist/templates/trellis/scripts/common/tasks.py +6 -5
- package/dist/templates/trellis/scripts/hooks/linear_sync.py +13 -3
- package/dist/templates/trellis/scripts/task.py +71 -24
- package/dist/templates/trellis/teamwork.json +10 -0
- package/dist/templates/trellis/workflow.md +11 -2
- package/dist/utils/ablation-store.d.ts +1 -1
- package/dist/utils/ablation-store.d.ts.map +1 -1
- package/dist/utils/ablation-store.js +58 -24
- package/dist/utils/ablation-store.js.map +1 -1
- package/dist/utils/asset-backup.d.ts +138 -0
- package/dist/utils/asset-backup.d.ts.map +1 -0
- package/dist/utils/asset-backup.js +513 -0
- package/dist/utils/asset-backup.js.map +1 -0
- package/dist/utils/atomic-write.d.ts +1 -1
- package/dist/utils/atomic-write.d.ts.map +1 -1
- package/dist/utils/atomic-write.js +6 -3
- package/dist/utils/atomic-write.js.map +1 -1
- package/dist/utils/manifest-prune.d.ts +4 -1
- package/dist/utils/manifest-prune.d.ts.map +1 -1
- package/dist/utils/manifest-prune.js +17 -6
- package/dist/utils/manifest-prune.js.map +1 -1
- package/dist/utils/template-fetcher.d.ts +4 -19
- package/dist/utils/template-fetcher.d.ts.map +1 -1
- package/dist/utils/template-fetcher.js +9 -45
- package/dist/utils/template-fetcher.js.map +1 -1
- package/dist/utils/template-hash.d.ts +5 -4
- package/dist/utils/template-hash.d.ts.map +1 -1
- package/dist/utils/template-hash.js +24 -17
- package/dist/utils/template-hash.js.map +1 -1
- package/package.json +3 -2
- package/dist/templates/copilot/prompts/before-dev.prompt.md +0 -39
- package/dist/templates/copilot/prompts/brainstorm.prompt.md +0 -13
- package/dist/templates/copilot/prompts/break-loop.prompt.md +0 -129
- package/dist/templates/copilot/prompts/check-cross-layer.prompt.md +0 -170
- package/dist/templates/copilot/prompts/check.prompt.md +0 -110
- package/dist/templates/copilot/prompts/create-command.prompt.md +0 -116
- package/dist/templates/copilot/prompts/finish-work.prompt.md +0 -22
- package/dist/templates/copilot/prompts/integrate-skill.prompt.md +0 -223
- package/dist/templates/copilot/prompts/onboard.prompt.md +0 -362
- package/dist/templates/copilot/prompts/record-session.prompt.md +0 -58
- package/dist/templates/copilot/prompts/start.prompt.md +0 -65
- package/dist/templates/copilot/prompts/update-spec.prompt.md +0 -358
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { parseFrozenTeammate, } from "./teammate-launch.js";
|
|
5
|
+
import { assertCoordinationMembers, } from "./coordination.js";
|
|
6
|
+
import { REASONING_EFFORTS } from "./profiles.js";
|
|
7
|
+
import { teammateContentSchema } from "./result.js";
|
|
4
8
|
const ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
5
9
|
const SECRET = /(-----BEGIN [A-Z ]*PRIVATE KEY-----|\b(?:sk|gh[pousr])_[A-Za-z0-9]{20,}\b|\bBearer\s+\S+)/i;
|
|
6
10
|
function id(value, field) {
|
|
@@ -45,7 +49,7 @@ function relativePathList(value, field) {
|
|
|
45
49
|
throw new Error(`${field} must not contain duplicates`);
|
|
46
50
|
return result;
|
|
47
51
|
}
|
|
48
|
-
function safePath(root, candidate) {
|
|
52
|
+
export function safePath(root, candidate) {
|
|
49
53
|
const absoluteRoot = path.resolve(root);
|
|
50
54
|
const lexical = path.resolve(root, candidate);
|
|
51
55
|
const relative = path.relative(absoluteRoot, lexical);
|
|
@@ -100,9 +104,7 @@ function canonicalJson(value) {
|
|
|
100
104
|
if (Array.isArray(value))
|
|
101
105
|
return `[${value.map(canonicalJson).join(",")}]`;
|
|
102
106
|
if (value && typeof value === "object") {
|
|
103
|
-
const entries = Object.entries(value)
|
|
104
|
-
.filter(([key]) => key !== "plan_hash")
|
|
105
|
-
.sort(([a], [b]) => a.localeCompare(b));
|
|
107
|
+
const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b));
|
|
106
108
|
return `{${entries.map(([key, item]) => `${JSON.stringify(key)}:${canonicalJson(item)}`).join(",")}}`;
|
|
107
109
|
}
|
|
108
110
|
return JSON.stringify(value);
|
|
@@ -111,14 +113,20 @@ function withoutFields(value, fields) {
|
|
|
111
113
|
return Object.fromEntries(Object.entries(value).filter(([field]) => !fields.includes(field)));
|
|
112
114
|
}
|
|
113
115
|
export function computeTeamworkPlanHash(value) {
|
|
114
|
-
|
|
116
|
+
const contents = value && typeof value === "object" && !Array.isArray(value)
|
|
117
|
+
? withoutFields(value, ["plan_hash"])
|
|
118
|
+
: value;
|
|
119
|
+
return crypto
|
|
120
|
+
.createHash("sha256")
|
|
121
|
+
.update(canonicalJson(contents))
|
|
122
|
+
.digest("hex");
|
|
115
123
|
}
|
|
116
|
-
export function validateTeamworkPlan(input, taskRoot, expectedContext) {
|
|
124
|
+
export function validateTeamworkPlan(input, taskRoot, expectedContext, options = {}) {
|
|
117
125
|
if (!input || typeof input !== "object" || Array.isArray(input))
|
|
118
126
|
throw new Error("Teamwork plan must be an object");
|
|
119
127
|
const value = input;
|
|
120
|
-
if (value.schema_version !==
|
|
121
|
-
throw new Error("Teamwork plan schema_version must be
|
|
128
|
+
if (value.schema_version !== 2)
|
|
129
|
+
throw new Error("Teamwork plan schema_version must be 2; construct a new frozen plan");
|
|
122
130
|
const taskId = id(value.task_id, "task_id");
|
|
123
131
|
const batchId = id(value.batch_id, "batch_id");
|
|
124
132
|
const sessionId = id(value.session_id, "session_id");
|
|
@@ -126,6 +134,7 @@ export function validateTeamworkPlan(input, taskRoot, expectedContext) {
|
|
|
126
134
|
const taskRouteRevision = boundedText(value.task_route_revision, "task_route_revision");
|
|
127
135
|
const inputRevision = boundedText(value.input_revision, "input_revision");
|
|
128
136
|
const planSummary = boundedText(value.plan_summary, "plan_summary");
|
|
137
|
+
const coordinationDigest = digest(value.coordination_digest, "coordination_digest");
|
|
129
138
|
const coordinationMode = value.coordination_mode;
|
|
130
139
|
if (coordinationMode !== "general" &&
|
|
131
140
|
coordinationMode !== "advisor" &&
|
|
@@ -147,13 +156,13 @@ export function validateTeamworkPlan(input, taskRoot, expectedContext) {
|
|
|
147
156
|
const deadlineAt = Date.parse(deadline);
|
|
148
157
|
if (Number.isNaN(deadlineAt))
|
|
149
158
|
throw new Error("deadline must be an ISO date");
|
|
150
|
-
if (deadlineAt <= Date.now())
|
|
159
|
+
if (!options.allowExpired && deadlineAt <= Date.now())
|
|
151
160
|
throw new Error("deadline must be in the future");
|
|
152
161
|
const assignmentValue = value.assignments;
|
|
153
162
|
if (!Array.isArray(assignmentValue) || assignmentValue.length === 0)
|
|
154
163
|
throw new Error("Teamwork plan assignments must be non-empty");
|
|
155
|
-
if (coordinationMode === "advisor" && assignmentValue.length
|
|
156
|
-
throw new Error("advisor mode requires
|
|
164
|
+
if (coordinationMode === "advisor" && assignmentValue.length > 3)
|
|
165
|
+
throw new Error("advisor mode requires one to three assignments");
|
|
157
166
|
if (coordinationMode === "committee" &&
|
|
158
167
|
(assignmentValue.length < 2 || assignmentValue.length > 3))
|
|
159
168
|
throw new Error("committee mode requires two or three assignments");
|
|
@@ -188,8 +197,10 @@ export function validateTeamworkPlan(input, taskRoot, expectedContext) {
|
|
|
188
197
|
else if (coordinationMode === "committee") {
|
|
189
198
|
throw new Error(`assignments[${index}] must declare an evaluation group`);
|
|
190
199
|
}
|
|
191
|
-
if (item.role_id !==
|
|
192
|
-
throw new Error(`assignments[${index}].role_id
|
|
200
|
+
if (item.role_id !== undefined)
|
|
201
|
+
throw new Error(`assignments[${index}].role_id is retired; teammate is an internal execution type`);
|
|
202
|
+
const execution = parseFrozenTeammate(item.execution);
|
|
203
|
+
const selectionReason = boundedText(item.selection_reason, `assignments[${index}].selection_reason`);
|
|
193
204
|
const provider = item.provider;
|
|
194
205
|
if (provider !== "claude" &&
|
|
195
206
|
provider !== "codex" &&
|
|
@@ -205,7 +216,9 @@ export function validateTeamworkPlan(input, taskRoot, expectedContext) {
|
|
|
205
216
|
throw new Error(`assignments[${index}].max_retries must be non-negative`);
|
|
206
217
|
const briefPath = boundedText(item.brief_path, `assignments[${index}].brief_path`);
|
|
207
218
|
const scope = boundedText(item.scope, `assignments[${index}].scope`);
|
|
208
|
-
const lens =
|
|
219
|
+
const lens = item.lens === undefined
|
|
220
|
+
? undefined
|
|
221
|
+
: boundedText(item.lens, `assignments[${index}].lens`);
|
|
209
222
|
const summary = boundedText(item.summary, `assignments[${index}].summary`);
|
|
210
223
|
const briefDigest = digest(item.brief_digest, `assignments[${index}].brief_digest`);
|
|
211
224
|
const sourceDigest = digest(item.source_digest, `assignments[${index}].source_digest`);
|
|
@@ -222,22 +235,31 @@ export function validateTeamworkPlan(input, taskRoot, expectedContext) {
|
|
|
222
235
|
if (path.relative(path.resolve(taskRoot), absoluteBrief) !==
|
|
223
236
|
expectedRelative)
|
|
224
237
|
throw new Error(`assignments[${index}].brief_path must be ${expectedRelative}`);
|
|
225
|
-
const
|
|
238
|
+
const prepared = options.briefContents?.get(briefPath);
|
|
239
|
+
if (options.briefContents && prepared === undefined)
|
|
240
|
+
throw new Error(`missing prepared brief: ${briefPath}`);
|
|
241
|
+
const briefBytes = prepared === undefined
|
|
242
|
+
? fs.readFileSync(absoluteBrief)
|
|
243
|
+
: Buffer.from(prepared);
|
|
226
244
|
if (briefBytes.byteLength > 64 * 1024)
|
|
227
245
|
throw new Error(`brief for assignment '${assignmentId}' exceeds 65536 bytes`);
|
|
228
246
|
const brief = JSON.parse(briefBytes.toString("utf8"));
|
|
229
247
|
if (!brief || typeof brief !== "object" || Array.isArray(brief))
|
|
230
248
|
throw new Error(`brief for assignment '${assignmentId}' must be an object`);
|
|
249
|
+
if (typeof brief.input !== "string" ||
|
|
250
|
+
brief.input.trim() === "" ||
|
|
251
|
+
brief.input.length > 32768 ||
|
|
252
|
+
brief.input.includes("\0"))
|
|
253
|
+
throw new Error("brief.input must be nonempty task text of at most 32768 characters");
|
|
231
254
|
briefs.set(assignmentId, brief);
|
|
232
255
|
rejectSecrets(brief, `brief for assignment '${assignmentId}'`);
|
|
233
256
|
if (computeTeamworkPlanHash(brief) !== briefDigest)
|
|
234
257
|
throw new Error(`brief.${assignmentId} digest does not match the Teamwork plan`);
|
|
235
258
|
for (const [field, expected] of Object.entries({
|
|
236
|
-
schema_version:
|
|
259
|
+
schema_version: 2,
|
|
237
260
|
task_id: taskId,
|
|
238
261
|
batch_id: batchId,
|
|
239
262
|
assignment_id: assignmentId,
|
|
240
|
-
role_id: "teammate",
|
|
241
263
|
provider,
|
|
242
264
|
summary,
|
|
243
265
|
scope,
|
|
@@ -247,6 +269,16 @@ export function validateTeamworkPlan(input, taskRoot, expectedContext) {
|
|
|
247
269
|
if (brief[field] !== expected)
|
|
248
270
|
throw new Error(`brief.${field} does not match the Teamwork plan`);
|
|
249
271
|
}
|
|
272
|
+
if (brief.role_id !== undefined)
|
|
273
|
+
throw new Error("brief.role_id is retired");
|
|
274
|
+
if (canonicalJson(brief.execution) !== canonicalJson(item.execution))
|
|
275
|
+
throw new Error("brief.execution does not match the frozen plan");
|
|
276
|
+
if (brief.selection_reason !== selectionReason)
|
|
277
|
+
throw new Error("brief.selection_reason does not match the frozen plan");
|
|
278
|
+
if (execution.profile.provider !== provider ||
|
|
279
|
+
execution.profile.profile !== profile ||
|
|
280
|
+
execution.profile.model !== model)
|
|
281
|
+
throw new Error("assignment provider, profile, or model does not match frozen execution");
|
|
250
282
|
const briefSourceDigest = digest(brief.source_digest, `brief.${assignmentId}.source_digest`);
|
|
251
283
|
if (briefSourceDigest !== sourceDigest)
|
|
252
284
|
throw new Error(`brief.${assignmentId}.source_digest does not match the Teamwork plan`);
|
|
@@ -279,6 +311,9 @@ export function validateTeamworkPlan(input, taskRoot, expectedContext) {
|
|
|
279
311
|
summary,
|
|
280
312
|
scope,
|
|
281
313
|
lens,
|
|
314
|
+
execution,
|
|
315
|
+
selectionReason,
|
|
316
|
+
taskInput: brief.input,
|
|
282
317
|
briefDigest,
|
|
283
318
|
sourceDigest,
|
|
284
319
|
...(contextFiles ? { contextFiles } : {}),
|
|
@@ -289,6 +324,7 @@ export function validateTeamworkPlan(input, taskRoot, expectedContext) {
|
|
|
289
324
|
rejectSecrets(assignment, `assignments[${index}]`);
|
|
290
325
|
return assignment;
|
|
291
326
|
});
|
|
327
|
+
assertCoordinationMembers(coordinationMode, assignments);
|
|
292
328
|
if (coordinationMode === "committee") {
|
|
293
329
|
const groups = new Map();
|
|
294
330
|
for (const assignment of assignments) {
|
|
@@ -315,6 +351,8 @@ export function validateTeamworkPlan(input, taskRoot, expectedContext) {
|
|
|
315
351
|
"lens",
|
|
316
352
|
"brief_path",
|
|
317
353
|
"brief_digest",
|
|
354
|
+
"execution",
|
|
355
|
+
"selection_reason",
|
|
318
356
|
];
|
|
319
357
|
const briefFields = [
|
|
320
358
|
"assignment_id",
|
|
@@ -322,6 +360,8 @@ export function validateTeamworkPlan(input, taskRoot, expectedContext) {
|
|
|
322
360
|
"profile",
|
|
323
361
|
"model",
|
|
324
362
|
"lens",
|
|
363
|
+
"execution",
|
|
364
|
+
"selection_reason",
|
|
325
365
|
];
|
|
326
366
|
const first = members[0];
|
|
327
367
|
if (!first)
|
|
@@ -348,12 +388,32 @@ export function validateTeamworkPlan(input, taskRoot, expectedContext) {
|
|
|
348
388
|
if (new Set(protectedTargets).size !== protectedTargets.length)
|
|
349
389
|
throw new Error("protected_targets must not contain duplicates");
|
|
350
390
|
const requestedCapacityValue = value.requested_capacity;
|
|
391
|
+
let retryOf;
|
|
392
|
+
if (value.retry_of !== undefined) {
|
|
393
|
+
const retry = value.retry_of;
|
|
394
|
+
const assignmentIds = retry?.assignment_ids;
|
|
395
|
+
if (!retry ||
|
|
396
|
+
typeof retry !== "object" ||
|
|
397
|
+
!Array.isArray(assignmentIds) ||
|
|
398
|
+
assignmentIds.length !== assignments.length ||
|
|
399
|
+
new Set(assignmentIds).size !== assignments.length ||
|
|
400
|
+
assignments.some((entry) => !assignmentIds.includes(entry.assignmentId)))
|
|
401
|
+
throw new Error("Retry lineage must contain the exact selected assignment set");
|
|
402
|
+
retryOf = {
|
|
403
|
+
batchId: id(retry.batch_id, "retry_of.batch_id"),
|
|
404
|
+
planHash: digest(retry.plan_hash, "retry_of.plan_hash"),
|
|
405
|
+
assignmentIds: assignmentIds.map((entry) => id(entry, "retry_of.assignment_ids")),
|
|
406
|
+
approvalRef: boundedText(retry.approval_ref, "retry_of.approval_ref"),
|
|
407
|
+
};
|
|
408
|
+
if (retryOf.batchId === batchId)
|
|
409
|
+
throw new Error("Retry must use a new batch identity");
|
|
410
|
+
}
|
|
351
411
|
if (requestedCapacityValue !== undefined &&
|
|
352
412
|
(!Number.isInteger(requestedCapacityValue) ||
|
|
353
413
|
requestedCapacityValue <= 0))
|
|
354
414
|
throw new Error("requested_capacity must be a positive integer");
|
|
355
415
|
const plan = {
|
|
356
|
-
schemaVersion:
|
|
416
|
+
schemaVersion: 2,
|
|
357
417
|
taskId,
|
|
358
418
|
batchId,
|
|
359
419
|
sessionId,
|
|
@@ -362,6 +422,11 @@ export function validateTeamworkPlan(input, taskRoot, expectedContext) {
|
|
|
362
422
|
inputRevision,
|
|
363
423
|
planSummary,
|
|
364
424
|
coordinationMode,
|
|
425
|
+
coordinationDigest,
|
|
426
|
+
...(retryOf ? { retryOf } : {}),
|
|
427
|
+
...(value.coordination_snapshot
|
|
428
|
+
? { coordinationSnapshot: value.coordination_snapshot }
|
|
429
|
+
: {}),
|
|
365
430
|
planHash: boundedText(value.plan_hash, "plan_hash"),
|
|
366
431
|
...(requestedCapacityValue !== undefined
|
|
367
432
|
? { requestedCapacity: requestedCapacityValue }
|
|
@@ -380,8 +445,31 @@ export function validateTeammateReport(input, identity, expectedSourceDigest) {
|
|
|
380
445
|
if (!input || typeof input !== "object" || Array.isArray(input))
|
|
381
446
|
throw new Error("teammate report must be an object");
|
|
382
447
|
const value = input;
|
|
383
|
-
if (value.schema_version !== 1)
|
|
384
|
-
throw new Error("teammate report schema_version must be 1");
|
|
448
|
+
if (value.schema_version !== 1 && value.schema_version !== 2)
|
|
449
|
+
throw new Error("teammate report schema_version must be 1 or 2");
|
|
450
|
+
if (value.schema_version === 2) {
|
|
451
|
+
const allowed = new Set([
|
|
452
|
+
...Object.keys(teammateContentSchema.shape),
|
|
453
|
+
"task_id",
|
|
454
|
+
"batch_id",
|
|
455
|
+
"assignment_id",
|
|
456
|
+
"attempt_id",
|
|
457
|
+
"teammate_id",
|
|
458
|
+
"plan_hash",
|
|
459
|
+
"phase_id",
|
|
460
|
+
"task_route_revision",
|
|
461
|
+
"input_revision",
|
|
462
|
+
"source_digest",
|
|
463
|
+
]);
|
|
464
|
+
if (Object.keys(value).some((key) => !allowed.has(key)))
|
|
465
|
+
throw new Error("teammate report contains unknown fields");
|
|
466
|
+
}
|
|
467
|
+
const content = value.schema_version === 2
|
|
468
|
+
? teammateContentSchema.parse(Object.fromEntries(Object.keys(teammateContentSchema.shape).map((key) => [
|
|
469
|
+
key,
|
|
470
|
+
value[key],
|
|
471
|
+
])))
|
|
472
|
+
: undefined;
|
|
385
473
|
for (const key of [
|
|
386
474
|
"task_id",
|
|
387
475
|
"batch_id",
|
|
@@ -434,11 +522,11 @@ export function validateTeammateReport(input, identity, expectedSourceDigest) {
|
|
|
434
522
|
summary: boundedText(item.summary, `report.evidence[${index}].summary`),
|
|
435
523
|
};
|
|
436
524
|
});
|
|
437
|
-
if (
|
|
438
|
-
throw new Error(
|
|
439
|
-
}
|
|
525
|
+
if (evidence.length === 0)
|
|
526
|
+
throw new Error("report.evidence must include at least one item");
|
|
440
527
|
const report = {
|
|
441
|
-
schemaVersion:
|
|
528
|
+
schemaVersion: value.schema_version,
|
|
529
|
+
...(content ? { content } : {}),
|
|
442
530
|
taskId: identity.taskId,
|
|
443
531
|
batchId: identity.batchId,
|
|
444
532
|
assignmentId: identity.assignmentId,
|
|
@@ -504,8 +592,8 @@ export function validateTeammateClaim(input, identity, expectedPlanHash, expecte
|
|
|
504
592
|
if (!input || typeof input !== "object" || Array.isArray(input))
|
|
505
593
|
throw new Error("teammate claim must be an object");
|
|
506
594
|
const value = input;
|
|
507
|
-
if (value.schema_version !==
|
|
508
|
-
throw new Error("teammate claim schema_version must be
|
|
595
|
+
if (value.schema_version !== 2)
|
|
596
|
+
throw new Error("teammate claim schema_version must be 2");
|
|
509
597
|
for (const key of [
|
|
510
598
|
"task_id",
|
|
511
599
|
"batch_id",
|
|
@@ -541,7 +629,7 @@ export function validateTeammateClaim(input, identity, expectedPlanHash, expecte
|
|
|
541
629
|
if (!Number.isInteger(value.slot) || value.slot < 0)
|
|
542
630
|
throw new Error("claim.slot must be non-negative");
|
|
543
631
|
const snapshotKeys = [
|
|
544
|
-
"
|
|
632
|
+
"configuration",
|
|
545
633
|
"provider",
|
|
546
634
|
"profile",
|
|
547
635
|
"model",
|
|
@@ -555,8 +643,8 @@ export function validateTeammateClaim(input, identity, expectedPlanHash, expecte
|
|
|
555
643
|
const hasSnapshot = snapshotKeys.some((key) => value[key] !== undefined);
|
|
556
644
|
let execution;
|
|
557
645
|
if (hasSnapshot) {
|
|
558
|
-
if (value.role_id !==
|
|
559
|
-
throw new Error("claim.role_id
|
|
646
|
+
if (value.role_id !== undefined)
|
|
647
|
+
throw new Error("claim.role_id is retired");
|
|
560
648
|
const provider = value.provider;
|
|
561
649
|
if (provider !== "claude" &&
|
|
562
650
|
provider !== "codex" &&
|
|
@@ -574,9 +662,7 @@ export function validateTeammateClaim(input, identity, expectedPlanHash, expecte
|
|
|
574
662
|
throw new Error("claim.model must be bounded single-line text");
|
|
575
663
|
const reasoningEffort = value.reasoning_effort;
|
|
576
664
|
if (reasoningEffort !== undefined &&
|
|
577
|
-
reasoningEffort
|
|
578
|
-
reasoningEffort !== "high" &&
|
|
579
|
-
reasoningEffort !== "xhigh") {
|
|
665
|
+
!REASONING_EFFORTS.includes(reasoningEffort)) {
|
|
580
666
|
throw new Error("claim.reasoning_effort is invalid");
|
|
581
667
|
}
|
|
582
668
|
if (!value.options ||
|
|
@@ -605,10 +691,13 @@ export function validateTeammateClaim(input, identity, expectedPlanHash, expecte
|
|
|
605
691
|
}
|
|
606
692
|
execution = {
|
|
607
693
|
roleId: "teammate",
|
|
694
|
+
configuration: id(value.configuration, "claim.configuration"),
|
|
608
695
|
provider,
|
|
609
696
|
...(profile ? { profile } : {}),
|
|
610
697
|
...(model ? { model } : {}),
|
|
611
|
-
...(reasoningEffort
|
|
698
|
+
...(reasoningEffort
|
|
699
|
+
? { reasoningEffort: reasoningEffort }
|
|
700
|
+
: {}),
|
|
612
701
|
options,
|
|
613
702
|
...(value.profile_digest === undefined
|
|
614
703
|
? {}
|
|
@@ -621,7 +710,7 @@ export function validateTeammateClaim(input, identity, expectedPlanHash, expecte
|
|
|
621
710
|
};
|
|
622
711
|
}
|
|
623
712
|
const claim = {
|
|
624
|
-
schemaVersion:
|
|
713
|
+
schemaVersion: 2,
|
|
625
714
|
...identity,
|
|
626
715
|
planHash,
|
|
627
716
|
...(briefDigest ? { briefDigest } : {}),
|
|
@@ -680,7 +769,7 @@ export function validateTeammateDisposition(input, identity, expectedSourceDiges
|
|
|
680
769
|
export function writeTeammateClaim(input) {
|
|
681
770
|
const execution = input.launch
|
|
682
771
|
? {
|
|
683
|
-
|
|
772
|
+
configuration: input.launch.configuration,
|
|
684
773
|
provider: input.launch.provider,
|
|
685
774
|
...(input.launch.profile ? { profile: input.launch.profile } : {}),
|
|
686
775
|
...(input.launch.model ? { model: input.launch.model } : {}),
|
|
@@ -697,7 +786,7 @@ export function writeTeammateClaim(input) {
|
|
|
697
786
|
}
|
|
698
787
|
: undefined;
|
|
699
788
|
const claim = validateTeammateClaim({
|
|
700
|
-
schema_version:
|
|
789
|
+
schema_version: 2,
|
|
701
790
|
task_id: input.identity.taskId,
|
|
702
791
|
batch_id: input.identity.batchId,
|
|
703
792
|
assignment_id: input.identity.assignmentId,
|
|
@@ -724,7 +813,7 @@ export function writeTeammateClaim(input) {
|
|
|
724
813
|
status: claim.status,
|
|
725
814
|
...(claim.execution
|
|
726
815
|
? {
|
|
727
|
-
|
|
816
|
+
configuration: claim.execution.configuration,
|
|
728
817
|
provider: claim.execution.provider,
|
|
729
818
|
...(claim.execution.profile
|
|
730
819
|
? { profile: claim.execution.profile }
|
|
@@ -789,8 +878,13 @@ export function appendTeammateWorklog(input) {
|
|
|
789
878
|
}
|
|
790
879
|
}
|
|
791
880
|
export function writeTeammateReport(input) {
|
|
881
|
+
if (input.content &&
|
|
882
|
+
(input.content.status !== input.status ||
|
|
883
|
+
JSON.stringify(input.content.evidence) !== JSON.stringify(input.evidence)))
|
|
884
|
+
throw new Error("report content status/evidence must match the submitted report");
|
|
792
885
|
const report = validateTeammateReport({
|
|
793
|
-
|
|
886
|
+
...input.content,
|
|
887
|
+
schema_version: input.content ? 2 : 1,
|
|
794
888
|
task_id: input.identity.taskId,
|
|
795
889
|
batch_id: input.identity.batchId,
|
|
796
890
|
assignment_id: input.identity.assignmentId,
|
|
@@ -805,6 +899,7 @@ export function writeTeammateReport(input) {
|
|
|
805
899
|
evidence: input.evidence,
|
|
806
900
|
}, input.identity, input.sourceDigest);
|
|
807
901
|
writeImmutableJson(attemptArtifactPath(input.taskRoot, input.briefPath, input.identity.attemptId, "report.json"), {
|
|
902
|
+
...report.content,
|
|
808
903
|
schema_version: report.schemaVersion,
|
|
809
904
|
task_id: report.taskId,
|
|
810
905
|
batch_id: report.batchId,
|
|
@@ -854,15 +949,57 @@ export function writeTeammateDisposition(input) {
|
|
|
854
949
|
...(disposition.reason ? { reason: disposition.reason } : {}),
|
|
855
950
|
});
|
|
856
951
|
}
|
|
952
|
+
export class TeammateReportReadError extends Error {
|
|
953
|
+
kind;
|
|
954
|
+
constructor(kind, message) {
|
|
955
|
+
super(message);
|
|
956
|
+
this.kind = kind;
|
|
957
|
+
this.name = "TeammateReportReadError";
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
function isMissingFile(error) {
|
|
961
|
+
return (error !== null &&
|
|
962
|
+
typeof error === "object" &&
|
|
963
|
+
"code" in error &&
|
|
964
|
+
error.code === "ENOENT");
|
|
965
|
+
}
|
|
857
966
|
export function readTeammateReport(input) {
|
|
858
967
|
if (!ID.test(input.attemptId))
|
|
859
968
|
throw new Error("attempt id must be safe");
|
|
860
|
-
|
|
861
|
-
|
|
969
|
+
let reportPath;
|
|
970
|
+
try {
|
|
971
|
+
reportPath = safePath(input.taskRoot, path.join(path.dirname(input.briefPath), "attempts", input.attemptId, "report.json"));
|
|
972
|
+
}
|
|
973
|
+
catch {
|
|
974
|
+
throw new TeammateReportReadError("storage", "teammate report path is unsafe");
|
|
975
|
+
}
|
|
976
|
+
let stat;
|
|
977
|
+
try {
|
|
978
|
+
stat = fs.lstatSync(reportPath);
|
|
979
|
+
}
|
|
980
|
+
catch (error) {
|
|
981
|
+
if (isMissingFile(error))
|
|
982
|
+
throw new TeammateReportReadError("missing", "teammate report is missing");
|
|
983
|
+
throw new TeammateReportReadError("storage", "could not inspect teammate report");
|
|
984
|
+
}
|
|
862
985
|
if (!stat.isFile() || stat.size > 128 * 1024)
|
|
863
|
-
throw new
|
|
864
|
-
|
|
865
|
-
|
|
986
|
+
throw new TeammateReportReadError("storage", "teammate report must be a regular file under 131072 bytes");
|
|
987
|
+
let raw;
|
|
988
|
+
try {
|
|
989
|
+
raw = fs.readFileSync(reportPath, "utf8");
|
|
990
|
+
}
|
|
991
|
+
catch (error) {
|
|
992
|
+
if (isMissingFile(error))
|
|
993
|
+
throw new TeammateReportReadError("missing", "teammate report is missing");
|
|
994
|
+
throw new TeammateReportReadError("storage", "could not read teammate report");
|
|
995
|
+
}
|
|
996
|
+
let report;
|
|
997
|
+
try {
|
|
998
|
+
report = JSON.parse(raw);
|
|
999
|
+
}
|
|
1000
|
+
catch {
|
|
1001
|
+
throw new TeammateReportReadError("incomplete", "teammate report is not complete JSON");
|
|
1002
|
+
}
|
|
866
1003
|
rejectSecrets(report, "teammate report");
|
|
867
1004
|
return validateTeammateReport(report, { ...input.identity, attemptId: input.attemptId }, input.sourceDigest);
|
|
868
1005
|
}
|
|
@@ -881,13 +1018,8 @@ export function cleanupSettledTeamworkArtifacts(input) {
|
|
|
881
1018
|
if (!ID.test(attemptId))
|
|
882
1019
|
continue;
|
|
883
1020
|
const attemptDir = safePath(input.taskRoot, path.join(attemptsDir, attemptId));
|
|
884
|
-
|
|
885
|
-
const transientFiles = [
|
|
886
|
-
"claim.json",
|
|
887
|
-
"disposition.json",
|
|
888
|
-
"worklog.md",
|
|
889
|
-
...(keepReport ? [] : ["report.json"]),
|
|
890
|
-
];
|
|
1021
|
+
// Keep every attempt's evidence until an explicit native cleanup.
|
|
1022
|
+
const transientFiles = ["claim.json", "disposition.json"];
|
|
891
1023
|
for (const fileName of transientFiles) {
|
|
892
1024
|
const filePath = safePath(input.taskRoot, path.join(attemptDir, fileName));
|
|
893
1025
|
if (fs.existsSync(filePath))
|