@tianhai/pi-workflow-kit 0.5.3 → 0.6.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 +44 -494
- package/docs/developer-usage-guide.md +41 -401
- package/docs/oversight-model.md +13 -34
- package/docs/workflow-phases.md +32 -46
- package/extensions/workflow-guard.ts +67 -0
- package/package.json +3 -7
- package/skills/brainstorming/SKILL.md +16 -67
- package/skills/executing-tasks/SKILL.md +26 -227
- package/skills/finalizing/SKILL.md +33 -0
- package/skills/writing-plans/SKILL.md +23 -132
- package/ROADMAP.md +0 -16
- package/agents/code-reviewer.md +0 -18
- package/agents/config.ts +0 -5
- package/agents/implementer.md +0 -26
- package/agents/spec-reviewer.md +0 -13
- package/agents/worker.md +0 -17
- package/docs/plans/2026-04-10-brainstorming-boundary-enforcement-design.md +0 -60
- package/docs/plans/completed/2026-04-09-cleanup-legacy-state-and-enforce-think-phases-design.md +0 -56
- package/docs/plans/completed/2026-04-09-cleanup-legacy-state-and-enforce-think-phases-implementation.md +0 -196
- package/docs/plans/completed/2026-04-09-workflow-next-autocomplete-design.md +0 -185
- package/docs/plans/completed/2026-04-09-workflow-next-autocomplete-implementation.md +0 -334
- package/docs/plans/completed/2026-04-09-workflow-next-handoff-state-design.md +0 -251
- package/docs/plans/completed/2026-04-09-workflow-next-handoff-state-implementation.md +0 -253
- package/extensions/constants.ts +0 -15
- package/extensions/lib/logging.ts +0 -138
- package/extensions/plan-tracker.ts +0 -508
- package/extensions/subagent/agents.ts +0 -144
- package/extensions/subagent/concurrency.ts +0 -52
- package/extensions/subagent/env.ts +0 -47
- package/extensions/subagent/index.ts +0 -1181
- package/extensions/subagent/lifecycle.ts +0 -25
- package/extensions/subagent/timeout.ts +0 -13
- package/extensions/workflow-monitor/debug-monitor.ts +0 -98
- package/extensions/workflow-monitor/git.ts +0 -31
- package/extensions/workflow-monitor/heuristics.ts +0 -58
- package/extensions/workflow-monitor/investigation.ts +0 -52
- package/extensions/workflow-monitor/reference-tool.ts +0 -42
- package/extensions/workflow-monitor/skip-confirmation.ts +0 -19
- package/extensions/workflow-monitor/tdd-monitor.ts +0 -137
- package/extensions/workflow-monitor/test-runner.ts +0 -37
- package/extensions/workflow-monitor/verification-monitor.ts +0 -61
- package/extensions/workflow-monitor/warnings.ts +0 -81
- package/extensions/workflow-monitor/workflow-handler.ts +0 -363
- package/extensions/workflow-monitor/workflow-next-completions.ts +0 -68
- package/extensions/workflow-monitor/workflow-next-state.ts +0 -112
- package/extensions/workflow-monitor/workflow-tracker.ts +0 -286
- package/extensions/workflow-monitor/workflow-transitions.ts +0 -88
- package/extensions/workflow-monitor.ts +0 -909
- package/skills/dispatching-parallel-agents/SKILL.md +0 -194
- package/skills/receiving-code-review/SKILL.md +0 -196
- package/skills/systematic-debugging/SKILL.md +0 -170
- package/skills/systematic-debugging/condition-based-waiting-example.ts +0 -158
- package/skills/systematic-debugging/condition-based-waiting.md +0 -115
- package/skills/systematic-debugging/defense-in-depth.md +0 -122
- package/skills/systematic-debugging/find-polluter.sh +0 -63
- package/skills/systematic-debugging/reference/rationalizations.md +0 -61
- package/skills/systematic-debugging/root-cause-tracing.md +0 -169
- package/skills/test-driven-development/SKILL.md +0 -266
- package/skills/test-driven-development/reference/examples.md +0 -101
- package/skills/test-driven-development/reference/rationalizations.md +0 -67
- package/skills/test-driven-development/reference/when-stuck.md +0 -33
- package/skills/test-driven-development/testing-anti-patterns.md +0 -299
- package/skills/using-git-worktrees/SKILL.md +0 -231
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
# /workflow-next Handoff State Implementation Plan
|
|
2
|
-
|
|
3
|
-
> **REQUIRED SUB-SKILL:** Use the executing-tasks skill to implement this plan task-by-task.
|
|
4
|
-
|
|
5
|
-
**Goal:** Make `/workflow-next` preserve prior completed workflow history for same-feature handoffs, enforce immediate-next-only transitions, and rename the persisted local state file with legacy fallback.
|
|
6
|
-
|
|
7
|
-
**Architecture:** Add a small workflow-next state helper that validates allowed handoffs and derives the workflow snapshot for the new session. Update the workflow monitor to seed the new session through `ctx.newSession({ setup })` with derived workflow state plus fresh monitor state, and add focused tests for validation, state derivation, and file migration behavior.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** TypeScript, Vitest, pi extension API (`ctx.newSession({ setup })`, `SessionManager.appendCustomEntry`)
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Verification
|
|
14
|
-
|
|
15
|
-
All tasks completed. Final test results:
|
|
16
|
-
- `tests/extension/workflow-monitor/workflow-next-command.test.ts` — 17/17 pass
|
|
17
|
-
- `tests/extension/workflow-monitor/state-persistence.test.ts` — 25/25 pass
|
|
18
|
-
- `tests/extension/workflow-monitor/` (full suite) — 360/360 pass
|
|
19
|
-
|
|
20
|
-
No regressions. All acceptance criteria met.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
### Task 1: Add failing tests for workflow-next handoff validation and state seeding
|
|
26
|
-
|
|
27
|
-
**Type:** code
|
|
28
|
-
**TDD scenario:** Modifying tested code — run existing tests first
|
|
29
|
-
|
|
30
|
-
**Files:**
|
|
31
|
-
- Modify: `tests/extension/workflow-monitor/workflow-next-command.test.ts`
|
|
32
|
-
- Test: `tests/extension/workflow-monitor/workflow-next-command.test.ts`
|
|
33
|
-
|
|
34
|
-
**Step 1: Write the failing tests**
|
|
35
|
-
|
|
36
|
-
Add tests covering:
|
|
37
|
-
- allows `plan -> execute` only when `plan` is complete
|
|
38
|
-
- rejects same-phase handoff
|
|
39
|
-
- rejects backward handoff
|
|
40
|
-
- rejects direct jump handoff
|
|
41
|
-
- rejects handoff when current phase is active
|
|
42
|
-
- seeds new session setup with derived workflow state preserving earlier completed phases, artifacts, and prompted flags
|
|
43
|
-
- resets TDD/debug/verification state in the seeded session snapshot
|
|
44
|
-
|
|
45
|
-
**Step 2: Run test to verify it fails**
|
|
46
|
-
|
|
47
|
-
Run: `npx vitest run tests/extension/workflow-monitor/workflow-next-command.test.ts`
|
|
48
|
-
Expected: FAIL with missing validation and missing setup-state assertions
|
|
49
|
-
|
|
50
|
-
**Step 3: Write minimal implementation support in test scaffolding only if needed**
|
|
51
|
-
|
|
52
|
-
If needed, extend the fake `ctx.newSession` stub in the test so it records the `setup` callback and lets the test invoke it with a fake session manager that captures appended custom entries.
|
|
53
|
-
|
|
54
|
-
**Step 4: Run test to verify it still fails for the intended production behavior gap**
|
|
55
|
-
|
|
56
|
-
Run: `npx vitest run tests/extension/workflow-monitor/workflow-next-command.test.ts`
|
|
57
|
-
Expected: FAIL only on the new assertions tied to unimplemented production code
|
|
58
|
-
|
|
59
|
-
**Step 5: Commit**
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
git add tests/extension/workflow-monitor/workflow-next-command.test.ts
|
|
63
|
-
git commit -m "test: cover workflow-next handoff validation"
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### Task 2: Add failing tests for state-file rename and legacy fallback
|
|
67
|
-
|
|
68
|
-
**Type:** code
|
|
69
|
-
**TDD scenario:** Modifying tested code — run existing tests first
|
|
70
|
-
|
|
71
|
-
**Files:**
|
|
72
|
-
- Modify: `tests/extension/workflow-monitor/state-persistence.test.ts`
|
|
73
|
-
- Test: `tests/extension/workflow-monitor/state-persistence.test.ts`
|
|
74
|
-
|
|
75
|
-
**Step 1: Write the failing tests**
|
|
76
|
-
|
|
77
|
-
Add tests covering:
|
|
78
|
-
- `getStateFilePath()` returns `.pi/workflow-kit-state.json`
|
|
79
|
-
- `reconstructState()` prefers `.pi/workflow-kit-state.json` when present
|
|
80
|
-
- `reconstructState()` falls back to `.pi/superpowers-state.json` when the new file is absent
|
|
81
|
-
- extension persistence writes the new filename only
|
|
82
|
-
|
|
83
|
-
**Step 2: Run test to verify it fails**
|
|
84
|
-
|
|
85
|
-
Run: `npx vitest run tests/extension/workflow-monitor/state-persistence.test.ts`
|
|
86
|
-
Expected: FAIL because current code still uses `.pi/superpowers-state.json`
|
|
87
|
-
|
|
88
|
-
**Step 3: Keep test fixtures minimal**
|
|
89
|
-
|
|
90
|
-
Reuse existing `withTempCwd()` and fake pi helpers. When testing persistence wiring, assert against files under `.pi/` in the temp directory rather than broad repo state.
|
|
91
|
-
|
|
92
|
-
**Step 4: Run test to verify it still fails for the intended production behavior gap**
|
|
93
|
-
|
|
94
|
-
Run: `npx vitest run tests/extension/workflow-monitor/state-persistence.test.ts`
|
|
95
|
-
Expected: FAIL only on filename/migration assertions
|
|
96
|
-
|
|
97
|
-
**Step 5: Commit**
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
git add tests/extension/workflow-monitor/state-persistence.test.ts
|
|
101
|
-
git commit -m "test: cover workflow state file migration"
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
### Task 3: Implement workflow-next handoff validation and derived state helper
|
|
105
|
-
|
|
106
|
-
**Type:** code
|
|
107
|
-
**TDD scenario:** New feature — full TDD cycle
|
|
108
|
-
|
|
109
|
-
**Files:**
|
|
110
|
-
- Create: `extensions/workflow-monitor/workflow-next-state.ts`
|
|
111
|
-
- Modify: `extensions/workflow-monitor.ts`
|
|
112
|
-
- Test: `tests/extension/workflow-monitor/workflow-next-command.test.ts`
|
|
113
|
-
|
|
114
|
-
**Step 1: Write the helper module with pure functions**
|
|
115
|
-
|
|
116
|
-
Implement functions such as:
|
|
117
|
-
- `getImmediateNextPhase(currentPhase)`
|
|
118
|
-
- `validateWorkflowNextRequest(currentState, requestedPhase)`
|
|
119
|
-
- `deriveWorkflowHandoffState(currentState, requestedPhase)`
|
|
120
|
-
|
|
121
|
-
Behavior:
|
|
122
|
-
- require an existing current phase
|
|
123
|
-
- require current phase status to be exactly `complete`
|
|
124
|
-
- allow only the immediate next phase
|
|
125
|
-
- reject same/backward/direct-jump handoffs with precise messages
|
|
126
|
-
- derive workflow state with earlier phases `complete`, target `active`, later `pending`
|
|
127
|
-
- preserve earlier-phase artifacts and prompted flags
|
|
128
|
-
|
|
129
|
-
**Step 2: Update `/workflow-next` to use the helper and seed session state**
|
|
130
|
-
|
|
131
|
-
In `extensions/workflow-monitor.ts`:
|
|
132
|
-
- import the helper functions
|
|
133
|
-
- validate before calling `ctx.newSession(...)`
|
|
134
|
-
- use `ctx.newSession({ parentSession, setup })`
|
|
135
|
-
- inside `setup`, append a `superpowers_state` custom entry containing:
|
|
136
|
-
- derived `workflow`
|
|
137
|
-
- fresh `tdd` from `TDD_DEFAULTS`
|
|
138
|
-
- fresh `debug` from `DEBUG_DEFAULTS`
|
|
139
|
-
- fresh `verification` from `VERIFICATION_DEFAULTS`
|
|
140
|
-
- `savedAt: Date.now()`
|
|
141
|
-
- keep the editor prefill behavior unchanged
|
|
142
|
-
|
|
143
|
-
**Step 3: Run targeted tests**
|
|
144
|
-
|
|
145
|
-
Run: `npx vitest run tests/extension/workflow-monitor/workflow-next-command.test.ts`
|
|
146
|
-
Expected: PASS
|
|
147
|
-
|
|
148
|
-
**Step 4: Review for YAGNI and edge cases**
|
|
149
|
-
|
|
150
|
-
Verify:
|
|
151
|
-
- helper stays pure and focused
|
|
152
|
-
- no generic tracker semantics are changed outside `/workflow-next`
|
|
153
|
-
- invalid requests exit before session creation
|
|
154
|
-
|
|
155
|
-
**Step 5: Commit**
|
|
156
|
-
|
|
157
|
-
```bash
|
|
158
|
-
git add extensions/workflow-monitor/workflow-next-state.ts extensions/workflow-monitor.ts tests/extension/workflow-monitor/workflow-next-command.test.ts
|
|
159
|
-
git commit -m "feat: preserve workflow state across workflow-next"
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### Task 4: Implement state-file rename with legacy fallback
|
|
163
|
-
|
|
164
|
-
**Type:** code
|
|
165
|
-
**TDD scenario:** Modifying tested code — run existing tests first
|
|
166
|
-
|
|
167
|
-
**Files:**
|
|
168
|
-
- Modify: `extensions/workflow-monitor.ts`
|
|
169
|
-
- Test: `tests/extension/workflow-monitor/state-persistence.test.ts`
|
|
170
|
-
|
|
171
|
-
**Step 1: Update state file path helpers**
|
|
172
|
-
|
|
173
|
-
In `extensions/workflow-monitor.ts`:
|
|
174
|
-
- change `getStateFilePath()` to return `.pi/workflow-kit-state.json`
|
|
175
|
-
- add a legacy-path helper for `.pi/superpowers-state.json` if needed
|
|
176
|
-
- update `reconstructState()` to check new path first, then legacy path
|
|
177
|
-
|
|
178
|
-
**Step 2: Keep persistence write path singular**
|
|
179
|
-
|
|
180
|
-
Ensure `persistState()` writes only the new path and does not continue writing the legacy file.
|
|
181
|
-
|
|
182
|
-
**Step 3: Run targeted tests**
|
|
183
|
-
|
|
184
|
-
Run: `npx vitest run tests/extension/workflow-monitor/state-persistence.test.ts`
|
|
185
|
-
Expected: PASS
|
|
186
|
-
|
|
187
|
-
**Step 4: Verify no unintended regressions in reconstruction logic**
|
|
188
|
-
|
|
189
|
-
Confirm the existing session-entry reconstruction behavior still works when no file exists.
|
|
190
|
-
|
|
191
|
-
**Step 5: Commit**
|
|
192
|
-
|
|
193
|
-
```bash
|
|
194
|
-
git add extensions/workflow-monitor.ts tests/extension/workflow-monitor/state-persistence.test.ts
|
|
195
|
-
git commit -m "refactor: rename workflow state file"
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
### Task 5: Update user-facing docs for the new workflow-next contract
|
|
199
|
-
|
|
200
|
-
**Type:** non-code
|
|
201
|
-
|
|
202
|
-
**Files:**
|
|
203
|
-
- Modify: `README.md`
|
|
204
|
-
- Modify: `docs/developer-usage-guide.md`
|
|
205
|
-
- Modify: `docs/workflow-phases.md`
|
|
206
|
-
|
|
207
|
-
**Acceptance criteria:**
|
|
208
|
-
- Criterion 1: `/workflow-next` docs describe immediate-next-only handoff semantics.
|
|
209
|
-
- Criterion 2: docs mention that the command preserves prior completed workflow history for the same feature.
|
|
210
|
-
- Criterion 3: docs do not claim arbitrary phase jumps are supported.
|
|
211
|
-
|
|
212
|
-
**Implementation notes:**
|
|
213
|
-
- Keep examples aligned with allowed transitions only.
|
|
214
|
-
- Mention the stricter behavior near existing `/workflow-next` examples rather than adding a long new section.
|
|
215
|
-
- If the local state file is mentioned anywhere, rename it to `.pi/workflow-kit-state.json`.
|
|
216
|
-
|
|
217
|
-
**Verification:**
|
|
218
|
-
- Review each acceptance criterion one-by-one.
|
|
219
|
-
- Confirm wording matches the implemented behavior and test coverage.
|
|
220
|
-
|
|
221
|
-
### Task 6: Run focused verification and capture final status
|
|
222
|
-
|
|
223
|
-
**Type:** code
|
|
224
|
-
**TDD scenario:** Trivial change — use judgment
|
|
225
|
-
|
|
226
|
-
**Files:**
|
|
227
|
-
- Modify: `docs/plans/2026-04-09-workflow-next-handoff-state-implementation.md`
|
|
228
|
-
- Test: `tests/extension/workflow-monitor/workflow-next-command.test.ts`
|
|
229
|
-
- Test: `tests/extension/workflow-monitor/state-persistence.test.ts`
|
|
230
|
-
|
|
231
|
-
**Step 1: Run focused verification**
|
|
232
|
-
|
|
233
|
-
Run:
|
|
234
|
-
- `npx vitest run tests/extension/workflow-monitor/workflow-next-command.test.ts`
|
|
235
|
-
- `npx vitest run tests/extension/workflow-monitor/state-persistence.test.ts`
|
|
236
|
-
|
|
237
|
-
Expected: PASS
|
|
238
|
-
|
|
239
|
-
**Step 2: Run a broader confidence check**
|
|
240
|
-
|
|
241
|
-
Run: `npx vitest run tests/extension/workflow-monitor`
|
|
242
|
-
Expected: PASS
|
|
243
|
-
|
|
244
|
-
**Step 3: Update the implementation plan artifact with verification notes if useful**
|
|
245
|
-
|
|
246
|
-
Add a short note under the plan or in a small completion section summarizing which test commands passed.
|
|
247
|
-
|
|
248
|
-
**Step 4: Commit**
|
|
249
|
-
|
|
250
|
-
```bash
|
|
251
|
-
git add docs/plans/2026-04-09-workflow-next-handoff-state-implementation.md
|
|
252
|
-
git commit -m "test: verify workflow-next handoff changes"
|
|
253
|
-
```
|
package/extensions/constants.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared constants for pi-workflow-kit extensions.
|
|
3
|
-
*
|
|
4
|
-
* PLAN_TRACKER_TOOL_NAME is the stable integration contract between plan-tracker
|
|
5
|
-
* and workflow-monitor: when plan-tracker receives an "init" action,
|
|
6
|
-
* workflow-monitor observes it to advance the workflow phase to "execute".
|
|
7
|
-
* This tool id intentionally remains unchanged across the rebrand.
|
|
8
|
-
*/
|
|
9
|
-
export const PLAN_TRACKER_TOOL_NAME = "plan_tracker";
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Custom entry type written by workflow-monitor's /workflow-reset so that
|
|
13
|
-
* plan-tracker's reconstructState picks up an empty task list.
|
|
14
|
-
*/
|
|
15
|
-
export const PLAN_TRACKER_CLEARED_TYPE = "plan_tracker_cleared";
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* File-based logger for pi-workflow-kit.
|
|
3
|
-
*
|
|
4
|
-
* Default singleton writes to ~/.pi/logs/workflow-kit.log.
|
|
5
|
-
* Info/warn/error always write. Debug writes when PI_WORKFLOW_KIT_DEBUG=1.
|
|
6
|
-
* The legacy PI_SUPERPOWERS_DEBUG env var is also honored for compatibility.
|
|
7
|
-
* One-deep rotation when file exceeds 5 MB.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import * as fs from "node:fs";
|
|
11
|
-
import * as os from "node:os";
|
|
12
|
-
import * as path from "node:path";
|
|
13
|
-
|
|
14
|
-
export interface LoggerOptions {
|
|
15
|
-
verbose?: boolean;
|
|
16
|
-
maxSizeBytes?: number;
|
|
17
|
-
rotationCheckInterval?: number;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface Logger {
|
|
21
|
-
info(message: string): void;
|
|
22
|
-
warn(message: string): void;
|
|
23
|
-
error(message: string, err?: unknown): void;
|
|
24
|
-
debug(message: string): void;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const DEFAULT_MAX_SIZE = 5 * 1024 * 1024; // 5 MB
|
|
28
|
-
const DEFAULT_ROTATION_CHECK_INTERVAL = 60 * 60 * 1000; // 1 hour
|
|
29
|
-
export const MAX_MESSAGE_LENGTH = 10 * 1024; // 10 KB
|
|
30
|
-
const TRUNCATED_MARKER = "...(truncated)";
|
|
31
|
-
|
|
32
|
-
function formatError(err: unknown): string {
|
|
33
|
-
if (err instanceof Error) {
|
|
34
|
-
return err.stack ?? `${err.name}: ${err.message}`;
|
|
35
|
-
}
|
|
36
|
-
return String(err);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function timestamp(): string {
|
|
40
|
-
// Strip milliseconds + trailing Z so log lines stay compact and second-precision.
|
|
41
|
-
return new Date().toISOString().replace(/\.\d{3}Z$/, "");
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function truncateMessage(message: string): string {
|
|
45
|
-
if (message.length <= MAX_MESSAGE_LENGTH) return message;
|
|
46
|
-
return message.slice(0, MAX_MESSAGE_LENGTH - TRUNCATED_MARKER.length) + TRUNCATED_MARKER;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function createLogger(logPath: string, options?: LoggerOptions): Logger {
|
|
50
|
-
const verbose = options?.verbose ?? false;
|
|
51
|
-
const maxSizeBytes = options?.maxSizeBytes ?? DEFAULT_MAX_SIZE;
|
|
52
|
-
const rotationCheckInterval = options?.rotationCheckInterval ?? DEFAULT_ROTATION_CHECK_INTERVAL;
|
|
53
|
-
/** Timestamp (ms) of the last rotation size check. Re-checks after rotationCheckInterval. */
|
|
54
|
-
let lastRotationCheck = -Infinity;
|
|
55
|
-
/** Set after the first error is reported to stderr, to avoid spamming. */
|
|
56
|
-
let stderrFallbackFired = false;
|
|
57
|
-
|
|
58
|
-
function ensureDir(): void {
|
|
59
|
-
const dir = path.dirname(logPath);
|
|
60
|
-
if (!fs.existsSync(dir)) {
|
|
61
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Emit a one-time warning to stderr so the user knows logging is broken.
|
|
67
|
-
* Only fires once per logger instance to avoid spamming.
|
|
68
|
-
*/
|
|
69
|
-
function stderrFallback(context: string, err: unknown): void {
|
|
70
|
-
if (stderrFallbackFired) return;
|
|
71
|
-
stderrFallbackFired = true;
|
|
72
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
73
|
-
process.stderr.write(
|
|
74
|
-
`[pi-workflow-kit] Logger ${context} failed: ${detail}. Further log errors will be silenced.\n`,
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Rotate the log file if it exceeds maxSizeBytes.
|
|
80
|
-
* Re-checks at most once per rotationCheckInterval (default 1 hour)
|
|
81
|
-
* so long-running processes can still rotate without checking on every write.
|
|
82
|
-
*/
|
|
83
|
-
function rotateIfNeeded(): void {
|
|
84
|
-
const now = Date.now();
|
|
85
|
-
if (now - lastRotationCheck < rotationCheckInterval) return;
|
|
86
|
-
lastRotationCheck = now;
|
|
87
|
-
try {
|
|
88
|
-
const stat = fs.statSync(logPath);
|
|
89
|
-
if (stat.size > maxSizeBytes) {
|
|
90
|
-
fs.renameSync(logPath, `${logPath}.1`);
|
|
91
|
-
}
|
|
92
|
-
} catch (err) {
|
|
93
|
-
// File doesn't exist yet — nothing to rotate. But surface unexpected errors once.
|
|
94
|
-
if ((err as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
95
|
-
stderrFallback("rotation", err);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Append a log line to the file. Uses synchronous I/O for simplicity and ordering guarantees — acceptable for low-volume diagnostic logging.
|
|
102
|
-
*/
|
|
103
|
-
function write(level: string, message: string): void {
|
|
104
|
-
try {
|
|
105
|
-
ensureDir();
|
|
106
|
-
rotateIfNeeded();
|
|
107
|
-
const line = `${timestamp()} [${level}] ${truncateMessage(message)}\n`;
|
|
108
|
-
fs.appendFileSync(logPath, line, "utf-8");
|
|
109
|
-
} catch (err) {
|
|
110
|
-
// Logger must never crash the application, but surface the first failure.
|
|
111
|
-
stderrFallback("write", err);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return {
|
|
116
|
-
info(message: string): void {
|
|
117
|
-
write("INFO", message);
|
|
118
|
-
},
|
|
119
|
-
warn(message: string): void {
|
|
120
|
-
write("WARN", message);
|
|
121
|
-
},
|
|
122
|
-
error(message: string, err?: unknown): void {
|
|
123
|
-
const suffix = err ? ` — ${formatError(err)}` : "";
|
|
124
|
-
write("ERROR", message + suffix);
|
|
125
|
-
},
|
|
126
|
-
debug(message: string): void {
|
|
127
|
-
if (!verbose) return;
|
|
128
|
-
write("DEBUG", message);
|
|
129
|
-
},
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/** Default singleton logger used across all extensions. */
|
|
134
|
-
const LOG_PATH = path.join(os.homedir(), ".pi", "logs", "workflow-kit.log");
|
|
135
|
-
|
|
136
|
-
export const log: Logger = createLogger(LOG_PATH, {
|
|
137
|
-
verbose: process.env.PI_WORKFLOW_KIT_DEBUG === "1" || process.env.PI_SUPERPOWERS_DEBUG === "1",
|
|
138
|
-
});
|