@nanobpm/urban 0.51.0 → 0.53.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 +47 -20
- package/dist/runtime/core/events.d.ts +135 -0
- package/dist/runtime/core/events.js +329 -0
- package/dist/runtime/core/execContext.d.ts +5 -0
- package/dist/runtime/core/extensions.d.ts +131 -0
- package/dist/runtime/core/extensions.js +137 -0
- package/dist/runtime/core/glob.d.ts +7 -6
- package/dist/runtime/core/glob.js +16 -14
- package/dist/runtime/core/host.d.ts +4 -1
- package/dist/runtime/core/lineage.d.ts +116 -0
- package/dist/runtime/core/lineage.js +186 -0
- package/dist/runtime/core/modules/agent.d.ts +17 -0
- package/dist/runtime/core/modules/agent.js +63 -0
- package/dist/runtime/core/modules/datasource.d.ts +6 -0
- package/dist/runtime/core/modules/datasource.js +8 -0
- package/dist/runtime/core/modules/deploy.d.ts +8 -5
- package/dist/runtime/core/modules/deploy.js +62 -16
- package/dist/runtime/core/modules/lineage-store.d.ts +81 -0
- package/dist/runtime/core/modules/lineage-store.js +175 -0
- package/dist/runtime/core/modules/pages.js +397 -20
- package/dist/runtime/core/modules/surfaces.js +8 -0
- package/dist/runtime/core/modules/workers.js +69 -2
- package/dist/runtime/core/phase.d.ts +168 -0
- package/dist/runtime/core/phase.js +367 -0
- package/dist/runtime/core/runtime.d.ts +17 -0
- package/dist/runtime/core/runtime.js +30 -0
- package/dist/runtime/engine/nanosdk.js +8 -2
- package/dist/runtime/index.d.ts +10 -0
- package/dist/runtime/index.js +12 -0
- package/dist/toolkit/derivers/system-brief.d.ts +62 -0
- package/dist/toolkit/derivers/system-brief.js +156 -0
- package/dist/toolkit/gen.d.ts +5 -5
- package/dist/toolkit/gen.js +20 -14
- package/dist/toolkit/index.d.ts +5 -0
- package/dist/toolkit/index.js +3 -0
- package/dist/toolkit/models.d.ts +4 -3
- package/dist/toolkit/models.js +4 -3
- package/package.json +1 -1
- package/src/runtime/core/events.test.ts +382 -0
- package/src/runtime/core/events.ts +370 -0
- package/src/runtime/core/execContext.ts +5 -0
- package/src/runtime/core/extensions.test.ts +378 -0
- package/src/runtime/core/extensions.ts +276 -0
- package/src/runtime/core/glob.ts +15 -12
- package/src/runtime/core/host.ts +4 -1
- package/src/runtime/core/lineage.test.ts +215 -0
- package/src/runtime/core/lineage.ts +297 -0
- package/src/runtime/core/modules/agent.test.ts +104 -0
- package/src/runtime/core/modules/agent.ts +76 -0
- package/src/runtime/core/modules/datasource.ts +9 -0
- package/src/runtime/core/modules/deploy.test.ts +84 -16
- package/src/runtime/core/modules/deploy.ts +59 -16
- package/src/runtime/core/modules/lineage-store.test.ts +177 -0
- package/src/runtime/core/modules/lineage-store.ts +239 -0
- package/src/runtime/core/modules/pages.test.ts +309 -5
- package/src/runtime/core/modules/pages.ts +398 -20
- package/src/runtime/core/modules/surfaces.ts +9 -0
- package/src/runtime/core/modules/workers.test.ts +136 -1
- package/src/runtime/core/modules/workers.ts +72 -6
- package/src/runtime/core/phase.test.ts +350 -0
- package/src/runtime/core/phase.ts +526 -0
- package/src/runtime/core/runtime.extensions.test.ts +151 -0
- package/src/runtime/core/runtime.ts +49 -0
- package/src/runtime/devserver.test.ts +3 -0
- package/src/runtime/engine/nanosdk.test.ts +97 -3
- package/src/runtime/engine/nanosdk.ts +8 -2
- package/src/runtime/index.ts +92 -0
- package/src/toolkit/derivers/system-brief.test.ts +150 -0
- package/src/toolkit/derivers/system-brief.ts +210 -0
- package/src/toolkit/gen.test.ts +28 -4
- package/src/toolkit/gen.ts +20 -13
- package/src/toolkit/index.ts +14 -0
- package/src/toolkit/models.ts +4 -3
|
@@ -4,6 +4,7 @@ import { DataLayer } from "./modules/datasource.ts";
|
|
|
4
4
|
import { type Logger } from "./logger.ts";
|
|
5
5
|
import type { SchedulerDeps } from "./modules/scheduler.ts";
|
|
6
6
|
import { type SecurityPolicy } from "./modules/security.ts";
|
|
7
|
+
import { type UrbanEvents, type UrbanExtension } from "./extensions.ts";
|
|
7
8
|
/** Resolve the HTTP port: explicit option, else $PORT, else 8090. Throws a clear
|
|
8
9
|
* error when $PORT is set but not a valid integer in 0..65535. */
|
|
9
10
|
export declare function resolvePort(explicit: number | undefined, envPort: string | undefined): number;
|
|
@@ -40,6 +41,14 @@ export interface CreateUrbanAppOptions {
|
|
|
40
41
|
* so one injected scheduler drives them both (no per-module wiring, no drift).
|
|
41
42
|
*/
|
|
42
43
|
scheduler?: SchedulerDeps;
|
|
44
|
+
/**
|
|
45
|
+
* Pluggable Urban {@link UrbanExtension}s — the agentic families and connector
|
|
46
|
+
* packs that extend the app lifecycle through the typed extension-event taxonomy
|
|
47
|
+
* (issue #262) instead of editing the runtime. The runtime runs each through the
|
|
48
|
+
* `extension/register` serial checkpoint in a deterministic order and disposes
|
|
49
|
+
* everything they register on `stop()` / HMR. Empty by default.
|
|
50
|
+
*/
|
|
51
|
+
extensions?: readonly UrbanExtension[];
|
|
43
52
|
}
|
|
44
53
|
export interface UrbanApp {
|
|
45
54
|
readonly manifest: AppManifest;
|
|
@@ -69,5 +78,13 @@ export interface UrbanApp {
|
|
|
69
78
|
* `undefined` before `start()`, after `stop()`, and on hosts that don't surface one (Deno).
|
|
70
79
|
*/
|
|
71
80
|
readonly httpServer: object | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* The app's typed extension-event taxonomy (issue #262): lifecycle notifications,
|
|
83
|
+
* the extension-registration checkpoint, request/security waterfall gates, and
|
|
84
|
+
* the reconcile fan-out — each a channel with a declared dispatch mode. Modules
|
|
85
|
+
* and {@link UrbanExtension}s hook onto these seams instead of wiring directly;
|
|
86
|
+
* every registration is an effect on a dispose ladder that `stop()` unwinds.
|
|
87
|
+
*/
|
|
88
|
+
readonly events: UrbanEvents;
|
|
72
89
|
}
|
|
73
90
|
export declare function createUrbanApp(opts: CreateUrbanAppOptions): Promise<UrbanApp>;
|
|
@@ -15,6 +15,8 @@ import { mountSurfaces } from "./modules/surfaces.js";
|
|
|
15
15
|
import { mountTriggers } from "./modules/triggers.js";
|
|
16
16
|
import { mountInstanceTracking } from "./modules/instance-tracking.js";
|
|
17
17
|
import { mountSecurity } from "./modules/security.js";
|
|
18
|
+
import { EventBus } from "./events.js";
|
|
19
|
+
import { createUrbanEvents, mountExtensions } from "./extensions.js";
|
|
18
20
|
/** Resolve the HTTP port: explicit option, else $PORT, else 8090. Throws a clear
|
|
19
21
|
* error when $PORT is set but not a valid integer in 0..65535. */
|
|
20
22
|
export function resolvePort(explicit, envPort) {
|
|
@@ -53,6 +55,18 @@ export async function createUrbanApp(opts) {
|
|
|
53
55
|
// `app.log`) and the per-invocation `AppApi.log` (workers/route delegates `child()` it with their
|
|
54
56
|
// correlation context).
|
|
55
57
|
const appLog = createLogger((l, m, f) => host.log(l, m, f));
|
|
58
|
+
// The app-wide extension-event microkernel (issue #262): one typed taxonomy over
|
|
59
|
+
// one dispose ladder. Contained listener throws land in the structured log rather
|
|
60
|
+
// than stranding the pipeline. Modules and extensions hook onto `events`; the
|
|
61
|
+
// whole ladder unwinds on teardown.
|
|
62
|
+
const bus = new EventBus({
|
|
63
|
+
onError: (err, info) => appLog.warn("extension listener threw and was contained", {
|
|
64
|
+
event: info.event,
|
|
65
|
+
mode: info.mode,
|
|
66
|
+
error: String(err),
|
|
67
|
+
}),
|
|
68
|
+
});
|
|
69
|
+
const events = createUrbanEvents(bus);
|
|
56
70
|
// Install the ambient job-execution store once per process (idempotent) so worker dispatch can
|
|
57
71
|
// stamp write-provenance onto DataLayer inserts. Absent-safe: a host without `createAsyncStore`
|
|
58
72
|
// leaves provenance capture disabled.
|
|
@@ -74,6 +88,8 @@ export async function createUrbanApp(opts) {
|
|
|
74
88
|
// Release every mounted resource and reset internal state so a subsequent
|
|
75
89
|
// start() begins clean. Used by stop() and by start()'s failure path.
|
|
76
90
|
const teardown = async () => {
|
|
91
|
+
// Notify lifecycle listeners before we start tearing seams down (issue #262).
|
|
92
|
+
events.lifecycle.emit({ app: manifest.id, phase: "stopping" });
|
|
77
93
|
if (server) {
|
|
78
94
|
try {
|
|
79
95
|
await server.stop();
|
|
@@ -106,11 +122,17 @@ export async function createUrbanApp(opts) {
|
|
|
106
122
|
data = undefined;
|
|
107
123
|
security = undefined;
|
|
108
124
|
started = false;
|
|
125
|
+
// Terminal lifecycle notification, then unwind the whole dispose ladder LIFO:
|
|
126
|
+
// every extension listener/effect (and the lifecycle channel itself) is torn
|
|
127
|
+
// down, so a subsequent start() — or a dev-server HMR reload — leaks nothing.
|
|
128
|
+
events.lifecycle.emit({ app: manifest.id, phase: "stopped" });
|
|
129
|
+
bus.dispose();
|
|
109
130
|
};
|
|
110
131
|
const app = {
|
|
111
132
|
manifest,
|
|
112
133
|
root,
|
|
113
134
|
log: appLog,
|
|
135
|
+
events,
|
|
114
136
|
get data() {
|
|
115
137
|
return data;
|
|
116
138
|
},
|
|
@@ -128,6 +150,7 @@ export async function createUrbanApp(opts) {
|
|
|
128
150
|
if (started)
|
|
129
151
|
throw new Error("app already started");
|
|
130
152
|
started = true;
|
|
153
|
+
events.lifecycle.emit({ app: manifest.id, phase: "starting" });
|
|
131
154
|
try {
|
|
132
155
|
if (flags.security)
|
|
133
156
|
security = mountSecurity(ctx);
|
|
@@ -153,6 +176,12 @@ export async function createUrbanApp(opts) {
|
|
|
153
176
|
if (c.jobTypes.length > 0)
|
|
154
177
|
describe.connectors = c.describe?.();
|
|
155
178
|
}
|
|
179
|
+
// Run the agentic-family / connector-pack extension surface through the
|
|
180
|
+
// typed taxonomy (issue #262). Everything an extension registers rides the
|
|
181
|
+
// shared dispose ladder, so teardown's single `bus.dispose()` unwinds it —
|
|
182
|
+
// the extension host is deliberately NOT pushed onto `mounted`.
|
|
183
|
+
const extHost = await mountExtensions(api, opts.extensions ?? [], { bus, events });
|
|
184
|
+
describe.extensions = extHost.describe?.();
|
|
156
185
|
const routes = [];
|
|
157
186
|
let hasUiSurfaces = false;
|
|
158
187
|
if (flags.surfaces) {
|
|
@@ -226,6 +255,7 @@ export async function createUrbanApp(opts) {
|
|
|
226
255
|
}
|
|
227
256
|
}
|
|
228
257
|
host.log("info", `urban app "${manifest.id}" started`, {});
|
|
258
|
+
events.lifecycle.emit({ app: manifest.id, phase: "started" });
|
|
229
259
|
}
|
|
230
260
|
catch (err) {
|
|
231
261
|
// A failed start must not leave the app half-mounted (leaked workers,
|
|
@@ -21,6 +21,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
21
21
|
import { isBpmnError } from "../core/host.js";
|
|
22
22
|
import { buildFormSchema, parseFormSchema, pickFormLinkage, resolveFormIdentifier, } from "../core/form-contract.js";
|
|
23
23
|
import { isRecord } from "../core/guards.js";
|
|
24
|
+
import { applyAmbientLineage } from "../core/lineage.js";
|
|
24
25
|
/** Coerce an engine response's process-instance key to a non-empty string, or
|
|
25
26
|
* throw — a missing key means a malformed/partial response, not a real instance. */
|
|
26
27
|
export function requireProcessInstanceKey(key) {
|
|
@@ -76,9 +77,12 @@ export class SdkEngineClient {
|
|
|
76
77
|
return { deployed: resources.length };
|
|
77
78
|
}
|
|
78
79
|
async createInstance(input) {
|
|
80
|
+
// Auto-thread the `_urban.lineage` envelope (issue #254): a handler that spawns an
|
|
81
|
+
// instance propagates its `rootRequestKey` and stamps `causedByInstanceKey`; a genuine
|
|
82
|
+
// top-level request mints a fresh root. An explicit caller-supplied envelope wins.
|
|
79
83
|
const body = await this.client.createProcessInstance({
|
|
80
84
|
processDefinitionId: input.processDefinitionId,
|
|
81
|
-
variables: input.variables
|
|
85
|
+
variables: applyAmbientLineage(input.variables),
|
|
82
86
|
awaitCompletion: input.awaitCompletion ?? false,
|
|
83
87
|
});
|
|
84
88
|
const rawKey = body.processInstanceKey ?? body.key;
|
|
@@ -93,10 +97,12 @@ export class SdkEngineClient {
|
|
|
93
97
|
await this.client.cancelProcessInstance({ processInstanceKey: input.processInstanceKey });
|
|
94
98
|
}
|
|
95
99
|
async publishMessage(input) {
|
|
100
|
+
// Message-started instances inherit lineage too (issue #254): thread the envelope onto the
|
|
101
|
+
// message variables so the instance the message starts carries `_urban.lineage`.
|
|
96
102
|
await this.client.publishMessage({
|
|
97
103
|
name: input.name,
|
|
98
104
|
correlationKey: input.correlationKey ?? "",
|
|
99
|
-
variables: input.variables
|
|
105
|
+
variables: applyAmbientLineage(input.variables),
|
|
100
106
|
});
|
|
101
107
|
}
|
|
102
108
|
async searchUserTasks(filter) {
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export { createUrbanApp } from "./core/runtime.ts";
|
|
2
2
|
export type { CreateUrbanAppOptions, MountFlags, UrbanApp, } from "./core/runtime.ts";
|
|
3
|
+
export { EventBus } from "./core/events.ts";
|
|
4
|
+
export type { DispatchMode, Disposer, EmitChannel, ErrorSink, EventBusOptions, Listener, Middleware, ParallelChannel, SerialChannel, WaterfallChannel, } from "./core/events.ts";
|
|
5
|
+
export { URBAN_EVENT_MODES, createUrbanEvents, mountExtensions, urbanEventMode } from "./core/extensions.ts";
|
|
6
|
+
export type { DispatchRequest, DispatchResponse, ExtensionHost, ExtensionRegistered, ExtensionSetupContext, GateDecision, GateRequest, LifecycleEvent, MountExtensionsOptions, ReconcileEvent, UrbanEventName, UrbanEvents, UrbanExtension, } from "./core/extensions.ts";
|
|
3
7
|
export { bindModeToHost, expandEnv, expandEnvString, isBindMode, loadManifest, parseManifest, resolveBindHost, resolveBindMode, workerJobType, ALL_INTERFACES_HOST, BIND_ENV_VAR, LOOPBACK_HOST, } from "./core/manifest.ts";
|
|
4
8
|
export type { ActionDecl, AppManifest, BindMode, ChatSurface, DataSource, DomainField, DomainType, LlmBinding, NetworkConfig, PagesSurface, Surfaces, TaskInboxSurface, Trigger, Worker, } from "./core/manifest.ts";
|
|
5
9
|
export { collectManifestIssues, ManifestValidationError, validateManifest, } from "./core/validate.ts";
|
|
@@ -31,6 +35,12 @@ export { resolveHandler, sdkDecisionEvaluator } from "./core/modules/workers.ts"
|
|
|
31
35
|
export { buildMessages, callLlm, resolveProvider, runLlmJob, } from "./core/modules/llm.ts";
|
|
32
36
|
export type { ChatMessage, DecisionEvaluator, EnvLookup, LlmRuntime, LlmVars, ProviderConfig, } from "./core/modules/llm.ts";
|
|
33
37
|
export { evalCorrelation } from "./core/modules/triggers.ts";
|
|
38
|
+
export { applyAmbientLineage, buildLineageTree, deriveLineage, LINEAGE_KEY, LINEAGE_NAMESPACE, mintRootRequestKey, readLineage, writeLineage, } from "./core/lineage.ts";
|
|
39
|
+
export type { ApplyLineageOptions, LineageAttachment, LineageEdge, LineageEdgeType, LineageEnvelope, LineageNode, LineageTree, } from "./core/lineage.ts";
|
|
40
|
+
export { LINEAGE_ATTACHMENTS_TABLE, LINEAGE_EDGES_TABLE, LINEAGE_SCHEMA_SQL, LineageStore, systemClock as lineageSystemClock, } from "./core/modules/lineage-store.ts";
|
|
41
|
+
export type { Clock as LineageClock, LineageJobLike, LineageStoreOptions, } from "./core/modules/lineage-store.ts";
|
|
42
|
+
export { buildScopeIndex, derivePhase, deriveInstancePhases, furthestReached, rollupLineagePhase, SCOPE_CONTAINERS, } from "./core/phase.ts";
|
|
43
|
+
export type { CrumbKind, CrumbSource, DerivePhaseOptions, FurthestReached, InstancePhase, LineagePhaseRollup, Phase, PhaseCrumb, PhaseGranularity, ProvenanceProgressRow, ScopeElement, ScopeIndex, } from "./core/phase.ts";
|
|
34
44
|
export { deployModels, RESOURCES_DIR } from "./core/modules/deploy.ts";
|
|
35
45
|
export { defaultScheduler, MAX_TIMER_DELAY_MS } from "./core/modules/scheduler.ts";
|
|
36
46
|
export type { SchedulerDeps } from "./core/modules/scheduler.ts";
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// Public API for the Urban runtime (@nanobpm/urban, subpath ./runtime).
|
|
2
2
|
// Core runtime
|
|
3
3
|
export { createUrbanApp } from "./core/runtime.js";
|
|
4
|
+
// Extension-event taxonomy + microkernel (issue #262)
|
|
5
|
+
export { EventBus } from "./core/events.js";
|
|
6
|
+
export { URBAN_EVENT_MODES, createUrbanEvents, mountExtensions, urbanEventMode } from "./core/extensions.js";
|
|
4
7
|
// Manifest
|
|
5
8
|
export { bindModeToHost, expandEnv, expandEnvString, isBindMode, loadManifest, parseManifest, resolveBindHost, resolveBindMode, workerJobType, ALL_INTERFACES_HOST, BIND_ENV_VAR, LOOPBACK_HOST, } from "./core/manifest.js";
|
|
6
9
|
// Validation
|
|
@@ -28,6 +31,15 @@ export { defineOperation, mountApi, resolveOperationHandler, NotImplemented } fr
|
|
|
28
31
|
export { resolveHandler, sdkDecisionEvaluator } from "./core/modules/workers.js";
|
|
29
32
|
export { buildMessages, callLlm, resolveProvider, runLlmJob, } from "./core/modules/llm.js";
|
|
30
33
|
export { evalCorrelation } from "./core/modules/triggers.js";
|
|
34
|
+
// Lineage — the framework-level lineage primitive (issue #254): the `_urban.lineage`
|
|
35
|
+
// envelope + auto-threading, and the generic read projection that stitches user intent →
|
|
36
|
+
// progress (a root request → the instances/PRs/tasks it causes).
|
|
37
|
+
export { applyAmbientLineage, buildLineageTree, deriveLineage, LINEAGE_KEY, LINEAGE_NAMESPACE, mintRootRequestKey, readLineage, writeLineage, } from "./core/lineage.js";
|
|
38
|
+
export { LINEAGE_ATTACHMENTS_TABLE, LINEAGE_EDGES_TABLE, LINEAGE_SCHEMA_SQL, LineageStore, systemClock as lineageSystemClock, } from "./core/modules/lineage-store.js";
|
|
39
|
+
// Phase — the framework-level *domain phase* primitive (issue #266): derive "which phase is this
|
|
40
|
+
// instance in?" from the BPMN scope hierarchy + write-provenance (Tier 0, zero declaration), an
|
|
41
|
+
// optional `nano:phase` override (Tier 1), and a lineage rollup for the epic frontier (Tier 2).
|
|
42
|
+
export { buildScopeIndex, derivePhase, deriveInstancePhases, furthestReached, rollupLineagePhase, SCOPE_CONTAINERS, } from "./core/phase.js";
|
|
31
43
|
// Model deploy (deploy-by-convention under `resources/`, ADR 0062)
|
|
32
44
|
export { deployModels, RESOURCES_DIR } from "./core/modules/deploy.js";
|
|
33
45
|
export { defaultScheduler, MAX_TIMER_DELAY_MS } from "./core/modules/scheduler.js";
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { DerivedArtifact, Deriver } from "../artifact.ts";
|
|
2
|
+
import { type ModelSource, type WorkerIo } from "./worker-io.ts";
|
|
3
|
+
/** Basenames of the two emitted artifacts. */
|
|
4
|
+
export declare const SYSTEM_BRIEF_MD = "system-brief.md";
|
|
5
|
+
export declare const SYSTEM_BRIEF_JSON = "system-brief.json";
|
|
6
|
+
/** Reserved `nano:meta` keys the brief recognises as ownership / provenance context (ADR 0060
|
|
7
|
+
* §1). All optional and additive — absence degrades the brief to structure-only. `adr` may be
|
|
8
|
+
* declared more than once (repeated `nano:meta`, matching the existing scan) to reference
|
|
9
|
+
* multiple ADRs; the scan collects them into `adrs[]`. */
|
|
10
|
+
export interface Ownership {
|
|
11
|
+
owner?: string;
|
|
12
|
+
team?: string;
|
|
13
|
+
slack?: string;
|
|
14
|
+
runbook?: string;
|
|
15
|
+
since?: string;
|
|
16
|
+
adrs: string[];
|
|
17
|
+
}
|
|
18
|
+
/** One decision the app encodes: a `businessRuleTask` with a `zeebe:calledDecision`. */
|
|
19
|
+
export interface DecisionRef {
|
|
20
|
+
process?: string;
|
|
21
|
+
elementId?: string;
|
|
22
|
+
decisionId: string;
|
|
23
|
+
}
|
|
24
|
+
/** The derived, machine-readable system model — the payload of `system-brief.json` and the
|
|
25
|
+
* input the runtime injects as session context / the retro plane consumes (ADR 0060 §3). */
|
|
26
|
+
export interface SystemBrief {
|
|
27
|
+
/** App id/name from the manifest, if provided. */
|
|
28
|
+
app?: string;
|
|
29
|
+
/** Every process id the models declare, in scan order. */
|
|
30
|
+
processes: string[];
|
|
31
|
+
/** Service-task call graph: each worker binding (task type + in/out envelope + process). The
|
|
32
|
+
* dependency edges are implicit — a process depends on the task types its service tasks invoke. */
|
|
33
|
+
workers: WorkerIo[];
|
|
34
|
+
/** Decisions (`businessRuleTask` → DMN) the models encode. */
|
|
35
|
+
decisions: DecisionRef[];
|
|
36
|
+
/** Ownership / provenance folded from reserved `nano:meta` keys. */
|
|
37
|
+
ownership: Ownership;
|
|
38
|
+
}
|
|
39
|
+
/** Scan one BPMN document for `businessRuleTask` → `zeebe:calledDecision` decision refs, in
|
|
40
|
+
* document order, tagged with the enclosing process (mirrors `scanModelWorkers`' shape). */
|
|
41
|
+
export declare function scanModelDecisions(xml: string): DecisionRef[];
|
|
42
|
+
/** Fold the models' reserved `nano:meta` entries into `Ownership`. Single-valued keys take the
|
|
43
|
+
* last (scan-order) write, matching `foldMeta`; `adr` is multi-valued and accumulates. */
|
|
44
|
+
export declare function foldOwnership(models: ModelSource[]): Ownership;
|
|
45
|
+
/** Fold all models + manifest into the machine-readable `SystemBrief`. Deterministic: models
|
|
46
|
+
* are scanned in path order. */
|
|
47
|
+
export declare function buildSystemBrief(models: ModelSource[], app?: string): SystemBrief;
|
|
48
|
+
/** Emit the agent- and human-readable `system-brief.md` from the machine model. Compact by
|
|
49
|
+
* design (call graph + owners, not model XML) to keep the per-session prompt budget small
|
|
50
|
+
* (ADR 0060 §3 / open question 1). */
|
|
51
|
+
export declare function emitSystemBriefMd(b: SystemBrief): string;
|
|
52
|
+
/**
|
|
53
|
+
* Derive `nano-generated/system-brief.md` + `system-brief.json` from BPMN models (ADR 0060 §1).
|
|
54
|
+
* Pure and deterministic (path-ordered scan), so it is a drop-in drift-checkable artifact like
|
|
55
|
+
* its sibling derivers.
|
|
56
|
+
*/
|
|
57
|
+
export declare function deriveSystemBrief(models: ModelSource[], app?: string): DerivedArtifact[];
|
|
58
|
+
/** The `Deriver` binding, peer to `worker-io` / `meta`, for wiring into `gen.ts`. */
|
|
59
|
+
export declare const systemBriefDeriver: Deriver<{
|
|
60
|
+
models: ModelSource[];
|
|
61
|
+
app?: string;
|
|
62
|
+
}>;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// Deriver: BPMN models + manifest → `system-brief.md` / `system-brief.json`, the app's
|
|
2
|
+
// *institutional-memory* brief (ADR 0060). Where `worker-io.ts` emits worker *types* and
|
|
3
|
+
// `meta.ts` emits a *typed accessor*, this deriver folds the SAME scanned structure into
|
|
4
|
+
// agent- and human-readable **system context**: the app's processes, its service-task call
|
|
5
|
+
// graph, the decisions it encodes, and the ownership / "why" carried on
|
|
6
|
+
// the model as reserved `nano:meta` keys. It reuses the sibling scanners (single parse rule
|
|
7
|
+
// per vocabulary) and is pure (models in, artifacts out) so `urban gen --check` keeps it
|
|
8
|
+
// honest — the brief can never rot the way a hand-written README does (ADR 0060 §1).
|
|
9
|
+
//
|
|
10
|
+
// Wired into `runGen` (gen.ts) as a standard artifact and served at runtime via `/app/agent`
|
|
11
|
+
// (agent.ts, ADR 0060 §2): the shape, scanners, fold, and both emitters are real and tested.
|
|
12
|
+
import { GENERATED_DIR } from "../artifact.js";
|
|
13
|
+
import { byModelPath, scanModelWorkers } from "./worker-io.js";
|
|
14
|
+
import { scanModelMeta } from "./meta.js";
|
|
15
|
+
/** Basenames of the two emitted artifacts. */
|
|
16
|
+
export const SYSTEM_BRIEF_MD = "system-brief.md";
|
|
17
|
+
export const SYSTEM_BRIEF_JSON = "system-brief.json";
|
|
18
|
+
function attr(tag, name) {
|
|
19
|
+
const m = tag.match(new RegExp(`\\b${name}\\s*=\\s*"([^"]*)"`));
|
|
20
|
+
return m ? m[1] : undefined;
|
|
21
|
+
}
|
|
22
|
+
function processId(xml) {
|
|
23
|
+
const m = xml.match(/<bpmn:process\b[^>]*>/);
|
|
24
|
+
return m ? attr(m[0], "id") : undefined;
|
|
25
|
+
}
|
|
26
|
+
/** Scan one BPMN document for `businessRuleTask` → `zeebe:calledDecision` decision refs, in
|
|
27
|
+
* document order, tagged with the enclosing process (mirrors `scanModelWorkers`' shape). */
|
|
28
|
+
export function scanModelDecisions(xml) {
|
|
29
|
+
const proc = processId(xml);
|
|
30
|
+
const out = [];
|
|
31
|
+
const blockRe = /<bpmn:businessRuleTask\b([^>]*)>([\s\S]*?)<\/bpmn:businessRuleTask>/g;
|
|
32
|
+
let m;
|
|
33
|
+
while ((m = blockRe.exec(xml)) !== null) {
|
|
34
|
+
const elementId = attr(`<x ${m[1]}>`, "id");
|
|
35
|
+
const cd = m[2].match(/<zeebe:calledDecision\b[^>]*>/);
|
|
36
|
+
if (!cd)
|
|
37
|
+
continue;
|
|
38
|
+
const decisionId = attr(cd[0], "decisionId");
|
|
39
|
+
if (!decisionId)
|
|
40
|
+
continue;
|
|
41
|
+
out.push({ process: proc, elementId, decisionId });
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
/** Reserved single-valued ownership keys → their `Ownership` field. */
|
|
46
|
+
const OWNERSHIP_KEYS = {
|
|
47
|
+
owner: "owner",
|
|
48
|
+
team: "team",
|
|
49
|
+
slack: "slack",
|
|
50
|
+
runbook: "runbook",
|
|
51
|
+
since: "since",
|
|
52
|
+
};
|
|
53
|
+
/** Fold the models' reserved `nano:meta` entries into `Ownership`. Single-valued keys take the
|
|
54
|
+
* last (scan-order) write, matching `foldMeta`; `adr` is multi-valued and accumulates. */
|
|
55
|
+
export function foldOwnership(models) {
|
|
56
|
+
const own = { adrs: [] };
|
|
57
|
+
for (const model of [...models].sort(byModelPath)) {
|
|
58
|
+
for (const { key, value } of scanModelMeta(model.xml)) {
|
|
59
|
+
const k = key.trim().toLowerCase();
|
|
60
|
+
if (k === "adr") {
|
|
61
|
+
if (value && !own.adrs.includes(value))
|
|
62
|
+
own.adrs.push(value);
|
|
63
|
+
}
|
|
64
|
+
else if (Object.hasOwn(OWNERSHIP_KEYS, k)) {
|
|
65
|
+
own[OWNERSHIP_KEYS[k]] = value ?? "";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return own;
|
|
70
|
+
}
|
|
71
|
+
/** Fold all models + manifest into the machine-readable `SystemBrief`. Deterministic: models
|
|
72
|
+
* are scanned in path order. */
|
|
73
|
+
export function buildSystemBrief(models, app) {
|
|
74
|
+
const sorted = [...models].sort(byModelPath);
|
|
75
|
+
const workers = [];
|
|
76
|
+
const decisions = [];
|
|
77
|
+
const processes = [];
|
|
78
|
+
for (const model of sorted) {
|
|
79
|
+
const proc = processId(model.xml);
|
|
80
|
+
if (proc && !processes.includes(proc))
|
|
81
|
+
processes.push(proc);
|
|
82
|
+
workers.push(...scanModelWorkers(model.xml));
|
|
83
|
+
decisions.push(...scanModelDecisions(model.xml));
|
|
84
|
+
}
|
|
85
|
+
return { app, processes, workers, decisions, ownership: foldOwnership(models) };
|
|
86
|
+
}
|
|
87
|
+
/** Escape a Markdown table cell: neutralise `|` and newlines, which would otherwise break the
|
|
88
|
+
* table. Ownership values come from model-authored `nano:meta`, so this both keeps rendering
|
|
89
|
+
* honest and blunts Markdown/prompt injection into the agent-facing brief. Backticks are left
|
|
90
|
+
* intact — the emitter deliberately wraps ids in code spans. */
|
|
91
|
+
function mdCell(s) {
|
|
92
|
+
return s.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
93
|
+
}
|
|
94
|
+
function mdTable(headers, rows) {
|
|
95
|
+
if (rows.length === 0)
|
|
96
|
+
return "_none_\n";
|
|
97
|
+
const head = `| ${headers.join(" | ")} |\n| ${headers.map(() => "---").join(" | ")} |\n`;
|
|
98
|
+
return head + rows.map((r) => `| ${r.map((c) => mdCell(c || "")).join(" | ")} |`).join("\n") + "\n";
|
|
99
|
+
}
|
|
100
|
+
/** Emit the agent- and human-readable `system-brief.md` from the machine model. Compact by
|
|
101
|
+
* design (call graph + owners, not model XML) to keep the per-session prompt budget small
|
|
102
|
+
* (ADR 0060 §3 / open question 1). */
|
|
103
|
+
export function emitSystemBriefMd(b) {
|
|
104
|
+
const o = b.ownership;
|
|
105
|
+
let m = `# ${b.app ?? "App"} — system brief\n\n`;
|
|
106
|
+
m += "_Auto-derived from the process models (ADR 0060). Do not edit — regenerated by " +
|
|
107
|
+
"`urban gen`; drift fails `urban gen --check`._\n\n";
|
|
108
|
+
m += "## Ownership\n\n";
|
|
109
|
+
const ownRows = [
|
|
110
|
+
["Owner", o.owner ?? ""],
|
|
111
|
+
["Team", o.team ?? ""],
|
|
112
|
+
["Slack", o.slack ?? ""],
|
|
113
|
+
["Runbook", o.runbook ?? ""],
|
|
114
|
+
["Since", o.since ?? ""],
|
|
115
|
+
["ADRs", o.adrs.join(", ")],
|
|
116
|
+
].filter((r) => r[1]);
|
|
117
|
+
m += ownRows.length ? mdTable(["Field", "Value"], ownRows) : "_No ownership metadata declared " +
|
|
118
|
+
"(add reserved `nano:meta` keys: owner, team, slack, runbook, adr, since)._\n";
|
|
119
|
+
m += "\n";
|
|
120
|
+
m += "## Processes\n\n";
|
|
121
|
+
m += b.processes.length ? b.processes.map((p) => `- \`${p}\``).join("\n") + "\n" : "_none_\n";
|
|
122
|
+
m += "\n";
|
|
123
|
+
m += "## Service-task call graph (dependency edges)\n\n";
|
|
124
|
+
m += mdTable(["Process", "Task type (dependency)", "In", "Out"], b.workers.map((w) => [
|
|
125
|
+
w.process ? `\`${w.process}\`` : "",
|
|
126
|
+
`\`${w.taskType}\``,
|
|
127
|
+
w.in ? `\`${w.in}\`` : "",
|
|
128
|
+
w.out ? `\`${w.out}\`` : "",
|
|
129
|
+
]));
|
|
130
|
+
m += "\n";
|
|
131
|
+
m += "## Decisions (DMN)\n\n";
|
|
132
|
+
m += mdTable(["Process", "Element", "Decision"], b.decisions.map((d) => [
|
|
133
|
+
d.process ? `\`${d.process}\`` : "",
|
|
134
|
+
d.elementId ? `\`${d.elementId}\`` : "",
|
|
135
|
+
`\`${d.decisionId}\``,
|
|
136
|
+
]));
|
|
137
|
+
return m;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Derive `nano-generated/system-brief.md` + `system-brief.json` from BPMN models (ADR 0060 §1).
|
|
141
|
+
* Pure and deterministic (path-ordered scan), so it is a drop-in drift-checkable artifact like
|
|
142
|
+
* its sibling derivers.
|
|
143
|
+
*/
|
|
144
|
+
export function deriveSystemBrief(models, app) {
|
|
145
|
+
const brief = buildSystemBrief(models, app);
|
|
146
|
+
return [
|
|
147
|
+
{ path: `${GENERATED_DIR}/${SYSTEM_BRIEF_MD}`, content: emitSystemBriefMd(brief) },
|
|
148
|
+
{ path: `${GENERATED_DIR}/${SYSTEM_BRIEF_JSON}`, content: JSON.stringify(brief, null, 2) + "\n" },
|
|
149
|
+
];
|
|
150
|
+
}
|
|
151
|
+
/** The `Deriver` binding, peer to `worker-io` / `meta`, for wiring into `gen.ts`. */
|
|
152
|
+
export const systemBriefDeriver = {
|
|
153
|
+
id: "system-brief",
|
|
154
|
+
describe: "App institutional-memory brief (processes, call graph, decisions, ownership) — ADR 0060",
|
|
155
|
+
derive: ({ models, app }) => deriveSystemBrief(models, app),
|
|
156
|
+
};
|
package/dist/toolkit/gen.d.ts
CHANGED
|
@@ -57,13 +57,13 @@ declare function dirOf(p: string): string;
|
|
|
57
57
|
/** Resolve a `dir/*.ext` (or literal) manifest pattern to file paths relative to root. */
|
|
58
58
|
export declare function expandPattern(root: string, io: GenIO, pattern: string): Promise<string[]>;
|
|
59
59
|
/** The deploy-by-convention directory (ADR 0062): when the manifest declares no `models`, both the
|
|
60
|
-
* runtime deploy and this codegen scan discover deployables/models under it —
|
|
61
|
-
*
|
|
60
|
+
* runtime deploy and this codegen scan discover deployables/models under it — **recursively**,
|
|
61
|
+
* every file at any depth (issue #231). Deploy-only by convention. */
|
|
62
62
|
export declare const RESOURCES_DIR = "resources";
|
|
63
63
|
/**
|
|
64
|
-
* Discover model files under `resources/` by convention —
|
|
65
|
-
*
|
|
66
|
-
* and the deploy see the same set. Returns root-relative paths, sorted. Descending
|
|
64
|
+
* Discover model files under `resources/` by convention — **recursively**, every `.bpmn`/`.dmn`
|
|
65
|
+
* under `resources/` at any depth (issue #231) — mirroring the runtime deploy walk so the codegen
|
|
66
|
+
* scan and the deploy see the same set. Returns root-relative paths, sorted. Descending needs
|
|
67
67
|
* `io.listSubdirs`; without it only the files directly under `resources/` are scanned.
|
|
68
68
|
*/
|
|
69
69
|
export declare function discoverResourceModels(root: string, io: GenIO): Promise<string[]>;
|
package/dist/toolkit/gen.js
CHANGED
|
@@ -10,6 +10,7 @@ import { deriveMeta } from "./derivers/meta.js";
|
|
|
10
10
|
import { deriveMessageBindings } from "./derivers/messages.js";
|
|
11
11
|
import { resolveShapes, scanModelShapes } from "./derivers/shapes.js";
|
|
12
12
|
import { deriveApi } from "./derivers/api.js";
|
|
13
|
+
import { deriveSystemBrief } from "./derivers/system-brief.js";
|
|
13
14
|
import { parseSpec, sharedRequestBodySchemas } from "../openapi/spec.js";
|
|
14
15
|
import { deriveModels, MODEL_PROVENANCE } from "./models.js";
|
|
15
16
|
function join(root, rel) {
|
|
@@ -47,31 +48,31 @@ export async function expandPattern(root, io, pattern) {
|
|
|
47
48
|
.sort();
|
|
48
49
|
}
|
|
49
50
|
/** The deploy-by-convention directory (ADR 0062): when the manifest declares no `models`, both the
|
|
50
|
-
* runtime deploy and this codegen scan discover deployables/models under it —
|
|
51
|
-
*
|
|
51
|
+
* runtime deploy and this codegen scan discover deployables/models under it — **recursively**,
|
|
52
|
+
* every file at any depth (issue #231). Deploy-only by convention. */
|
|
52
53
|
export const RESOURCES_DIR = "resources";
|
|
53
54
|
/** Model file extensions the `nano:shape`/code-first scan reads by convention (BPMN + DMN). */
|
|
54
55
|
const MODEL_EXTS = [".bpmn", ".dmn"];
|
|
55
56
|
/**
|
|
56
|
-
* Discover model files under `resources/` by convention —
|
|
57
|
-
*
|
|
58
|
-
* and the deploy see the same set. Returns root-relative paths, sorted. Descending
|
|
57
|
+
* Discover model files under `resources/` by convention — **recursively**, every `.bpmn`/`.dmn`
|
|
58
|
+
* under `resources/` at any depth (issue #231) — mirroring the runtime deploy walk so the codegen
|
|
59
|
+
* scan and the deploy see the same set. Returns root-relative paths, sorted. Descending needs
|
|
59
60
|
* `io.listSubdirs`; without it only the files directly under `resources/` are scanned.
|
|
60
61
|
*/
|
|
61
62
|
export async function discoverResourceModels(root, io) {
|
|
62
63
|
const isModel = (n) => MODEL_EXTS.some((e) => n.endsWith(e));
|
|
63
64
|
const out = [];
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
out.push(`${RESOURCES_DIR}/${n}`);
|
|
67
|
-
}
|
|
68
|
-
const subdirs = io.listSubdirs ? await io.listSubdirs(join(root, RESOURCES_DIR)) : [];
|
|
69
|
-
for (const sub of subdirs.slice().sort()) {
|
|
70
|
-
for (const n of await io.listDir(join(root, `${RESOURCES_DIR}/${sub}`))) {
|
|
65
|
+
const walk = async (rel) => {
|
|
66
|
+
for (const n of await io.listDir(join(root, rel))) {
|
|
71
67
|
if (isModel(n))
|
|
72
|
-
out.push(`${
|
|
68
|
+
out.push(`${rel}/${n}`);
|
|
73
69
|
}
|
|
74
|
-
|
|
70
|
+
const subdirs = io.listSubdirs ? await io.listSubdirs(join(root, rel)) : [];
|
|
71
|
+
for (const sub of subdirs.slice().sort()) {
|
|
72
|
+
await walk(`${rel}/${sub}`);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
await walk(RESOURCES_DIR);
|
|
75
76
|
return out.sort();
|
|
76
77
|
}
|
|
77
78
|
/**
|
|
@@ -162,6 +163,11 @@ async function collectAll(opts) {
|
|
|
162
163
|
artifacts.push(...deriveWorkerBindings(models, declaredTypeIds));
|
|
163
164
|
artifacts.push(...deriveMeta(models));
|
|
164
165
|
artifacts.push(...deriveMessageBindings(models, declaredTypeIds));
|
|
166
|
+
// Institutional-memory brief (ADR 0060): fold the same scanned model structure into the
|
|
167
|
+
// app's agent/human-readable system brief. Flows through `artifacts` like its siblings, so
|
|
168
|
+
// the `nano-generated/` stale sweep and the `urban gen --check` drift gate own the two new
|
|
169
|
+
// artifacts (system-brief.md / .json) with no extra bookkeeping.
|
|
170
|
+
artifacts.push(...deriveSystemBrief(models, manifest.id));
|
|
165
171
|
// Surface genuine data-envelope conflicts: a taskType whose variants disagree on a field's
|
|
166
172
|
// TYPE. The emitted contract is the union of the variants (sound for a shared handler), so a
|
|
167
173
|
// type clash would silently widen to `A | B` — warn instead so the author unifies the envelope.
|
package/dist/toolkit/index.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export type { MetaDecl } from "./derivers/meta.ts";
|
|
|
14
14
|
export { deriveMessageBindings, emitMessageBindings, emitMessageBindingsRuntime, messagesDeriver, scanModelMessages, MESSAGE_BINDINGS_DTS, MESSAGE_BINDINGS_TS, } from "./derivers/messages.ts";
|
|
15
15
|
export type { MessageIo, MessageBindingDecl } from "./derivers/messages.ts";
|
|
16
16
|
export { apiDeriver, deriveApi, emitApiBindings, emitApiBindingsRuntime, emitApiController, schemaToTs, API_BINDINGS_DTS, API_BINDINGS_TS, API_CONTROLLER_TS, } from "./derivers/api.ts";
|
|
17
|
+
export { buildSystemBrief, deriveSystemBrief, emitSystemBriefMd, foldOwnership, scanModelDecisions, systemBriefDeriver, SYSTEM_BRIEF_JSON, SYSTEM_BRIEF_MD, } from "./derivers/system-brief.ts";
|
|
18
|
+
export type { DecisionRef, Ownership, SystemBrief } from "./derivers/system-brief.ts";
|
|
17
19
|
export { collectOperations, HTTP_METHODS, isSafeOperationId, operationsWithoutId, operationsWithUnsafeId, parseSpec, refName, resolveSchema, toRouteMatcher, undeclaredPathParams, validateValue, } from "../openapi/spec.ts";
|
|
18
20
|
export type { HttpMethodLower, OpenApiDoc, OpenApiParameter, OpenApiSchema, OperationInfo, } from "../openapi/spec.ts";
|
|
19
21
|
export declare const DERIVERS: readonly [import("./artifact.ts").Deriver<import("./derivers/migrations.ts").ToolkitManifest>, import("./artifact.ts").Deriver<import("./derivers/migrations.ts").ToolkitManifest>, import("./artifact.ts").Deriver<{
|
|
@@ -28,6 +30,9 @@ export declare const DERIVERS: readonly [import("./artifact.ts").Deriver<import(
|
|
|
28
30
|
doc: import("../openapi/spec.ts").OpenApiDoc;
|
|
29
31
|
operationsDir?: string;
|
|
30
32
|
surfaceEject?: boolean;
|
|
33
|
+
}>, import("./artifact.ts").Deriver<{
|
|
34
|
+
models: import("./derivers/worker-io.ts").ModelSource[];
|
|
35
|
+
app?: string;
|
|
31
36
|
}>];
|
|
32
37
|
export { collectArtifacts, runGen, joinPath, readModels, expandPattern, previewModels } from "./gen.ts";
|
|
33
38
|
export type { GenIO, GenOptions, GenResult } from "./gen.ts";
|
package/dist/toolkit/index.js
CHANGED
|
@@ -12,6 +12,7 @@ export { byModelPath, typeRefFor } from "./derivers/worker-io.js";
|
|
|
12
12
|
export { deriveMeta, emitMeta, foldMeta, metaDeriver, scanModelMeta, META_TS, } from "./derivers/meta.js";
|
|
13
13
|
export { deriveMessageBindings, emitMessageBindings, emitMessageBindingsRuntime, messagesDeriver, scanModelMessages, MESSAGE_BINDINGS_DTS, MESSAGE_BINDINGS_TS, } from "./derivers/messages.js";
|
|
14
14
|
export { apiDeriver, deriveApi, emitApiBindings, emitApiBindingsRuntime, emitApiController, schemaToTs, API_BINDINGS_DTS, API_BINDINGS_TS, API_CONTROLLER_TS, } from "./derivers/api.js";
|
|
15
|
+
export { buildSystemBrief, deriveSystemBrief, emitSystemBriefMd, foldOwnership, scanModelDecisions, systemBriefDeriver, SYSTEM_BRIEF_JSON, SYSTEM_BRIEF_MD, } from "./derivers/system-brief.js";
|
|
15
16
|
// The OpenAPI machinery the deriver + runtime share (ADR 0058).
|
|
16
17
|
export { collectOperations, HTTP_METHODS, isSafeOperationId, operationsWithoutId, operationsWithUnsafeId, parseSpec, refName, resolveSchema, toRouteMatcher, undeclaredPathParams, validateValue, } from "../openapi/spec.js";
|
|
17
18
|
// The registry of all derivers (for discovery / IDE migration).
|
|
@@ -21,6 +22,7 @@ import { workerIoDeriver } from "./derivers/worker-io.js";
|
|
|
21
22
|
import { metaDeriver } from "./derivers/meta.js";
|
|
22
23
|
import { messagesDeriver } from "./derivers/messages.js";
|
|
23
24
|
import { apiDeriver } from "./derivers/api.js";
|
|
25
|
+
import { systemBriefDeriver } from "./derivers/system-brief.js";
|
|
24
26
|
export const DERIVERS = [
|
|
25
27
|
migrationsDeriver,
|
|
26
28
|
domainDeriver,
|
|
@@ -28,6 +30,7 @@ export const DERIVERS = [
|
|
|
28
30
|
metaDeriver,
|
|
29
31
|
messagesDeriver,
|
|
30
32
|
apiDeriver,
|
|
33
|
+
systemBriefDeriver,
|
|
31
34
|
];
|
|
32
35
|
// Gen orchestrator + IO
|
|
33
36
|
export { collectArtifacts, runGen, joinPath, readModels, expandPattern, previewModels } from "./gen.js";
|
package/dist/toolkit/models.d.ts
CHANGED
|
@@ -5,9 +5,10 @@ import type { ModelSource } from "./derivers/worker-io.ts";
|
|
|
5
5
|
/** Default source glob for code-first flows (matches the code-first scaffold layout). */
|
|
6
6
|
export declare const DEFAULT_WORKFLOW_PATTERNS: string[];
|
|
7
7
|
/** Default output dir for derived models when the manifest declares no `models.processes`: under
|
|
8
|
-
* the deploy-by-convention `resources/` tree (ADR 0062),
|
|
9
|
-
*
|
|
10
|
-
* `processesOutDir` derives the dir from that glob instead (the
|
|
8
|
+
* the deploy-by-convention `resources/` tree (ADR 0062), so a derived model lands where the
|
|
9
|
+
* convention deploy + codegen scan (which walk `resources/` recursively) look for it. When
|
|
10
|
+
* `models.processes` IS set, `processesOutDir` derives the dir from that glob instead (the
|
|
11
|
+
* model-first override). */
|
|
11
12
|
export declare const PROCESSES_DIR = "resources/processes";
|
|
12
13
|
/** Marker stamped into every derived `.bpmn` (an XML comment) so re-gen overwrites and the
|
|
13
14
|
* stale sweep deletes ONLY derived output — never an authored, human-owned model. */
|
package/dist/toolkit/models.js
CHANGED
|
@@ -14,9 +14,10 @@ import { isRecord } from "../runtime/core/guards.js";
|
|
|
14
14
|
/** Default source glob for code-first flows (matches the code-first scaffold layout). */
|
|
15
15
|
export const DEFAULT_WORKFLOW_PATTERNS = ["workflows/*.ts"];
|
|
16
16
|
/** Default output dir for derived models when the manifest declares no `models.processes`: under
|
|
17
|
-
* the deploy-by-convention `resources/` tree (ADR 0062),
|
|
18
|
-
*
|
|
19
|
-
* `processesOutDir` derives the dir from that glob instead (the
|
|
17
|
+
* the deploy-by-convention `resources/` tree (ADR 0062), so a derived model lands where the
|
|
18
|
+
* convention deploy + codegen scan (which walk `resources/` recursively) look for it. When
|
|
19
|
+
* `models.processes` IS set, `processesOutDir` derives the dir from that glob instead (the
|
|
20
|
+
* model-first override). */
|
|
20
21
|
export const PROCESSES_DIR = "resources/processes";
|
|
21
22
|
/** Marker stamped into every derived `.bpmn` (an XML comment) so re-gen overwrites and the
|
|
22
23
|
* stale sweep deletes ONLY derived output — never an authored, human-owned model. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nanobpm/urban",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.53.0",
|
|
4
4
|
"description": "Urban: build and run code-first apps on Nano — runtime, derivation toolkit, and CLI in one. Author durable processes with @nanobpm/workflow (defineFlow), a typed datasource, forms, triggers and surfaces from a nano.app.json manifest, on Node or Deno.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|