specpi 0.20.0 → 0.20.1
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 +5 -0
- package/README.md +2 -2
- package/SECURITY_MODEL.md +1 -1
- package/docs/structural-search.md +7 -7
- package/extensions/structural-search/config.mjs +1 -1
- package/package.json +1 -1
- package/scripts/specpi.mjs +13 -18
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.20.1 - 2026-09-10
|
|
4
|
+
|
|
5
|
+
- Enable `structural_search` by default on fresh installs and updates without a saved choice. Persist enablement transactionally and preserve explicit opt-outs; disable with `specpi update --structural-search=off`, then restart Pi.
|
|
6
|
+
- Keep acquisition skip flags, malformed-configuration failures, selected-source limits and Command Guard approvals unchanged. Unsupported native hosts must pass `--structural-search=off` during install/update to avoid runtime acquisition failures.
|
|
7
|
+
|
|
3
8
|
## 0.20.0 - 2026-09-09
|
|
4
9
|
|
|
5
10
|
- Add opt-in `structural_search` with pinned ast-grep 0.45.3, protected explicit source selection, bounded output and subprocess cleanup, and exact-call approval in Strict mode. Enable with `specpi update --structural-search=on`, then restart Pi.
|
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ SpecPi extends Pi with chat, review tools, and focused delegation. Its principle
|
|
|
32
32
|
- **Focused delegation.** One agent makes changes. Up to two read-only subagents help investigate and review. [Research and design](https://tannermidd.github.io/SpecPi/single-agent/)
|
|
33
33
|
- **Background tasks.** Start an approved dev server, test suite, or watch build, inspect bounded output, and stop it without blocking other work.
|
|
34
34
|
- **Review as you work.** Track changed files, inspect diffs, check pages in a browser, and review risky commands.
|
|
35
|
-
- **Structural search.**
|
|
35
|
+
- **Structural search.** Bounded ast-grep patterns over selected code are enabled by default. Disable with `specpi update --structural-search=off`; on unsupported native hosts, pass `--structural-search=off` during installation too. [Usage and limits](docs/structural-search.md)
|
|
36
36
|
- **Accessibility checks.** Scan the current browser state for automated WCAG and optional best-practice findings. [Browser verification](docs/browser-testing.md)
|
|
37
37
|
- **Improvements you choose.** Record recurring problems, select one with `/harness-improvement`, and test the change before calling it done.
|
|
38
38
|
|
|
@@ -51,7 +51,7 @@ specpi doctor
|
|
|
51
51
|
|
|
52
52
|
Preview the changes, confirm the install, then check the setup. Restart Pi when finished.
|
|
53
53
|
|
|
54
|
-
To pin this release, use `npm install --global specpi@0.20.
|
|
54
|
+
To pin this release, use `npm install --global specpi@0.20.1`.
|
|
55
55
|
|
|
56
56
|
Delegation is enabled at startup. Use `/delegate off` to turn it off.
|
|
57
57
|
|
package/SECURITY_MODEL.md
CHANGED
|
@@ -197,7 +197,7 @@ The browser is not an operating-system or network sandbox. Use a container or VM
|
|
|
197
197
|
|
|
198
198
|
## Structural search
|
|
199
199
|
|
|
200
|
-
Structural search is disabled
|
|
200
|
+
Structural search is enabled by default when no enablement configuration exists; an explicit saved opt-out remains disabled on update or reinstall. The owned `specpi/tool-integrations.json` file stores nonsecret enablement; plan does not mutate it, updates back it up and roll it back with managed state, and uninstall preserves it. Unparseable content does not abort the non-mutating plan and does not silently enable anything: install and update stop and name the file unless an explicit `--structural-search` selection rewrites it, and the prior bytes go to the operation backup first. A configuration that is a link or not a bounded regular file stays a hard failure that no selection rewrites. The extension itself treats any unreadable configuration as disabled. Runtime acquisition is private, pinned, script-free and transactional. Enabled acquisition or smoke failures abort install/update and roll back managed changes; unsupported native hosts must explicitly opt out with `--structural-search=off` or skip acquisition. Configuration output is checked against the same 16 KiB bound as reads before mutation, with compact JSON fallback. Doctor checks source/runtime integrity before its offline fixture; unverified or modified prior runtime directories are preserved rather than deleted. Runtime ownership now binds the acquired tree's contents, paths, directories, permissions and link targets; the tree fingerprint does not traverse links, and the marker is checked separately. Legacy binary-only markers remain unverified. Retirement rechecks the tree before deletion. Rollback quarantines the new runtime and restores the prior directory before attempting recursive cleanup, reporting any retained quarantine. No global executable search or PATH injection is used.
|
|
201
201
|
|
|
202
202
|
The parent captures explicit selected source with the existing snapshot path/private-store/link/descriptor/digest checks. A parent-only byte callback rechecks the original digest and clears its buffer after parsing. Existing workers gain no tool or byte API route. Files are capped at 1 MiB, selection at 8 MiB/200 files, pattern at 4 KiB, returned evidence at 24 KiB, raw stdout at 2 MiB and stderr at 8 KiB per call. Source bytes go to a reviewed native parser over stdin; only a neutral configuration is written to private scratch. Files containing secrets under ordinary source names are not automatically detectable.
|
|
203
203
|
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# Structural search
|
|
2
2
|
|
|
3
|
-
`structural_search` is
|
|
3
|
+
`structural_search` is a default-on, read-only ast-grep 0.45.3 tool. It matches code structures across formatting changes. It does not resolve types/references, edit code or replace literal search for comments, strings and filenames.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Provision it through the installer, then restart Pi:
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
specpi plan
|
|
9
|
-
specpi update
|
|
8
|
+
specpi plan
|
|
9
|
+
specpi update
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
For a fresh installation use `install`. `--
|
|
12
|
+
For a fresh installation use `install`. With no saved choice, structural search is enabled by default on install and update. Omitting `--structural-search` preserves a saved choice, including an explicit opt-out. Use `--structural-search=on` to re-enable it. `--yes` confirms the operation without changing that selection. `--skip-package-install` and `--skip-tool-install` skip acquisition without disabling an existing runtime. Direct `pi install npm:specpi` does not provision the runtime; use the SpecPi installer for setup.
|
|
13
13
|
|
|
14
14
|
```json
|
|
15
15
|
{
|
|
@@ -31,10 +31,10 @@ The parser receives selected source over stdin, a fixed argument list, a neutral
|
|
|
31
31
|
|
|
32
32
|
Guard and Off permit these bounded reads; Strict asks for the exact call. The approval receives the operation cancellation signal and remaining timeout. Terminal prompts dismiss on cancellation; Pi 0.84.4 releases cancelled RPC approvals server-side but sends no remote dismissal event, so clients may display them until the forwarded timeout expires. Late answers cannot authorize the cancelled call. Locked or ambiguous Guard state denies. If Guard is absent, the same source/input limits remain. Policy, root and enablement are rechecked before parsing. A denial must not be retried through a different tool. Existing read-only workers do not gain structural-search access.
|
|
33
33
|
|
|
34
|
-
Enablement lives in `<agentDir>/specpi/tool-integrations.json`. The installer preserves unrelated fields, backs up the owned file before changes and rolls it back on failure. Serialized configuration must also fit the 16 KiB reader limit: the installer uses compact JSON when needed and rejects output that still exceeds the limit before changing configuration or runtimes. If that file becomes unparseable, `plan` reports it and continues without mutating anything, while `install` and `update` stop and name the file; repair or remove it, or pass `--structural-search=on` or `--structural-search=off` to rewrite it from the backed-up original. A configuration that is a link or not a bounded regular file remains a hard failure that no selection rewrites. The private runtime has an exact npm lockfile, script-free acquisition and binary/full-tree checksums; no global PATH entry is added. Doctor checks integrity and runs an offline fixture smoke. The
|
|
34
|
+
Enablement lives in `<agentDir>/specpi/tool-integrations.json`. The installer preserves unrelated fields, backs up the owned file before changes and rolls it back on failure. Serialized configuration must also fit the 16 KiB reader limit: the installer uses compact JSON when needed and rejects output that still exceeds the limit before changing configuration or runtimes. If that file becomes unparseable, `plan` reports it and continues without mutating anything, while `install` and `update` stop and name the file; repair or remove it, or pass `--structural-search=on` or `--structural-search=off` to rewrite it from the backed-up original. A configuration that is a link or not a bounded regular file remains a hard failure that no selection rewrites. The private runtime has an exact npm lockfile, script-free acquisition and binary/full-tree checksums; no global PATH entry is added. Doctor checks integrity and runs an offline fixture smoke. The supported native platforms are Windows x64, macOS x64/arm64 and Linux glibc x64. On other hosts, use `specpi install --structural-search=off` (or `update`) to avoid acquiring an unsupported runtime. With structural search enabled, acquisition or smoke failures abort install/update and roll back managed changes rather than silently disabling the tool; tool calls on unsupported hosts report unavailable.
|
|
35
35
|
|
|
36
36
|
Disable with `specpi update --structural-search=off`, then restart Pi. Intact owned runtimes are removed transactionally. Modified/unverified runtimes are preserved with a warning; replacement preserves them outside the active runtime path. The tree check covers file contents, paths, directories, permissions and link targets without traversing links, and is repeated before retired-tree deletion. Older ownership markers without a tree checksum are unverified and preserved. Rollback quarantines the new runtime and restores the prior directory before recursive cleanup; a cleanup failure reports the retained quarantine path. Uninstall preserves enablement configuration and user evidence. Trusted native executables still run with the user's permissions; these controls are not an OS sandbox.
|
|
37
37
|
|
|
38
38
|
Development verification uses `npm run setup:structural` followed by `npm run test:structural`. This installs only the locked native test runtime in `.specpi-test/structural-runtime/`. Installer tests use disposable Pi directories and skip external acquisition.
|
|
39
39
|
|
|
40
|
-
Six synthetic lookup trials on Windows x64 / Node 24.18.0 on September 9, 2026 covered call sites, constructors, filesystem calls, JSX/TSX components and Python calls. Each fixture contained two valid structures with different formatting plus one comment/string decoy. All 12 expected matches were found with no false positives; each response was 669–707 bytes and took 32–48 ms in that single run. A simple fixed-string `rg` query per fixture found six valid matches, missed six formatting variants and returned six decoys (37–85 bytes, 24–33 ms per query). This demonstrates the intended syntax-sensitive use case, not superiority over carefully constructed regex/manual inspection or measured agent productivity. Literal search remains faster and smaller in these trials; structural search
|
|
40
|
+
Six synthetic lookup trials on Windows x64 / Node 24.18.0 on September 9, 2026 covered call sites, constructors, filesystem calls, JSX/TSX components and Python calls. Each fixture contained two valid structures with different formatting plus one comment/string decoy. All 12 expected matches were found with no false positives; each response was 669–707 bytes and took 32–48 ms in that single run. A simple fixed-string `rg` query per fixture found six valid matches, missed six formatting variants and returned six decoys (37–85 bytes, 24–33 ms per query). This demonstrates the intended syntax-sensitive use case, not superiority over carefully constructed regex/manual inspection or measured agent productivity. Literal search remains faster and smaller in these trials; choose structural search for syntax-sensitive lookups.
|
package/package.json
CHANGED
package/scripts/specpi.mjs
CHANGED
|
@@ -105,7 +105,7 @@ Options:
|
|
|
105
105
|
--skip-package-install Do not bootstrap Pi or install external Pi packages (also skips browser/structural runtime acquisition).
|
|
106
106
|
--skip-browser-install Install browser tools but skip the managed Playwright/Chromium runtime.
|
|
107
107
|
--skip-tool-install Skip DonSeTch and structural-search runtime acquisition.
|
|
108
|
-
--structural-search=on|off
|
|
108
|
+
--structural-search=on|off Enable (default) or disable/remove the private runtime; omission preserves a saved choice.
|
|
109
109
|
--skip-shell Do not install shell profile functions or edit a shell rc file.
|
|
110
110
|
|
|
111
111
|
Environment:
|
|
@@ -1471,16 +1471,13 @@ async function installOrUpdate(options, update) {
|
|
|
1471
1471
|
const integrations = readIntegrationsForOperation(options.structuralSearch);
|
|
1472
1472
|
const structuralEnabled = options.structuralSearch ?? integrations.structuralSearch.enabled;
|
|
1473
1473
|
// Bound the output before any runtime/configuration mutation, not only when reading the input.
|
|
1474
|
-
const integrationsText =
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
integrationsPath,
|
|
1482
|
-
)
|
|
1483
|
-
: undefined;
|
|
1474
|
+
const integrationsText = serializeIntegrations(
|
|
1475
|
+
{
|
|
1476
|
+
...integrations,
|
|
1477
|
+
structuralSearch: { ...integrations.structuralSearch, enabled: structuralEnabled },
|
|
1478
|
+
},
|
|
1479
|
+
integrationsPath,
|
|
1480
|
+
);
|
|
1484
1481
|
if (!update && previousManifest) {
|
|
1485
1482
|
throw new Error(`SpecPi is already installed. Run ${CLI} update.`);
|
|
1486
1483
|
}
|
|
@@ -1537,15 +1534,13 @@ async function installOrUpdate(options, update) {
|
|
|
1537
1534
|
);
|
|
1538
1535
|
}
|
|
1539
1536
|
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
fs.copyFileSync(integrationsPath, path.join(backupDir, "tool-integrations.json"));
|
|
1544
|
-
}
|
|
1545
|
-
|
|
1546
|
-
atomicWrite(integrationsPath, integrationsText, 0o600);
|
|
1537
|
+
// Back up the owned configuration only, never a whole Pi settings/profile store.
|
|
1538
|
+
if (fs.existsSync(integrationsPath)) {
|
|
1539
|
+
fs.copyFileSync(integrationsPath, path.join(backupDir, "tool-integrations.json"));
|
|
1547
1540
|
}
|
|
1548
1541
|
|
|
1542
|
+
atomicWrite(integrationsPath, integrationsText, 0o600);
|
|
1543
|
+
|
|
1549
1544
|
injectTestFailure("after-structural-runtime");
|
|
1550
1545
|
const blockFiles = structuredClone(previousManifest?.blockFiles || {});
|
|
1551
1546
|
blockFiles.agents ||= { existed: pathExists(agentsPath) };
|