@nanobpm/nano-workforce 0.38.0 → 0.39.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 +14 -0
- package/nano.app.json +10 -0
- package/openapi.yaml +34 -45
- package/operations/answerFeatureEscalation.ts +3 -12
- package/operations/appendBlackboard.ts +3 -6
- package/operations/checkAbandon.ts +3 -5
- package/operations/getVersion.ts +4 -6
- package/operations/listActivePrs.ts +4 -8
- package/operations/postMessage.ts +3 -11
- package/operations/readBlackboard.ts +3 -6
- package/operations/startConvergenceLoop.ts +3 -12
- package/operations/startPlanFanout.ts +3 -14
- package/package.json +3 -2
- package/tsconfig.json +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [0.39.1](https://github.com/nanobpm/nano-workforce/compare/v0.39.0...v0.39.1) (2026-08-10)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **openapi:** use 3.0 nullable idiom instead of 3.1 type-arrays ([#111](https://github.com/nanobpm/nano-workforce/issues/111)) ([28f40c8](https://github.com/nanobpm/nano-workforce/commit/28f40c891d48043ef7537158466bafdfb79b9792))
|
|
7
|
+
|
|
8
|
+
# [0.39.0](https://github.com/nanobpm/nano-workforce/compare/v0.38.0...v0.39.0) (2026-08-10)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* adopt urban 0.38.0 typed delegate registry for the OpenAPI surface ([#110](https://github.com/nanobpm/nano-workforce/issues/110)) ([fe62908](https://github.com/nanobpm/nano-workforce/commit/fe62908968c0bd707f8e2da58fa550cca9fbab5b))
|
|
14
|
+
|
|
1
15
|
# [0.38.0](https://github.com/nanobpm/nano-workforce/compare/v0.37.0...v0.38.0) (2026-08-10)
|
|
2
16
|
|
|
3
17
|
|
package/nano.app.json
CHANGED
|
@@ -124,6 +124,16 @@
|
|
|
124
124
|
"handler": "workers/retro-record/worker.ts"
|
|
125
125
|
}
|
|
126
126
|
],
|
|
127
|
+
"externalTaskTypes": [
|
|
128
|
+
"senior:pr-review",
|
|
129
|
+
"senior:fix-ci",
|
|
130
|
+
"senior:rebase",
|
|
131
|
+
"senior:plan",
|
|
132
|
+
"senior:plan-review",
|
|
133
|
+
"senior:feature",
|
|
134
|
+
"senior:trial-merge",
|
|
135
|
+
"senior:retro"
|
|
136
|
+
],
|
|
127
137
|
"surfaces": {
|
|
128
138
|
"pages": {
|
|
129
139
|
"enabled": true,
|
package/openapi.yaml
CHANGED
|
@@ -38,6 +38,7 @@ components:
|
|
|
38
38
|
ActivePr:
|
|
39
39
|
type: object
|
|
40
40
|
description: A tracked PR that is not in a terminal (converged/abandoned) state.
|
|
41
|
+
additionalProperties: false
|
|
41
42
|
required:
|
|
42
43
|
- prKey
|
|
43
44
|
- repo
|
|
@@ -62,36 +63,30 @@ components:
|
|
|
62
63
|
url:
|
|
63
64
|
type: string
|
|
64
65
|
title:
|
|
65
|
-
type:
|
|
66
|
-
|
|
67
|
-
- "null"
|
|
66
|
+
type: string
|
|
67
|
+
nullable: true
|
|
68
68
|
status:
|
|
69
69
|
type: string
|
|
70
70
|
round:
|
|
71
71
|
type: integer
|
|
72
72
|
processKey:
|
|
73
|
-
type:
|
|
74
|
-
|
|
75
|
-
- "null"
|
|
73
|
+
type: string
|
|
74
|
+
nullable: true
|
|
76
75
|
description: The engine process instance key; also the keyField the pages processExplorer link uses.
|
|
77
76
|
waitingSince:
|
|
78
|
-
type:
|
|
79
|
-
|
|
80
|
-
- "null"
|
|
77
|
+
type: string
|
|
78
|
+
nullable: true
|
|
81
79
|
openEscalation:
|
|
82
|
-
type:
|
|
83
|
-
|
|
84
|
-
- "null"
|
|
80
|
+
type: string
|
|
81
|
+
nullable: true
|
|
85
82
|
updatedAt:
|
|
86
83
|
type: string
|
|
87
84
|
activeWorker:
|
|
88
|
-
type:
|
|
89
|
-
|
|
90
|
-
- "null"
|
|
85
|
+
type: string
|
|
86
|
+
nullable: true
|
|
91
87
|
leaseUntil:
|
|
92
|
-
type:
|
|
93
|
-
|
|
94
|
-
- "null"
|
|
88
|
+
type: string
|
|
89
|
+
nullable: true
|
|
95
90
|
ActivePrList:
|
|
96
91
|
type: object
|
|
97
92
|
required:
|
|
@@ -107,6 +102,7 @@ components:
|
|
|
107
102
|
VersionInfo:
|
|
108
103
|
type: object
|
|
109
104
|
description: The running app's identity (which code is actually live).
|
|
105
|
+
additionalProperties: false
|
|
110
106
|
required:
|
|
111
107
|
- name
|
|
112
108
|
- version
|
|
@@ -121,27 +117,22 @@ components:
|
|
|
121
117
|
name:
|
|
122
118
|
type: string
|
|
123
119
|
version:
|
|
124
|
-
type:
|
|
125
|
-
|
|
126
|
-
- "null"
|
|
120
|
+
type: string
|
|
121
|
+
nullable: true
|
|
127
122
|
urbanVersion:
|
|
128
|
-
type:
|
|
129
|
-
|
|
130
|
-
- "null"
|
|
123
|
+
type: string
|
|
124
|
+
nullable: true
|
|
131
125
|
gitSha:
|
|
132
|
-
type:
|
|
133
|
-
|
|
134
|
-
- "null"
|
|
126
|
+
type: string
|
|
127
|
+
nullable: true
|
|
135
128
|
gitBranch:
|
|
136
|
-
type:
|
|
137
|
-
|
|
138
|
-
- "null"
|
|
129
|
+
type: string
|
|
130
|
+
nullable: true
|
|
139
131
|
runtime:
|
|
140
132
|
type: string
|
|
141
133
|
pid:
|
|
142
|
-
type:
|
|
143
|
-
|
|
144
|
-
- "null"
|
|
134
|
+
type: integer
|
|
135
|
+
nullable: true
|
|
145
136
|
startedAt:
|
|
146
137
|
type: string
|
|
147
138
|
uptimeSeconds:
|
|
@@ -154,9 +145,8 @@ components:
|
|
|
154
145
|
prKey:
|
|
155
146
|
type: string
|
|
156
147
|
processKey:
|
|
157
|
-
type:
|
|
158
|
-
|
|
159
|
-
- "null"
|
|
148
|
+
type: string
|
|
149
|
+
nullable: true
|
|
160
150
|
description: The started convergence-loop instance key (null if the engine did not return one).
|
|
161
151
|
alreadyRunning:
|
|
162
152
|
type: boolean
|
|
@@ -170,9 +160,8 @@ components:
|
|
|
170
160
|
planKey:
|
|
171
161
|
type: string
|
|
172
162
|
processKey:
|
|
173
|
-
type:
|
|
174
|
-
|
|
175
|
-
- "null"
|
|
163
|
+
type: string
|
|
164
|
+
nullable: true
|
|
176
165
|
alreadyRunning:
|
|
177
166
|
type: boolean
|
|
178
167
|
description: True when a non-terminal plan for this issue already exists; no new instance was started.
|
|
@@ -232,6 +221,7 @@ components:
|
|
|
232
221
|
description: The operator's answer that resumes the parked implementation agent.
|
|
233
222
|
BlackboardEntry:
|
|
234
223
|
type: object
|
|
224
|
+
additionalProperties: false
|
|
235
225
|
required:
|
|
236
226
|
- id
|
|
237
227
|
- author_task
|
|
@@ -254,9 +244,8 @@ components:
|
|
|
254
244
|
body:
|
|
255
245
|
type: string
|
|
256
246
|
wave:
|
|
257
|
-
type:
|
|
258
|
-
|
|
259
|
-
- "null"
|
|
247
|
+
type: integer
|
|
248
|
+
nullable: true
|
|
260
249
|
created_at:
|
|
261
250
|
type: string
|
|
262
251
|
BlackboardPage:
|
|
@@ -273,9 +262,8 @@ components:
|
|
|
273
262
|
items:
|
|
274
263
|
$ref: "#/components/schemas/BlackboardEntry"
|
|
275
264
|
cursor:
|
|
276
|
-
type:
|
|
277
|
-
|
|
278
|
-
- "null"
|
|
265
|
+
type: integer
|
|
266
|
+
nullable: true
|
|
279
267
|
description: The plan's current head id; pass it back as `since` on the next poll (Tier 2).
|
|
280
268
|
BlackboardAppendRequest:
|
|
281
269
|
type: object
|
|
@@ -321,6 +309,7 @@ components:
|
|
|
321
309
|
description: Prior sibling file-claims on the same file(s) (advisory first-writer-wins; never a lock).
|
|
322
310
|
items:
|
|
323
311
|
type: object
|
|
312
|
+
additionalProperties: false
|
|
324
313
|
required:
|
|
325
314
|
- file
|
|
326
315
|
- author_task
|
|
@@ -10,25 +10,16 @@
|
|
|
10
10
|
// Body accepts either the raw correlation key or a plan+task pair:
|
|
11
11
|
// { "corrKey": "owner/repo#12:task-3", "answer": "…" }
|
|
12
12
|
// { "plan": "owner/repo#12", "task": "task-3", "answer": "…" }
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
import { answerTaskEscalation, featureCorrKey } from "../app/plan.ts";
|
|
15
15
|
import { envVar } from "../app/version.ts";
|
|
16
|
+
import { defineOperation } from "../nano-generated/operations.ts";
|
|
16
17
|
|
|
17
18
|
const WEBHOOK_SECRET = envVar("NANO_PR_WEBHOOK_SECRET") ?? "";
|
|
18
19
|
|
|
19
20
|
const str = (v: unknown): string => (typeof v === "string" ? v.trim() : "");
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
corrKey?: unknown;
|
|
23
|
-
plan?: unknown;
|
|
24
|
-
task?: unknown;
|
|
25
|
-
answer?: unknown;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export default defineOperation<
|
|
29
|
-
{ params: Record<string, string>; query: Record<string, string | string[] | undefined>; body: Body },
|
|
30
|
-
{ ok: boolean } & Record<string, unknown>
|
|
31
|
-
>("answerFeatureEscalation", async ({ req, body }, app) => {
|
|
22
|
+
export default defineOperation("answerFeatureEscalation", async ({ req, body }, app) => {
|
|
32
23
|
if (WEBHOOK_SECRET && req.headers.get("x-hook-secret") !== WEBHOOK_SECRET) {
|
|
33
24
|
return { status: 401, body: { ok: false, error: "unauthorized" } };
|
|
34
25
|
}
|
|
@@ -7,19 +7,16 @@
|
|
|
7
7
|
// POST → append one entry: { author_task?, kind?, files?, body, wave?, dedupe_key? }. Idempotent
|
|
8
8
|
// on (plan, dedupe_key). Returns { id, inserted, conflicts } — `conflicts` lists prior
|
|
9
9
|
// sibling `file-claim`s on the same file(s) (advisory first-writer-wins; never a lock).
|
|
10
|
-
|
|
11
|
-
import type { ClaimConflict } from "../app/blackboard.ts";
|
|
10
|
+
|
|
12
11
|
import {
|
|
13
12
|
appendEntry,
|
|
14
13
|
detectFileClaimConflicts,
|
|
15
14
|
normalizeKind,
|
|
16
15
|
planKeyForToken,
|
|
17
16
|
} from "../app/blackboard.ts";
|
|
17
|
+
import { defineOperation } from "../nano-generated/operations.ts";
|
|
18
18
|
|
|
19
|
-
export default defineOperation
|
|
20
|
-
{ params: Record<string, string>; query: { token?: string }; body: Record<string, unknown> },
|
|
21
|
-
{ id: number; inserted: boolean; conflicts: ClaimConflict[] } | { error: string }
|
|
22
|
-
>("appendBlackboard", async ({ req, body }, app) => {
|
|
19
|
+
export default defineOperation("appendBlackboard", async ({ req, body }, app) => {
|
|
23
20
|
const token = (req.query.get("token") ?? req.headers.get("x-blackboard-token") ?? "").trim();
|
|
24
21
|
if (!token) return { status: 400, body: { error: "missing blackboard token" } };
|
|
25
22
|
const planKey = await planKeyForToken(app.data, token);
|
|
@@ -9,13 +9,11 @@
|
|
|
9
9
|
//
|
|
10
10
|
// GET → { prKey, status, abandoned } — `abandoned` is derived from `pull_requests.status`,
|
|
11
11
|
// which Urban's cancel primitive sets to 'abandoned' on cancel. `true` ⇒ the agent must stop.
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
import { abandonStatusForToken } from "../app/abandon.ts";
|
|
14
|
+
import { defineOperation } from "../nano-generated/operations.ts";
|
|
14
15
|
|
|
15
|
-
export default defineOperation
|
|
16
|
-
{ params: Record<string, string>; query: { token?: string }; body: unknown },
|
|
17
|
-
{ prKey: string; status: string; abandoned: boolean } | { error: string }
|
|
18
|
-
>("checkAbandon", async ({ req }, app) => {
|
|
16
|
+
export default defineOperation("checkAbandon", async ({ req }, app) => {
|
|
19
17
|
const token = (req.query.get("token") ?? req.headers.get("x-abandon-token") ?? "").trim();
|
|
20
18
|
if (!token) return { status: 400, body: { error: "missing abandon token" } };
|
|
21
19
|
const state = await abandonStatusForToken(app.data, token);
|
package/operations/getVersion.ts
CHANGED
|
@@ -6,17 +6,15 @@
|
|
|
6
6
|
// Read-only and unauthenticated by design (no secrets in the payload). The optional shared-secret
|
|
7
7
|
// guard stays HERE (the runtime does not enforce OpenAPI `security`); the OpenAPI document only
|
|
8
8
|
// routes GET to this operation, so a wrong method is a 404 from the router (no explicit 405 needed).
|
|
9
|
-
|
|
10
|
-
import { buildVersionInfo, envVar
|
|
9
|
+
|
|
10
|
+
import { buildVersionInfo, envVar } from "../app/version.ts";
|
|
11
|
+
import { defineOperation } from "../nano-generated/operations.ts";
|
|
11
12
|
|
|
12
13
|
// The optional shared-secret guard: when NANO_PR_WEBHOOK_SECRET is set, callers must present it via
|
|
13
14
|
// the x-hook-secret header. Captured once, at module load.
|
|
14
15
|
const SECRET = envVar("NANO_PR_WEBHOOK_SECRET") ?? "";
|
|
15
16
|
|
|
16
|
-
export default defineOperation
|
|
17
|
-
{ params: Record<string, string>; query: Record<string, string | string[] | undefined>; body: undefined },
|
|
18
|
-
VersionInfo | { error: string }
|
|
19
|
-
>("getVersion", ({ req }) => {
|
|
17
|
+
export default defineOperation("getVersion", ({ req }) => {
|
|
20
18
|
if (SECRET && req.headers.get("x-hook-secret") !== SECRET) {
|
|
21
19
|
return { status: 401, body: { error: "unauthorized" } };
|
|
22
20
|
}
|
|
@@ -6,20 +6,16 @@
|
|
|
6
6
|
// The runtime validates the (empty) request against openapi.yaml; the optional shared-secret guard
|
|
7
7
|
// stays HERE (the runtime does not enforce OpenAPI `security`): when NANO_PR_WEBHOOK_SECRET is set,
|
|
8
8
|
// callers must present it via the x-hook-secret header. Unset → open (unchanged default).
|
|
9
|
-
|
|
10
|
-
import {
|
|
9
|
+
|
|
10
|
+
import { activePrs } from "../app/service.ts";
|
|
11
11
|
import { envVar } from "../app/version.ts";
|
|
12
|
+
import { defineOperation } from "../nano-generated/operations.ts";
|
|
12
13
|
|
|
13
14
|
// The optional shared-secret guard: when NANO_PR_WEBHOOK_SECRET is set, callers must present it via
|
|
14
15
|
// the x-hook-secret header. Captured once, at module load.
|
|
15
16
|
const SECRET = envVar("NANO_PR_WEBHOOK_SECRET") ?? "";
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
export default defineOperation<
|
|
20
|
-
{ params: Record<string, string>; query: Record<string, string | string[] | undefined>; body: undefined },
|
|
21
|
-
Res
|
|
22
|
-
>("listActivePrs", async ({ req }, app) => {
|
|
18
|
+
export default defineOperation("listActivePrs", async ({ req }, app) => {
|
|
23
19
|
if (SECRET && req.headers.get("x-hook-secret") !== SECRET) {
|
|
24
20
|
return { status: 401, body: { error: "unauthorized" } };
|
|
25
21
|
}
|
|
@@ -8,20 +8,12 @@
|
|
|
8
8
|
// The runtime validates the body against openapi.yaml (`name` is required, so a missing name is a 400
|
|
9
9
|
// for free); this delegate keeps the message-name dispatch — the discriminator + downstream behavior
|
|
10
10
|
// is app logic, not something the JSON schema can express.
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
import { answerTaskEscalation, FEATURE_ESCALATION_MESSAGE } from "../app/plan.ts";
|
|
13
13
|
import { answerEscalation } from "../app/service.ts";
|
|
14
|
+
import { defineOperation } from "../nano-generated/operations.ts";
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
name?: unknown;
|
|
17
|
-
correlationKey?: unknown;
|
|
18
|
-
variables?: Record<string, unknown>;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export default defineOperation<
|
|
22
|
-
{ params: Record<string, string>; query: Record<string, string | string[] | undefined>; body: Body },
|
|
23
|
-
Record<string, unknown>
|
|
24
|
-
>("postMessage", async ({ body }, app) => {
|
|
16
|
+
export default defineOperation("postMessage", async ({ body }, app) => {
|
|
25
17
|
const b = body ?? {};
|
|
26
18
|
const name = String(b.name ?? "");
|
|
27
19
|
if (!name) return { status: 400, body: { error: "name is required" } };
|
|
@@ -9,14 +9,11 @@
|
|
|
9
9
|
// GET → { planKey, entries: [ { id, author_task, kind, files, body, wave, created_at } ], cursor }
|
|
10
10
|
// optional ?since=<id> returns only entries with id > since (incremental poll). `cursor` is
|
|
11
11
|
// the plan's current head id; pass it back as `since` on the next poll (Tier 2).
|
|
12
|
-
|
|
13
|
-
import type { BlackboardPage } from "../app/blackboard.ts";
|
|
12
|
+
|
|
14
13
|
import { planKeyForToken, readBlackboardPage } from "../app/blackboard.ts";
|
|
14
|
+
import { defineOperation } from "../nano-generated/operations.ts";
|
|
15
15
|
|
|
16
|
-
export default defineOperation
|
|
17
|
-
{ params: Record<string, string>; query: { token?: string; since?: string }; body: unknown },
|
|
18
|
-
(BlackboardPage & { planKey: string }) | { error: string }
|
|
19
|
-
>("readBlackboard", async ({ req }, app) => {
|
|
16
|
+
export default defineOperation("readBlackboard", async ({ req }, app) => {
|
|
20
17
|
const token = (req.query.get("token") ?? req.headers.get("x-blackboard-token") ?? "").trim();
|
|
21
18
|
if (!token) return { status: 400, body: { error: "missing blackboard token" } };
|
|
22
19
|
const planKey = await planKeyForToken(app.data, token);
|
|
@@ -8,20 +8,11 @@
|
|
|
8
8
|
// not leak the engine's variable-map concept to callers. The runtime validates the body against
|
|
9
9
|
// openapi.yaml; this delegate keeps the PR-parse guard because the reference format (owner/repo#123
|
|
10
10
|
// or a URL) is app logic, not something the JSON schema can express — an unparseable reference is a 400.
|
|
11
|
-
import { defineOperation } from "@nanobpm/urban";
|
|
12
|
-
import { clampRounds, MAX_ROUNDS, parsePr, submitPr } from "../app/service.ts";
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
url?: string;
|
|
17
|
-
dependsOn?: unknown;
|
|
18
|
-
maxRounds?: unknown;
|
|
19
|
-
}
|
|
12
|
+
import { clampRounds, MAX_ROUNDS, parsePr, submitPr } from "../app/service.ts";
|
|
13
|
+
import { defineOperation } from "../nano-generated/operations.ts";
|
|
20
14
|
|
|
21
|
-
export default defineOperation
|
|
22
|
-
{ params: Record<string, string>; query: Record<string, string | string[] | undefined>; body: Body },
|
|
23
|
-
{ prKey: string; alreadyRunning?: boolean; processKey?: string | null } | { error: string }
|
|
24
|
-
>("startConvergenceLoop", async ({ body }, app) => {
|
|
15
|
+
export default defineOperation("startConvergenceLoop", async ({ body }, app) => {
|
|
25
16
|
const b = body ?? {};
|
|
26
17
|
const raw = String(b.pr ?? b.url ?? "").trim();
|
|
27
18
|
const parsed = parsePr(raw);
|
|
@@ -7,22 +7,11 @@
|
|
|
7
7
|
//
|
|
8
8
|
// The request body is FLAT (`{ issue | url }`), not wrapped in a `variables` envelope — this is a
|
|
9
9
|
// purpose-built operation, not a generic engine "start process" call.
|
|
10
|
-
import { defineOperation } from "@nanobpm/urban";
|
|
11
|
-
import { parseIssue, startPlan } from "../app/plan.ts";
|
|
12
|
-
|
|
13
|
-
interface Body {
|
|
14
|
-
issue?: string;
|
|
15
|
-
url?: string;
|
|
16
|
-
}
|
|
17
10
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
| { error: string };
|
|
11
|
+
import { parseIssue, startPlan } from "../app/plan.ts";
|
|
12
|
+
import { defineOperation } from "../nano-generated/operations.ts";
|
|
21
13
|
|
|
22
|
-
export default defineOperation
|
|
23
|
-
{ params: Record<string, string>; query: Record<string, string | string[] | undefined>; body: Body },
|
|
24
|
-
Res
|
|
25
|
-
>("startPlanFanout", async ({ body }, app) => {
|
|
14
|
+
export default defineOperation("startPlanFanout", async ({ body }, app) => {
|
|
26
15
|
const b = body ?? {};
|
|
27
16
|
const raw = String(b.issue ?? b.url ?? "").trim();
|
|
28
17
|
const parsed = parseIssue(raw);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nanobpm/nano-workforce",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.1",
|
|
4
4
|
"description": "Nano Workforce — an Agent Graph Orchestration application for Agentic SDLC: durable BPMN processes that coordinate a graph of AI agents across the software delivery lifecycle.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "main.ts",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"upgrade": "node --experimental-strip-types scripts/upgrade-from-pack.ts",
|
|
34
34
|
"check": "urban check",
|
|
35
35
|
"typecheck": "tsc --noEmit",
|
|
36
|
+
"pretypecheck": "urban gen",
|
|
36
37
|
"check:prompts": "node --experimental-strip-types scripts/check-agent-prompts.ts",
|
|
37
38
|
"gen": "urban gen",
|
|
38
39
|
"gen:check": "urban gen --check",
|
|
@@ -44,7 +45,7 @@
|
|
|
44
45
|
"lint:fix": "biome check --write app operations workers pages components scripts main.ts"
|
|
45
46
|
},
|
|
46
47
|
"dependencies": {
|
|
47
|
-
"@nanobpm/urban": "^0.
|
|
48
|
+
"@nanobpm/urban": "^0.38.0"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"@biomejs/biome": "^2.4.11",
|