replen 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -1
- package/dist/commands.js +61 -0
- package/dist/index.js +10 -2
- package/dist/init.js +9 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# replen
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Smarter AI Development workflows.** One-command setup for [replen](https://replen.dev) - the AI that asks *"can we do this better?"* on your codebase. Calm cadence: 1-3 actionable matches a month, not a daily feed.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npx replen
|
|
@@ -24,6 +24,23 @@ npx replen mcp setup # re-wire MCP using saved auth
|
|
|
24
24
|
npx replen logout # forget saved auth (token stays valid; rotate on /settings to revoke)
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
## Plain-shell usage (no Claude Code / Codex needed)
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx replen run # trigger a pipeline run
|
|
31
|
+
npx replen progress # tail the run live; exits when done
|
|
32
|
+
npx replen feed # show recent matches (default 2 days)
|
|
33
|
+
npx replen watch # keep a terminal open — rings the bell when
|
|
34
|
+
# a new match lands. Default poll 5min.
|
|
35
|
+
npx replen search <query> # full-text search past matches
|
|
36
|
+
npx replen starred # starred matches + handoff PR status
|
|
37
|
+
npx replen handoff <matchId> # open the handoff PR for a starred match
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`watch` is the calm-utility companion: leave it running in a `tmux` pane and forget about it. The first poll establishes a baseline; existing matches don't ring. Pair with `--no-bell` for a silent log feed, or `--json` to pipe into anything.
|
|
41
|
+
|
|
42
|
+
Every data command accepts `--json` for scripting.
|
|
43
|
+
|
|
27
44
|
## Self-host
|
|
28
45
|
|
|
29
46
|
Pointing at your own replen instance:
|
package/dist/commands.js
CHANGED
|
@@ -169,6 +169,67 @@ export async function runStarred(argv) {
|
|
|
169
169
|
handleApiError(e);
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
|
+
// Watch for new matches in the background. Polls /api/mcp/today, diffs against
|
|
173
|
+
// the matchIds seen on the previous poll, prints anything new, and rings the
|
|
174
|
+
// terminal bell (\x07). First poll establishes a baseline — existing matches
|
|
175
|
+
// don't ring. Default interval 5 minutes (the pipeline runs daily by default,
|
|
176
|
+
// so polling tighter is pure overhead).
|
|
177
|
+
export async function runWatch(argv) {
|
|
178
|
+
const cfg = await loadConfigOrExit();
|
|
179
|
+
const json = hasFlag(argv, "--json");
|
|
180
|
+
const noBell = hasFlag(argv, "--no-bell");
|
|
181
|
+
const intervalSec = Math.max(30, Number(getFlag(argv, "--interval") ?? 300));
|
|
182
|
+
const days = Number(getFlag(argv, "--days") ?? 2);
|
|
183
|
+
const project = getFlag(argv, "--project");
|
|
184
|
+
const relevance = getFlag(argv, "--relevance") ?? "high,medium";
|
|
185
|
+
const seen = new Set();
|
|
186
|
+
let firstPass = true;
|
|
187
|
+
if (!json) {
|
|
188
|
+
const target = project ? ` · project=${project}` : "";
|
|
189
|
+
console.log(`Watching for new ${relevance} matches${target} · poll every ${intervalSec}s · Ctrl-C to stop.`);
|
|
190
|
+
}
|
|
191
|
+
while (true) {
|
|
192
|
+
let r;
|
|
193
|
+
try {
|
|
194
|
+
r = await apiGet(cfg, "/api/mcp/today", {
|
|
195
|
+
days,
|
|
196
|
+
relevance,
|
|
197
|
+
project,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
catch (e) {
|
|
201
|
+
// Don't kill the watcher on a transient network blip — just log + retry.
|
|
202
|
+
console.error(`✗ ${e.message ?? String(e)} (retrying in ${intervalSec}s)`);
|
|
203
|
+
await sleep(intervalSec * 1000);
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
const fresh = [];
|
|
207
|
+
for (const m of r.matches) {
|
|
208
|
+
if (!seen.has(m.matchId)) {
|
|
209
|
+
if (!firstPass)
|
|
210
|
+
fresh.push(m);
|
|
211
|
+
seen.add(m.matchId);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (json) {
|
|
215
|
+
// Emit one JSON line per poll, regardless of new/no-new — easy to pipe.
|
|
216
|
+
console.log(JSON.stringify({ ts: new Date().toISOString(), new: fresh.length, matches: fresh }));
|
|
217
|
+
}
|
|
218
|
+
else if (fresh.length > 0) {
|
|
219
|
+
const stamp = new Date().toISOString().slice(11, 19);
|
|
220
|
+
console.log(`\n[${stamp}] ${fresh.length} new:`);
|
|
221
|
+
for (const m of fresh)
|
|
222
|
+
renderMatchLine(m);
|
|
223
|
+
if (!noBell)
|
|
224
|
+
process.stdout.write("\x07");
|
|
225
|
+
}
|
|
226
|
+
else if (firstPass) {
|
|
227
|
+
console.log(`Baseline: ${seen.size} match(es) already in feed; will alert on anything new.`);
|
|
228
|
+
}
|
|
229
|
+
firstPass = false;
|
|
230
|
+
await sleep(intervalSec * 1000);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
172
233
|
// Open a handoff PR for a starred match in the matched project's own repo.
|
|
173
234
|
export async function runHandoff(argv) {
|
|
174
235
|
const cfg = await loadConfigOrExit();
|
package/dist/index.js
CHANGED
|
@@ -3,8 +3,8 @@ import { runInit } from "./init.js";
|
|
|
3
3
|
import { setupMcp } from "./mcp-setup.js";
|
|
4
4
|
import { readConfig, configPath } from "./config.js";
|
|
5
5
|
import { runProjectInit } from "./project-init.js";
|
|
6
|
-
import { runFeed, runHandoff, runProgress, runRun, runSearch, runStarred } from "./commands.js";
|
|
7
|
-
const HELP = `replen:
|
|
6
|
+
import { runFeed, runHandoff, runProgress, runRun, runSearch, runStarred, runWatch } from "./commands.js";
|
|
7
|
+
const HELP = `replen: Smarter AI Development workflows
|
|
8
8
|
|
|
9
9
|
Usage:
|
|
10
10
|
npx replen Sign up / sign in + wire MCP into Claude Code
|
|
@@ -21,6 +21,12 @@ Use replen from a plain shell (no Claude Code / Codex needed):
|
|
|
21
21
|
npx replen feed [--days N] Today's matches (default 2 days)
|
|
22
22
|
[--project SLUG] Limit to one project
|
|
23
23
|
[--relevance high,medium]
|
|
24
|
+
npx replen watch Long-running poll: rings the terminal bell
|
|
25
|
+
[--interval SEC] when a new match lands (default 300s).
|
|
26
|
+
[--days N] First poll establishes baseline; existing
|
|
27
|
+
[--project SLUG] matches don't ring. Ctrl-C to stop.
|
|
28
|
+
[--relevance high,medium]
|
|
29
|
+
[--no-bell]
|
|
24
30
|
npx replen search <query> Full-text search across past matches
|
|
25
31
|
npx replen starred Starred matches + handoff PR status
|
|
26
32
|
npx replen handoff <matchId> Open the handoff PR for a starred match
|
|
@@ -88,6 +94,8 @@ async function main() {
|
|
|
88
94
|
return runProgress(argv);
|
|
89
95
|
if (cmd === "feed")
|
|
90
96
|
return runFeed(argv);
|
|
97
|
+
if (cmd === "watch")
|
|
98
|
+
return runWatch(argv);
|
|
91
99
|
if (cmd === "search")
|
|
92
100
|
return runSearch(argv);
|
|
93
101
|
if (cmd === "starred")
|
package/dist/init.js
CHANGED
|
@@ -55,7 +55,15 @@ function waitForCallback(port, expectedState) {
|
|
|
55
55
|
res.end("state mismatch");
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
|
-
|
|
58
|
+
// Referrer-Policy: no-referrer means anything rendered in SUCCESS_HTML
|
|
59
|
+
// (even if a future maintainer adds an external <img>, <link>, or fetch)
|
|
60
|
+
// cannot leak the callback URL — which carries the exchange code in
|
|
61
|
+
// its query string — via an outbound Referer header.
|
|
62
|
+
res.writeHead(200, {
|
|
63
|
+
"content-type": "text/html; charset=utf-8",
|
|
64
|
+
"referrer-policy": "no-referrer",
|
|
65
|
+
"cache-control": "no-store",
|
|
66
|
+
});
|
|
59
67
|
res.end(SUCCESS_HTML);
|
|
60
68
|
// Give the response a tick to flush before we shut down the listener.
|
|
61
69
|
setTimeout(() => server.close(), 100);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "replen",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Smarter AI Development workflows. The AI that asks 'can we do this better?' - replen reads your codebase against the live ecosystem and surfaces drop-in libraries, ideas to port, and patterns to learn from. Calm cadence: 1-3 actionable matches a month. One-command setup: opens a browser to sign in, then wires the MCP server into Claude Code / Codex.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"replen": "dist/index.js"
|