pi-jscpd 0.1.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 +99 -0
- package/CONTRIBUTING.md +144 -0
- package/LICENSE +21 -0
- package/README.md +231 -0
- package/SECURITY.md +93 -0
- package/docs/automatic-checkpoint.md +235 -0
- package/docs/compatibility.md +119 -0
- package/docs/effect-architecture.md +128 -0
- package/docs/fallow-coexistence.md +120 -0
- package/docs/overlay-interaction.md +347 -0
- package/docs/release.md +115 -0
- package/package.json +86 -0
- package/scripts/check-compatibility.mjs +103 -0
- package/skills/jscpd/SKILL.md +90 -0
- package/src/acknowledgements.ts +268 -0
- package/src/automatic.ts +396 -0
- package/src/baseline.ts +400 -0
- package/src/capability.ts +569 -0
- package/src/changed-files.ts +372 -0
- package/src/changed.ts +548 -0
- package/src/clone-identity.ts +373 -0
- package/src/config.ts +414 -0
- package/src/contract.ts +39 -0
- package/src/dispatch.ts +90 -0
- package/src/effect/clock.ts +10 -0
- package/src/effect/errors.ts +311 -0
- package/src/effect/filesystem.ts +240 -0
- package/src/effect/runtime-boundary.ts +25 -0
- package/src/effect/runtime-contract.ts +18 -0
- package/src/effect/services.ts +131 -0
- package/src/extension.ts +708 -0
- package/src/fallow.ts +479 -0
- package/src/finding-presentation.ts +73 -0
- package/src/index.ts +8 -0
- package/src/jscpd-report.ts +819 -0
- package/src/jscpd.ts +748 -0
- package/src/overlay.ts +1166 -0
- package/src/parser.ts +189 -0
- package/src/path-utils.ts +44 -0
- package/src/presentation.ts +232 -0
- package/src/process.ts +425 -0
- package/src/registry.ts +102 -0
- package/src/scan.ts +441 -0
- package/src/scheduler.ts +434 -0
- package/src/session-state.ts +229 -0
- package/src/status.ts +534 -0
- package/src/types.ts +334 -0
- package/src/value-utils.ts +14 -0
- package/src/verification.ts +220 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# Automatic advisory checkpoint decision
|
|
2
|
+
|
|
3
|
+
Status: **implemented with Effect-owned scheduling and automatic delivery**
|
|
4
|
+
|
|
5
|
+
Scope: lifecycle and process model
|
|
6
|
+
|
|
7
|
+
The completed Effect source migration preserves this trigger, generation,
|
|
8
|
+
quiet-delivery, cancellation, and shutdown contract. Scheduling/background work
|
|
9
|
+
uses scoped fibers and Effect transactions, application workflows compose native
|
|
10
|
+
programs, and Pi host adapters use one managed runtime.
|
|
11
|
+
|
|
12
|
+
## Decision
|
|
13
|
+
|
|
14
|
+
Use Pi's `agent_settled` event as the only automatic-checkpoint eligibility
|
|
15
|
+
signal. The handler must enqueue at most one generation-bound background check
|
|
16
|
+
and return immediately; it must not await a jscpd process.
|
|
17
|
+
|
|
18
|
+
Successful built-in `write` and `edit` results continue to mark the session
|
|
19
|
+
changed and increment a mutation generation. They do not start scans. At
|
|
20
|
+
`agent_settled`, the scheduler may start one check only when all of these remain
|
|
21
|
+
true:
|
|
22
|
+
|
|
23
|
+
- the session is enabled and trusted configuration has been restored;
|
|
24
|
+
- at least one attributable mutation is newer than the last terminal automatic
|
|
25
|
+
attempt;
|
|
26
|
+
- the pre-session baseline is accepted;
|
|
27
|
+
- no automatic check already owns that mutation generation; and
|
|
28
|
+
- the extension runtime is still active and Pi is idle.
|
|
29
|
+
|
|
30
|
+
This makes the checkpoint **settled-triggered, dirty-coalesced, asynchronous,
|
|
31
|
+
and latest-generation-only**. Multiple writes in one agent run produce one
|
|
32
|
+
candidate check, not one process per write or model turn.
|
|
33
|
+
|
|
34
|
+
## Evidence
|
|
35
|
+
|
|
36
|
+
The decision was evaluated against Pi 0.84.4's installed extension
|
|
37
|
+
documentation, public type definitions, and `AgentSession` runtime.
|
|
38
|
+
|
|
39
|
+
Pi documents and types distinguish the candidate events as follows:
|
|
40
|
+
|
|
41
|
+
- `tool_result` occurs after each tool execution and can interleave for parallel
|
|
42
|
+
tools.
|
|
43
|
+
- `turn_end` occurs after one assistant response and its tool results; another
|
|
44
|
+
model/tool turn may start immediately.
|
|
45
|
+
- `agent_end` ends one low-level agent run, but retry, automatic compaction, or a
|
|
46
|
+
queued continuation may still follow.
|
|
47
|
+
- `agent_settled` occurs only after retry, compaction retry, and queued steering
|
|
48
|
+
or follow-up work are exhausted.
|
|
49
|
+
- `session_shutdown` is the teardown boundary for quit, reload, new, resume, and
|
|
50
|
+
fork flows.
|
|
51
|
+
|
|
52
|
+
The installed `AgentSession` runtime drains post-run retries, compaction, and
|
|
53
|
+
queued messages before emitting `agent_settled`. Extension handlers are awaited,
|
|
54
|
+
so doing the scan directly in the handler would extend prompt settlement by as
|
|
55
|
+
much as the configured scan timeout. The handler therefore only schedules
|
|
56
|
+
owned background work and returns.
|
|
57
|
+
|
|
58
|
+
### Trigger cardinality
|
|
59
|
+
|
|
60
|
+
For one logical user request with `W` successful attributable writes, `T` model
|
|
61
|
+
turns, and `R` low-level runs caused by retry/compaction/queued continuations:
|
|
62
|
+
|
|
63
|
+
| Candidate | Trigger opportunities | Settled tree? | Result |
|
|
64
|
+
| --- | ---: | --- | --- |
|
|
65
|
+
| `tool_result` | `W` | No | Reject: scan stampede and parallel-tool races |
|
|
66
|
+
| `message_end` | user, assistant, and tool-result messages | No | Reject: noisy and not mutation-specific |
|
|
67
|
+
| `turn_end` | `T` | No | Reject: can delay or race the next model turn |
|
|
68
|
+
| `agent_end` | `R` | No | Reject: follow-ups and recovery may still mutate files |
|
|
69
|
+
| `agent_settled` | 1 after the logical run settles | Yes | **Select as eligibility signal** |
|
|
70
|
+
| next `before_agent_start` | 1 per later prompt | Previous run only | Reject as primary: delays the next user request |
|
|
71
|
+
| idle/debounce timer | timing-dependent | Not guaranteed | Reject: duplicates Pi's settled lifecycle and adds timer races |
|
|
72
|
+
| `session_shutdown` | 1 per teardown | Yes | Reject as scan trigger: too late to advise and conflicts with cleanup |
|
|
73
|
+
|
|
74
|
+
`agent_settled` gives the lowest safe trigger cardinality. A dirty generation is
|
|
75
|
+
still required because settled can occur after read-only work and because
|
|
76
|
+
automatic work may be cancelled and retried later.
|
|
77
|
+
|
|
78
|
+
## Runtime process model
|
|
79
|
+
|
|
80
|
+
### While Pi is active
|
|
81
|
+
|
|
82
|
+
1. A successful verified built-in mutation records its canonical project path,
|
|
83
|
+
invalidates acknowledgements touching that path, increments the mutation
|
|
84
|
+
generation, and marks automatic work dirty.
|
|
85
|
+
2. No automatic scan runs during assistant streaming, tool execution, retries,
|
|
86
|
+
compaction recovery, steering, or queued follow-ups.
|
|
87
|
+
3. `agent_settled` asks the scheduler to cover the latest dirty generation and
|
|
88
|
+
returns immediately.
|
|
89
|
+
4. The scheduler reuses the existing bounded capability probe, accepted
|
|
90
|
+
baseline, full-project changed comparison, one serialized jscpd adapter, and
|
|
91
|
+
temporary-report ownership.
|
|
92
|
+
5. A completion is accepted only if its runtime generation, branch scope,
|
|
93
|
+
mutation generation, and project identity are still current.
|
|
94
|
+
6. Record a current terminal outcome—clean, findings, unavailable, timed out, or
|
|
95
|
+
failed—as the automatic attempt for the covered generation. Do not retry the
|
|
96
|
+
same unchanged generation after every later read-only prompt. Cancellation,
|
|
97
|
+
supersession, or a stale completion does not consume the generation; a newer
|
|
98
|
+
attributable mutation always becomes eligible.
|
|
99
|
+
|
|
100
|
+
No interval, filesystem watcher, long-lived jscpd server, or process starts from
|
|
101
|
+
the extension factory.
|
|
102
|
+
|
|
103
|
+
### A new run during a background check
|
|
104
|
+
|
|
105
|
+
A new accepted prompt or agent run supersedes an automatic check. Abort its
|
|
106
|
+
owned signal, leave that generation unattempted, and discard any late completion.
|
|
107
|
+
Cancellation should be requested before the new run can mutate files; cleanup
|
|
108
|
+
may finish through the serialized adapter without blocking the prompt.
|
|
109
|
+
|
|
110
|
+
Explicit `/jscpd` and `jscpd_run` operations also take priority over automatic
|
|
111
|
+
work. They may cancel the automatic owner and then use the same serialized
|
|
112
|
+
adapter. The automatic scheduler must never create a second process owner.
|
|
113
|
+
|
|
114
|
+
### Queued steering and follow-ups
|
|
115
|
+
|
|
116
|
+
Do nothing at intermediate `agent_end` events. Pi drains automatic retries,
|
|
117
|
+
automatic compaction retries, steering, and follow-up messages before
|
|
118
|
+
`agent_settled`, so all attributable mutations from that logical run coalesce
|
|
119
|
+
into the same latest dirty generation. Follow-up delivery mode does not create
|
|
120
|
+
an extra checkpoint between queued tasks.
|
|
121
|
+
|
|
122
|
+
### Reload, session replacement, branch navigation, and shutdown
|
|
123
|
+
|
|
124
|
+
- On reload, new, resume, or fork shutdown: close the scheduler first, abort its
|
|
125
|
+
owned check, invalidate queued work, and await existing adapter cleanup. The
|
|
126
|
+
replacement runtime restores only its active-branch state and creates a new
|
|
127
|
+
scheduler generation.
|
|
128
|
+
- On `/tree` navigation: invalidate automatic work before restoring the target
|
|
129
|
+
branch. A completion from the abandoned branch must never update or
|
|
130
|
+
acknowledge the target branch.
|
|
131
|
+
- On quit: cancel and clean up only. Never start a final scan from
|
|
132
|
+
`session_shutdown`.
|
|
133
|
+
- Shutdown remains idempotent and bounded by the existing child-process
|
|
134
|
+
termination and cleanup model.
|
|
135
|
+
|
|
136
|
+
## Context and presentation policy
|
|
137
|
+
|
|
138
|
+
A clean automatic check must not call `pi.sendMessage()` and must not append a
|
|
139
|
+
message entry. It may update bounded internal session state and terminal status,
|
|
140
|
+
which stay outside model context.
|
|
141
|
+
|
|
142
|
+
A failed automatic check is also quiet by default. `/jscpd status` remains the
|
|
143
|
+
place to inspect bounded failure state; missing binaries stay dormant rather
|
|
144
|
+
than producing one warning per settled run.
|
|
145
|
+
|
|
146
|
+
For a new actionable finding, append one bounded custom finding message while
|
|
147
|
+
Pi is still idle with `triggerTurn: false`. Pi persists that message and includes
|
|
148
|
+
it in the next model context without starting a surprise LLM turn. It may also
|
|
149
|
+
be displayed immediately by supported UI modes. Before appending, recheck the
|
|
150
|
+
runtime, branch, mutation generation, and idle state; otherwise discard the
|
|
151
|
+
completion and keep the generation dirty.
|
|
152
|
+
|
|
153
|
+
Automatic acknowledgement must happen only after that durable finding message
|
|
154
|
+
is successfully appended. The explicit changed executor's current
|
|
155
|
+
"acknowledge on presentation" side effect therefore must not be reused blindly
|
|
156
|
+
by a background scheduler. Omitted findings remain unacknowledged.
|
|
157
|
+
|
|
158
|
+
## Rejected alternatives
|
|
159
|
+
|
|
160
|
+
### Scan on every successful write/edit result
|
|
161
|
+
|
|
162
|
+
This has the best proximity to a mutation but the worst multiplicity. Parallel
|
|
163
|
+
or rapid tool batches can request overlapping scans while the agent is still
|
|
164
|
+
working, and the result can become stale before it is presented.
|
|
165
|
+
|
|
166
|
+
### Scan at every turn end
|
|
167
|
+
|
|
168
|
+
A tool-using response can have many turns. Waiting in `turn_end` adds scan
|
|
169
|
+
latency directly between model turns; detaching the work introduces races with
|
|
170
|
+
the next tool batch. Dirty coalescing does not make an unsettled tree safe.
|
|
171
|
+
|
|
172
|
+
### Scan at agent end
|
|
173
|
+
|
|
174
|
+
`agent_end` is not a logical idle boundary. Pi may retry a provider error,
|
|
175
|
+
compact and retry, or continue queued messages after it. Triggering there can
|
|
176
|
+
scan intermediate source and duplicate work.
|
|
177
|
+
|
|
178
|
+
### Scan before the next user prompt
|
|
179
|
+
|
|
180
|
+
This sees the previous tree at rest but makes the user pay the full checkpoint
|
|
181
|
+
latency before work starts, and no check occurs if the session ends. It remains
|
|
182
|
+
a cancellation boundary, not the primary trigger.
|
|
183
|
+
|
|
184
|
+
### Debounce timer after mutation
|
|
185
|
+
|
|
186
|
+
A timer guesses idleness and must race streaming, queued messages, session
|
|
187
|
+
replacement, and process cleanup. Pi already exposes the stronger settled
|
|
188
|
+
signal, so an additional wall-clock debounce adds complexity without a better
|
|
189
|
+
safety guarantee.
|
|
190
|
+
|
|
191
|
+
### Scan during shutdown
|
|
192
|
+
|
|
193
|
+
The result has no reliable advisory destination, can prolong exit, and opposes
|
|
194
|
+
the invariant that shutdown only cancels and cleans owned work.
|
|
195
|
+
|
|
196
|
+
## Implementation boundary
|
|
197
|
+
|
|
198
|
+
M4.2 adds the bounded scheduler primitive: attributable mutations advance a
|
|
199
|
+
generation, repeated automatic requests coalesce to one active plus one latest
|
|
200
|
+
pending generation, explicit scans cancel only automatic ownership, deferred
|
|
201
|
+
completions remain retryable, and reset or shutdown rejects stale work.
|
|
202
|
+
|
|
203
|
+
M4.3 wires `agent_settled` to a detached automatic changed check. It reuses the
|
|
204
|
+
configured capability, baseline, timeout, finding cap, changed-file set, and
|
|
205
|
+
serialized adapter; cancellation or baseline-pending outcomes remain retryable,
|
|
206
|
+
while other terminal failures are consumed once per unchanged generation.
|
|
207
|
+
Lifecycle transitions cancel owned work and shutdown awaits bounded adapter
|
|
208
|
+
cleanup. Automatic findings are deliberately not acknowledged or injected yet.
|
|
209
|
+
|
|
210
|
+
M4.4 implements the presentation boundary. Automatic checks cap delivery at
|
|
211
|
+
five findings, prioritize groups whose two locations changed in the session,
|
|
212
|
+
and preserve deterministic size/location ordering within that priority. Clean
|
|
213
|
+
and failed outcomes update only bounded session/footer status. A current
|
|
214
|
+
finding result sends one custom message with `triggerTurn: false`, then commits
|
|
215
|
+
only the delivered acknowledgement identities; omitted findings remain
|
|
216
|
+
eligible. Non-TUI mode uses the same model-context message with transcript
|
|
217
|
+
display disabled. Delivery failure, queued work, a newer mutation, or a stale
|
|
218
|
+
lifecycle scope leaves the generation retryable without acknowledging it.
|
|
219
|
+
|
|
220
|
+
M7.5 replaces the scheduler's mutable Promise/microtask owner with scoped Effect
|
|
221
|
+
fibers, composes automatic checks directly through the scheduler's native Effect
|
|
222
|
+
path, and moves acknowledgement staging plus Pi delivery ordering to Effect. M7.7
|
|
223
|
+
supplies the managed host runtime, and M7.8 removes obsolete facade paths. See
|
|
224
|
+
[Effect architecture and conformance](effect-architecture.md).
|
|
225
|
+
|
|
226
|
+
Focused tests cover coalescing, scheduler freshness, clean and failure status,
|
|
227
|
+
bounded finding delivery, repeated-finding suppression, non-TUI behavior,
|
|
228
|
+
scoped interruption, and acknowledgement-after-delivery ordering.
|
|
229
|
+
|
|
230
|
+
M6 must pin a Pi compatibility range that includes the documented
|
|
231
|
+
`agent_settled` contract. If that contract is unavailable or changes, remain
|
|
232
|
+
on-demand and revisit this decision; do not silently fall back to `agent_end`.
|
|
233
|
+
|
|
234
|
+
The lifecycle decision adds no separate configuration and does not change the
|
|
235
|
+
public command/tool contract.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Compatibility policy
|
|
2
|
+
|
|
3
|
+
`pi-jscpd` deliberately has a narrow, tested host contract. The package uses
|
|
4
|
+
Pi's extension, event, tool, custom-message, and TUI APIs directly, so an open
|
|
5
|
+
peer range would imply compatibility that has not been verified.
|
|
6
|
+
|
|
7
|
+
## Package identity and ownership
|
|
8
|
+
|
|
9
|
+
The canonical package name is **`pi-jscpd`**. The source and package metadata are
|
|
10
|
+
owned and maintained by [Revaz Zakalashvili](https://github.com/revazi) at
|
|
11
|
+
[`revazi/pi-jscpd`](https://github.com/revazi/pi-jscpd). A public npm lookup
|
|
12
|
+
returned no existing package when this name was selected, but a lookup does not
|
|
13
|
+
reserve a name.
|
|
14
|
+
|
|
15
|
+
The first supported release is `0.1.0`. The completed runtime design is
|
|
16
|
+
documented in [Effect architecture and conformance](effect-architecture.md).
|
|
17
|
+
The manual readiness workflow has no publication permission or credentials;
|
|
18
|
+
tagged publication is handled separately by the protected release workflow. The
|
|
19
|
+
source and package are MIT licensed; see the [release policy](release.md).
|
|
20
|
+
|
|
21
|
+
## Supported and tested matrix
|
|
22
|
+
|
|
23
|
+
| Component | Supported range | Tested fixture | Notes |
|
|
24
|
+
| --- | --- | --- | --- |
|
|
25
|
+
| Node.js | `>=22.19.0 <23 || >=24 <25` | `22.19.0`, `24.12.0` | Node 22.19.0 is Pi 0.84.4's minimum; Node 24 is the second supported LTS line. |
|
|
26
|
+
| `@earendil-works/pi-coding-agent` | `>=0.84.4 <0.85.0` | `0.84.4` | The supported 0.84 patch line only. |
|
|
27
|
+
| `@earendil-works/pi-ai` | `>=0.84.4 <0.85.0` | `0.84.4` | Kept on the same tested Pi release line. |
|
|
28
|
+
| `@earendil-works/pi-tui` | `>=0.84.4 <0.85.0` | `0.84.4` | Required by the interactive overlay. |
|
|
29
|
+
| `typebox` | `>=1.3.7 <2` | `1.3.7` | Required by the agent-tool schema. |
|
|
30
|
+
| `effect` | Exact `3.22.1` | `3.22.1` | Reviewed MIT runtime for scoped process/analyzer, bounded-filesystem, lifecycle domain-state, scheduling, automatic delivery, application workflows, and the single managed Pi runtime. |
|
|
31
|
+
| `jscpd` | Compatible v5 | `5.1.2` | Exact runtime dependency and fallback analyzer. |
|
|
32
|
+
|
|
33
|
+
Effect `3.22.1` was the npm registry's current stable 3.x release when foundation
|
|
34
|
+
issue [#64](https://github.com/revazi/pi-jscpd/issues/64) selected it. Installed
|
|
35
|
+
package metadata confirms its MIT license, and the lockfile preserves the
|
|
36
|
+
reviewed registry integrity. See
|
|
37
|
+
[Effect architecture and conformance](effect-architecture.md) for dependency,
|
|
38
|
+
service/error, resource, and runtime-boundary policy. No open range or automatic upgrade is implied.
|
|
39
|
+
|
|
40
|
+
The Pi and TypeBox packages remain peer dependencies so the extension uses the
|
|
41
|
+
host Pi installation instead of bundling a second runtime. Development
|
|
42
|
+
dependencies pin the exact tested fixtures. Effect and jscpd are normal, exact
|
|
43
|
+
runtime dependencies; installing `pi-jscpd` provides the reviewed composition
|
|
44
|
+
foundation and analyzer without a later network request.
|
|
45
|
+
`npm run compatibility:check` verifies the active Node version, peer ranges,
|
|
46
|
+
aligned Pi fixture versions, installed fixture versions, locked Effect metadata
|
|
47
|
+
and integrity, and the pinned jscpd runtime before type checking and tests.
|
|
48
|
+
|
|
49
|
+
The supported ranges cover the Node 22 and 24 LTS lines, not the intervening
|
|
50
|
+
non-LTS Node 23 line. They are a contract, not a claim that every patch
|
|
51
|
+
combination was run separately. The minimum Node release and the current Node 24 fixture receive
|
|
52
|
+
the full project check; Pi 0.84.4 is the API fixture. A future Pi `0.85` release,
|
|
53
|
+
Node 25 release, or TypeBox 2 release requires an explicit compatibility review
|
|
54
|
+
and range update rather than being accepted automatically.
|
|
55
|
+
|
|
56
|
+
## Packed-artifact certification
|
|
57
|
+
|
|
58
|
+
`npm run pack:certify` tests the artifact that would be published, not the source
|
|
59
|
+
checkout alone. Its disposable install resolves the exact declared jscpd version
|
|
60
|
+
through npm just as a user installation would; runtime checks remain offline. It:
|
|
61
|
+
|
|
62
|
+
- compares `npm pack --json` output with the complete tracked runtime, license,
|
|
63
|
+
and public-document allowlist, including regular-file modes and unsafe/private
|
|
64
|
+
path rejection;
|
|
65
|
+
- installs that exact tarball with lifecycle scripts disabled in a restrictive
|
|
66
|
+
disposable location and verifies exact, importable Effect `3.22.1` plus jscpd
|
|
67
|
+
`5.1.2` dependencies;
|
|
68
|
+
- uses the locked Pi `0.84.4` CLI with isolated home, agent, session, and
|
|
69
|
+
temporary directories and only the explicit installed package enabled;
|
|
70
|
+
- verifies that Pi discovers exactly one packaged `/skill:jscpd`, then verifies
|
|
71
|
+
`/jscpd` discovery and provider-free help/status behavior through RPC,
|
|
72
|
+
exercises the registered `jscpd_run` contract, Effect-owned analyzer resources,
|
|
73
|
+
and installed overlay component, proves the installed artifact resolves and
|
|
74
|
+
probes bundled jscpd `5.1.2`, and
|
|
75
|
+
checks JSON, print, and non-TUI fallback paths; and
|
|
76
|
+
- separately places a deterministic fake jscpd v5 executable on the disposable
|
|
77
|
+
`PATH`, then stops Pi during an active scan and asserts that the process tree
|
|
78
|
+
and every `pi-jscpd-*` report directory are gone.
|
|
79
|
+
|
|
80
|
+
The generated probe and fake executable remain certification fixtures for
|
|
81
|
+
controlled output and process-tree behavior; the bundled capability check runs
|
|
82
|
+
the real pinned jscpd release. CI runs this certification on both supported Node
|
|
83
|
+
fixtures. The certification script itself is development tooling and is
|
|
84
|
+
deliberately excluded from the publishable file allowlist.
|
|
85
|
+
|
|
86
|
+
## Unsupported-version behavior
|
|
87
|
+
|
|
88
|
+
- npm uses `engines.node` and peer dependency ranges during installation. Based
|
|
89
|
+
on the user's npm configuration, an unsupported Node or peer version may
|
|
90
|
+
produce a warning or reject dependency resolution.
|
|
91
|
+
- The extension does not add a second runtime version detector or compatibility
|
|
92
|
+
shim. A forced install outside the declared ranges is unsupported and may fail
|
|
93
|
+
to load if Pi's API or Node's runtime behavior changed.
|
|
94
|
+
- Once the extension loads on a supported host, its ordinary operational errors
|
|
95
|
+
remain advisory and fail open. That runtime policy does not turn an
|
|
96
|
+
unsupported host into a supported one.
|
|
97
|
+
- The adapter first checks compatible project-local and `PATH` installations,
|
|
98
|
+
then falls back to the package-owned jscpd `5.1.2` dependency. A missing or
|
|
99
|
+
damaged bundled dependency is reported without breaking the Pi session; the
|
|
100
|
+
extension never invokes `npx` or downloads an analyzer at runtime.
|
|
101
|
+
|
|
102
|
+
## Updating compatibility
|
|
103
|
+
|
|
104
|
+
A support-range or Effect-runtime change must:
|
|
105
|
+
|
|
106
|
+
1. update `engines`, peer ranges, exact development fixtures, and the exact
|
|
107
|
+
reviewed Effect dependency as applicable;
|
|
108
|
+
2. run `npm install` so the lockfile records those fixtures;
|
|
109
|
+
3. pass `npm run check` at the minimum supported Node version and the current
|
|
110
|
+
supported Node LTS fixture;
|
|
111
|
+
4. run `npm run pack:certify` to smoke-test the exact tarball, extension loading,
|
|
112
|
+
representative command/tool/UI behavior, and shutdown cleanup with the
|
|
113
|
+
candidate Pi version; and
|
|
114
|
+
5. update this matrix, Effect architecture checks, and release notes; and
|
|
115
|
+
6. run the non-publishing `npm run release:check` gate documented in
|
|
116
|
+
[the release policy](release.md).
|
|
117
|
+
|
|
118
|
+
Do not widen peer ranges solely because installation succeeds. Pi lifecycle and
|
|
119
|
+
TUI behavior must be exercised before a new release line is declared supported.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Effect architecture and conformance
|
|
2
|
+
|
|
3
|
+
Status: **implemented and recertified for the first public release**
|
|
4
|
+
|
|
5
|
+
`pi-jscpd` uses Effect 3.22.1 for fallible asynchronous work, resource ownership,
|
|
6
|
+
cancellation, concurrency, and shared service workflows. jscpd remains the source
|
|
7
|
+
of truth for clone detection, while deterministic parsing, normalization,
|
|
8
|
+
comparison, registry data, and presentation remain plain TypeScript.
|
|
9
|
+
|
|
10
|
+
This document describes the final architecture. Migration issue history belongs
|
|
11
|
+
in Git and the local maintainer roadmap rather than the published package.
|
|
12
|
+
|
|
13
|
+
## Runtime topology
|
|
14
|
+
|
|
15
|
+
Each extension instance owns exactly one `ManagedRuntime` created in
|
|
16
|
+
`src/effect/runtime-boundary.ts`. Its production layer graph supplies:
|
|
17
|
+
|
|
18
|
+
- `JscpdProcess` for shell-free bounded child-process execution;
|
|
19
|
+
- `JscpdFileSystem` for canonical paths, metadata, bounded reads/writes,
|
|
20
|
+
restrictive temporary directories, and cleanup; and
|
|
21
|
+
- `JscpdClock` for timeouts and scheduling.
|
|
22
|
+
|
|
23
|
+
Pi tool, slash-command, lifecycle, and overlay adapters execute native programs
|
|
24
|
+
through that runtime. Infrastructure, domain, and application modules never call
|
|
25
|
+
`Effect.run*` or create independent runtimes. Isolated test execution lives under
|
|
26
|
+
`test/support/`.
|
|
27
|
+
|
|
28
|
+
Promise workflow orchestration is intentionally limited to three reviewed files:
|
|
29
|
+
|
|
30
|
+
- `src/extension.ts` — imperative Pi callbacks and tracked shutdown coordination;
|
|
31
|
+
- `src/overlay.ts` — the callback-driven TUI adapter; and
|
|
32
|
+
- `src/effect/filesystem.ts` — Node filesystem promises wrapped by typed effects
|
|
33
|
+
and bracketed handle ownership.
|
|
34
|
+
|
|
35
|
+
The AST architecture gate enforces these boundaries and rejects Promise service
|
|
36
|
+
contracts, nested Effect runners, unmanaged timers, and direct filesystem access
|
|
37
|
+
from migrated modules.
|
|
38
|
+
|
|
39
|
+
## Services and layers
|
|
40
|
+
|
|
41
|
+
Infrastructure services own effects and resources:
|
|
42
|
+
|
|
43
|
+
- analyzer resolution and capability probing;
|
|
44
|
+
- bounded process-tree execution;
|
|
45
|
+
- report workspace creation, reading, and removal;
|
|
46
|
+
- filesystem/configuration access;
|
|
47
|
+
- lifecycle cancellation and time; and
|
|
48
|
+
- narrow Pi persistence/delivery callbacks.
|
|
49
|
+
|
|
50
|
+
Domain owners maintain one bounded state implementation each:
|
|
51
|
+
|
|
52
|
+
- baseline generation and deferred completion;
|
|
53
|
+
- changed-file project generation and canonical file set;
|
|
54
|
+
- acknowledgement branch scope and revision;
|
|
55
|
+
- verification checkpoints;
|
|
56
|
+
- session mode and last-check status; and
|
|
57
|
+
- Fallow coexistence policy and notice state.
|
|
58
|
+
|
|
59
|
+
Application programs compose scan, changed comparison, status/session controls,
|
|
60
|
+
automatic checkpoints, scheduling, and refactor verification. Service effects
|
|
61
|
+
retain their process/filesystem requirements until the host runtime supplies the
|
|
62
|
+
production layers.
|
|
63
|
+
|
|
64
|
+
## Resource and cancellation ownership
|
|
65
|
+
|
|
66
|
+
Every analyzer child is acquired and finalized by `JscpdProcess`. Execution uses
|
|
67
|
+
argument arrays with `shell: false`, bounds combined output and time, propagates
|
|
68
|
+
interruption, sends TERM before bounded KILL escalation, checks remaining process
|
|
69
|
+
roots, destroys abandoned streams, and detaches listeners.
|
|
70
|
+
|
|
71
|
+
Each analyzer run is serialized by an Effect semaphore. It creates a mode-0700
|
|
72
|
+
workspace outside the project, supplies one fixed report path, reads only a
|
|
73
|
+
bounded regular non-symlink artifact, consumes the report before cleanup, and
|
|
74
|
+
removes the workspace on success, failure, timeout, cancellation, invalidation,
|
|
75
|
+
or disposal. Cleanup uncertainty overrides an otherwise valid result.
|
|
76
|
+
|
|
77
|
+
Bounded file reads use `acquireUseRelease`. Acquisition is bracketed, an in-flight
|
|
78
|
+
read settles before the handle closes, and a handle acquired after interruption
|
|
79
|
+
is closed without starting the read. Typed filesystem and size failures map to
|
|
80
|
+
bounded report/configuration outcomes.
|
|
81
|
+
|
|
82
|
+
Automatic checks run as scoped scheduler fibers. The scheduler owns one active
|
|
83
|
+
and one latest pending generation, coalesces through `JscpdClock`, interrupts only
|
|
84
|
+
its own automatic work when explicit scans take priority, and leaves interrupted,
|
|
85
|
+
stale, or deferred generations retryable. Task construction and result delivery
|
|
86
|
+
are suspended inside failure/finalizer boundaries so defects cannot strand active
|
|
87
|
+
ownership.
|
|
88
|
+
|
|
89
|
+
Quiet baseline capture is host-launched but explicitly tracked. Branch changes
|
|
90
|
+
invalidate and await prior baseline settlement before replacement work starts;
|
|
91
|
+
shutdown awaits baseline finalizers before disposing scheduler, capability,
|
|
92
|
+
analyzer, and runtime resources. Shutdown is idempotent.
|
|
93
|
+
|
|
94
|
+
## Failure and privacy contract
|
|
95
|
+
|
|
96
|
+
Expected operational failures use tagged Effect errors for analyzer, process,
|
|
97
|
+
filesystem, cancellation, timeout, limits, invalid input, stale work, workspace,
|
|
98
|
+
persistence, and delivery conditions. Application and host boundaries translate
|
|
99
|
+
them to the existing bounded fail-open result unions.
|
|
100
|
+
|
|
101
|
+
Unexpected defects are contained only at reviewed outer workflow/host boundaries.
|
|
102
|
+
Public output never includes raw exceptions, child output, environment values,
|
|
103
|
+
source fragments, internal fingerprints, or temporary paths. Interruption remains
|
|
104
|
+
distinct from ordinary failure so resource finalizers run and stale work cannot
|
|
105
|
+
commit state.
|
|
106
|
+
|
|
107
|
+
Automatic delivery rechecks generation, branch, idle state, and pending messages;
|
|
108
|
+
appends findings with `triggerTurn: false`; commits acknowledgements only after
|
|
109
|
+
successful delivery; and treats persistence/footer failures as advisory. Clean
|
|
110
|
+
and failed automatic checks stay out of model context.
|
|
111
|
+
|
|
112
|
+
## Conformance evidence
|
|
113
|
+
|
|
114
|
+
The final non-publishing gate passes on Node 22.19.0 and 24.12.0 with the pinned
|
|
115
|
+
Pi 0.84.4, TypeBox 1.3.7, Effect 3.22.1, and jscpd 5.1.2 fixtures. Evidence covers:
|
|
116
|
+
|
|
117
|
+
- strict TypeScript and Biome checks;
|
|
118
|
+
- architecture, documentation-link, and repository-hygiene gates;
|
|
119
|
+
- more than 400 network-free tests, including cancellation and finalizer regressions;
|
|
120
|
+
- Fallow dead-code, architecture, security, and full-audit checks;
|
|
121
|
+
- a production dependency audit with no reported vulnerabilities; and
|
|
122
|
+
- exact release tarball installation and runtime certification through RPC,
|
|
123
|
+
skill, tool, TUI-compatible, JSON, and print paths, package-owned jscpd probing,
|
|
124
|
+
active process-tree shutdown, and temporary-report cleanup.
|
|
125
|
+
|
|
126
|
+
Certification proves only the reviewed source and artifact state. Versioning,
|
|
127
|
+
tagging, and publication remain explicit maintainer decisions under the
|
|
128
|
+
[release policy](release.md).
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Fallow coexistence policy
|
|
2
|
+
|
|
3
|
+
Status: implemented with Effect-owned policy evaluation
|
|
4
|
+
|
|
5
|
+
Applies to: automatic `pi-jscpd` changed checks only
|
|
6
|
+
|
|
7
|
+
Effect-owned policy evaluation uses the shared bounded filesystem service. These
|
|
8
|
+
detection signals and coexistence outcomes remain product contracts and require a
|
|
9
|
+
separate product decision to change.
|
|
10
|
+
|
|
11
|
+
## Purpose
|
|
12
|
+
|
|
13
|
+
Fallow and jscpd both detect duplication. When Pi Fallow or a project Fallow
|
|
14
|
+
command already runs duplication analysis, two automatic warnings for the same
|
|
15
|
+
change are noisy. `pi-jscpd` therefore detects only a small set of conservative
|
|
16
|
+
signals and, on a high-confidence match, keeps its automatic changed checks on
|
|
17
|
+
demand. Explicit `/jscpd` commands and `jscpd_run` remain available.
|
|
18
|
+
|
|
19
|
+
No coexistence state disables Fallow, changes either analyzer's detection
|
|
20
|
+
semantics, edits project configuration, or changes jscpd's own ignore and format
|
|
21
|
+
policy.
|
|
22
|
+
|
|
23
|
+
## Configuration
|
|
24
|
+
|
|
25
|
+
`.pi/jscpd-guardrail.json` and its local override accept:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"fallowCoexistence": "auto"
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
- `auto` (default): apply conservative detection. A detected overlap suppresses
|
|
34
|
+
automatic jscpd changed checks and explains the choice once. Ambiguous or
|
|
35
|
+
absent evidence leaves automatic checks enabled.
|
|
36
|
+
- `on-demand`: explicitly suppress automatic jscpd changed checks. Explicit
|
|
37
|
+
changed, project, and scoped scans remain available.
|
|
38
|
+
- `allow`: explicitly allow both automatic analyzers, even when Fallow is
|
|
39
|
+
available.
|
|
40
|
+
|
|
41
|
+
The normal trust-gated, strict, atomic extension configuration rules apply.
|
|
42
|
+
|
|
43
|
+
## Supported signals
|
|
44
|
+
|
|
45
|
+
Under `auto`, these are treated as high confidence:
|
|
46
|
+
|
|
47
|
+
1. an active Pi tool named `fallow_run` together with project Fallow evidence
|
|
48
|
+
(a config file or `fallow`/`pi-fallow` dependency), because Pi Fallow's
|
|
49
|
+
default aggregate includes Fallow duplication;
|
|
50
|
+
2. the first supported strict-JSON Fallow config (`.fallowrc` or
|
|
51
|
+
`.fallowrc.json`) contains a `duplicates` object whose `enabled` value is
|
|
52
|
+
`true` or omitted; or
|
|
53
|
+
3. a direct `package.json` script command invokes `fallow`'s combined root,
|
|
54
|
+
`dupes`, `audit`, `all`, `check-changed`, or `review` command. Commands must
|
|
55
|
+
occur at a shell command-segment boundary; prose such as
|
|
56
|
+
`echo fallow dupes` is not accepted.
|
|
57
|
+
|
|
58
|
+
A readable `duplicates.enabled: false` is authoritative for detection and keeps
|
|
59
|
+
automatic jscpd checks enabled, even when the Fallow tool or script is present.
|
|
60
|
+
This only observes Fallow's setting; it does not alter it.
|
|
61
|
+
|
|
62
|
+
The following evidence is deliberately ambiguous and never suppresses an
|
|
63
|
+
automatic check:
|
|
64
|
+
|
|
65
|
+
- an active `fallow_run` tool with no project Fallow evidence;
|
|
66
|
+
- a `fallow` or `pi-fallow` package dependency without an active tool or direct
|
|
67
|
+
duplication command;
|
|
68
|
+
- a Fallow config with no `duplicates` section and no active Pi Fallow tool;
|
|
69
|
+
- JSONC or TOML Fallow configuration, which this adapter does not partially
|
|
70
|
+
parse;
|
|
71
|
+
- malformed, oversized, unreadable, non-regular, or out-of-project signal
|
|
72
|
+
files; and
|
|
73
|
+
- an untrusted project, because project-use evidence is not inspected.
|
|
74
|
+
|
|
75
|
+
Signal reads are trust-gated, no-follow, project-contained, and capped at 64
|
|
76
|
+
KiB. Only fixed signal identifiers enter status; file contents and absolute
|
|
77
|
+
paths do not.
|
|
78
|
+
|
|
79
|
+
## User-visible behavior
|
|
80
|
+
|
|
81
|
+
A detected automatic overlap emits one informational notice per Pi session:
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
Fallow duplication analysis appears active. To avoid duplicate warnings,
|
|
85
|
+
automatic jscpd changed checks are on demand; no configuration was changed.
|
|
86
|
+
Use /jscpd changed or a scoped /jscpd scan <target>.
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`/jscpd status` and the overlay report whether overlap is absent, ambiguous,
|
|
90
|
+
detected/on-demand, or explicitly configured. Pending footer state says
|
|
91
|
+
`jscpd: on demand (Fallow overlap)` instead of implying that an automatic check
|
|
92
|
+
will run.
|
|
93
|
+
|
|
94
|
+
The quiet pre-session jscpd baseline remains available so an explicit
|
|
95
|
+
`/jscpd changed` request can still classify session deltas. Opening the overlay
|
|
96
|
+
still performs status only. Automatic Fallow suppression does not acknowledge
|
|
97
|
+
jscpd findings or consume scheduler generations.
|
|
98
|
+
|
|
99
|
+
## Division of responsibility
|
|
100
|
+
|
|
101
|
+
- **Fallow** is the broader JavaScript/TypeScript codebase analyzer: duplication,
|
|
102
|
+
dead code, complexity, architecture, security candidates, and related
|
|
103
|
+
evidence in one workflow.
|
|
104
|
+
- **jscpd** remains the polyglot tokenization, clone-detection, format, and
|
|
105
|
+
duplication-statistics authority for `pi-jscpd`.
|
|
106
|
+
- **pi-jscpd** adds Pi session attribution, changed-only comparisons,
|
|
107
|
+
acknowledgement, verification, and a jscpd-focused overlay. It is useful on
|
|
108
|
+
demand for polyglot or embedded-format coverage and for repositories whose
|
|
109
|
+
existing jscpd policy is authoritative.
|
|
110
|
+
|
|
111
|
+
When both are desired, set `fallowCoexistence` to `allow`. Otherwise keep the
|
|
112
|
+
default detected on-demand behavior and use scoped jscpd scans where its
|
|
113
|
+
polyglot coverage adds value.
|
|
114
|
+
|
|
115
|
+
## Known limitations
|
|
116
|
+
|
|
117
|
+
Detection intentionally does not inspect arbitrary CI YAML, recursively resolve
|
|
118
|
+
npm scripts, infer globally installed CLI binaries, parse shell expansions, or
|
|
119
|
+
interpret JSONC/TOML. These omissions avoid false positives. Users can select
|
|
120
|
+
`on-demand` or `allow` explicitly when unsupported project policy is known.
|