@ultimat3/cli 25.1.0 → 26.0.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 +3 -3
- package/package.json +28 -28
- package/src/cmd-db-branch.ts +15 -11
- package/src/cmd-db-spec.ts +2 -2
- package/src/cmd-deploy-drain.ts +6 -1
- package/src/cmd-docs.ts +1 -1
- package/src/cmd-jobs-spec.ts +11 -7
- package/src/cmd-jobs.ts +10 -10
- package/src/cmd-planned.ts +3 -3
- package/src/cmd-registries-spec.ts +6 -6
- package/src/cmd-registries.ts +6 -6
- package/src/cmd-routes-spec.ts +1 -1
- package/src/cmd-routes.ts +9 -52
- package/src/cmd-tasks.ts +2 -2
- package/src/db-branch.ts +6 -6
- package/src/db-finding.ts +1 -1
- package/src/dev-restart-retire.ts +3 -1
- package/src/doctor-guards.ts +74 -19
- package/src/document-styles.ts +2 -4
- package/src/error-contract.ts +1 -1
- package/src/errors.ts +4 -4
- package/src/fix-command.ts +1 -1
- package/src/index.ts +6 -6
- package/src/jobs-report.ts +3 -3
- package/src/jobs-table.ts +1 -1
- package/src/live-routes.ts +0 -1
- package/src/mcp-db-target.ts +1 -1
- package/src/mcp-errors.ts +2 -2
- package/src/mcp-host.ts +4 -2
- package/src/messages.ts +4 -2
- package/src/parse.ts +23 -2
- package/src/role-replicator.ts +1 -1
- package/src/route-table.ts +113 -0
- package/src/runtime-jobs.ts +1 -1
- package/src/serve-boot.ts +8 -2
- package/src/serve-drain.ts +5 -1
- package/src/serve-retire.ts +7 -3
- package/src/site-seo.ts +1 -4
- package/src/templates/scaffold-claude-agents.ts +4 -4
- package/src/templates/scaffold-claude-commands.ts +2 -2
- package/src/templates/scaffold-claude.ts +1 -1
- package/src/templates/scaffold-guards.ts +12 -0
- package/src/templates/scaffold-helm-templates.ts +6 -2
- package/src/templates/scaffold-helm.ts +4 -1
|
@@ -40,7 +40,7 @@ stop; that answer is worth more than a plan built on a shape the app cannot hold
|
|
|
40
40
|
|---|---|
|
|
41
41
|
| \`apps/web/site/<path>/page.tsx\` | public, SEO-critical, 0kb JS |
|
|
42
42
|
| \`apps/web/app/<slice>/\` | the feature slice: entity, repo, policy, actions, queries, jobs, UI |
|
|
43
|
-
| \`apps/web/api
|
|
43
|
+
| \`apps/web/api/index.ts\` | the one \`defineApi()\` collecting every action and query — no route file lives under \`api/\` |
|
|
44
44
|
| \`apps/web/shared/\` | tokens, primitives, the actor type — a leaf, imports nothing of yours |
|
|
45
45
|
| \`packages/db/\` | schema, migrations, seed |
|
|
46
46
|
| \`packages/ui/\` | components with no feature knowledge |
|
|
@@ -79,7 +79,7 @@ feature slice. Nothing else. A change outside that set is a collision — report
|
|
|
79
79
|
| Money | \`{ minor, currency }\` — integer minor units and an ISO code, both, always. Never a float |
|
|
80
80
|
| Time | store UTC; a formatted date always names an explicit IANA time zone |
|
|
81
81
|
|
|
82
|
-
Inspect before you change: \`x entities list\`, \`x entities
|
|
82
|
+
Inspect before you change: \`x entities list\`, \`x entities show <name>\`, both with \`--json\`.
|
|
83
83
|
|
|
84
84
|
Checks: \`bun test <path>/entity.test.ts\`, \`bunx biome check --write <paths>\`, and \`bun run typecheck\`
|
|
85
85
|
once when you are otherwise done. Never \`x verify\` — that belongs to whoever coordinates you.
|
|
@@ -105,7 +105,7 @@ renders. A change outside that set is a collision — report it, do not make it.
|
|
|
105
105
|
| Tasks name a time zone | a cron schedule with an ambient zone is a different time twice a year |
|
|
106
106
|
| No \`any\` | \`unknown\` plus a schema parse |
|
|
107
107
|
|
|
108
|
-
Inspect before you change: \`x actions
|
|
108
|
+
Inspect before you change: \`x actions show <name>\`, \`x queries show <name>\`, \`x jobs list\`,
|
|
109
109
|
\`x tasks list\`, \`x policy explain <subject>\` — every one takes \`--json\`.
|
|
110
110
|
|
|
111
111
|
Checks: \`bun test <path>/<file>.test.ts\`, \`bunx biome check --write <paths>\`, and \`bun run typecheck\`
|
|
@@ -126,7 +126,7 @@ calls. A change outside that set is a collision — report it, do not make it.
|
|
|
126
126
|
|---|---|
|
|
127
127
|
| \`site/\` is 0kb JS | and may not import from \`app/\`. One interactive control on a static page is an island: \`x g island <name> --at <dir>\` |
|
|
128
128
|
| \`shared/\` is a leaf | tokens, primitives, the actor type. It imports nothing of yours |
|
|
129
|
-
| The directory is the URL | \`page.tsx\` under \`site/\`/\`app
|
|
129
|
+
| The directory is the URL | \`page.tsx\` under \`site/\`/\`app/\`; \`api/\` holds no route file, only \`defineApi()\`'s actions and queries. The filename is never the path |
|
|
130
130
|
| Every string through \`t()\` | a literal in a component is a string no locale can ever translate |
|
|
131
131
|
| Semantic tokens only | never a raw hex, in a component or a stylesheet |
|
|
132
132
|
| Dates name a zone | explicit IANA time zone at every call site, no ambient default |
|
|
@@ -66,12 +66,12 @@ SQL into \`packages/db/migrations/\`.
|
|
|
66
66
|
|---|---|---|
|
|
67
67
|
| \`apps/web/site/\` | 0kb JS, may not import \`apps/web/app/\` | the static path pays the app's bundle |
|
|
68
68
|
| \`apps/web/app/\` | authed, streaming, hydrated | — |
|
|
69
|
-
| \`apps/web/api/\` | actions only, \`
|
|
69
|
+
| \`apps/web/api/\` | actions and queries only, collected by \`defineApi()\` — no route file | a second HTTP surface |
|
|
70
70
|
| \`apps/web/shared/\` | a leaf: imports nothing of yours | an import cycle across surfaces |
|
|
71
71
|
| \`repo.ts\` | the only file that touches the database | authz bypassed by a raw read |
|
|
72
72
|
| routes | call actions and queries, never a repo | policy skipped |
|
|
73
73
|
|
|
74
|
-
Route files: \`page.tsx\` under \`site/\`/\`app/\`,
|
|
74
|
+
Route files: \`page.tsx\` under \`site/\`/\`app/\`, and none under \`api/\`. **The directory is the URL** —
|
|
75
75
|
the filename never is. One interactive control on a 0kb page is an island: \`x g island <name> --at <dir>\`.
|
|
76
76
|
|
|
77
77
|
## 4. Gate it
|
|
@@ -75,6 +75,18 @@ export const SHIPPED_GUARD_NAMES: readonly string[] = SHIPPED.map(([name]) => na
|
|
|
75
75
|
export const shippedGuardFiles = (name: string): readonly GeneratedFile[] | undefined =>
|
|
76
76
|
SHIPPED.find(([shipped]) => shipped === name)?.[1]();
|
|
77
77
|
|
|
78
|
+
/**
|
|
79
|
+
* The current text of a shipped guard's rule file (`guards/<name>.ts`), or `undefined` when the
|
|
80
|
+
* name was never shipped — what `x doctor` compares an app's copy against.
|
|
81
|
+
*/
|
|
82
|
+
export const shippedGuardSource = (name: string): string | undefined => {
|
|
83
|
+
const contents = shippedGuardFiles(name)?.find(
|
|
84
|
+
(file) => file.path === `guards/${name}.ts`,
|
|
85
|
+
)?.contents;
|
|
86
|
+
// A guard is source text; bytes would be a template bug, and comparing them as text would hide it.
|
|
87
|
+
return typeof contents === 'string' ? contents : undefined;
|
|
88
|
+
};
|
|
89
|
+
|
|
78
90
|
/**
|
|
79
91
|
* Every guard `x new` ships, each with its test. One module per guard, because an app deletes a
|
|
80
92
|
* rule it does not want by deleting one file — and a guard the app then writes for itself is
|
|
@@ -195,14 +195,18 @@ nobody bound. Derived here rather than stated twice in values.yaml, where the tw
|
|
|
195
195
|
{{/*
|
|
196
196
|
A role's terminationGracePeriodSeconds, in the order the kubelet's budget is spent: the preStop
|
|
197
197
|
sleep (web and sync, 1.30+), the worker's opt-in retire (roles.worker.retireSeconds), the
|
|
198
|
-
readiness grace (web and sync — every other role drains with none), the drain budget (app.config.ts drain.deadlineMs, every role
|
|
198
|
+
readiness grace (web and sync — every other role drains with none), the drain budget (app.config.ts drain.deadlineMs, every role;
|
|
199
|
+
the worker's is drain.workerDeadlineSeconds instead when > 0, from drain.workerDeadlineMs) and the teardown margin.
|
|
199
200
|
Defaults: 45s web/sync (40s below 1.30), 35s the rest. x deploy --method helm sets
|
|
200
|
-
drain.deadlineSeconds and drain.readinessGraceSeconds from app.config.ts.
|
|
201
|
+
drain.deadlineSeconds, drain.workerDeadlineSeconds and drain.readinessGraceSeconds from app.config.ts.
|
|
201
202
|
*/}}
|
|
202
203
|
{{- define "${app.kebab}.terminationGracePeriodSeconds" -}}
|
|
203
204
|
{{- $drain := .root.Values.drain -}}
|
|
204
205
|
{{- $total := add (int $drain.deadlineSeconds) (int $drain.teardownMarginSeconds) -}}
|
|
205
206
|
{{- if eq .role "worker" -}}
|
|
207
|
+
{{- if gt (int $drain.workerDeadlineSeconds) 0 -}}
|
|
208
|
+
{{- $total = add (int $drain.workerDeadlineSeconds) (int $drain.teardownMarginSeconds) -}}
|
|
209
|
+
{{- end -}}
|
|
206
210
|
{{- $total = add $total (int .cfg.retireSeconds) -}}
|
|
207
211
|
{{- end -}}
|
|
208
212
|
{{- if .cfg.port -}}
|
|
@@ -99,11 +99,14 @@ securityContext:
|
|
|
99
99
|
# readinessGraceSeconds app.config.ts drain.readinessGraceMs / 1000 (web and sync only)
|
|
100
100
|
# deadlineSeconds app.config.ts drain.deadlineMs / 1000 — x deploy --method helm sets
|
|
101
101
|
# both from app.config.ts, so a raised budget raises the grace with it
|
|
102
|
+
# workerDeadlineSeconds app.config.ts drain.workerDeadlineMs / 1000 — the worker's budget in place
|
|
103
|
+
# of deadlineSeconds, up to a day; 0 means the worker uses deadlineSeconds
|
|
102
104
|
# teardownMarginSeconds the release after the drain, the telemetry flush, the pool close
|
|
103
105
|
drain:
|
|
104
106
|
preStopSleepSeconds: 5
|
|
105
107
|
readinessGraceSeconds: 5
|
|
106
108
|
deadlineSeconds: 25
|
|
109
|
+
workerDeadlineSeconds: 0
|
|
107
110
|
teardownMarginSeconds: 10
|
|
108
111
|
|
|
109
112
|
# How long a new pod must stay Ready before a rollout counts it and stops an old one.
|
|
@@ -166,7 +169,7 @@ roles:
|
|
|
166
169
|
replicas: 2
|
|
167
170
|
# The retire, OFF at 0. Set to the longest a held job may run, in seconds, and the worker's
|
|
168
171
|
# preStop sends its PID 1 SIGUSR2: stop claiming, finish every held job, abort nothing, exit 0
|
|
169
|
-
# — for a job whose side effect must happen at most once and may outlast drain.
|
|
172
|
+
# — for a job whose side effect must happen at most once and may outlast its drain budget.
|
|
170
173
|
# Added to this role's terminationGracePeriodSeconds, which the kubelet counts the preStop against.
|
|
171
174
|
retireSeconds: 0
|
|
172
175
|
resources:
|