pi-crew 0.5.14 → 0.5.16

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +117 -0
  2. package/README.md +1 -1
  3. package/docs/pi-crew-v0.5.16-audit-fix-plan.md +35 -0
  4. package/docs/pi-crew-v0.5.17-audit-fix-plan.md +80 -0
  5. package/docs/skills/REFERENCE.md +11 -0
  6. package/package.json +1 -1
  7. package/skills/iterative-audit/SKILL.md +330 -0
  8. package/src/extension/management.ts +1 -1
  9. package/src/extension/plan-orchestrate.ts +0 -1
  10. package/src/extension/register.ts +16 -7
  11. package/src/extension/registration/viewers.ts +1 -1
  12. package/src/extension/run-index.ts +1 -1
  13. package/src/extension/team-tool/explain.ts +0 -1
  14. package/src/extension/team-tool/handle-schedule.ts +0 -1
  15. package/src/extension/team-tool/health-monitor.ts +0 -1
  16. package/src/extension/team-tool/run.ts +2 -2
  17. package/src/extension/team-tool/status.ts +1 -1
  18. package/src/extension/team-tool.ts +2 -30
  19. package/src/observability/exporters/otlp-exporter.ts +11 -1
  20. package/src/runtime/child-pi.ts +1 -1
  21. package/src/runtime/crash-recovery.ts +1 -1
  22. package/src/runtime/crew-agent-records.ts +23 -3
  23. package/src/runtime/crew-hooks.ts +1 -1
  24. package/src/runtime/handoff-manager.ts +0 -1
  25. package/src/runtime/heartbeat-watcher.ts +1 -1
  26. package/src/runtime/live-session-runtime.ts +0 -1
  27. package/src/runtime/loop-gates.ts +0 -1
  28. package/src/runtime/mcp-proxy.ts +2 -2
  29. package/src/runtime/pipeline-runner.ts +1 -2
  30. package/src/runtime/task-runner/live-executor.ts +1 -2
  31. package/src/runtime/task-runner.ts +1 -1
  32. package/src/state/jsonl-writer.ts +24 -0
  33. package/src/state/locks.ts +66 -35
  34. package/src/state/run-metrics.ts +1 -2
  35. package/src/state/schedule.ts +13 -5
  36. package/src/state/state-store.ts +1 -1
  37. package/src/tools/safe-bash.ts +0 -1
  38. package/src/ui/crew-widget.ts +2 -2
  39. package/src/ui/render-diff.ts +1 -1
  40. package/src/ui/run-dashboard.ts +1 -2
  41. package/src/ui/tool-render.ts +20 -3
  42. package/src/utils/conflict-detect.ts +0 -1
  43. package/src/utils/gh-protocol.ts +0 -2
@@ -7,6 +7,9 @@
7
7
  * - parseRelativeTime(): "+10m" → ISO timestamp
8
8
  * - parseInterval(): "5m" → milliseconds
9
9
  */
10
+ import * as fs from "node:fs";
11
+ import * as path from "node:path";
12
+ import { logInternalError } from "../utils/internal-error.ts";
10
13
 
11
14
  import type { ScheduleStoreData, ScheduledTask } from "./types.ts";
12
15
 
@@ -88,8 +91,8 @@ export class ScheduleStore {
88
91
  this.path = path;
89
92
  this.data = { version: 1, jobs: [] };
90
93
  try {
91
- if (require("node:fs").existsSync(path)) {
92
- const content = require("node:fs").readFileSync(path, "utf-8");
94
+ if (fs.existsSync(path)) {
95
+ const content = fs.readFileSync(path, "utf-8");
93
96
  const parsed = JSON.parse(content);
94
97
  if (parsed && typeof parsed === "object" && "version" in parsed && "jobs" in parsed) {
95
98
  this.data = parsed as ScheduleStoreData;
@@ -102,10 +105,15 @@ export class ScheduleStore {
102
105
 
103
106
  private save(): void {
104
107
  try {
105
- require("node:fs").mkdirSync(require("node:path").dirname(this.path), { recursive: true });
106
- require("node:fs").writeFileSync(this.path, JSON.stringify(this.data, null, 2), "utf-8");
108
+ fs.mkdirSync(path.dirname(this.path), { recursive: true });
109
+ fs.writeFileSync(this.path, JSON.stringify(this.data, null, 2), "utf-8");
107
110
  } catch (error) {
108
- console.warn(`[pi-crew] Failed to save schedule store: ${error instanceof Error ? error.message : String(error)}`);
111
+ // FIX (Round 21, L1): Use logInternalError for consistency with
112
+ // the rest of the codebase. Previously console.warn may not be
113
+ // visible in all environments (e.g. JSON-RPC mode, redirected
114
+ // stderr). Also import the dependency properly at the top of
115
+ // the file (this method used the legacy require() pattern).
116
+ logInternalError("schedule.save", error, `path=${this.path}`);
109
117
  }
110
118
  }
111
119
 
@@ -1,7 +1,7 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import type { TeamRunManifest, TeamTaskState } from "./types.ts";
4
- import { canTransitionRunStatus, isTerminalRunStatus } from "./contracts.ts";
4
+ import { canTransitionRunStatus } from "./contracts.ts";
5
5
  import { unregisterActiveRun } from "./active-run-registry.ts";
6
6
  import { atomicWriteJson, atomicWriteJsonAsync, atomicWriteJsonCoalesced, readJsonFile } from "./atomic-write.ts";
7
7
  import { appendEvent } from "./event-log.ts";
@@ -4,7 +4,6 @@
4
4
  * Uses linear-time scanning to prevent ReDoS attacks
5
5
  */
6
6
 
7
- import { Type } from "@sinclair/typebox";
8
7
 
9
8
  // Backward-compatible pattern array (kept for getPatterns API)
10
9
  // IMPORTANT: Line 8 (rm pattern with nested quantifiers) has been replaced
@@ -9,8 +9,8 @@ import { getTaskUsage } from "../runtime/usage-tracker.ts";
9
9
  import type { TeamRunManifest } from "../state/types.ts";
10
10
  import type { ManifestCache } from "../runtime/manifest-cache.ts";
11
11
  import { reconcileAllStaleRuns } from "../runtime/crash-recovery.ts";
12
- import { colorForStatus, iconForStatus, type RunStatus } from "./status-colors.ts";
13
- import { pad, truncate } from "../utils/visual.ts";
12
+ import { iconForStatus } from "./status-colors.ts";
13
+ import { truncate } from "../utils/visual.ts";
14
14
  import type { CrewTheme } from "./theme-adapter.ts";
15
15
  import { asCrewTheme, subscribeThemeChange } from "./theme-adapter.ts";
16
16
  import { Box, Text } from "./layout-primitives.ts";
@@ -18,7 +18,7 @@ function parseDiffLine(line: string): ParsedDiffLine | null {
18
18
  return { prefix: match[1], lineNum: match[2], content: match[3] };
19
19
  }
20
20
 
21
- function replaceTabs(text: string): string {
21
+ export function replaceTabs(text: string): string {
22
22
  return text.replace(/\t/g, " ");
23
23
  }
24
24
 
@@ -1,7 +1,7 @@
1
1
  import * as fs from "node:fs";
2
2
  import type { TeamRunManifest, TeamTaskState, UsageState } from "../state/types.ts";
3
3
  import { readCrewAgents } from "../runtime/crew-agent-records.ts";
4
- import { getLiveAgentContextPercent, listLiveAgents } from "../runtime/live-agent-manager.ts";
4
+ import { getLiveAgentContextPercent } from "../runtime/live-agent-manager.ts";
5
5
  import type { CrewAgentRecord } from "../runtime/crew-agent-runtime.ts";
6
6
  import { isDisplayActiveRun, isLikelyOrphanedActiveRun } from "../runtime/process-status.ts";
7
7
  import { readJsonFileCoalesced } from "../utils/file-coalescer.ts";
@@ -11,7 +11,6 @@ import { applyStatusColor, iconForStatus, type RunStatus } from "./status-colors
11
11
  import { pad, truncate, sanitizeLine } from "../utils/visual.ts";
12
12
  import { Box, Text } from "./layout-primitives.ts";
13
13
  import { DynamicCrewBorder } from "./dynamic-border.ts";
14
- import { CrewFooter } from "./crew-footer.ts";
15
14
  import { aggregateUsage } from "../state/usage.ts";
16
15
  import { logInternalError } from "../utils/internal-error.ts";
17
16
  import { renderAgentsPane } from "./dashboard-panes/agents-pane.ts";
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { Container, Spacer, Text, visibleWidth } from "@earendil-works/pi-tui";
7
7
  import type { CrewAgentRecord } from "../runtime/crew-agent-runtime.ts";
8
+ import { replaceTabs } from "./render-diff.ts";
8
9
 
9
10
  // ── Types ──────────────────────────────────────────────────────────────
10
11
  export interface Theme {
@@ -185,7 +186,15 @@ export function renderAgentProgress(
185
186
  }
186
187
 
187
188
  // Error
188
- if (record.error) addLine(theme.fg("error", `Error: ${record.error}`));
189
+ // FIX (Round 20, render-utils sanitization): Sanitize tool-error display so
190
+ // embedded tabs / control chars / newlines / very long strings cannot break
191
+ // the terminal layout. Mirrors the upstream oh-my-pi pattern at
192
+ // packages/coding-agent/src/tools/render-utils.ts:177-185:
193
+ // formatErrorMessage = replaceTabs(truncateToWidth(clean, LINE_CAP))
194
+ if (record.error) {
195
+ const clean = truncLine(replaceTabs(String(record.error)), innerW);
196
+ addLine(theme.fg("error", `Error: ${clean}`));
197
+ }
189
198
 
190
199
  // Usage line
191
200
  const usage = record.usage;
@@ -300,7 +309,12 @@ export function renderAgentToolResult(
300
309
  const label = item.agentId || "agent";
301
310
  c.addChild(new Text(`${icon} ${theme.fg("toolTitle", theme.bold(label))}`, 0, 0));
302
311
  if (item.error) {
303
- c.addChild(new Text(theme.fg("error", ` Error: ${item.error}`), 0, 0));
312
+ // FIX (Round 20, render-utils sanitization): Sanitize tool-error
313
+ // display so embedded tabs / newlines / very long strings cannot
314
+ // break the TUI border alignment. Mirrors upstream oh-my-pi
315
+ // render-utils.ts:177-185.
316
+ const clean = truncLine(replaceTabs(String(item.error)), w - 2);
317
+ c.addChild(new Text(theme.fg("error", ` Error: ${clean}`), 0, 0));
304
318
  } else if (item.output) {
305
319
  for (const line of item.output.split("\n").slice(0, 5))
306
320
  c.addChild(new Text(theme.fg("dim", ` ${truncLine(line, w - 2)}`), 0, 0));
@@ -318,7 +332,10 @@ export function renderAgentToolResult(
318
332
  const label = d.agentId;
319
333
  c.addChild(new Text(`${icon} ${theme.fg("toolTitle", theme.bold(label))}`, 0, 0));
320
334
  if (d.error) {
321
- c.addChild(new Text(theme.fg("error", ` Error: ${d.error}`), 0, 0));
335
+ // FIX (Round 20, render-utils sanitization): Same sanitization as
336
+ // above — see renderAgentToolResult header comment.
337
+ const clean = truncLine(replaceTabs(String(d.error)), w - 2);
338
+ c.addChild(new Text(theme.fg("error", ` Error: ${clean}`), 0, 0));
322
339
  } else if (d.output) {
323
340
  for (const line of d.output.split("\n").slice(0, 5))
324
341
  c.addChild(new Text(theme.fg("dim", ` ${truncLine(line, w - 2)}`), 0, 0));
@@ -20,7 +20,6 @@
20
20
  * merely start with `<` or `=` never match.
21
21
  */
22
22
  import * as fs from "node:fs";
23
- import * as path from "node:path";
24
23
 
25
24
  const OURS_PREFIX = "<<<<<<<";
26
25
  const BASE_PREFIX = "|||||||";
@@ -22,8 +22,6 @@
22
22
  * Repo resolution: git remote get-url origin from cwd.
23
23
  */
24
24
  import { execFileSync } from "node:child_process";
25
- import { readFileSync } from "node:fs";
26
- import * as path from "node:path";
27
25
 
28
26
  /** Resolve the default repo from `git remote get-url origin` in cwd. */
29
27
  export function resolveDefaultRepo(cwd: string): string {