pi-crew 0.1.49 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +74 -1
- package/README.md +176 -781
- package/agents/analyst.md +11 -11
- package/agents/critic.md +11 -11
- package/agents/executor.md +11 -11
- package/agents/explorer.md +11 -11
- package/agents/planner.md +11 -11
- package/agents/reviewer.md +11 -11
- package/agents/security-reviewer.md +11 -11
- package/agents/test-engineer.md +11 -11
- package/agents/verifier.md +70 -11
- package/agents/writer.md +11 -11
- package/docs/actions-reference.md +595 -0
- package/docs/commands-reference.md +347 -0
- package/docs/runtime-flow.md +148 -148
- package/index.ts +6 -6
- package/package.json +99 -99
- package/skills/async-worker-recovery/SKILL.md +42 -42
- package/skills/context-artifact-hygiene/SKILL.md +52 -52
- package/skills/delegation-patterns/SKILL.md +54 -54
- package/skills/mailbox-interactive/SKILL.md +40 -40
- package/skills/model-routing-context/SKILL.md +39 -39
- package/skills/multi-perspective-review/SKILL.md +58 -58
- package/skills/observability-reliability/SKILL.md +41 -41
- package/skills/orchestration/SKILL.md +157 -157
- package/skills/ownership-session-security/SKILL.md +41 -41
- package/skills/pi-extension-lifecycle/SKILL.md +39 -39
- package/skills/requirements-to-task-packet/SKILL.md +63 -63
- package/skills/resource-discovery-config/SKILL.md +41 -41
- package/skills/runtime-state-reader/SKILL.md +44 -44
- package/skills/secure-agent-orchestration-review/SKILL.md +45 -45
- package/skills/state-mutation-locking/SKILL.md +42 -42
- package/skills/systematic-debugging/SKILL.md +67 -67
- package/skills/ui-render-performance/SKILL.md +39 -39
- package/skills/verification-before-done/SKILL.md +57 -57
- package/skills/worktree-isolation/SKILL.md +39 -39
- package/src/adapters/claude-adapter.ts +25 -0
- package/src/adapters/codex-adapter.ts +21 -0
- package/src/adapters/cursor-adapter.ts +17 -0
- package/src/adapters/export-util.ts +137 -0
- package/src/adapters/index.ts +15 -0
- package/src/adapters/registry.ts +18 -0
- package/src/adapters/types.ts +23 -0
- package/src/agents/agent-config.ts +2 -0
- package/src/agents/agent-search.ts +98 -98
- package/src/agents/discover-agents.ts +2 -1
- package/src/config/config.ts +14 -1
- package/src/config/defaults.ts +5 -5
- package/src/config/drift-detector.ts +211 -0
- package/src/config/markers.ts +327 -0
- package/src/config/resilient-parser.ts +108 -0
- package/src/config/suggestions.ts +74 -0
- package/src/extension/cross-extension-rpc.ts +103 -82
- package/src/extension/project-init.ts +36 -4
- package/src/extension/register.ts +67 -22
- package/src/extension/registration/commands.ts +77 -8
- package/src/extension/registration/subagent-tools.ts +10 -1
- package/src/extension/registration/team-tool.ts +10 -1
- package/src/extension/registration/viewers.ts +48 -34
- package/src/extension/run-bundle-schema.ts +89 -89
- package/src/extension/run-export.ts +26 -12
- package/src/extension/run-import.ts +25 -1
- package/src/extension/run-index.ts +5 -1
- package/src/extension/run-maintenance.ts +142 -68
- package/src/extension/team-manager-command.ts +10 -1
- package/src/extension/team-tool/context.ts +1 -1
- package/src/extension/team-tool/doctor.ts +28 -3
- package/src/extension/team-tool/handle-settings.ts +195 -188
- package/src/extension/team-tool/inspect.ts +41 -41
- package/src/extension/team-tool/intent-policy.ts +42 -42
- package/src/extension/team-tool/lifecycle-actions.ts +27 -8
- package/src/extension/team-tool/plan.ts +19 -19
- package/src/extension/team-tool/run.ts +12 -1
- package/src/extension/team-tool.ts +14 -3
- package/src/i18n.ts +184 -184
- package/src/observability/exporters/otlp-exporter.ts +92 -77
- package/src/prompt/prompt-runtime.ts +72 -72
- package/src/runtime/agent-memory.ts +72 -72
- package/src/runtime/agent-observability.ts +114 -114
- package/src/runtime/async-marker.ts +26 -26
- package/src/runtime/attention-events.ts +28 -28
- package/src/runtime/auto-resume.ts +100 -0
- package/src/runtime/background-runner.ts +11 -1
- package/src/runtime/cancellation-token.ts +89 -89
- package/src/runtime/cancellation.ts +61 -61
- package/src/runtime/capability-inventory.ts +116 -116
- package/src/runtime/child-pi.ts +7 -2
- package/src/runtime/compaction-summary.ts +271 -0
- package/src/runtime/completion-guard.ts +190 -190
- package/src/runtime/concurrency.ts +3 -1
- package/src/runtime/crash-recovery.ts +33 -0
- package/src/runtime/delta-conflict.ts +360 -0
- package/src/runtime/diagnostic-export.ts +3 -1
- package/src/runtime/direct-run.ts +35 -35
- package/src/runtime/event-stream-bridge.ts +3 -1
- package/src/runtime/foreground-control.ts +82 -82
- package/src/runtime/green-contract.ts +46 -46
- package/src/runtime/group-join.ts +106 -106
- package/src/runtime/heartbeat-gradient.ts +28 -28
- package/src/runtime/heartbeat-watcher.ts +124 -124
- package/src/runtime/iteration-hooks.ts +262 -0
- package/src/runtime/live-agent-control.ts +88 -88
- package/src/runtime/live-control-realtime.ts +36 -36
- package/src/runtime/live-extension-bridge.ts +150 -150
- package/src/runtime/live-irc.ts +92 -92
- package/src/runtime/live-session-health.ts +100 -100
- package/src/runtime/loop-gates.ts +129 -0
- package/src/runtime/metric-parser.ts +40 -0
- package/src/runtime/notebook-helpers.ts +90 -90
- package/src/runtime/orphan-sentinel.ts +7 -7
- package/src/runtime/parallel-research.ts +44 -44
- package/src/runtime/phase-progress.ts +217 -0
- package/src/runtime/pi-args.ts +38 -2
- package/src/runtime/pi-json-output.ts +111 -111
- package/src/runtime/pi-spawn.ts +74 -6
- package/src/runtime/policy-engine.ts +79 -79
- package/src/runtime/post-checks.ts +122 -0
- package/src/runtime/process-status.ts +14 -1
- package/src/runtime/progress-event-coalescer.ts +43 -43
- package/src/runtime/prose-compressor.ts +164 -164
- package/src/runtime/recovery-recipes.ts +74 -74
- package/src/runtime/result-extractor.ts +121 -121
- package/src/runtime/role-permission.ts +39 -39
- package/src/runtime/sensitive-paths.ts +3 -3
- package/src/runtime/session-resources.ts +25 -25
- package/src/runtime/session-snapshot.ts +59 -59
- package/src/runtime/session-usage.ts +79 -79
- package/src/runtime/sidechain-output.ts +29 -29
- package/src/runtime/stream-preview.ts +177 -177
- package/src/runtime/supervisor-contact.ts +59 -59
- package/src/runtime/task-display.ts +38 -38
- package/src/runtime/task-graph.ts +207 -0
- package/src/runtime/task-quality.ts +207 -0
- package/src/runtime/task-runner/capabilities.ts +78 -78
- package/src/runtime/task-runner/live-executor.ts +7 -1
- package/src/runtime/task-runner/progress.ts +119 -119
- package/src/runtime/task-runner/prompt-builder.ts +1 -1
- package/src/runtime/task-runner/prompt-pipeline.ts +64 -64
- package/src/runtime/task-runner/result-utils.ts +14 -14
- package/src/runtime/task-runner/run-projection.ts +103 -103
- package/src/runtime/task-runner/state-helpers.ts +22 -22
- package/src/runtime/team-runner.ts +126 -7
- package/src/runtime/worker-heartbeat.ts +21 -21
- package/src/runtime/worker-startup.ts +57 -57
- package/src/runtime/workflow-state.ts +187 -0
- package/src/runtime/workspace-tree.ts +298 -298
- package/src/schema/config-schema.ts +12 -0
- package/src/schema/validation-types.ts +148 -0
- package/src/skills/skill-templates.ts +374 -0
- package/src/state/active-run-registry.ts +35 -11
- package/src/state/atomic-write.ts +33 -26
- package/src/state/contracts.ts +1 -0
- package/src/state/event-reconstructor.ts +217 -0
- package/src/state/locks.ts +2 -11
- package/src/state/mailbox.ts +4 -3
- package/src/state/state-store.ts +32 -14
- package/src/state/task-claims.ts +44 -44
- package/src/state/types.ts +9 -0
- package/src/state/usage.ts +29 -29
- package/src/subagents/async-entry.ts +1 -1
- package/src/subagents/index.ts +3 -3
- package/src/subagents/live/control.ts +1 -1
- package/src/subagents/live/manager.ts +1 -1
- package/src/subagents/live/realtime.ts +1 -1
- package/src/subagents/live/session-runtime.ts +1 -1
- package/src/subagents/manager.ts +1 -1
- package/src/subagents/spawn.ts +1 -1
- package/src/teams/team-serializer.ts +38 -38
- package/src/types/diff.d.ts +18 -18
- package/src/ui/crew-footer.ts +101 -101
- package/src/ui/crew-select-list.ts +111 -111
- package/src/ui/crew-widget.ts +9 -4
- package/src/ui/dashboard-panes/cancellation-pane.ts +42 -42
- package/src/ui/dashboard-panes/capability-pane.ts +59 -59
- package/src/ui/dashboard-panes/mailbox-pane.ts +35 -35
- package/src/ui/dashboard-panes/metrics-pane.ts +34 -34
- package/src/ui/dashboard-panes/progress-pane.ts +11 -0
- package/src/ui/dynamic-border.ts +25 -25
- package/src/ui/layout-primitives.ts +106 -106
- package/src/ui/loaders.ts +158 -158
- package/src/ui/powerbar-publisher.ts +6 -0
- package/src/ui/render-coalescer.ts +51 -51
- package/src/ui/render-diff.ts +119 -119
- package/src/ui/render-scheduler.ts +143 -143
- package/src/ui/run-action-dispatcher.ts +10 -1
- package/src/ui/spinner.ts +17 -17
- package/src/ui/status-colors.ts +58 -58
- package/src/ui/syntax-highlight.ts +116 -116
- package/src/ui/transcript-entries.ts +258 -258
- package/src/utils/completion-dedupe.ts +63 -63
- package/src/utils/frontmatter.ts +68 -68
- package/src/utils/git.ts +262 -262
- package/src/utils/ids.ts +17 -17
- package/src/utils/incremental-reader.ts +104 -104
- package/src/utils/names.ts +27 -27
- package/src/utils/redaction.ts +44 -44
- package/src/utils/safe-paths.ts +47 -47
- package/src/utils/scan-cache.ts +136 -136
- package/src/utils/sleep.ts +40 -26
- package/src/utils/task-name-generator.ts +337 -337
- package/src/workflows/validate-workflow.ts +40 -40
- package/src/worktree/branch-freshness.ts +45 -45
- package/src/worktree/worktree-manager.ts +11 -3
- package/teams/default.team.md +12 -12
- package/teams/fast-fix.team.md +11 -11
- package/teams/implementation.team.md +18 -18
- package/teams/parallel-research.team.md +14 -14
- package/teams/research.team.md +11 -11
- package/teams/review.team.md +12 -12
- package/workflows/default.workflow.md +30 -29
- package/workflows/fast-fix.workflow.md +23 -22
- package/workflows/implementation.workflow.md +43 -38
- package/workflows/parallel-research.workflow.md +46 -46
- package/workflows/research.workflow.md +22 -22
- package/workflows/review.workflow.md +30 -30
- package/docs/refactor-tasks-phase3.md +0 -394
- package/docs/refactor-tasks-phase4.md +0 -564
- package/docs/refactor-tasks-phase5.md +0 -402
- package/docs/refactor-tasks-phase6.md +0 -662
- package/docs/refactor-tasks.md +0 -1484
- package/docs/research/AGENT-EXECUTION-ARCHITECTURE.md +0 -261
- package/docs/research/AGENT-LIFECYCLE-COMPARISON.md +0 -111
- package/docs/research/AUDIT_OH_MY_PI.md +0 -261
- package/docs/research/AUDIT_PI_CREW.md +0 -457
- package/docs/research/CAVEMAN-DEEP-RESEARCH.md +0 -281
- package/docs/research/COMPARISON_OH_MY_PI_VS_PI_CREW.md +0 -264
- package/docs/research/DEEP-RESEARCH-PI-POWERBAR.md +0 -343
- package/docs/research/DEEP_RESEARCH_SUBAGENT_ARCHITECTURE.md +0 -480
- package/docs/research/GAP_CLOSURE_IMPLEMENTATION_PLAN.md +0 -354
- package/docs/research/IMPLEMENTATION_PLAN.md +0 -385
- package/docs/research/LIVE-SESSION-PRODUCTION-READY-PLAN.md +0 -502
- package/docs/research/OH-MY-PI-DEEP-RESEARCH-v14.7.6.md +0 -266
- package/docs/research/REMAINING-GAPS-PLAN.md +0 -363
- package/docs/research/SESSION-SUMMARY-2026-05-08.md +0 -146
- package/docs/research/UI-RESPONSIVENESS-AUDIT.md +0 -173
- package/docs/research-awesome-agent-skills-distillation.md +0 -100
- package/docs/research-extension-examples.md +0 -297
- package/docs/research-extension-system.md +0 -324
- package/docs/research-oh-my-pi-distillation.md +0 -369
- package/docs/research-optimization-plan.md +0 -548
- package/docs/research-phase10-distillation.md +0 -199
- package/docs/research-phase11-distillation.md +0 -201
- package/docs/research-phase8-operator-experience-plan.md +0 -819
- package/docs/research-phase9-observability-reliability-plan.md +0 -1190
- package/docs/research-pi-coding-agent.md +0 -357
- package/docs/research-source-pi-crew-reference.md +0 -174
- package/docs/research-ui-optimization-plan.md +0 -480
- package/docs/source-runtime-refactor-map.md +0 -107
- package/src/utils/atomic-write.ts +0 -33
|
@@ -19,7 +19,7 @@ export type TeamContext = Pick<ExtensionContext, "cwd"> & Partial<Pick<Extension
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
export function withSessionId<T extends Pick<ExtensionContext, "sessionManager">>(ctx: T): T & { sessionId?: string } {
|
|
22
|
-
const sessionId = ctx.sessionManager
|
|
22
|
+
const sessionId = ctx.sessionManager?.getSessionId?.();
|
|
23
23
|
return sessionId ? { ...ctx, sessionId } : { ...ctx };
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -10,6 +10,7 @@ import { DEFAULT_PATHS } from "../../config/defaults.ts";
|
|
|
10
10
|
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
11
11
|
import { getPiSpawnCommand } from "../../runtime/pi-spawn.ts";
|
|
12
12
|
import { validateResources } from "../validate-resources.ts";
|
|
13
|
+
import { detectDrift, formatDriftReport, type DriftReport } from "../../config/drift-detector.ts";
|
|
13
14
|
import { TeamToolParams } from "../../schema/team-tool-schema.ts";
|
|
14
15
|
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
15
16
|
import { configRecord, result, type TeamContext } from "./context.ts";
|
|
@@ -112,9 +113,19 @@ export interface TeamDoctorReportInput {
|
|
|
112
113
|
export interface TeamDoctorReport {
|
|
113
114
|
text: string;
|
|
114
115
|
hasErrors: boolean;
|
|
116
|
+
drift?: DriftReport;
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
export function buildTeamDoctorReport(input: TeamDoctorReportInput): TeamDoctorReport {
|
|
120
|
+
// Compute drift once — reused in both Drift section and return value
|
|
121
|
+
const driftResult = detectDrift(
|
|
122
|
+
{
|
|
123
|
+
agents: allAgents(discoverAgents(input.cwd)).map((a) => a.name),
|
|
124
|
+
teams: allTeams(discoverTeams(input.cwd)).map((t) => t.name),
|
|
125
|
+
workflows: allWorkflows(discoverWorkflows(input.cwd)).map((w) => w.name),
|
|
126
|
+
},
|
|
127
|
+
loadConfig(input.cwd).config,
|
|
128
|
+
);
|
|
118
129
|
const sections = [
|
|
119
130
|
section("Runtime", () => {
|
|
120
131
|
const git = commandExists("git", ["--version"]);
|
|
@@ -156,6 +167,15 @@ export function buildTeamDoctorReport(input: TeamDoctorReportInput): TeamDoctorR
|
|
|
156
167
|
ok: input.validationErrors === 0,
|
|
157
168
|
detail: `${input.validationErrors} errors, ${input.validationWarnings} warnings`,
|
|
158
169
|
}]),
|
|
170
|
+
section("Drift", () => {
|
|
171
|
+
const driftErrors = driftResult.items.filter((item) => item.severity === "error").length;
|
|
172
|
+
const driftWarnings = driftResult.items.filter((item) => item.severity === "warning").length;
|
|
173
|
+
return [{
|
|
174
|
+
label: "config drift",
|
|
175
|
+
ok: !driftResult.hasDrift || driftErrors === 0,
|
|
176
|
+
detail: driftResult.hasDrift ? `${driftErrors} errors, ${driftWarnings} warnings` : "no drift detected",
|
|
177
|
+
}];
|
|
178
|
+
}),
|
|
159
179
|
section("Schema", () => {
|
|
160
180
|
const schemaIssues = auditJsonSchema(TeamToolParams);
|
|
161
181
|
return [{ label: "strict-provider schema", ok: schemaIssues.length === 0, detail: schemaIssues.length ? schemaIssues.slice(0, 3).join("; ") : "team tool schema compatible" }];
|
|
@@ -181,7 +201,7 @@ export function buildTeamDoctorReport(input: TeamDoctorReportInput): TeamDoctorR
|
|
|
181
201
|
}
|
|
182
202
|
if (lines.at(-1) === "") lines.pop();
|
|
183
203
|
const text = lines.join("\n");
|
|
184
|
-
return { text, hasErrors: sections.some((sectionLines) => sectionLines.some((line) => line.includes("FAIL"))) };
|
|
204
|
+
return { text, hasErrors: sections.some((sectionLines) => sectionLines.some((line) => line.includes("FAIL"))), drift: driftResult.hasDrift ? driftResult : undefined };
|
|
185
205
|
}
|
|
186
206
|
|
|
187
207
|
export function handleDoctor(ctx: TeamContext, params: TeamToolParamsValue = {}): PiTeamsToolResult {
|
|
@@ -203,7 +223,7 @@ export function handleDoctor(ctx: TeamContext, params: TeamToolParamsValue = {})
|
|
|
203
223
|
}
|
|
204
224
|
}
|
|
205
225
|
const validation = validateResources(ctx.cwd);
|
|
206
|
-
const { text, hasErrors } = buildTeamDoctorReport({
|
|
226
|
+
const { text, hasErrors, drift } = buildTeamDoctorReport({
|
|
207
227
|
cwd: ctx.cwd,
|
|
208
228
|
configPath: loadedConfig.path,
|
|
209
229
|
configErrors: loadedConfig.error ? [loadedConfig.error] : [],
|
|
@@ -213,5 +233,10 @@ export function handleDoctor(ctx: TeamContext, params: TeamToolParamsValue = {})
|
|
|
213
233
|
validationWarnings: validation.issues.filter((issue) => issue.level === "warning").length,
|
|
214
234
|
smokeChildPi,
|
|
215
235
|
});
|
|
216
|
-
|
|
236
|
+
// Append detailed drift section if any drift was detected
|
|
237
|
+
let finalText = text;
|
|
238
|
+
if (drift?.hasDrift) {
|
|
239
|
+
finalText = `${text}\n\nDrift details:\n${formatDriftReport(drift)}`;
|
|
240
|
+
}
|
|
241
|
+
return result(finalText, { action: "doctor", status: hasErrors ? "error" : "ok" }, hasErrors);
|
|
217
242
|
}
|
|
@@ -1,188 +1,195 @@
|
|
|
1
|
-
import type { TeamContext } from "../team-tool/context.ts";
|
|
2
|
-
import { loadConfig, updateConfig } from "../../config/config.ts";
|
|
3
|
-
import { configPatchFromConfig } from "../team-tool/config-patch.ts";
|
|
4
|
-
import { result } from "../team-tool/context.ts";
|
|
5
|
-
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
current
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return raw;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
"runtime.
|
|
60
|
-
"runtime.
|
|
61
|
-
"runtime.
|
|
62
|
-
"runtime.
|
|
63
|
-
"runtime.
|
|
64
|
-
"runtime.
|
|
65
|
-
"runtime.
|
|
66
|
-
"runtime.
|
|
67
|
-
"runtime.
|
|
68
|
-
"runtime.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
"limits.
|
|
72
|
-
"limits.
|
|
73
|
-
"limits.
|
|
74
|
-
"limits.
|
|
75
|
-
"limits.
|
|
76
|
-
"limits.
|
|
77
|
-
"limits.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
"control.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
"autonomous.
|
|
84
|
-
"autonomous.
|
|
85
|
-
"autonomous.
|
|
86
|
-
"autonomous.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
"tools.
|
|
90
|
-
"tools.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
"observability.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
const
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
1
|
+
import type { TeamContext } from "../team-tool/context.ts";
|
|
2
|
+
import { loadConfig, updateConfig } from "../../config/config.ts";
|
|
3
|
+
import { configPatchFromConfig } from "../team-tool/config-patch.ts";
|
|
4
|
+
import { result } from "../team-tool/context.ts";
|
|
5
|
+
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
6
|
+
import { suggestConfigKey } from "../../config/suggestions.ts";
|
|
7
|
+
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Helpers
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
function setNested(obj: Record<string, unknown>, path: string, value: unknown): void {
|
|
13
|
+
const keys = path.split(".");
|
|
14
|
+
let target: Record<string, unknown> = obj;
|
|
15
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
16
|
+
if (!target[keys[i]] || typeof target[keys[i]] !== "object") {
|
|
17
|
+
target[keys[i]] = {};
|
|
18
|
+
}
|
|
19
|
+
target = target[keys[i]] as Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
target[keys[keys.length - 1]] = value;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getNested(obj: Record<string, unknown>, path: string): unknown {
|
|
25
|
+
const keys = path.split(".");
|
|
26
|
+
let current: unknown = obj;
|
|
27
|
+
for (const key of keys) {
|
|
28
|
+
if (!current || typeof current !== "object") return undefined;
|
|
29
|
+
current = (current as Record<string, unknown>)[key];
|
|
30
|
+
}
|
|
31
|
+
return current;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function formatValue(value: unknown): string {
|
|
35
|
+
if (value === undefined) return "<not set>";
|
|
36
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
37
|
+
return String(value);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function parseValue(raw: string): unknown {
|
|
41
|
+
// JSON handles strings (quoted), numbers, booleans, null, arrays, objects.
|
|
42
|
+
try { return JSON.parse(raw); } catch { /* keep as string */ }
|
|
43
|
+
return raw;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Known config keys — mirrors config-schema.ts + config.ts.
|
|
48
|
+
// When adding new config fields, add the dotted path here so team-settings
|
|
49
|
+
// can discover and display them.
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
|
|
52
|
+
const KNOWN_KEYS = new Set([
|
|
53
|
+
// top-level
|
|
54
|
+
"asyncByDefault",
|
|
55
|
+
"executeWorkers",
|
|
56
|
+
"notifierIntervalMs",
|
|
57
|
+
"requireCleanWorktreeLeader",
|
|
58
|
+
// runtime
|
|
59
|
+
"runtime.mode",
|
|
60
|
+
"runtime.preferLiveSession",
|
|
61
|
+
"runtime.allowChildProcessFallback",
|
|
62
|
+
"runtime.maxTurns",
|
|
63
|
+
"runtime.graceTurns",
|
|
64
|
+
"runtime.inheritContext",
|
|
65
|
+
"runtime.promptMode",
|
|
66
|
+
"runtime.groupJoin",
|
|
67
|
+
"runtime.groupJoinAckTimeoutMs",
|
|
68
|
+
"runtime.requirePlanApproval",
|
|
69
|
+
"runtime.completionMutationGuard",
|
|
70
|
+
// limits
|
|
71
|
+
"limits.maxConcurrentWorkers",
|
|
72
|
+
"limits.allowUnboundedConcurrency",
|
|
73
|
+
"limits.maxTaskDepth",
|
|
74
|
+
"limits.maxChildrenPerTask",
|
|
75
|
+
"limits.maxRunMinutes",
|
|
76
|
+
"limits.maxRetriesPerTask",
|
|
77
|
+
"limits.maxTasksPerRun",
|
|
78
|
+
"limits.heartbeatStaleMs",
|
|
79
|
+
// control
|
|
80
|
+
"control.enabled",
|
|
81
|
+
"control.needsAttentionAfterMs",
|
|
82
|
+
// autonomous
|
|
83
|
+
"autonomous.profile",
|
|
84
|
+
"autonomous.enabled",
|
|
85
|
+
"autonomous.injectPolicy",
|
|
86
|
+
"autonomous.preferAsyncForLongTasks",
|
|
87
|
+
"autonomous.allowWorktreeSuggestion",
|
|
88
|
+
// tools
|
|
89
|
+
"tools.enableClaudeStyleAliases",
|
|
90
|
+
"tools.enableSteer",
|
|
91
|
+
"tools.terminateOnForeground",
|
|
92
|
+
// agents
|
|
93
|
+
"agents.disableBuiltins",
|
|
94
|
+
// observability
|
|
95
|
+
"observability.prometheus.enabled",
|
|
96
|
+
"observability.otlp.enabled",
|
|
97
|
+
// worktree
|
|
98
|
+
"worktree.enabled",
|
|
99
|
+
]);
|
|
100
|
+
|
|
101
|
+
const KNOWN_SORTED = [...KNOWN_KEYS].sort();
|
|
102
|
+
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
// Detail objects – all require { action, status } from TeamToolDetails.
|
|
105
|
+
// Extras (count, key, value, path) are passed as never to bypass the narrow
|
|
106
|
+
// TeamToolDetails interface (consistent with the rest of the codebase).
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
const OK = { action: "settings", status: "ok" as const };
|
|
110
|
+
const ERR = { action: "settings", status: "error" as const };
|
|
111
|
+
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
// Main handler
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
|
|
116
|
+
export function handleSettings(params: { config?: Record<string, unknown> }, ctx: TeamContext): PiTeamsToolResult {
|
|
117
|
+
const cfg = (params.config ?? {}) as Record<string, unknown>;
|
|
118
|
+
const args = typeof cfg.args === "string" ? cfg.args.trim() : "";
|
|
119
|
+
const scope = cfg.scope === "project" ? "project" : "user";
|
|
120
|
+
const loaded = loadConfig(ctx.cwd);
|
|
121
|
+
const effective = loaded.config as Record<string, unknown>;
|
|
122
|
+
|
|
123
|
+
// team-settings list
|
|
124
|
+
if (!args || args === "list") {
|
|
125
|
+
const lines = ["pi-crew settings:", `Path: ${loaded.path}`, ""];
|
|
126
|
+
for (const key of KNOWN_SORTED) {
|
|
127
|
+
const value = getNested(effective, key);
|
|
128
|
+
lines.push(` ${key} = ${formatValue(value)}`);
|
|
129
|
+
}
|
|
130
|
+
lines.push("", "Usage: team-settings [list|get <key>|set <key> <value>|unset <key>|path|scope]");
|
|
131
|
+
return result(lines.join("\n"), { ...OK, count: KNOWN_KEYS.size } as never);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// team-settings path
|
|
135
|
+
if (args === "path") {
|
|
136
|
+
return result(`pi-crew config path: ${loaded.path}`, { ...OK, path: loaded.path } as never);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// team-settings scope
|
|
140
|
+
if (args === "scope") {
|
|
141
|
+
return result(`Current scope: ${scope}\nConfig at: ${loaded.path}`, { ...OK, scope } as never);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// team-settings get <key>
|
|
145
|
+
if (args.startsWith("get ")) {
|
|
146
|
+
const key = args.slice(4).trim();
|
|
147
|
+
if (!key) return result("Usage: team-settings get <key>", { ...ERR }, true);
|
|
148
|
+
const value = getNested(effective, key);
|
|
149
|
+
let note = KNOWN_KEYS.has(key) ? "" : " (unknown key — may not take effect)";
|
|
150
|
+
if (!KNOWN_KEYS.has(key)) {
|
|
151
|
+
const suggestion = suggestConfigKey(key, KNOWN_SORTED);
|
|
152
|
+
if (suggestion) note += ` (did you mean '${suggestion}'?)`;
|
|
153
|
+
}
|
|
154
|
+
return result(`${key} = ${formatValue(value)}${note}`, { ...OK, key, value } as never);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// team-settings unset <key>
|
|
158
|
+
if (args.startsWith("unset ")) {
|
|
159
|
+
const key = args.slice(6).trim();
|
|
160
|
+
if (!key) return result("Usage: team-settings unset <key>", { ...ERR }, true);
|
|
161
|
+
try {
|
|
162
|
+
const saved = updateConfig({}, { cwd: ctx.cwd, scope, unsetPaths: [key] });
|
|
163
|
+
return result(`Unset ${key}\nPath: ${saved.path}`, { ...OK, key } as never);
|
|
164
|
+
} catch (error) {
|
|
165
|
+
return result(error instanceof Error ? error.message : String(error), { ...ERR }, true);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// team-settings set <key> <value>
|
|
170
|
+
if (args.startsWith("set ")) {
|
|
171
|
+
const rest = args.slice(4).trim();
|
|
172
|
+
const spaceIdx = rest.indexOf(" ");
|
|
173
|
+
if (spaceIdx === -1) return result("Usage: team-settings set <key> <value>", { ...ERR }, true);
|
|
174
|
+
const key = rest.slice(0, spaceIdx);
|
|
175
|
+
const rawValue = rest.slice(spaceIdx + 1).trim();
|
|
176
|
+
if (!key) return result("Usage: team-settings set <key> <value>", { ...ERR }, true);
|
|
177
|
+
|
|
178
|
+
const value = parseValue(rawValue);
|
|
179
|
+
const patch = {};
|
|
180
|
+
setNested(patch as Record<string, unknown>, key, value);
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
const converted = configPatchFromConfig({ config: patch as Record<string, unknown> });
|
|
184
|
+
const saved = updateConfig(converted, { cwd: ctx.cwd, scope });
|
|
185
|
+
const warning = KNOWN_KEYS.has(key) ? "" : "\nWarning: unknown key — verify it exists in config schema.";
|
|
186
|
+
const suggestion = KNOWN_KEYS.has(key) ? null : suggestConfigKey(key, KNOWN_SORTED);
|
|
187
|
+
const hint = suggestion ? `\nDid you mean '${suggestion}'?` : "";
|
|
188
|
+
return result(`Set ${key} = ${formatValue(value)}\nPath: ${saved.path}${warning}${hint}`, { ...OK, key, value } as never);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
return result(error instanceof Error ? error.message : String(error), { ...ERR }, true);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return result("Unknown subcommand. Usage: team-settings [list|get <key>|set <key> <value>|unset <key>|path|scope]", { ...ERR }, true);
|
|
195
|
+
}
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
2
|
-
import { readEvents } from "../../state/event-log.ts";
|
|
3
|
-
import { loadRunManifestById } from "../../state/state-store.ts";
|
|
4
|
-
import { aggregateUsage, formatUsage } from "../../state/usage.ts";
|
|
5
|
-
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
6
|
-
import { result, type TeamContext } from "./context.ts";
|
|
7
|
-
|
|
8
|
-
export function handleEvents(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
|
|
9
|
-
if (!params.runId) return result("Events requires runId.", { action: "events", status: "error" }, true);
|
|
10
|
-
const loaded = loadRunManifestById(ctx.cwd, params.runId);
|
|
11
|
-
if (!loaded) return result(`Run '${params.runId}' not found.`, { action: "events", status: "error" }, true);
|
|
12
|
-
const events = readEvents(loaded.manifest.eventsPath);
|
|
13
|
-
const lines = [`Events for ${loaded.manifest.runId}:`, ...(events.length ? events.map((event) => `${event.time} ${event.type}${event.taskId ? ` ${event.taskId}` : ""}${event.message ? `: ${event.message}` : ""}${event.data ? ` ${JSON.stringify(event.data)}` : ""}`) : ["(none)"])];
|
|
14
|
-
return result(lines.join("\n"), { action: "events", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function handleArtifacts(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
|
|
18
|
-
if (!params.runId) return result("Artifacts requires runId.", { action: "artifacts", status: "error" }, true);
|
|
19
|
-
const loaded = loadRunManifestById(ctx.cwd, params.runId);
|
|
20
|
-
if (!loaded) return result(`Run '${params.runId}' not found.`, { action: "artifacts", status: "error" }, true);
|
|
21
|
-
const lines = [`Artifacts for ${loaded.manifest.runId}:`, ...(loaded.manifest.artifacts.length ? loaded.manifest.artifacts.map((artifact) => `- ${artifact.kind}: ${artifact.path}${artifact.sizeBytes !== undefined ? ` (${artifact.sizeBytes} bytes)` : ""}${artifact.contentHash ? ` sha256=${artifact.contentHash.slice(0, 12)}` : ""}`) : ["- (none)"])];
|
|
22
|
-
return result(lines.join("\n"), { action: "artifacts", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function handleSummary(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
|
|
26
|
-
if (!params.runId) return result("Summary requires runId.", { action: "summary", status: "error" }, true);
|
|
27
|
-
const loaded = loadRunManifestById(ctx.cwd, params.runId);
|
|
28
|
-
if (!loaded) return result(`Run '${params.runId}' not found.`, { action: "summary", status: "error" }, true);
|
|
29
|
-
const usage = aggregateUsage(loaded.tasks);
|
|
30
|
-
const lines = [
|
|
31
|
-
`Summary for ${loaded.manifest.runId}`,
|
|
32
|
-
`Status: ${loaded.manifest.status}`,
|
|
33
|
-
`Team: ${loaded.manifest.team}`,
|
|
34
|
-
`Workflow: ${loaded.manifest.workflow ?? "(none)"}`,
|
|
35
|
-
`Goal: ${loaded.manifest.goal}`,
|
|
36
|
-
`Usage: ${formatUsage(usage)}`,
|
|
37
|
-
"Tasks:",
|
|
38
|
-
...loaded.tasks.map((task) => `- ${task.id}: ${task.status} (${task.role} -> ${task.agent})${task.error ? ` - ${task.error}` : ""}`),
|
|
39
|
-
];
|
|
40
|
-
return result(lines.join("\n"), { action: "summary", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
|
|
41
|
-
}
|
|
1
|
+
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
2
|
+
import { readEvents } from "../../state/event-log.ts";
|
|
3
|
+
import { loadRunManifestById } from "../../state/state-store.ts";
|
|
4
|
+
import { aggregateUsage, formatUsage } from "../../state/usage.ts";
|
|
5
|
+
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
6
|
+
import { result, type TeamContext } from "./context.ts";
|
|
7
|
+
|
|
8
|
+
export function handleEvents(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
|
|
9
|
+
if (!params.runId) return result("Events requires runId.", { action: "events", status: "error" }, true);
|
|
10
|
+
const loaded = loadRunManifestById(ctx.cwd, params.runId);
|
|
11
|
+
if (!loaded) return result(`Run '${params.runId}' not found.`, { action: "events", status: "error" }, true);
|
|
12
|
+
const events = readEvents(loaded.manifest.eventsPath);
|
|
13
|
+
const lines = [`Events for ${loaded.manifest.runId}:`, ...(events.length ? events.map((event) => `${event.time} ${event.type}${event.taskId ? ` ${event.taskId}` : ""}${event.message ? `: ${event.message}` : ""}${event.data ? ` ${JSON.stringify(event.data)}` : ""}`) : ["(none)"])];
|
|
14
|
+
return result(lines.join("\n"), { action: "events", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function handleArtifacts(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
|
|
18
|
+
if (!params.runId) return result("Artifacts requires runId.", { action: "artifacts", status: "error" }, true);
|
|
19
|
+
const loaded = loadRunManifestById(ctx.cwd, params.runId);
|
|
20
|
+
if (!loaded) return result(`Run '${params.runId}' not found.`, { action: "artifacts", status: "error" }, true);
|
|
21
|
+
const lines = [`Artifacts for ${loaded.manifest.runId}:`, ...(loaded.manifest.artifacts.length ? loaded.manifest.artifacts.map((artifact) => `- ${artifact.kind}: ${artifact.path}${artifact.sizeBytes !== undefined ? ` (${artifact.sizeBytes} bytes)` : ""}${artifact.contentHash ? ` sha256=${artifact.contentHash.slice(0, 12)}` : ""}`) : ["- (none)"])];
|
|
22
|
+
return result(lines.join("\n"), { action: "artifacts", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function handleSummary(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
|
|
26
|
+
if (!params.runId) return result("Summary requires runId.", { action: "summary", status: "error" }, true);
|
|
27
|
+
const loaded = loadRunManifestById(ctx.cwd, params.runId);
|
|
28
|
+
if (!loaded) return result(`Run '${params.runId}' not found.`, { action: "summary", status: "error" }, true);
|
|
29
|
+
const usage = aggregateUsage(loaded.tasks);
|
|
30
|
+
const lines = [
|
|
31
|
+
`Summary for ${loaded.manifest.runId}`,
|
|
32
|
+
`Status: ${loaded.manifest.status}`,
|
|
33
|
+
`Team: ${loaded.manifest.team}`,
|
|
34
|
+
`Workflow: ${loaded.manifest.workflow ?? "(none)"}`,
|
|
35
|
+
`Goal: ${loaded.manifest.goal}`,
|
|
36
|
+
`Usage: ${formatUsage(usage)}`,
|
|
37
|
+
"Tasks:",
|
|
38
|
+
...loaded.tasks.map((task) => `- ${task.id}: ${task.status} (${task.role} -> ${task.agent})${task.error ? ` - ${task.error}` : ""}`),
|
|
39
|
+
];
|
|
40
|
+
return result(lines.join("\n"), { action: "summary", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
|
|
41
|
+
}
|