@raquezha/notrace 0.0.5 → 0.0.6

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 (95) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +102 -55
  3. package/assets/notrace-logo.svg +20 -0
  4. package/assets/notrace-mark.svg +18 -0
  5. package/assets/notrace-wordmark.svg +4 -0
  6. package/dist/notrace/adapters.d.ts +32 -0
  7. package/dist/notrace/adapters.js +83 -0
  8. package/dist/notrace/index.d.ts +2 -0
  9. package/dist/notrace/index.js +295 -0
  10. package/dist/notrace/renderer.d.ts +4 -0
  11. package/dist/notrace/renderer.js +605 -0
  12. package/dist/notrace/types.d.ts +93 -0
  13. package/dist/notrace/types.js +1 -0
  14. package/extensions/notrace/adapters.ts +88 -0
  15. package/extensions/notrace/index.ts +359 -0
  16. package/extensions/notrace/renderer.ts +616 -0
  17. package/extensions/notrace/types.ts +108 -0
  18. package/package.json +4 -3
  19. package/templates/README.md +24 -0
  20. package/templates/dashboard.sample.html +361 -0
  21. package/templates/dashboard.sample.json +113 -0
  22. package/templates/notrace-logo.preview.png +0 -0
  23. package/templates/render-samples.mjs +44 -0
  24. package/templates/session.sample.html +431 -0
  25. package/templates/session.sample.json +127 -0
  26. package/templates/sessions/019ecec4-1c48-7b47-bdbf-cec3500978ed/notrace.html +313 -0
  27. package/templates/sessions/019ecec4-1c48-7b47-bdbf-cec3500978ed/notrace.json +129 -0
  28. package/templates/sessions/019ecfa1-7ac2-7c00-bbe9-541f37751201/notrace.html +313 -0
  29. package/templates/sessions/019ecfa1-7ac2-7c00-bbe9-541f37751201/notrace.json +129 -0
  30. package/templates/sessions/019ed2ee-1000-76ee-b353-000000000001/notrace.html +426 -0
  31. package/templates/sessions/019ed2ee-1000-76ee-b353-000000000001/notrace.json +134 -0
  32. package/templates/sessions/019ed2ee-1001-76ee-b353-000000000002/notrace.html +425 -0
  33. package/templates/sessions/019ed2ee-1001-76ee-b353-000000000002/notrace.json +133 -0
  34. package/templates/sessions/019ed2ee-1002-76ee-b353-000000000003/notrace.html +426 -0
  35. package/templates/sessions/019ed2ee-1002-76ee-b353-000000000003/notrace.json +134 -0
  36. package/templates/sessions/019ed2ee-1003-76ee-b353-000000000004/notrace.html +423 -0
  37. package/templates/sessions/019ed2ee-1003-76ee-b353-000000000004/notrace.json +130 -0
  38. package/templates/sessions/019ed2ee-1004-76ee-b353-000000000005/notrace.html +423 -0
  39. package/templates/sessions/019ed2ee-1004-76ee-b353-000000000005/notrace.json +130 -0
  40. package/templates/sessions/019ed2ee-1005-76ee-b353-000000000006/notrace.html +423 -0
  41. package/templates/sessions/019ed2ee-1005-76ee-b353-000000000006/notrace.json +130 -0
  42. package/templates/sessions/019ed2ee-1006-76ee-b353-000000000007/notrace.html +423 -0
  43. package/templates/sessions/019ed2ee-1006-76ee-b353-000000000007/notrace.json +130 -0
  44. package/templates/sessions/019ed2ee-1007-76ee-b353-000000000008/notrace.html +423 -0
  45. package/templates/sessions/019ed2ee-1007-76ee-b353-000000000008/notrace.json +130 -0
  46. package/templates/sessions/019ed2ee-1008-76ee-b353-000000000009/notrace.html +423 -0
  47. package/templates/sessions/019ed2ee-1008-76ee-b353-000000000009/notrace.json +130 -0
  48. package/templates/sessions/019ed2ee-1009-76ee-b353-000000000010/notrace.html +423 -0
  49. package/templates/sessions/019ed2ee-1009-76ee-b353-000000000010/notrace.json +130 -0
  50. package/templates/sessions/019ed2ee-1010-76ee-b353-000000000011/notrace.html +423 -0
  51. package/templates/sessions/019ed2ee-1010-76ee-b353-000000000011/notrace.json +130 -0
  52. package/templates/sessions/019ed2ee-1011-76ee-b353-000000000012/notrace.html +423 -0
  53. package/templates/sessions/019ed2ee-1011-76ee-b353-000000000012/notrace.json +130 -0
  54. package/templates/sessions/019ed2ee-1012-76ee-b353-000000000013/notrace.html +423 -0
  55. package/templates/sessions/019ed2ee-1012-76ee-b353-000000000013/notrace.json +130 -0
  56. package/templates/sessions/019ed2ee-1013-76ee-b353-000000000014/notrace.html +423 -0
  57. package/templates/sessions/019ed2ee-1013-76ee-b353-000000000014/notrace.json +130 -0
  58. package/templates/sessions/019ed2ee-1014-76ee-b353-000000000015/notrace.html +423 -0
  59. package/templates/sessions/019ed2ee-1014-76ee-b353-000000000015/notrace.json +130 -0
  60. package/templates/sessions/019ed2ee-1015-76ee-b353-000000000016/notrace.html +423 -0
  61. package/templates/sessions/019ed2ee-1015-76ee-b353-000000000016/notrace.json +130 -0
  62. package/templates/sessions/019ed2ee-1016-76ee-b353-000000000017/notrace.html +423 -0
  63. package/templates/sessions/019ed2ee-1016-76ee-b353-000000000017/notrace.json +130 -0
  64. package/templates/sessions/019ed2ee-1017-76ee-b353-000000000018/notrace.html +423 -0
  65. package/templates/sessions/019ed2ee-1017-76ee-b353-000000000018/notrace.json +130 -0
  66. package/templates/sessions/019ed2ee-1018-76ee-b353-000000000019/notrace.html +423 -0
  67. package/templates/sessions/019ed2ee-1018-76ee-b353-000000000019/notrace.json +130 -0
  68. package/templates/sessions/019ed2ee-1019-76ee-b353-000000000020/notrace.html +423 -0
  69. package/templates/sessions/019ed2ee-1019-76ee-b353-000000000020/notrace.json +130 -0
  70. package/templates/sessions/019ed2ee-1020-76ee-b353-000000000021/notrace.html +423 -0
  71. package/templates/sessions/019ed2ee-1020-76ee-b353-000000000021/notrace.json +130 -0
  72. package/templates/sessions/019ed2ee-1021-76ee-b353-000000000022/notrace.html +423 -0
  73. package/templates/sessions/019ed2ee-1021-76ee-b353-000000000022/notrace.json +130 -0
  74. package/templates/sessions/019ed2ee-1022-76ee-b353-000000000023/notrace.html +423 -0
  75. package/templates/sessions/019ed2ee-1022-76ee-b353-000000000023/notrace.json +130 -0
  76. package/templates/sessions/019ed2ee-1023-76ee-b353-000000000024/notrace.html +423 -0
  77. package/templates/sessions/019ed2ee-1023-76ee-b353-000000000024/notrace.json +130 -0
  78. package/templates/sessions/019ed2ee-1024-76ee-b353-000000000025/notrace.html +423 -0
  79. package/templates/sessions/019ed2ee-1024-76ee-b353-000000000025/notrace.json +130 -0
  80. package/templates/sessions/019ed2ee-1025-76ee-b353-000000000026/notrace.html +423 -0
  81. package/templates/sessions/019ed2ee-1025-76ee-b353-000000000026/notrace.json +130 -0
  82. package/templates/sessions/019ed2ee-1026-76ee-b353-000000000027/notrace.html +423 -0
  83. package/templates/sessions/019ed2ee-1026-76ee-b353-000000000027/notrace.json +130 -0
  84. package/templates/sessions/019ed2ee-1027-76ee-b353-000000000028/notrace.html +423 -0
  85. package/templates/sessions/019ed2ee-1027-76ee-b353-000000000028/notrace.json +130 -0
  86. package/templates/sessions/019ed2ee-1028-76ee-b353-000000000029/notrace.html +423 -0
  87. package/templates/sessions/019ed2ee-1028-76ee-b353-000000000029/notrace.json +130 -0
  88. package/templates/sessions/019ed2ee-1029-76ee-b353-000000000030/notrace.html +423 -0
  89. package/templates/sessions/019ed2ee-1029-76ee-b353-000000000030/notrace.json +130 -0
  90. package/templates/sessions/019ed2ee-5252-76ee-b353-ad925a6bad31/notrace.html +313 -0
  91. package/templates/sessions/019ed2ee-5252-76ee-b353-ad925a6bad31/notrace.json +129 -0
  92. package/tsconfig.json +1 -1
  93. package/dist/notrace.d.ts +0 -9
  94. package/dist/notrace.js +0 -914
  95. package/extensions/notrace.ts +0 -965
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @raquezha/notrace
2
2
 
3
+ ## 0.0.6
4
+
5
+ ### Patch Changes
6
+
7
+ - d349d36: Refresh the notrace UI and sample session rendering separately from the antigravity billing fix.
8
+ - 51fda83: fix: preserve assistant toolCall blocks in noheadroom compression and expose notrace failure metadata
9
+ - 7afa746: Package updates for antigravity, norpiv, and notrace.
10
+
3
11
  ## 0.0.5
4
12
 
5
13
  ### Patch Changes
package/README.md CHANGED
@@ -1,101 +1,148 @@
1
+ <p align="center">
2
+ <img src="./assets/notrace-logo.svg" alt="notrace logo" width="240" />
3
+ </p>
4
+
1
5
  # notrace
2
6
 
3
- Phase 0 / POC local-first trace capture for the Pi Coding Agent. It captures execution traces for workflow debugging — LLM calls, tool executions, token usage, costs — and writes both an interactive HTML report and a machine-readable `notrace.json` run record to your active task workspace at session end.
7
+ **Traces in, lessons out.**
4
8
 
5
- > **Security warning:** notrace is local-first and now redacts common secrets by default, escapes report rendering, blocks network access in generated reports, and writes private report files. Reports can still contain sensitive prompts, tool payloads, outputs, and local paths. Do not publish generated reports.
9
+ `notrace` is a local-first retrospective engine for the Pi Coding Agent.
10
+ It captures session evidence, writes a versioned `notrace.json` run record, renders a human-readable HTML report, and supports review/compare flows for workflow R&D.
6
11
 
7
- ## Boundary with RPIV
12
+ ## What notrace owns
8
13
 
9
- The relationship is intentionally optional both ways:
14
+ When enabled, `notrace` is the durable retrospective layer for a session.
15
+ It aggregates:
16
+ - core Pi session telemetry
17
+ - workflow/task context
18
+ - optional dynamic extension telemetry
10
19
 
11
- - **notrace without RPIV**: should work; notrace-owned artifacts belong under `.notrace/`
12
- - **RPIV without notrace**: should work; `WORK.md` remains the source of truth without any notrace dependency
13
- - **together**: RPIV `WORK.md [LOG]` may reference notrace artifacts, but `.workflow/` should not own them
20
+ Today, Pi is the first harness adapter.
21
+ The canonical run schema is designed so other harness adapters can be added later, but multi-harness support is not implemented in this package yet.
14
22
 
15
- Neither package should require the other to function.
23
+ ## What notrace does not own
16
24
 
17
- ## Features
25
+ `notrace` is **not**:
26
+ - the live Pi footer
27
+ - the Pi resume/session-switch UX
28
+ - a scraper of terminal status strings
18
29
 
19
- - **Session timeline**: Every turn, tool call, and LLM completion rendered as an expandable card
20
- - **Metrics dashboard**: Total tokens, input/output split, cache reads, cost (USD), duration
21
- - **Machine-readable run record**: Normalized `notrace.json` sidecar for future retrospective/compare flows
22
- - **Clickable `file://` links**: Artifact paths printed to console at session end for instant browser access
23
- - **Workdir aware**: notrace-owned artifacts are planned to live under `.notrace/` for the root execution directory
24
- - **RPIV attachment**: When a task has a `WORK.md`, notrace appends artifact/review references into `[LOG]`
25
- - **HTML report**: Self-contained/offline report with a restrictive CSP and no remote font/network loads
26
- - **Safer defaults**: Secret-key/value redaction, bounded payload sizes, metadata-only mode, private file permissions, and `.workflow`-confined artifact writes
30
+ Live footer output, resume hints, and extension footer badges may appear near `notrace` output during shutdown, but they are separate producers.
27
31
 
28
- ## Output
32
+ ## Retrospective spine
29
33
 
34
+ 1. **Capture evidence**: `notrace.json`
35
+ 2. **Inspect**: `notrace.html`
36
+ 3. **Review outcome**: `notrace.review.json`
37
+ 4. **Compare attempts**: `compare:notrace`
38
+
39
+ ## Storage
40
+
41
+ ```text
42
+ .notrace/
43
+ index.json
44
+ index.html
45
+ sessions/
46
+ <session-id>/
47
+ notrace.json
48
+ notrace.html
49
+ notrace.review.json
30
50
  ```
31
- 🔍 [notrace] Observability artifacts generated:
32
- 📂 file:///path/to/.notrace/sessions/<session-id>/notrace.html
33
- 📂 file:///path/to/.notrace/sessions/<session-id>/notrace.json
34
- ```
35
51
 
36
- ## Usage
52
+ ## Canonical run model
53
+
54
+ Generated `notrace.json` is the source of truth for runtime output, HTML rendering, and downstream tooling.
55
+ The record is versioned and centers on:
56
+ - `kind`
57
+ - `schemaVersion`
58
+ - `traceId`
59
+ - `repository`
60
+ - `session`
61
+ - `task`
62
+ - `captureMode`
63
+ - `conditions`
64
+ - `activity`
65
+ - `telemetry`
66
+ - `events`
67
+
68
+ Key rule:
69
+ - **consumed tokens** and **saved tokens** are separate metric families
70
+ - optimization telemetry belongs under `telemetry.extensions.*`
71
+ - presentation-only UI strings are not canonical evidence
72
+
73
+ ## Dynamic extension telemetry
74
+
75
+ `notrace` can include optional structured telemetry from dynamic extensions.
76
+ Current first target is `noheadroom`.
77
+
78
+ If an extension is absent, `notrace` should still succeed.
79
+ If an extension is present, it can contribute a structured summary such as:
80
+ - loaded / enabled / active state
81
+ - optimization attempts
82
+ - tokens saved
83
+ - last applied compression summary
84
+
85
+ ## Capture modes
86
+
87
+ Default capture mode is **full**.
37
88
 
38
89
  ```bash
39
- # Load directly
40
90
  pi --extension ./packages/notrace
41
-
42
- # Via nothing mindset (dev, rpiv)
43
- pi --dev
44
91
  ```
45
92
 
46
- ## NPM
93
+ Optional modes:
47
94
 
48
95
  ```bash
49
- npm install -g @raquezha/notrace
96
+ NOTRACE_CAPTURE=redacted pi --extension ./packages/notrace
97
+ NOTRACE_CAPTURE=metadata pi --extension ./packages/notrace
98
+ NOTRACE_CAPTURE=full pi --extension ./packages/notrace
50
99
  ```
51
100
 
52
- ## Add a human review
101
+ Mode meanings:
102
+ - `full`: full captured payloads; best for local debugging; highest sensitivity
103
+ - `redacted`: captured payloads with common secret-like values redacted
104
+ - `metadata`: minimal capture, no prompt/tool bodies
105
+
106
+ **Security warning:** even redacted reports can contain sensitive prompts, tool payloads, local paths, and outputs. Do not publish generated reports.
107
+
108
+ ## Review
53
109
 
54
110
  ```bash
55
- npm run review:notrace -- path/to/notrace.json \
111
+ npm run review:notrace -- \
112
+ .notrace/sessions/<id>/notrace.json \
56
113
  --outcome partial \
57
114
  --friction high \
58
115
  --lesson "Headroom reduced tokens but needed manual steering." \
59
116
  --next-change "Try same task with RepoScry enabled."
60
117
  ```
61
118
 
62
- This writes an adjacent review sidecar. For normal runs that means `notrace.review.json` next to `notrace.json`.
63
-
64
- If the run is attached to an RPIV task folder with `WORK.md`, the review is also logged into that task's `[LOG]` section as a reference to the notrace artifact.
65
-
66
119
  Review fields:
67
-
68
120
  - `outcome`: `success`, `partial`, `failed`, `abandoned`, `inconclusive`
69
121
  - `friction`: `low`, `medium`, `high`
70
- - `lesson`: short human conclusion
71
- - `nextChange`: what to try next run
122
+ - `lesson`
123
+ - `nextChange`
72
124
 
73
- ## Compare two runs
125
+ ## Compare
74
126
 
75
127
  ```bash
76
128
  npm run compare:notrace -- \
77
- path/to/baseline/notrace.json \
78
- path/to/candidate/notrace.json
129
+ .notrace/sessions/<baseline-id>/notrace.json \
130
+ .notrace/sessions/<candidate-id>/notrace.json
79
131
  ```
80
132
 
81
- This prints a small retrospective diff for:
133
+ ## Templates
82
134
 
83
- - total/input/output tokens
84
- - duration
85
- - LLM calls
86
- - tool calls
87
- - tool errors
88
- - total cost
89
- - model/provider mix
90
- - review sidecar outcome/friction/lesson when present
135
+ HTML source-of-truth lives in `templates/`:
136
+ - `dashboard.sample.json`
137
+ - `session.sample.json`
138
+ - `dashboard.sample.html`
139
+ - `session.sample.html`
91
140
 
92
- ## Capture controls
93
-
94
- By default, notrace uses `NOTRACE_CAPTURE=redacted`: it captures useful payloads but redacts common secret keys/values and truncates very large values.
141
+ Refresh previews after renderer changes:
95
142
 
96
143
  ```bash
97
- NOTRACE_CAPTURE=metadata pi --dev # no prompt/tool payload bodies
98
- NOTRACE_CAPTURE=full pi --dev # unsafe: raw payloads for local debugging only
144
+ cd packages/notrace
145
+ npm run render:samples
99
146
  ```
100
147
 
101
148
  ## Build
@@ -0,0 +1,20 @@
1
+ <svg viewBox="0 0 420 138" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="notrace">
2
+ <title>notrace logo</title>
3
+ <desc>Signal icon above and slightly overlapping the notrace wordmark.</desc>
4
+ <defs>
5
+ <linearGradient id="fadeGrad" x1="0%" y1="0%" x2="100%" y2="0%">
6
+ <stop offset="0%" stop-color="#E2754A"/>
7
+ <stop offset="100%" stop-color="#EDE2D2"/>
8
+ </linearGradient>
9
+ </defs>
10
+ <g id="trace-icon" transform="translate(1 -5) scale(0.93)">
11
+ <path d="M6,50 C16,18 26,18 36,50 C46,82 54,82 60,50 C64,30 68,30 71,50"
12
+ fill="none" stroke="url(#fadeGrad)" stroke-width="4" stroke-linecap="round"/>
13
+ <line x1="74" y1="50" x2="79" y2="50" stroke="#D9C9B5" stroke-width="4" stroke-linecap="round" stroke-opacity="0.6"/>
14
+ <circle cx="85" cy="50" r="2.2" fill="#D9C9B5" opacity="0.5"/>
15
+ <circle cx="90" cy="50" r="1.4" fill="#EDE2D2" opacity="0.32"/>
16
+ <circle cx="94" cy="50" r="0.9" fill="#EDE2D2" opacity="0.15"/>
17
+ </g>
18
+ <text x="0" y="114" fill="#ECE3DA" style="fill:#ECE3DA" font-family="Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif" font-size="96" font-weight="900" letter-spacing="-7">no</text>
19
+ <text x="82" y="114" fill="#D88462" font-family="Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif" font-size="96" font-weight="900" letter-spacing="-7">trace</text>
20
+ </svg>
@@ -0,0 +1,18 @@
1
+ <svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" role="img">
2
+ <title>notrace logo mark</title>
3
+ <desc>A wave that smooths into a flat line, then fades into dots — color shifts from trace orange to no cream as it dissolves.</desc>
4
+ <defs>
5
+ <linearGradient id="fadeGrad" x1="0%" y1="0%" x2="100%" y2="0%">
6
+ <stop offset="0%" stop-color="#E2754A"/>
7
+ <stop offset="100%" stop-color="#EDE2D2"/>
8
+ </linearGradient>
9
+ </defs>
10
+ <g id="trace-icon">
11
+ <path d="M6,50 C16,18 26,18 36,50 C46,82 54,82 60,50 C64,30 68,30 71,50"
12
+ fill="none" stroke="url(#fadeGrad)" stroke-width="4" stroke-linecap="round"/>
13
+ <line x1="74" y1="50" x2="79" y2="50" stroke="#D9C9B5" stroke-width="4" stroke-linecap="round" stroke-opacity="0.6"/>
14
+ <circle cx="85" cy="50" r="2.2" fill="#D9C9B5" opacity="0.5"/>
15
+ <circle cx="90" cy="50" r="1.4" fill="#EDE2D2" opacity="0.32"/>
16
+ <circle cx="94" cy="50" r="0.9" fill="#EDE2D2" opacity="0.15"/>
17
+ </g>
18
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg viewBox="0 0 420 96" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="notrace wordmark">
2
+ <text x="0" y="76" fill="#ECE3DA" font-family="Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif" font-size="96" font-weight="900" letter-spacing="-7">no</text>
3
+ <text x="82" y="76" fill="#D88462" font-family="Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif" font-size="96" font-weight="900" letter-spacing="-7">trace</text>
4
+ </svg>
@@ -0,0 +1,32 @@
1
+ import type { WorkflowContext } from "./types.js";
2
+ export interface WorkflowAdapter {
3
+ name: string;
4
+ detect(cwd: string): boolean;
5
+ getContext(cwd: string): WorkflowContext | null;
6
+ attach(context: WorkflowContext, artifacts: {
7
+ html: string;
8
+ record: string;
9
+ }): void;
10
+ }
11
+ export declare class NorpivAdapter implements WorkflowAdapter {
12
+ name: string;
13
+ detect(cwd: string): boolean;
14
+ getContext(cwd: string): WorkflowContext | null;
15
+ attach(context: WorkflowContext, artifacts: {
16
+ html: string;
17
+ record: string;
18
+ }): void;
19
+ }
20
+ export declare class ResearchAdapter implements WorkflowAdapter {
21
+ name: string;
22
+ detect(cwd: string): boolean;
23
+ getContext(cwd: string): WorkflowContext | null;
24
+ attach(): void;
25
+ }
26
+ export declare class GenericAdapter implements WorkflowAdapter {
27
+ name: string;
28
+ detect(): boolean;
29
+ getContext(): null;
30
+ attach(): void;
31
+ }
32
+ export declare function getActiveAdapter(cwd: string): WorkflowAdapter;
@@ -0,0 +1,83 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import * as path from "node:path";
3
+ function appendWorkLogEntry(taskDir, message) {
4
+ const workMd = path.join(taskDir, "WORK.md");
5
+ if (!existsSync(workMd))
6
+ return;
7
+ try {
8
+ const text = readFileSync(workMd, "utf-8");
9
+ const entry = `- ${new Date().toISOString()}: ${message}`;
10
+ if (!/^(## )?\[LOG\]\s*$/m.test(text)) {
11
+ writeFileSync(workMd, `${text.trimEnd()}\n\n## [LOG]\n${entry}\n`);
12
+ return;
13
+ }
14
+ const lines = text.split("\n");
15
+ const logIndex = lines.findIndex(l => /^(## )?\[LOG\]\s*$/.test(l));
16
+ let nextSection = lines.length;
17
+ for (let i = logIndex + 1; i < lines.length; i++) {
18
+ if (/^(## )?\[[A-Z0-9_-]+\]\s*$/.test(lines[i])) {
19
+ nextSection = i;
20
+ break;
21
+ }
22
+ }
23
+ const before = lines.slice(0, nextSection);
24
+ const after = lines.slice(nextSection);
25
+ before.push(entry);
26
+ writeFileSync(workMd, `${before.join("\n")}\n${after.join("\n")}`);
27
+ }
28
+ catch { }
29
+ }
30
+ export class NorpivAdapter {
31
+ name = "norpiv";
32
+ detect(cwd) {
33
+ return existsSync(path.join(cwd, ".workflow", "active_task.json"));
34
+ }
35
+ getContext(cwd) {
36
+ try {
37
+ const workflowDir = path.join(cwd, ".workflow");
38
+ const content = JSON.parse(readFileSync(path.join(workflowDir, "active_task.json"), "utf-8"));
39
+ const taskPath = content.taskPath || (content.active_task ? path.join("tasks", content.active_task) : null);
40
+ return {
41
+ workflow: this.name,
42
+ taskId: content.active_task || "unknown",
43
+ taskPath,
44
+ taskDir: taskPath ? path.resolve(cwd, taskPath) : null
45
+ };
46
+ }
47
+ catch {
48
+ return null;
49
+ }
50
+ }
51
+ attach(context, artifacts) {
52
+ if (!context.taskDir)
53
+ return;
54
+ appendWorkLogEntry(context.taskDir, `notrace retrospective: ${artifacts.html}`);
55
+ }
56
+ }
57
+ export class ResearchAdapter {
58
+ name = "research";
59
+ detect(cwd) {
60
+ return existsSync(path.join(cwd, ".git")) && !existsSync(path.join(cwd, ".workflow", "active_task.json"));
61
+ }
62
+ getContext(cwd) {
63
+ try {
64
+ const head = readFileSync(path.join(cwd, ".git", "HEAD"), "utf-8");
65
+ const branch = head.split("refs/heads/")[1]?.trim() || "main";
66
+ return { workflow: this.name, taskId: `branch:${branch}`, taskPath: null, taskDir: null };
67
+ }
68
+ catch {
69
+ return null;
70
+ }
71
+ }
72
+ attach() { }
73
+ }
74
+ export class GenericAdapter {
75
+ name = "generic";
76
+ detect() { return true; }
77
+ getContext() { return null; }
78
+ attach() { }
79
+ }
80
+ const ADAPTERS = [new NorpivAdapter(), new ResearchAdapter(), new GenericAdapter()];
81
+ export function getActiveAdapter(cwd) {
82
+ return ADAPTERS.find(a => a.detect(cwd)) || new GenericAdapter();
83
+ }
@@ -0,0 +1,2 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ export default function (pi: ExtensionAPI): void;