@nailuogg/pi-find-packages 0.1.2 → 0.1.4
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 +18 -3
- package/extensions/find-packages.ts +17 -12
- package/package.json +14 -2
- package/skills/find-packages/SKILL.md +167 -24
- package/.github/workflows/publish.yml +0 -41
- package/.github/workflows/update-data.yml +0 -45
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ A [pi](https://pi.dev) extension providing a local catalog of the pi package eco
|
|
|
7
7
|
- **Offline catalog**: syncs the full `keywords:pi-package` corpus (~5k+ packages) from npm to local JSONL; search with jq/grep over descriptions, names, and keywords — no dependence on npm's keyword-matched search
|
|
8
8
|
- **`/find-packages <need>`**: retrieve candidates → read-only source analysis in a sandbox → comparison table and recommendation against criteria (feature overlap / peer compatibility / maintenance activity / supply-chain signals)
|
|
9
9
|
- **Cold start**: the package ships a bundled catalog snapshot (`data/catalog.jsonl.gz`); install and use immediately with zero network requests on first run
|
|
10
|
-
- **Docker isolation by default**: candidate repos are
|
|
10
|
+
- **Docker isolation by default**: candidate repos are fetched and unpacked inside a credential-free, non-root container (read-only root, no capabilities, no-new-privileges, tmpfs work dirs; no host source mount); isolation can be disabled explicitly (a risk warning is shown on every use — not recommended)
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|
|
@@ -21,10 +21,25 @@ pi install /path/to/pi-find-packages # local trial
|
|
|
21
21
|
|
|
22
22
|
`<PI_CODING_AGENT_DIR>/data/pi-find-packages/` (default `~/.pi/agent/data/pi-find-packages/`)
|
|
23
23
|
|
|
24
|
-
- `catalog.jsonl` — catalog data (one package per line: name/version/description/date/author/keywords/repo)
|
|
24
|
+
- `catalog.jsonl` — catalog data (one package per line: name/version/description/date/author/publisher/keywords/repo)
|
|
25
25
|
- `config.json` — `{"isolation": "docker" | "off", "semantic": "auto" | "on" | "off"}`
|
|
26
26
|
- `isolation` defaults to `docker` (sandboxed source analysis)
|
|
27
27
|
- `semantic` controls semantic search over lazily-cached READMEs (via [qmd](https://github.com/tobi/qmd)); defaults to `auto`: enabled automatically when the `qmd` binary is present, force with `"on"`, disable with `"off"`
|
|
28
|
+
- `readmes/` — READMEs of reviewed candidates, the corpus behind semantic search (see below)
|
|
29
|
+
|
|
30
|
+
## Semantic search setup (optional)
|
|
31
|
+
|
|
32
|
+
Semantic search reads a qmd collection named `pi-pkg-readmes`, pointed at the `readmes/`
|
|
33
|
+
directory above. Nothing in this package registers that collection, and qmd does not create
|
|
34
|
+
it on demand: an unregistered directory simply stays empty, so semantic search degrades to
|
|
35
|
+
lexical search with no error. Register it once:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
qmd collection add "$HOME/.pi/agent/data/pi-find-packages/readmes" --name pi-pkg-readmes
|
|
39
|
+
qmd collection show pi-pkg-readmes # confirm the path matches your data directory
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Substitute your real data directory when `PI_CODING_AGENT_DIR` is set. Afterwards `/find-packages` uses qmd results only as leads: verify each candidate against its current npm version and the cached README's first line, then overwrite that README after review and index with `qmd update && qmd embed`. It does not bulk-update READMEs.
|
|
28
43
|
|
|
29
44
|
## Refreshing the catalog
|
|
30
45
|
|
|
@@ -52,7 +67,7 @@ the latest npm publish and therefore updates on release cadence.
|
|
|
52
67
|
docker build -t pi-find-packages-analysis -f docker/Dockerfile.analysis docker
|
|
53
68
|
```
|
|
54
69
|
|
|
55
|
-
The image contains no pi and no credentials: it exists solely to
|
|
70
|
+
The image contains no pi and no credentials: it exists solely to fetch, verify, unpack and read third-party source. Runtime must use a read-only root, `--cap-drop=ALL`, `--security-opt=no-new-privileges`, the non-root analyst user, and tmpfs `/analysis` and `/tmp` mounts (`mode=1777`); never bind-mount candidate source from the host. Allow required npm registry/GitHub access. Only analysis text returns to the host. Never execute a candidate package's install scripts or build artifacts in any environment.
|
|
56
71
|
|
|
57
72
|
## Releasing
|
|
58
73
|
|
|
@@ -36,7 +36,14 @@ export default function activate(pi: ExtensionAPI) {
|
|
|
36
36
|
mkdirSync(dataDir, { recursive: true });
|
|
37
37
|
if (existsSync(bundled)) {
|
|
38
38
|
writeFileSync(catalog, gunzipSync(readFileSync(bundled)));
|
|
39
|
-
pi
|
|
39
|
+
// pi only accepts registration calls while a factory runs; action methods
|
|
40
|
+
// such as appendEntry throw until pi commits the extension, and a throw here
|
|
41
|
+
// makes pi reject the whole extension (breaking every first run). Pure fs work
|
|
42
|
+
// is fine, so the audit entry is deferred to a session event instead.
|
|
43
|
+
const extracted = { event: "cold-start-extract", from: bundled };
|
|
44
|
+
pi.on("session_start", () => {
|
|
45
|
+
pi.appendEntry("find-packages", extracted);
|
|
46
|
+
});
|
|
40
47
|
}
|
|
41
48
|
}
|
|
42
49
|
|
|
@@ -163,7 +170,7 @@ export default function activate(pi: ExtensionAPI) {
|
|
|
163
170
|
"",
|
|
164
171
|
"⚠️ **Isolation disabled (isolation: off)**: candidate source will be cloned/unpacked on the host.",
|
|
165
172
|
"Third-party packages may contain malicious install scripts or build logic; host-side analysis is not sandboxed.",
|
|
166
|
-
"This mode is not recommended. Delete
|
|
173
|
+
"This mode is not recommended. Delete " + configFile + " or set isolation:\"docker\" to restore the default.",
|
|
167
174
|
].join("\n")
|
|
168
175
|
: "";
|
|
169
176
|
const prompt = [
|
|
@@ -171,16 +178,14 @@ export default function activate(pi: ExtensionAPI) {
|
|
|
171
178
|
`**${query}**`,
|
|
172
179
|
"",
|
|
173
180
|
"Steps:",
|
|
174
|
-
|
|
175
|
-
+ (semanticEnabled()
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
`3. Execution environment: ${iso === "docker" ? "all cloning/unpacking/source analysis must run inside the Docker container (see docker/Dockerfile.analysis); the host only receives analysis text; never run a candidate's install scripts." : "not isolated — analyze read-only on the host (see the risk note above)."}`,
|
|
183
|
-
"4. Criteria: feature overlap with the current setup / installed packages (Unix philosophy: features must not cross); pi compatibility (peer ranges); maintenance activity; dependency and supply-chain safety.",
|
|
181
|
+
`1. Search: run multiple jq/grep keyword passes over \`${catalog}\` against description/keywords/name, trying synonyms as needed; `
|
|
182
|
+
+ (semanticEnabled() ? "also run `qmd query --collection pi-pkg-readmes` for semantic search over cached READMEs (skip if empty); " : "")
|
|
183
|
+
+ `for broad jq searches, count matches first, then narrow terms or page results; never shortlist from truncated output. ${semanticEnabled() ? "Treat qmd hits only as leads: verify the current npm version against the cached README's first line, then after review overwrite that README with the verified version/date and run `qmd update && qmd embed`; never bulk-update. " : ""}Pick the 3-5 most relevant candidates.`,
|
|
184
|
+
`2. Review each candidate: npm view <pkg> for version/deps/peer, plus the README and registry metadata on the host; judge maintenance activity, dependency surface, and supply-chain signals. Any cloning or unpacking of candidate source happens in step 3's sandbox only — never fetch candidate source on the host. Save the reviewed README to \`${join(dataDir, "readmes")}/<name with / replaced by __>.md\` (first line \`# <name> <version> <date>\`)${semanticEnabled() ? " and refresh the semantic index with qmd update && qmd embed" : ""}.`,
|
|
185
|
+
`3. Execution environment: ${iso === "docker"
|
|
186
|
+
? "All source analysis must run inside the Docker container with --read-only --cap-drop=ALL --security-opt=no-new-privileges, as the image's non-root analyst user, and tmpfs mounts for /analysis and /tmp with mode=1777 (no host candidate-source bind mount). Allow network access needed for npm registry/GitHub. Fetch, verify, unpack and analyze candidate source only inside the container; only analysis text may reach the host. Never run candidate scripts or build artifacts."
|
|
187
|
+
: "not isolated — analyze read-only on the host (see the risk note above)."}`,
|
|
188
|
+
"4. Criteria: feature overlap with the current setup / installed packages (Unix philosophy: features must not cross); pi compatibility (check actual pi --version and the candidate peer range; note installed package-directory versus running-version drift rather than treating drift alone as incompatibility); maintenance activity; dependency and supply-chain safety.",
|
|
184
189
|
"5. Output: a candidate comparison table (name/version/activity/fit/risk) + a clear recommendation with reasons. The analysis report is not install authorization — I decide whether to integrate.",
|
|
185
190
|
riskNote,
|
|
186
191
|
].filter(Boolean).join("\n");
|
package/package.json
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nailuogg/pi-find-packages",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Local catalog of the pi package ecosystem with /find-packages: offline search, cold-start data, and sandboxed source analysis for integration review",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node --test"
|
|
8
|
+
},
|
|
6
9
|
"keywords": [
|
|
7
10
|
"pi-package",
|
|
8
11
|
"pi",
|
|
@@ -37,5 +40,14 @@
|
|
|
37
40
|
},
|
|
38
41
|
"publishConfig": {
|
|
39
42
|
"access": "public"
|
|
40
|
-
}
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"extensions/",
|
|
46
|
+
"skills/",
|
|
47
|
+
"scripts/",
|
|
48
|
+
"data/",
|
|
49
|
+
"docker/",
|
|
50
|
+
"README.md",
|
|
51
|
+
"LICENSE"
|
|
52
|
+
]
|
|
41
53
|
}
|
|
@@ -1,37 +1,180 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
name: find-packages
|
|
3
|
+
description: >-
|
|
4
|
+
Search a local offline catalog of the pi package ecosystem (npm keywords:pi-package) and review a
|
|
5
|
+
candidate package before installing it. Use when the user wants to find, compare, or evaluate a pi
|
|
6
|
+
package, extension, or skill to install: lexical and semantic catalog search over cached READMEs,
|
|
7
|
+
catalog refresh when stale, and a fixed integration review (feature overlap with pi built-ins and
|
|
8
|
+
installed packages, peer compatibility, maintenance activity, supply chain) plus sandboxed Docker
|
|
9
|
+
source analysis.
|
|
10
|
+
license: MIT
|
|
11
|
+
compatibility: >-
|
|
12
|
+
Requires jq, node >= 22 and npm; docker for source analysis; network access for catalog refresh and
|
|
13
|
+
npm view. qmd is optional and only enables semantic search over cached READMEs. POSIX shell assumed.
|
|
14
|
+
---
|
|
2
15
|
|
|
3
|
-
|
|
16
|
+
# find-packages
|
|
4
17
|
|
|
5
|
-
|
|
18
|
+
Find pi packages in a local, offline catalog of the pi ecosystem (npm `keywords:pi-package`) and review
|
|
19
|
+
a candidate before it gets installed. Search is lexical (`jq`), optionally semantic; review is a fixed
|
|
20
|
+
rubric with sandboxed Docker source analysis.
|
|
6
21
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
22
|
+
Catalog: `${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}/data/pi-find-packages/catalog.jsonl` — one JSON object
|
|
23
|
+
per line, with fields `name`, `version`, `description`, `date` (last publish), `author` (frequently
|
|
24
|
+
empty), `publisher` (use this as the maintainer), `keywords`, `npm`, `repo`, `homepage`. The same
|
|
25
|
+
directory holds `config.json` and the `readmes/` cache.
|
|
11
26
|
|
|
12
|
-
|
|
27
|
+
Throughout this file, paths are relative to this skill directory; `../../` is the package root.
|
|
13
28
|
|
|
14
|
-
|
|
15
|
-
2. Semantic (optional): `qmd query --collection pi-pkg-readmes "need description"` — searches cached READMEs of previously reviewed packages (grows over time; skip when the cache is empty). Only use when the `qmd` binary is available and not disabled via `"semantic":"off"` in `config.json`; otherwise skip this step and rely on lexical search.
|
|
16
|
-
3. When both come up empty, fall back to `npm search` and note the catalog may be stale.
|
|
29
|
+
## Workflow
|
|
17
30
|
|
|
18
|
-
|
|
31
|
+
1. **Search** the catalog for candidates — §1.
|
|
32
|
+
2. **Shortlist** the 3–5 closest matches.
|
|
33
|
+
3. **Review** each candidate against the rubric — §3. Feature overlap is a hard rule.
|
|
34
|
+
4. **Analyze sources** inside the Docker sandbox when the review needs code-level evidence — §4.
|
|
35
|
+
5. **Report** a comparison table plus a recommendation — §5.
|
|
19
36
|
|
|
20
|
-
|
|
37
|
+
Complete the steps in order; never skip the overlap check in step 3.
|
|
21
38
|
|
|
22
|
-
##
|
|
39
|
+
## 1. Search the catalog
|
|
23
40
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
- **Activity**: latest publish date, latest repo commit.
|
|
27
|
-
- **Supply chain**: author/maintainers, dependency count, install/preinstall scripts in package.json, any data-exfiltration paths.
|
|
41
|
+
Run one pass per synonym group, English first, and always include channel/transport words
|
|
42
|
+
(remote, telegram, discord, web, vnc) when the need is about access or reach:
|
|
28
43
|
|
|
29
|
-
|
|
44
|
+
```bash
|
|
45
|
+
CAT="${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}/data/pi-find-packages/catalog.jsonl"
|
|
46
|
+
jq -r 'select((.name + " " + (.description // "") + " " + ((.keywords // [])|join(" ")))
|
|
47
|
+
| test("remote|telegram|discord";"i"))
|
|
48
|
+
| [.name, .version, (.publisher // ""), .date] | @tsv' "$CAT"
|
|
49
|
+
```
|
|
30
50
|
|
|
31
|
-
|
|
32
|
-
- `"isolation":"off"` in `data/pi-find-packages/config.json` disables isolation — a risk warning is shown on every use; not recommended.
|
|
33
|
-
- Shallow lookups (`npm view`, registry JSON) do not need the container.
|
|
51
|
+
For broad searches, count matches first, then narrow the terms or page through results. Never choose a shortlist from truncated output.
|
|
34
52
|
|
|
35
|
-
|
|
53
|
+
Expected output — tab-separated, one candidate per line:
|
|
36
54
|
|
|
37
|
-
|
|
55
|
+
```text
|
|
56
|
+
@99percentpeople/pi-ssh-remote 0.6.2 GitHub Actions 2026-09-08T08:29:12.985Z
|
|
57
|
+
@bacnh85/pi-a2a 0.7.11 bacnh85 2026-09-21T03:51:02.441Z
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`.description` and `.keywords` can be `null`, hence the `// ""` guards. Keep `test()` case-insensitive.
|
|
61
|
+
|
|
62
|
+
**Semantic search (optional).** Only when `qmd` is installed and `semantic` is not `"off"` — see
|
|
63
|
+
Configuration. It searches cached READMEs of previously reviewed packages only, so check the collection
|
|
64
|
+
first and skip semantic search while it is empty — `qmd query` spends an LLM expansion pass per call,
|
|
65
|
+
`qmd ls` is free. Treat results only as leads; verify current facts against npm:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
qmd ls pi-pkg-readmes # "No files found" → skip
|
|
69
|
+
qmd query --collection pi-pkg-readmes "<one sentence>"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**When both come up empty**, fall back to `npm search` and say in the report that the catalog may be
|
|
73
|
+
stale.
|
|
74
|
+
|
|
75
|
+
## 2. Refresh the catalog
|
|
76
|
+
|
|
77
|
+
Refresh only when the catalog is missing, older than 30 days (`find "$CAT" -mtime +30`), or the user
|
|
78
|
+
asks. Avoid hammering the registry.
|
|
79
|
+
|
|
80
|
+
1. `/find-packages update` — the command provided by this package's extension. Pulls the snapshot from
|
|
81
|
+
the jsDelivr `data` branch (checksum-verified against the published `.sha256`), then falls back to
|
|
82
|
+
the npmmirror tarball of the latest published version.
|
|
83
|
+
2. Last resort, when both CDNs fail: run `node ../../scripts/sync-catalog.mjs` to rebuild the catalog
|
|
84
|
+
locally from the npm registry search API (~40 requests). It writes `catalog.jsonl`, its `.gz` and
|
|
85
|
+
`.sha256` into the catalog directory; CI invokes the same script with `--out <dir>`.
|
|
86
|
+
|
|
87
|
+
## 3. Integration review
|
|
88
|
+
|
|
89
|
+
Run every candidate through all four checks; record the evidence for each one.
|
|
90
|
+
|
|
91
|
+
| Check | How to verify | Verdict |
|
|
92
|
+
|---|---|---|
|
|
93
|
+
| **Feature overlap** (hard rule) | Compare against pi built-ins and the packages installed in the `packages` array of `$PI_CODING_AGENT_DIR/settings.json` and of the project `.pi/settings.json` | Any overlap → recommend against, whatever the other checks say |
|
|
94
|
+
| **pi compatibility** | Check actual `pi --version` and `npm view <pkg> peerDependencies` | Compare the peer range with the running version. If the installed package-directory copy reports another version, record that drift; do not call it incompatible on drift alone |
|
|
95
|
+
| **Maintenance activity** | Catalog `date` (last publish) plus the last commit in `repo` | Stale on both → note as risk, not a blocker |
|
|
96
|
+
| **Supply chain** | `npm view <pkg> maintainers dependencies scripts` | Flag `install`/`preinstall` scripts, large dependency trees, and any path that sends data off-host |
|
|
97
|
+
|
|
98
|
+
## 4. Analyze sources in the sandbox
|
|
99
|
+
|
|
100
|
+
Source analysis runs in Docker by default, using `../../docker/Dockerfile.analysis` (node24-slim + git +
|
|
101
|
+
ripgrep, no credentials). Do not mount candidate source from the host. Run read-only with
|
|
102
|
+
`--cap-drop=ALL --security-opt=no-new-privileges`, as the non-root analyst user, and tmpfs mounts for
|
|
103
|
+
`/analysis` and `/tmp` with `mode=1777`. Allow network access needed for npm registry/GitHub. Fetch,
|
|
104
|
+
verify, unpack and read candidate code **inside the container**; only analysis text reaches the host.
|
|
105
|
+
|
|
106
|
+
Before analysis, replace `<image>` with the built analysis image name and run this preflight to confirm
|
|
107
|
+
non-root execution and writable workdirs:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
docker run --rm --read-only --cap-drop=ALL --security-opt=no-new-privileges \
|
|
111
|
+
--tmpfs /analysis:rw,mode=1777 --tmpfs /tmp:rw,mode=1777 \
|
|
112
|
+
<image> -c 'test "$(id -u)" -ne 0 && touch /analysis/.probe /tmp/.probe'
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
This preflight only checks the runtime. Fetching candidate source, verifying its integrity, and
|
|
116
|
+
unpacking it must still happen inside a container with the same security options; never bind-mount
|
|
117
|
+
candidate source from the host.
|
|
118
|
+
|
|
119
|
+
**Never execute a candidate's install scripts or build artifacts** — not on the host and not in the
|
|
120
|
+
container. Reading `package.json`, the README or registry metadata needs no container, so shallow
|
|
121
|
+
lookups stay on the host.
|
|
122
|
+
|
|
123
|
+
`isolation: "off"` in `config.json` disables isolation and moves analysis to the host; every use shows a
|
|
124
|
+
risk warning. Do not recommend it, and do not fall back to host-side analysis on your own when Docker is
|
|
125
|
+
unavailable — report the blocker instead.
|
|
126
|
+
|
|
127
|
+
## 5. Report
|
|
128
|
+
|
|
129
|
+
Compare the shortlist in a table, then give one recommendation with reasons:
|
|
130
|
+
|
|
131
|
+
| name | version | last publish | activity | fit | risk |
|
|
132
|
+
|---|---|---|---|---|---|
|
|
133
|
+
| @acme/pi-search | 1.2.0 | 2026-09-05 | active (7d) | no overlap | low |
|
|
134
|
+
|
|
135
|
+
**A report is not install authorization.** The user decides whether to run `pi install`.
|
|
136
|
+
|
|
137
|
+
## README cache
|
|
138
|
+
|
|
139
|
+
After reviewing a candidate, verify the current npm version and compare it with the first line of any
|
|
140
|
+
cached README; qmd hits are leads only. Overwrite that candidate's README at
|
|
141
|
+
`<catalog dir>/readmes/<name with / replaced by __>.md`, first line `# <name> <verified version> <date>`,
|
|
142
|
+
then refresh the semantic index. Never bulk-update README files:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
qmd update && qmd embed
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
This cache is the corpus behind semantic search. Never bulk-fetch READMEs — it grows one real review at
|
|
149
|
+
a time.
|
|
150
|
+
|
|
151
|
+
**One-time setup.** Semantic search needs this directory registered as the qmd collection
|
|
152
|
+
`pi-pkg-readmes`, and nothing in this package registers it: an unregistered directory stays empty and
|
|
153
|
+
semantic search then degrades to lexical search without any error. Register it once:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
qmd collection add "<catalog dir>/readmes" --name pi-pkg-readmes
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Check where the collection points with `qmd collection show pi-pkg-readmes`. If it points at another
|
|
160
|
+
directory, say so and give the user the command above instead of saving READMEs into a directory that is
|
|
161
|
+
never indexed.
|
|
162
|
+
|
|
163
|
+
## Configuration
|
|
164
|
+
|
|
165
|
+
`<catalog dir>/config.json` (absent file → defaults apply):
|
|
166
|
+
|
|
167
|
+
- `isolation`: `"docker"` (default) | `"off"` — source-analysis environment.
|
|
168
|
+
- `semantic`: `"auto"` (default) | `"on"` | `"off"` — `auto` enables semantic search exactly when the
|
|
169
|
+
`qmd` binary is present.
|
|
170
|
+
|
|
171
|
+
## Edge cases
|
|
172
|
+
|
|
173
|
+
| Situation | Action |
|
|
174
|
+
|---|---|
|
|
175
|
+
| `catalog.jsonl` missing | Cold start extracts it automatically; if it is still missing, run `/find-packages update` |
|
|
176
|
+
| Catalog older than 30 days, or no matches | Refresh (§2), then search again; note staleness in the report if the refresh fails |
|
|
177
|
+
| `qmd` missing, or `semantic: "off"` | Skip semantic search; rely on lexical passes |
|
|
178
|
+
| `pi-pkg-readmes` empty or registered against another directory | Still skip semantic search, but tell the user the one-time setup command — an unindexed cache never becomes searchable on its own |
|
|
179
|
+
| Docker unavailable | Stop before source analysis, report the blocker, and ask the user how to proceed |
|
|
180
|
+
| `config.json` absent | Defaults apply: Docker isolation on, semantic `auto` |
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
name: publish
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags: ["v*"]
|
|
6
|
-
|
|
7
|
-
permissions:
|
|
8
|
-
contents: write # create the GitHub release
|
|
9
|
-
id-token: write # OIDC token for npm Trusted Publishing
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
publish:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
environment: npm
|
|
15
|
-
steps:
|
|
16
|
-
- uses: actions/checkout@v4
|
|
17
|
-
|
|
18
|
-
- uses: actions/setup-node@v4
|
|
19
|
-
with:
|
|
20
|
-
node-version: 24
|
|
21
|
-
registry-url: https://registry.npmjs.org/
|
|
22
|
-
|
|
23
|
-
- name: Ensure npm supports Trusted Publishing
|
|
24
|
-
run: npm install -g npm@latest # OIDC trusted publishing needs npm >= 11.5.1
|
|
25
|
-
|
|
26
|
-
- name: Verify version matches tag
|
|
27
|
-
run: |
|
|
28
|
-
PKG_VERSION="${GITHUB_REF_NAME#v}"
|
|
29
|
-
TAG_VERSION="$(node -p "require('./package.json').version")"
|
|
30
|
-
if [ "${PKG_VERSION}" != "${TAG_VERSION}" ]; then
|
|
31
|
-
echo "::error::tag ${GITHUB_REF_NAME} != package.json version ${TAG_VERSION}"
|
|
32
|
-
exit 1
|
|
33
|
-
fi
|
|
34
|
-
|
|
35
|
-
- name: Publish (OIDC trusted publishing, no token)
|
|
36
|
-
run: npm publish
|
|
37
|
-
|
|
38
|
-
- name: Create GitHub release
|
|
39
|
-
run: gh release create "${GITHUB_REF_NAME}" --verify-tag --generate-notes
|
|
40
|
-
env:
|
|
41
|
-
GH_TOKEN: ${{ github.token }}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
name: update-data
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
schedule:
|
|
5
|
-
- cron: "17 3 * * *" # daily, off the hour
|
|
6
|
-
workflow_dispatch:
|
|
7
|
-
|
|
8
|
-
permissions:
|
|
9
|
-
contents: write
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
refresh:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
steps:
|
|
15
|
-
- uses: actions/checkout@v4
|
|
16
|
-
|
|
17
|
-
- uses: actions/setup-node@v4
|
|
18
|
-
with:
|
|
19
|
-
node-version: 24
|
|
20
|
-
|
|
21
|
-
- name: Fetch latest catalog
|
|
22
|
-
run: node scripts/sync-catalog.mjs --out "${RUNNER_TEMP}/catalog"
|
|
23
|
-
|
|
24
|
-
- name: Skip if unchanged
|
|
25
|
-
id: diff
|
|
26
|
-
run: |
|
|
27
|
-
NEW="${RUNNER_TEMP}/catalog/catalog.jsonl.gz"
|
|
28
|
-
OLD="$(curl -fsSL --max-time 30 https://cdn.jsdelivr.net/gh/${GITHUB_REPOSITORY}@data/data/catalog.jsonl.gz 2>/dev/null | sha256sum | cut -d' ' -f1 || true)"
|
|
29
|
-
CUR="$(sha256sum "${NEW}" | cut -d' ' -f1)"
|
|
30
|
-
echo "changed=$([[ "${CUR}" != "${OLD}" ]] && echo true || echo false)" >> "$GITHUB_OUTPUT"
|
|
31
|
-
|
|
32
|
-
- name: Push to data branch
|
|
33
|
-
if: steps.diff.outputs.changed == 'true'
|
|
34
|
-
run: |
|
|
35
|
-
git config user.name "github-actions[bot]"
|
|
36
|
-
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
37
|
-
git fetch origin data || true
|
|
38
|
-
git checkout -B data origin/data 2>/dev/null || git checkout -B data
|
|
39
|
-
mkdir -p data
|
|
40
|
-
cp "${RUNNER_TEMP}/catalog/catalog.jsonl" data/
|
|
41
|
-
cp "${RUNNER_TEMP}/catalog/catalog.jsonl.gz" data/
|
|
42
|
-
cp "${RUNNER_TEMP}/catalog/catalog.jsonl.gz.sha256" data/
|
|
43
|
-
git add data/
|
|
44
|
-
git commit -qm "chore(data): refresh catalog ($(date -u +%Y-%m-%d))"
|
|
45
|
-
git push origin data
|