nerdsystem 0.0.21 → 0.0.22
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/dist/cli.js +11 -0
- package/dist/commands/init.js +1 -1
- package/dist/commands/status.d.ts +47 -0
- package/dist/commands/status.js +140 -0
- package/dist/commands/upgrade.js +20 -0
- package/dist/gates/index.js +2 -1
- package/dist/gates/review.d.ts +8 -0
- package/dist/gates/review.js +37 -0
- package/dist/gates/rules.js +1 -0
- package/package.json +1 -1
- package/template/.claude/settings.json +16 -1
- package/template/.claude/skills/nerdsystem/SKILL.md +2 -0
- package/template/.cursor/rules/nerdsystem.mdc +3 -1
- package/template/.github/copilot-instructions.md +3 -1
- package/template/AGENTS.md +3 -1
- package/template/CLAUDE.md +4 -0
- package/template/GEMINI.md +3 -1
package/dist/cli.js
CHANGED
|
@@ -9,6 +9,7 @@ import { cron, health, rollback, secretList, secretRemove, secretSet, transfer,
|
|
|
9
9
|
import { adminHelp, adminSuspend, adminUnsuspend } from "./commands/admin.js";
|
|
10
10
|
import { agentsSync } from "./commands/agents.js";
|
|
11
11
|
import { upgrade } from "./commands/upgrade.js";
|
|
12
|
+
import { review, status } from "./commands/status.js";
|
|
12
13
|
import { billingPortal, billingShow, billingUpgrade } from "./commands/billing.js";
|
|
13
14
|
import { auditExport, clientsCreate, clientsList, clientsRelease, domainsAdd, domainsList, domainsRemove, logs, membersInvite, membersList, membersRemove } from "./commands/org.js";
|
|
14
15
|
import { buildsList, buildsShow, buildsTrigger } from "./commands/builds.js";
|
|
@@ -59,6 +60,8 @@ const HELP = `nerd: start, check, and deploy a web app on nerdsystem
|
|
|
59
60
|
nerd builds trigger [--branch b] [--commit sha]
|
|
60
61
|
nerd agents sync Regenerate AGENTS.md, Cursor, Copilot, Gemini files from the skill
|
|
61
62
|
nerd upgrade Bring this app up to the current SDK, agent instructions, and test harness
|
|
63
|
+
nerd status What the platform has found for this app that needs attention (updates, review findings, vulnerable packages)
|
|
64
|
+
nerd review The latest model review's findings for this app, with the fix for each
|
|
62
65
|
nerd billing [--org slug] Plan, limits, and usage for the org
|
|
63
66
|
nerd billing upgrade --plan pro|studio [--annual] Start checkout
|
|
64
67
|
nerd billing portal Manage cards, invoices, and plan
|
|
@@ -135,6 +138,14 @@ export async function main(argv) {
|
|
|
135
138
|
const { values } = parse({ "skip-build": BOOL, "skip-probe": BOOL, force: BOOL, note: STR });
|
|
136
139
|
return deploy(values);
|
|
137
140
|
}
|
|
141
|
+
case "status": {
|
|
142
|
+
const { values } = parse({ hook: BOOL }, false);
|
|
143
|
+
return status({ json: Boolean(values.json), hook: Boolean(values.hook) });
|
|
144
|
+
}
|
|
145
|
+
case "review": {
|
|
146
|
+
const { values } = parse({}, false);
|
|
147
|
+
return review({ json: Boolean(values.json) });
|
|
148
|
+
}
|
|
138
149
|
case "upgrade": {
|
|
139
150
|
const { values } = parse({}, false);
|
|
140
151
|
return upgrade({ json: Boolean(values.json) });
|
package/dist/commands/init.js
CHANGED
|
@@ -192,4 +192,4 @@ export async function init(dir, args) {
|
|
|
192
192
|
log.ok(`Ready. Next:\n cd ${dir}\n pnpm install\n nerd dev\n\nThen open the folder in your coding agent and ask it to build the first feature; the nerdsystem skill walks it through.\nDeploys go to ${project.url}`);
|
|
193
193
|
}
|
|
194
194
|
// Kept in sync with packages/sdk/package.json by the release script.
|
|
195
|
-
const SDK_VERSION = "0.0.
|
|
195
|
+
const SDK_VERSION = "0.0.22";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ApiClient } from "../api.js";
|
|
2
|
+
/** One thing the platform wants looked at, in the catalog's words. */
|
|
3
|
+
export interface AttentionItem {
|
|
4
|
+
rule_id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
severity: "block" | "warn" | "info";
|
|
7
|
+
audience: "agent" | "human";
|
|
8
|
+
/** A file and line, or a package and version. Never free text from the app or from a model. */
|
|
9
|
+
where?: string;
|
|
10
|
+
risk: string;
|
|
11
|
+
fix: string;
|
|
12
|
+
}
|
|
13
|
+
export interface Attention {
|
|
14
|
+
app: string | null;
|
|
15
|
+
items: AttentionItem[];
|
|
16
|
+
/** When the review the findings come from was made, so a finding already fixed since is not a surprise. */
|
|
17
|
+
reviewedAt?: string;
|
|
18
|
+
}
|
|
19
|
+
/** The latest model review's findings for this app, mapped through this CLI's own catalog. */
|
|
20
|
+
export declare function reviewItems(api: ApiClient, base: string): Promise<{
|
|
21
|
+
items: AttentionItem[];
|
|
22
|
+
reviewedAt?: string;
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Everything the platform has noticed about this app that someone should act on, gathered in a few
|
|
26
|
+
* seconds without building or testing anything: a newer nerd or SDK, what the model review found in the
|
|
27
|
+
* live code, and packages with a serious vulnerability reported since the last deploy. Never throws and
|
|
28
|
+
* never waits long; whatever cannot be reached is simply left out.
|
|
29
|
+
*
|
|
30
|
+
* This is what a coding agent is shown when a session starts, so the app's owner does not have to know
|
|
31
|
+
* that any of it exists, let alone open a dashboard to find it.
|
|
32
|
+
*/
|
|
33
|
+
export declare function gatherAttention(root: string): Promise<Attention>;
|
|
34
|
+
/** Short enough to sit at the top of a session: what, where, and one line on what to do about each kind. */
|
|
35
|
+
export declare function attentionText(a: Attention): string;
|
|
36
|
+
/**
|
|
37
|
+
* `nerd status`: what needs attention. With `--hook` it is the session-start hook's output: it prints
|
|
38
|
+
* nothing when there is nothing to say, and exits 0 whatever happens, so a session never opens on an error.
|
|
39
|
+
*/
|
|
40
|
+
export declare function status(opts: {
|
|
41
|
+
json: boolean;
|
|
42
|
+
hook: boolean;
|
|
43
|
+
}): Promise<void>;
|
|
44
|
+
/** `nerd review`: only the model review's findings, with every fix written out. */
|
|
45
|
+
export declare function review(opts: {
|
|
46
|
+
json: boolean;
|
|
47
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { ApiClient } from "../api.js";
|
|
4
|
+
import { RULES } from "../gates/rules.js";
|
|
5
|
+
import { currentVersions, pinned, versionFindings } from "../gates/versions.js";
|
|
6
|
+
import { findProjectRoot, projectPath, readNerdJson } from "../project.js";
|
|
7
|
+
import { log } from "../util.js";
|
|
8
|
+
import { cliVersion } from "./source.js";
|
|
9
|
+
const within = (p, ms) => Promise.race([p.catch(() => null), new Promise((r) => setTimeout(() => r(null), ms))]);
|
|
10
|
+
const item = (rule_id, extra = {}) => {
|
|
11
|
+
const r = RULES[rule_id];
|
|
12
|
+
return r ? { rule_id, title: r.title, severity: r.severity, audience: r.audience, risk: r.risk, fix: extra.fix ?? r.fix, ...(extra.where ? { where: extra.where } : {}) } : null;
|
|
13
|
+
};
|
|
14
|
+
/** The latest model review's findings for this app, mapped through this CLI's own catalog. */
|
|
15
|
+
export async function reviewItems(api, base) {
|
|
16
|
+
const got = await within(api.get(`${base}/review`), 5000);
|
|
17
|
+
const review = got?.review;
|
|
18
|
+
if (!review || review.status !== "done")
|
|
19
|
+
return { items: [] };
|
|
20
|
+
const items = [];
|
|
21
|
+
for (const f of review.findings ?? []) {
|
|
22
|
+
if (typeof f.rule_id !== "string" || !f.rule_id.startsWith("review/") || typeof f.file !== "string" || !/^[\w./@-]{1,200}$/.test(f.file) || !Number.isInteger(f.line))
|
|
23
|
+
continue;
|
|
24
|
+
const it = item(f.rule_id, { where: `${f.file}:${f.line}` });
|
|
25
|
+
if (it)
|
|
26
|
+
items.push(it);
|
|
27
|
+
}
|
|
28
|
+
return { items, reviewedAt: review.createdAt };
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Everything the platform has noticed about this app that someone should act on, gathered in a few
|
|
32
|
+
* seconds without building or testing anything: a newer nerd or SDK, what the model review found in the
|
|
33
|
+
* live code, and packages with a serious vulnerability reported since the last deploy. Never throws and
|
|
34
|
+
* never waits long; whatever cannot be reached is simply left out.
|
|
35
|
+
*
|
|
36
|
+
* This is what a coding agent is shown when a session starts, so the app's owner does not have to know
|
|
37
|
+
* that any of it exists, let alone open a dashboard to find it.
|
|
38
|
+
*/
|
|
39
|
+
export async function gatherAttention(root) {
|
|
40
|
+
const items = [];
|
|
41
|
+
let app = null;
|
|
42
|
+
let sdk = null;
|
|
43
|
+
try {
|
|
44
|
+
sdk = pinned(JSON.parse(readFileSync(path.join(root, "package.json"), "utf8")).dependencies?.["@nerdsystem/sdk"]);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// no package.json: nothing to say about the SDK
|
|
48
|
+
}
|
|
49
|
+
const versions = process.env.NERD_NO_VERSION_CHECK ? null : await within(currentVersions(), 5000);
|
|
50
|
+
if (versions)
|
|
51
|
+
for (const f of versionFindings({ cli: cliVersion(), sdk, versions })) {
|
|
52
|
+
const it = item(f.rule_id, { fix: f.fix, ...(f.file ? { where: f.file } : {}) });
|
|
53
|
+
if (it)
|
|
54
|
+
items.push(it);
|
|
55
|
+
}
|
|
56
|
+
let reviewedAt;
|
|
57
|
+
try {
|
|
58
|
+
const nerd = readNerdJson(root);
|
|
59
|
+
app = `${nerd.org}/${nerd.project}`;
|
|
60
|
+
const api = ApiClient.fromConfig();
|
|
61
|
+
const base = projectPath(nerd);
|
|
62
|
+
const [review, project] = await Promise.all([reviewItems(api, base), within(api.get(base), 5000)]);
|
|
63
|
+
items.push(...review.items);
|
|
64
|
+
reviewedAt = review.reviewedAt;
|
|
65
|
+
for (const v of project?.project.depsStatus?.vulnerable ?? []) {
|
|
66
|
+
if (v.severity !== "critical" && v.severity !== "high")
|
|
67
|
+
continue;
|
|
68
|
+
// Names and versions come from the platform's look-up of the registry, and are checked again for shape.
|
|
69
|
+
if (!/^(@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/.test(v.name) || !/^\d+\.\d+\.\d+$/.test(v.version))
|
|
70
|
+
continue;
|
|
71
|
+
const it = item("platform/vulnerable-package", { where: `${v.name} ${v.version}` });
|
|
72
|
+
if (it)
|
|
73
|
+
items.push(it);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// not linked, or not signed in: the versions above are all there is to say
|
|
78
|
+
}
|
|
79
|
+
return { app, items, ...(reviewedAt ? { reviewedAt } : {}) };
|
|
80
|
+
}
|
|
81
|
+
/** Short enough to sit at the top of a session: what, where, and one line on what to do about each kind. */
|
|
82
|
+
export function attentionText(a) {
|
|
83
|
+
if (!a.items.length)
|
|
84
|
+
return "";
|
|
85
|
+
const lines = [`nerdsystem has ${a.items.length} thing(s) for this app${a.app ? ` (${a.app})` : ""} that someone should look at:`, ""];
|
|
86
|
+
const seen = new Set();
|
|
87
|
+
for (const it of a.items) {
|
|
88
|
+
lines.push(`- ${it.title}${it.where ? ` (${it.where})` : ""}${it.audience === "human" ? " [for the person to decide]" : ""}`);
|
|
89
|
+
if (!seen.has(it.rule_id)) {
|
|
90
|
+
seen.add(it.rule_id);
|
|
91
|
+
lines.push(` Why: ${it.risk}`, ` Fix: ${it.fix}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (a.reviewedAt)
|
|
95
|
+
lines.push("", `Findings with a file and a line come from a model's review of the version deployed on ${a.reviewedAt.slice(0, 10)}. It is a second opinion and can be wrong, and code changed since may already have fixed one: read the code at each place before changing anything.`);
|
|
96
|
+
lines.push("", "Before starting on what the person asked for, tell them about these in one or two plain sentences, with no file names or jargon, and offer to take care of them. If they say yes, fix what is real, run `nerd check`, and deploy. Anything marked for the person to decide, put to them as a plain question and wait for the answer. If they would rather get on with their own request, do that first and remind them once at the end.");
|
|
97
|
+
return lines.join("\n");
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* `nerd status`: what needs attention. With `--hook` it is the session-start hook's output: it prints
|
|
101
|
+
* nothing when there is nothing to say, and exits 0 whatever happens, so a session never opens on an error.
|
|
102
|
+
*/
|
|
103
|
+
export async function status(opts) {
|
|
104
|
+
let a = { app: null, items: [] };
|
|
105
|
+
try {
|
|
106
|
+
a = await gatherAttention(findProjectRoot());
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
if (!opts.hook && !opts.json)
|
|
110
|
+
log.info("This folder is not a nerdsystem app (no nerd.json found).");
|
|
111
|
+
}
|
|
112
|
+
if (opts.json) {
|
|
113
|
+
process.stdout.write(`${JSON.stringify(a, null, 2)}\n`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const text = attentionText(a);
|
|
117
|
+
if (text)
|
|
118
|
+
process.stdout.write(`${text}\n`);
|
|
119
|
+
else if (!opts.hook)
|
|
120
|
+
log.ok(`Nothing needs attention${a.app ? ` for ${a.app}` : ""}.`);
|
|
121
|
+
}
|
|
122
|
+
/** `nerd review`: only the model review's findings, with every fix written out. */
|
|
123
|
+
export async function review(opts) {
|
|
124
|
+
const root = findProjectRoot();
|
|
125
|
+
const nerd = readNerdJson(root);
|
|
126
|
+
const r = await reviewItems(ApiClient.fromConfig(), projectPath(nerd));
|
|
127
|
+
if (opts.json) {
|
|
128
|
+
process.stdout.write(`${JSON.stringify(r, null, 2)}\n`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (!r.reviewedAt) {
|
|
132
|
+
log.info("No model review of this app yet. One runs at the end of `nerd deploy`.");
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (!r.items.length) {
|
|
136
|
+
log.ok(`The review of the version deployed on ${r.reviewedAt.slice(0, 10)} found nothing to raise.`);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
process.stdout.write(`${attentionText({ app: `${nerd.org}/${nerd.project}`, items: r.items, reviewedAt: r.reviewedAt })}\n`);
|
|
140
|
+
}
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -87,6 +87,26 @@ export function upgradeProject(root, tpl, version) {
|
|
|
87
87
|
// The files other agents read are generated from the skill that was just replaced.
|
|
88
88
|
for (const [rel, content] of Object.entries(renderAgentFiles(root).files))
|
|
89
89
|
write(rel, content);
|
|
90
|
+
// Claude Code's settings for this folder: keep whatever the person or agent added, and make sure the
|
|
91
|
+
// session-start hook and the platform's read-only commands are there.
|
|
92
|
+
const tplSettings = read(path.join(tpl, ".claude/settings.json"));
|
|
93
|
+
if (tplSettings !== null) {
|
|
94
|
+
const want = JSON.parse(tplSettings);
|
|
95
|
+
let have = {};
|
|
96
|
+
try {
|
|
97
|
+
have = JSON.parse(read(path.join(root, ".claude/settings.json")) ?? "{}");
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
have = {}; // an unreadable settings file is replaced rather than left broken
|
|
101
|
+
}
|
|
102
|
+
const allow = new Set([...(have.permissions?.allow ?? []), ...(want.permissions?.allow ?? [])]);
|
|
103
|
+
const hooks = { ...(have.hooks ?? {}) };
|
|
104
|
+
for (const [event, groups] of Object.entries(want.hooks ?? {})) {
|
|
105
|
+
const kept = (hooks[event] ?? []).filter((g) => !(g.hooks ?? []).some((h) => typeof h.command === "string" && h.command.startsWith("nerd status")));
|
|
106
|
+
hooks[event] = [...kept, ...groups];
|
|
107
|
+
}
|
|
108
|
+
write(".claude/settings.json", `${JSON.stringify({ ...have, permissions: { ...(have.permissions ?? {}), allow: [...allow] }, hooks }, null, 2)}\n`);
|
|
109
|
+
}
|
|
90
110
|
const ignore = read(path.join(root, ".gitignore")) ?? "";
|
|
91
111
|
if (!/^\.nerd\/?$/m.test(ignore))
|
|
92
112
|
write(".gitignore", `${ignore}${ignore.endsWith("\n") || !ignore ? "" : "\n"}.nerd/\n`);
|
package/dist/gates/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { gitleaksGate, semgrepGate } from "./tools.js";
|
|
|
4
4
|
import { suppressionsGate } from "./suppressions.js";
|
|
5
5
|
import { staticGate } from "./static.js";
|
|
6
6
|
import { designGate } from "./design.js";
|
|
7
|
+
import { reviewGate } from "./review.js";
|
|
7
8
|
import { testsGate } from "./tests.js";
|
|
8
9
|
import { versionsGate } from "./versions.js";
|
|
9
10
|
import { applyAttempts, MAX_ATTEMPTS } from "./attempts.js";
|
|
@@ -13,7 +14,7 @@ export { mask } from "./secrets.js";
|
|
|
13
14
|
export { MAX_ATTEMPTS, readAttempts } from "./attempts.js";
|
|
14
15
|
export { probeDeployment, skippedProbe, waitForDeployment } from "./smoke.js";
|
|
15
16
|
/** Gates that run on source, before the build. Suppressions first so a human sees them before anything else. */
|
|
16
|
-
export const SOURCE_GATES = [suppressionsGate, secretsGate, gitleaksGate, depsGate, rulesGate, versionsGate, staticGate, semgrepGate, policyGate, piiGate, typecheckGate, testsGate, designGate];
|
|
17
|
+
export const SOURCE_GATES = [suppressionsGate, secretsGate, gitleaksGate, depsGate, rulesGate, versionsGate, staticGate, semgrepGate, policyGate, piiGate, typecheckGate, testsGate, designGate, reviewGate];
|
|
17
18
|
/** Gates that need the built output. */
|
|
18
19
|
export const BUILD_GATES = [bundleGate, policyGate];
|
|
19
20
|
function selectGates(gates, onlyRules) {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type Gate } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Brings the platform's latest model review of this app into the same list as every other check, so an
|
|
4
|
+
* agent meets its findings in the loop it already runs and nobody has to go and look for them. Advice
|
|
5
|
+
* only. The words are this CLI's catalog; the review itself contributes a rule id, a file, and a line.
|
|
6
|
+
* Skipped without comment when there is no sign-in, no linked project, no review, or no network.
|
|
7
|
+
*/
|
|
8
|
+
export declare const reviewGate: Gate;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ApiClient } from "../api.js";
|
|
2
|
+
import { reviewItems } from "../commands/status.js";
|
|
3
|
+
import { projectPath, readNerdJson } from "../project.js";
|
|
4
|
+
import { counts, result, verdict } from "./types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Brings the platform's latest model review of this app into the same list as every other check, so an
|
|
7
|
+
* agent meets its findings in the loop it already runs and nobody has to go and look for them. Advice
|
|
8
|
+
* only. The words are this CLI's catalog; the review itself contributes a rule id, a file, and a line.
|
|
9
|
+
* Skipped without comment when there is no sign-in, no linked project, no review, or no network.
|
|
10
|
+
*/
|
|
11
|
+
export const reviewGate = {
|
|
12
|
+
name: "review",
|
|
13
|
+
title: "Model review of the deployed version",
|
|
14
|
+
blocking: false,
|
|
15
|
+
rulePrefixes: ["review/"],
|
|
16
|
+
async run(ctx) {
|
|
17
|
+
const t = Date.now();
|
|
18
|
+
// A git build has no person's sign-in to ask with, and the review is of code already deployed.
|
|
19
|
+
if (ctx.committed || process.env.NERD_NO_REVIEW)
|
|
20
|
+
return result(this, "skip", "Not asked for here", [], t);
|
|
21
|
+
let got;
|
|
22
|
+
try {
|
|
23
|
+
got = await reviewItems(ApiClient.fromConfig(), projectPath(readNerdJson(ctx.root)));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return result(this, "skip", "No linked project or sign-in to ask with", [], t);
|
|
27
|
+
}
|
|
28
|
+
if (!got.reviewedAt)
|
|
29
|
+
return result(this, "skip", "No review yet; one runs at the end of nerd deploy", [], t);
|
|
30
|
+
const findings = got.items.map((i) => {
|
|
31
|
+
const [file, line] = (i.where ?? "").split(":");
|
|
32
|
+
return { rule_id: i.rule_id, severity: i.severity, audience: i.audience, file, line: Number(line) || undefined, risk: i.risk, fix: i.fix, verify: "nerd deploy (the code is reviewed again after the next deploy)", attempt: 1, fingerprint: `${i.rule_id}:${i.where}` };
|
|
33
|
+
});
|
|
34
|
+
const when = got.reviewedAt.slice(0, 10);
|
|
35
|
+
return result(this, verdict(findings), findings.length ? `${counts(findings)}, from the review of the version deployed on ${when}; a second opinion that can be wrong, so read the code first` : `Nothing raised in the review of the version deployed on ${when}`, findings, t);
|
|
36
|
+
},
|
|
37
|
+
};
|
package/dist/gates/rules.js
CHANGED
|
@@ -56,6 +56,7 @@ export const RULES = {
|
|
|
56
56
|
"design/unused-table": { title: "A table nothing uses", severity: "warn", audience: "agent", risk: "A table left over from the starter or from a removed feature confuses the next change and may still hold people's data.", fix: "If the feature is gone, remove the table from the schema and write a migration that drops it; tell the person first if it may hold data they want. If it is meant to be used, connect it." },
|
|
57
57
|
"design/long-file": { title: "A very long file", severity: "info", audience: "agent", risk: "Changes to a file this long are more likely to break something elsewhere in it, for a person or an agent.", fix: "Split it along its natural parts (one screen, one group of routes per file) the next time you change it. Do not reorganise working code just for this." },
|
|
58
58
|
"design/unfinished": { title: "Something marked as unfinished", severity: "info", audience: "agent", risk: "A note to finish something later, or placeholder text, is about to go live.", fix: "Finish it, remove it, or tell the person it is not done yet so they can decide." },
|
|
59
|
+
"platform/vulnerable-package": { title: "A package this app uses has a serious vulnerability reported since it was deployed", severity: "warn", audience: "agent", risk: "The app passed its checks when it went live. Since then a flaw has been made public in something it depends on, and the live app still carries it.", fix: "Run `nerd check`: it names the package and the version to move to. Update it, run the tests, and deploy." },
|
|
59
60
|
"versions/cli-outdated": { title: "The nerd command is behind", severity: "warn", audience: "agent", risk: "An older nerd runs fewer checks and may not know about newer platform features.", fix: "Run `npm install -g nerdsystem@latest`." },
|
|
60
61
|
"versions/sdk-outdated": { title: "The app's SDK is behind", severity: "warn", audience: "agent", risk: "The app is missing fixes and safeguards that newer versions of the platform's library and instructions carry.", fix: "Run `nerd upgrade`, then `pnpm install` and `nerd check`." },
|
|
61
62
|
"versions/sdk-unsupported": { title: "The app's SDK is too old for the platform", severity: "block", audience: "agent", risk: "This version of the platform's library lacks something the platform now depends on to keep apps safe, so it is no longer accepted.", fix: "Run `nerd upgrade`, then `pnpm install` and `nerd check`." },
|
package/package.json
CHANGED
|
@@ -6,7 +6,22 @@
|
|
|
6
6
|
"Bash(nerd db migrations:*)",
|
|
7
7
|
"Bash(nerd auth config)",
|
|
8
8
|
"Bash(pnpm db:generate)",
|
|
9
|
-
"Bash(pnpm typecheck)"
|
|
9
|
+
"Bash(pnpm typecheck)",
|
|
10
|
+
"Bash(nerd status:*)",
|
|
11
|
+
"Bash(nerd review:*)"
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
"hooks": {
|
|
15
|
+
"SessionStart": [
|
|
16
|
+
{
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "nerd status --hook 2>/dev/null || true",
|
|
21
|
+
"timeout": 20
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
10
25
|
]
|
|
11
26
|
}
|
|
12
27
|
}
|
|
@@ -39,6 +39,8 @@ Tell the person plainly what does not carry. Their users sign up again on the ne
|
|
|
39
39
|
4. `nerd deploy` when it is ready. It runs the checks, builds, stores a copy of the code, applies pending migrations, uploads, prints the URL, and probes the live URL (headers, the sign-in routes, and a signed-out GET of every route the tests found locked; a `smoke/route-open` finding means a locked route is answering strangers on the live app, so run `nerd rollback` first and investigate second). With `--json` the output carries `probes`, the same shape as a check result, with `status: "skip"` and the reason when it did not run; probe findings never fail the deploy.
|
|
40
40
|
5. If something is wrong after deploying: `nerd logs` shows recent output from the deployed app (`--q` to search, `--pr 12` for a preview), `nerd deployments` shows status and errors, `nerd db query "..."` inspects production data.
|
|
41
41
|
|
|
42
|
+
**At the start of every session in this app, run `nerd status` before anything else** (in Claude Code it runs by itself and its output is already above). It lists what the platform has found for this app that someone should act on: a newer `nerd` or SDK, what the model review found in the live code, a package with a newly reported vulnerability. The person who owns this app does not know these exist and should never have to open a dashboard or learn a command to find out. So tell them, in one or two plain sentences with no file names or jargon, and offer to take care of it; if they say yes, fix what is real, run `nerd check`, and deploy. If it prints nothing, say nothing about it. `nerd review` prints the review's findings again with every fix written out.
|
|
43
|
+
|
|
42
44
|
`nerd check` also says when the `nerd` command or this app's SDK has fallen behind (the `versions/` rules; it asks the platform once a day). For the command, run `npm install -g nerdsystem@latest`. For the app, run `nerd upgrade`: it updates the SDK version, these instructions, and the test harness, and leaves the app's own code alone; then `pnpm install`, `nerd check`, and work through what it reports. Tell the person what changed before you deploy. Never update the app's dependencies or instructions on your own initiative in the middle of other work; do it when the check asks or the person does.
|
|
43
45
|
|
|
44
46
|
Run `nerd check --json` when you want a machine-readable list of problems. Its summary says how many gates ran and which were skipped (`skipped` in the JSON): semgrep and gitleaks only run locally when installed. `nerd deploy` has the platform run whichever is missing on the stored copy of the code before anything goes live (a finding from it stops the deploy like any other), and git builds always run both in the builder.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
description: How to build, run, and deploy this app on nerdsystem. Applies to server, database, auth, and deploy work.
|
|
3
3
|
alwaysApply: true
|
|
4
4
|
---
|
|
5
|
-
<!-- generated from .claude/skills/nerdsystem/SKILL.md (
|
|
5
|
+
<!-- generated from .claude/skills/nerdsystem/SKILL.md (7bfa9a6cabd1); edit the skill, then run: nerd agents sync -->
|
|
6
6
|
|
|
7
7
|
# Building on nerdsystem
|
|
8
8
|
|
|
@@ -40,6 +40,8 @@ Tell the person plainly what does not carry. Their users sign up again on the ne
|
|
|
40
40
|
4. `nerd deploy` when it is ready. It runs the checks, builds, stores a copy of the code, applies pending migrations, uploads, prints the URL, and probes the live URL (headers, the sign-in routes, and a signed-out GET of every route the tests found locked; a `smoke/route-open` finding means a locked route is answering strangers on the live app, so run `nerd rollback` first and investigate second). With `--json` the output carries `probes`, the same shape as a check result, with `status: "skip"` and the reason when it did not run; probe findings never fail the deploy.
|
|
41
41
|
5. If something is wrong after deploying: `nerd logs` shows recent output from the deployed app (`--q` to search, `--pr 12` for a preview), `nerd deployments` shows status and errors, `nerd db query "..."` inspects production data.
|
|
42
42
|
|
|
43
|
+
**At the start of every session in this app, run `nerd status` before anything else** (in Claude Code it runs by itself and its output is already above). It lists what the platform has found for this app that someone should act on: a newer `nerd` or SDK, what the model review found in the live code, a package with a newly reported vulnerability. The person who owns this app does not know these exist and should never have to open a dashboard or learn a command to find out. So tell them, in one or two plain sentences with no file names or jargon, and offer to take care of it; if they say yes, fix what is real, run `nerd check`, and deploy. If it prints nothing, say nothing about it. `nerd review` prints the review's findings again with every fix written out.
|
|
44
|
+
|
|
43
45
|
`nerd check` also says when the `nerd` command or this app's SDK has fallen behind (the `versions/` rules; it asks the platform once a day). For the command, run `npm install -g nerdsystem@latest`. For the app, run `nerd upgrade`: it updates the SDK version, these instructions, and the test harness, and leaves the app's own code alone; then `pnpm install`, `nerd check`, and work through what it reports. Tell the person what changed before you deploy. Never update the app's dependencies or instructions on your own initiative in the middle of other work; do it when the check asks or the person does.
|
|
44
46
|
|
|
45
47
|
Run `nerd check --json` when you want a machine-readable list of problems. Its summary says how many gates ran and which were skipped (`skipped` in the JSON): semgrep and gitleaks only run locally when installed. `nerd deploy` has the platform run whichever is missing on the stored copy of the code before anything goes live (a finding from it stops the deploy like any other), and git builds always run both in the builder.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- generated from .claude/skills/nerdsystem/SKILL.md (
|
|
1
|
+
<!-- generated from .claude/skills/nerdsystem/SKILL.md (7bfa9a6cabd1); edit the skill, then run: nerd agents sync -->
|
|
2
2
|
|
|
3
3
|
# Building on nerdsystem
|
|
4
4
|
|
|
@@ -36,6 +36,8 @@ Tell the person plainly what does not carry. Their users sign up again on the ne
|
|
|
36
36
|
4. `nerd deploy` when it is ready. It runs the checks, builds, stores a copy of the code, applies pending migrations, uploads, prints the URL, and probes the live URL (headers, the sign-in routes, and a signed-out GET of every route the tests found locked; a `smoke/route-open` finding means a locked route is answering strangers on the live app, so run `nerd rollback` first and investigate second). With `--json` the output carries `probes`, the same shape as a check result, with `status: "skip"` and the reason when it did not run; probe findings never fail the deploy.
|
|
37
37
|
5. If something is wrong after deploying: `nerd logs` shows recent output from the deployed app (`--q` to search, `--pr 12` for a preview), `nerd deployments` shows status and errors, `nerd db query "..."` inspects production data.
|
|
38
38
|
|
|
39
|
+
**At the start of every session in this app, run `nerd status` before anything else** (in Claude Code it runs by itself and its output is already above). It lists what the platform has found for this app that someone should act on: a newer `nerd` or SDK, what the model review found in the live code, a package with a newly reported vulnerability. The person who owns this app does not know these exist and should never have to open a dashboard or learn a command to find out. So tell them, in one or two plain sentences with no file names or jargon, and offer to take care of it; if they say yes, fix what is real, run `nerd check`, and deploy. If it prints nothing, say nothing about it. `nerd review` prints the review's findings again with every fix written out.
|
|
40
|
+
|
|
39
41
|
`nerd check` also says when the `nerd` command or this app's SDK has fallen behind (the `versions/` rules; it asks the platform once a day). For the command, run `npm install -g nerdsystem@latest`. For the app, run `nerd upgrade`: it updates the SDK version, these instructions, and the test harness, and leaves the app's own code alone; then `pnpm install`, `nerd check`, and work through what it reports. Tell the person what changed before you deploy. Never update the app's dependencies or instructions on your own initiative in the middle of other work; do it when the check asks or the person does.
|
|
40
42
|
|
|
41
43
|
Run `nerd check --json` when you want a machine-readable list of problems. Its summary says how many gates ran and which were skipped (`skipped` in the JSON): semgrep and gitleaks only run locally when installed. `nerd deploy` has the platform run whichever is missing on the stored copy of the code before anything goes live (a finding from it stops the deploy like any other), and git builds always run both in the builder.
|
package/template/AGENTS.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- generated from .claude/skills/nerdsystem/SKILL.md (
|
|
1
|
+
<!-- generated from .claude/skills/nerdsystem/SKILL.md (7bfa9a6cabd1); edit the skill, then run: nerd agents sync -->
|
|
2
2
|
|
|
3
3
|
# Building on nerdsystem
|
|
4
4
|
|
|
@@ -36,6 +36,8 @@ Tell the person plainly what does not carry. Their users sign up again on the ne
|
|
|
36
36
|
4. `nerd deploy` when it is ready. It runs the checks, builds, stores a copy of the code, applies pending migrations, uploads, prints the URL, and probes the live URL (headers, the sign-in routes, and a signed-out GET of every route the tests found locked; a `smoke/route-open` finding means a locked route is answering strangers on the live app, so run `nerd rollback` first and investigate second). With `--json` the output carries `probes`, the same shape as a check result, with `status: "skip"` and the reason when it did not run; probe findings never fail the deploy.
|
|
37
37
|
5. If something is wrong after deploying: `nerd logs` shows recent output from the deployed app (`--q` to search, `--pr 12` for a preview), `nerd deployments` shows status and errors, `nerd db query "..."` inspects production data.
|
|
38
38
|
|
|
39
|
+
**At the start of every session in this app, run `nerd status` before anything else** (in Claude Code it runs by itself and its output is already above). It lists what the platform has found for this app that someone should act on: a newer `nerd` or SDK, what the model review found in the live code, a package with a newly reported vulnerability. The person who owns this app does not know these exist and should never have to open a dashboard or learn a command to find out. So tell them, in one or two plain sentences with no file names or jargon, and offer to take care of it; if they say yes, fix what is real, run `nerd check`, and deploy. If it prints nothing, say nothing about it. `nerd review` prints the review's findings again with every fix written out.
|
|
40
|
+
|
|
39
41
|
`nerd check` also says when the `nerd` command or this app's SDK has fallen behind (the `versions/` rules; it asks the platform once a day). For the command, run `npm install -g nerdsystem@latest`. For the app, run `nerd upgrade`: it updates the SDK version, these instructions, and the test harness, and leaves the app's own code alone; then `pnpm install`, `nerd check`, and work through what it reports. Tell the person what changed before you deploy. Never update the app's dependencies or instructions on your own initiative in the middle of other work; do it when the check asks or the person does.
|
|
40
42
|
|
|
41
43
|
Run `nerd check --json` when you want a machine-readable list of problems. Its summary says how many gates ran and which were skipped (`skipped` in the JSON): semgrep and gitleaks only run locally when installed. `nerd deploy` has the platform run whichever is missing on the stored copy of the code before anything goes live (a finding from it stops the deploy like any other), and git builds always run both in the builder.
|
package/template/CLAUDE.md
CHANGED
|
@@ -13,6 +13,10 @@ nerdsystem deploys this app to Cloudflare and provides authentication and author
|
|
|
13
13
|
- With a linked GitHub repo, pushes to the production branch and pull requests deploy automatically. `nerd builds` and `nerd builds show <id>` show what happened.
|
|
14
14
|
- `pnpm db:generate` creates a migration after editing `src/server/db/schema.ts`. Never edit the database by hand.
|
|
15
15
|
|
|
16
|
+
## When a session starts
|
|
17
|
+
|
|
18
|
+
Run `nerd status` first (Claude Code does this by itself). It lists what the platform has found for this app: updates, findings from the model review of the live code, packages with a new vulnerability. The app's owner does not know these exist. Tell them in plain words and offer to take care of them; they should never need a command or a dashboard to find out.
|
|
19
|
+
|
|
16
20
|
## Layout
|
|
17
21
|
|
|
18
22
|
- `src/server/index.ts` is the Worker entry. Build the API here with Hono; mount routers under `/api/...`.
|
package/template/GEMINI.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- generated from .claude/skills/nerdsystem/SKILL.md (
|
|
1
|
+
<!-- generated from .claude/skills/nerdsystem/SKILL.md (7bfa9a6cabd1); edit the skill, then run: nerd agents sync -->
|
|
2
2
|
|
|
3
3
|
# Building on nerdsystem
|
|
4
4
|
|
|
@@ -36,6 +36,8 @@ Tell the person plainly what does not carry. Their users sign up again on the ne
|
|
|
36
36
|
4. `nerd deploy` when it is ready. It runs the checks, builds, stores a copy of the code, applies pending migrations, uploads, prints the URL, and probes the live URL (headers, the sign-in routes, and a signed-out GET of every route the tests found locked; a `smoke/route-open` finding means a locked route is answering strangers on the live app, so run `nerd rollback` first and investigate second). With `--json` the output carries `probes`, the same shape as a check result, with `status: "skip"` and the reason when it did not run; probe findings never fail the deploy.
|
|
37
37
|
5. If something is wrong after deploying: `nerd logs` shows recent output from the deployed app (`--q` to search, `--pr 12` for a preview), `nerd deployments` shows status and errors, `nerd db query "..."` inspects production data.
|
|
38
38
|
|
|
39
|
+
**At the start of every session in this app, run `nerd status` before anything else** (in Claude Code it runs by itself and its output is already above). It lists what the platform has found for this app that someone should act on: a newer `nerd` or SDK, what the model review found in the live code, a package with a newly reported vulnerability. The person who owns this app does not know these exist and should never have to open a dashboard or learn a command to find out. So tell them, in one or two plain sentences with no file names or jargon, and offer to take care of it; if they say yes, fix what is real, run `nerd check`, and deploy. If it prints nothing, say nothing about it. `nerd review` prints the review's findings again with every fix written out.
|
|
40
|
+
|
|
39
41
|
`nerd check` also says when the `nerd` command or this app's SDK has fallen behind (the `versions/` rules; it asks the platform once a day). For the command, run `npm install -g nerdsystem@latest`. For the app, run `nerd upgrade`: it updates the SDK version, these instructions, and the test harness, and leaves the app's own code alone; then `pnpm install`, `nerd check`, and work through what it reports. Tell the person what changed before you deploy. Never update the app's dependencies or instructions on your own initiative in the middle of other work; do it when the check asks or the person does.
|
|
40
42
|
|
|
41
43
|
Run `nerd check --json` when you want a machine-readable list of problems. Its summary says how many gates ran and which were skipped (`skipped` in the JSON): semgrep and gitleaks only run locally when installed. `nerd deploy` has the platform run whichever is missing on the stored copy of the code before anything goes live (a finding from it stops the deploy like any other), and git builds always run both in the builder.
|