@hasna/contracts 0.1.0 → 0.2.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 +113 -3
- package/dist/cli/index.js +146 -4
- package/dist/index.js +154 -3
- package/dist/schemas.d.ts +4462 -2364
- package/dist/schemas.js +154 -3
- package/dist/validators.js +145 -3
- package/examples/scaffold-install-record.invalid.json +12 -0
- package/examples/scaffold-install-record.valid.json +43 -0
- package/examples/scaffold-manifest.invalid.json +13 -0
- package/examples/scaffold-manifest.valid.json +62 -0
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -124,6 +124,12 @@ defaults are applied; output aliases such as `EvidenceRef` describe parsed data.
|
|
|
124
124
|
- `hasna.validation_plan.v1`: deterministic checks a package or agent should run.
|
|
125
125
|
- `hasna.proof_bundle.v1`: reviewable validation result that ties a subject to
|
|
126
126
|
checks, evidence, verifier, and verdict.
|
|
127
|
+
- `hasna.scaffold_manifest.v1`: public, portable description of a scaffold's
|
|
128
|
+
type, status, capabilities, output shape, env vars, scripts, and validation
|
|
129
|
+
checks.
|
|
130
|
+
- `hasna.scaffold_install_record.v1`: portable receipt for a scaffold install
|
|
131
|
+
against a target repo or project, including installer, status, generated
|
|
132
|
+
resource refs, evidence, and proof refs.
|
|
127
133
|
|
|
128
134
|
Every top-level contract includes a literal `schema` field. Consumers should
|
|
129
135
|
reject objects whose embedded schema does not match the validator being used.
|
|
@@ -143,6 +149,7 @@ Common resource-kind mappings:
|
|
|
143
149
|
| `open-todos` | `task`, `project`, `verification`, `proof_bundle` |
|
|
144
150
|
| `open-loops` | `loop`, `workflow`, `run`, `artifact` |
|
|
145
151
|
| `open-actions` | `action`, `tool`, `event`; decisions are emitted as `DecisionEnvelope` contracts, not resource kinds |
|
|
152
|
+
| `open-automations` | `action`, `tool`, `event`; deterministic recipe decisions are emitted as `DecisionEnvelope` contracts |
|
|
146
153
|
| `open-sessions` | `session`, `run`, `machine`, `artifact` |
|
|
147
154
|
| `open-context` | `context_pack`, `file`, `url`, `knowledge` |
|
|
148
155
|
| `open-knowledge` / `open-mementos` | `knowledge`, `memento`, `context_pack` |
|
|
@@ -158,16 +165,28 @@ helpers. Owning packages still own storage and behavior.
|
|
|
158
165
|
|
|
159
166
|
- `open-todos` owns tasks, task plans, locks, comments, and task evidence.
|
|
160
167
|
- `open-loops` owns loop and workflow execution.
|
|
168
|
+
- `open-events` owns event envelopes, channels, delivery, replay, and
|
|
169
|
+
notification semantics.
|
|
161
170
|
- `open-actions` owns executable action manifests.
|
|
171
|
+
- `open-automations` owns deterministic product/app automations and
|
|
172
|
+
connector/action recipes. It does not own agent workflow invocation,
|
|
173
|
+
admission queues, task/PR/review worker routing, or canonical workflow run
|
|
174
|
+
artifacts.
|
|
162
175
|
- `open-sessions` owns transcript and trajectory ingestion.
|
|
163
176
|
- `open-context` owns context-pack construction and retrieval.
|
|
164
|
-
- `open-knowledge` owns durable knowledge records and promotion workflows
|
|
177
|
+
- `open-knowledge` owns durable knowledge records and promotion workflows under
|
|
178
|
+
`.hasna/knowledge`.
|
|
165
179
|
- `open-files` owns artifact storage, file indexing, and dereference logic.
|
|
166
180
|
- `open-mementos` owns memory lifecycle and recall.
|
|
167
181
|
- `open-reports` owns rendered reports and proof presentation.
|
|
168
182
|
- `open-evals` owns evaluation execution and scored validation results.
|
|
169
183
|
- `open-economy` owns budget, cost, and usage policy decisions.
|
|
170
184
|
- `open-monitor` owns fleet health classification and alerting.
|
|
185
|
+
- `iapp-scaffolds` owns scaffold templates, registry behavior, install/setup
|
|
186
|
+
behavior, MCP tools, CLI UX, and private/internal scaffold metadata. It should
|
|
187
|
+
validate public scaffold manifests and install records with
|
|
188
|
+
`@hasna/contracts`, but `@hasna/contracts` must not import or execute
|
|
189
|
+
`iapp-scaffolds`.
|
|
171
190
|
|
|
172
191
|
## Downstream Integration Recipes
|
|
173
192
|
|
|
@@ -179,10 +198,16 @@ native domain objects immediately.
|
|
|
179
198
|
records, versions, signed URLs, source manifests, and evidence assets.
|
|
180
199
|
- `open-todos`: expose task refs as `ResourceRef`; verification evidence as
|
|
181
200
|
`ProofBundle`; task execution receipts as `WorkRun`; review gates as
|
|
182
|
-
`ValidationPlan
|
|
201
|
+
`ValidationPlan`; and workflow/run manifest pointers as compact task fields,
|
|
202
|
+
not embedded handoff artifacts.
|
|
183
203
|
- `open-loops`: emit loop/workflow runs as `WorkRun`, audit traces as
|
|
184
204
|
`AgentTrajectory`, logs/artifacts as `EvidenceRef`, and verifier output as
|
|
185
|
-
`ProofBundle`.
|
|
205
|
+
`ProofBundle`. OpenLoops owns `WorkflowInvocation`, admission/work-item
|
|
206
|
+
queues, leases, workflow runs, retries, cancellation, worktrees, and run
|
|
207
|
+
artifacts.
|
|
208
|
+
- `open-events`: emit and replay validated event envelopes to channels.
|
|
209
|
+
OpenEvents delivers notifications only; it does not create workflow
|
|
210
|
+
invocations, own queue state, or retry agent work.
|
|
186
211
|
- `open-sessions`: convert messages/tool calls to `AgentTrajectory`, token
|
|
187
212
|
usage to `CostEstimate`, and transcript paths to `EvidenceRef`.
|
|
188
213
|
- `open-context`: serialize built context as `ContextPack` with citations as
|
|
@@ -202,10 +227,95 @@ native domain objects immediately.
|
|
|
202
227
|
- `open-actions`: keep domain action manifests, but expose shared `ActorRef`,
|
|
203
228
|
`EvidenceRef`, `CapabilityCard`, `DecisionEnvelope`, and `WorkRun` adapter
|
|
204
229
|
views.
|
|
230
|
+
- `iapp-scaffolds`: emit `ScaffoldManifest` documents for bundled templates,
|
|
231
|
+
write schema-tagged `ScaffoldInstallRecord` receipts for installs, and keep
|
|
232
|
+
template copying, setup wizards, source paths, and private metadata inside the
|
|
233
|
+
scaffold package.
|
|
234
|
+
- `open-automations`: keep deterministic app/product automation recipes and
|
|
235
|
+
connector/action recipes. Any agentic task, PR, review, or evaluation flow
|
|
236
|
+
must hand off to OpenLoops rather than creating a second workflow queue.
|
|
205
237
|
- `open-reports`: consume `ProofBundle`, `WorkRun`, `ContextPack`,
|
|
206
238
|
`CostEstimate`, and `EvidenceRef` to render compact Markdown/JSON/HTML proof
|
|
207
239
|
reports.
|
|
208
240
|
|
|
241
|
+
## WorkflowInvocation And App Storage Boundary
|
|
242
|
+
|
|
243
|
+
The canonical agent-work root is a `WorkflowInvocation`, not a todo task.
|
|
244
|
+
Only actionable unfinished work needs a todo. OpenTodos remains the
|
|
245
|
+
human-visible intent ledger; OpenLoops owns the durable workflow root,
|
|
246
|
+
admission queue, execution lifecycle, and canonical run artifacts.
|
|
247
|
+
|
|
248
|
+
A workflow invocation should carry these fields at the boundary:
|
|
249
|
+
|
|
250
|
+
- `id`
|
|
251
|
+
- `templateId` or `workflowId`
|
|
252
|
+
- `sourceRef`: a WorkflowInvocation-local source kind such as `task`, `event`,
|
|
253
|
+
`schedule`, `manual`, `pull_request`, `review`, or `knowledge`, plus an id
|
|
254
|
+
and dedupe key
|
|
255
|
+
- `subjectRef`: a WorkflowInvocation-local subject kind such as `repo`,
|
|
256
|
+
`pull_request`, `task`, `document`, `run`, or `metric`, plus a path, URL, or
|
|
257
|
+
id
|
|
258
|
+
- `intent`: `route`, `mutate`, `review`, `evaluate`, or `report`
|
|
259
|
+
- `scope`: project path, worktree policy, permissions, account policy, and
|
|
260
|
+
concurrency group
|
|
261
|
+
- `outputPolicy`: when to write reports and when to create a follow-up task
|
|
262
|
+
|
|
263
|
+
OpenLoops admission/work items are first-class records with route key,
|
|
264
|
+
idempotency key, source/subject refs, project key/group, priority, status,
|
|
265
|
+
attempts, next-attempt time, lease expiry, loop/workflow/run ids, and last
|
|
266
|
+
reason. Status values should be explicit: `queued`, `deferred`, `admitted`,
|
|
267
|
+
`running`, `succeeded`, `failed`, `dead_letter`, or `cancelled`.
|
|
268
|
+
|
|
269
|
+
Run artifacts live under:
|
|
270
|
+
|
|
271
|
+
```text
|
|
272
|
+
.hasna/loops/runs/<project-slug>/<subject-key>/<run-id>/manifest.json
|
|
273
|
+
.hasna/loops/runs/<project-slug>/<subject-key>/<run-id>/triage.md
|
|
274
|
+
.hasna/loops/runs/<project-slug>/<subject-key>/<run-id>/plan.md
|
|
275
|
+
.hasna/loops/runs/<project-slug>/<subject-key>/<run-id>/worker-report.md
|
|
276
|
+
.hasna/loops/runs/<project-slug>/<subject-key>/<run-id>/evaluation.md
|
|
277
|
+
.hasna/loops/runs/<project-slug>/<subject-key>/<run-id>/evidence/
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
The `<subject-key>` is never the raw subject reference. It must be a safe path
|
|
281
|
+
segment derived as `kind-safeSlug-shortHash`. Recommended normalization:
|
|
282
|
+
lowercase ASCII, replace non-alphanumeric runs with `-`, trim separators, cap
|
|
283
|
+
the slug portion at 72 characters, and append at least 12 hex characters from a
|
|
284
|
+
SHA-256 hash of the canonical raw `subjectRef`. Reject `.`/`..`, reserved device
|
|
285
|
+
names, path separators, empty keys, and path traversal. Store the raw
|
|
286
|
+
`subjectRef` only inside `manifest.json`.
|
|
287
|
+
|
|
288
|
+
OpenEvents webhooks/channels are notifications. A `task.created` notification
|
|
289
|
+
can be delivered through OpenEvents, but OpenLoops consumes the envelope and
|
|
290
|
+
upserts/admits work items. OpenEvents must not import OpenLoops or own
|
|
291
|
+
admission, retries, leases, verifier execution, or workflow run artifacts.
|
|
292
|
+
|
|
293
|
+
Every Hasna app stores local state under `.hasna/<app>/...`. The obsolete
|
|
294
|
+
`.hasna/apps/<app>` layout is not an operational read path. OpenKnowledge's
|
|
295
|
+
canonical storage is `.hasna/knowledge`, not `.hasna/apps/knowledge`.
|
|
296
|
+
|
|
297
|
+
No-backcompat migrations must preserve data without keeping legacy shims:
|
|
298
|
+
|
|
299
|
+
1. Create a read-only backup or export before moving data.
|
|
300
|
+
2. Atomically copy or rename into the canonical `.hasna/<app>` path.
|
|
301
|
+
3. Verify JSON item counts, SQLite integrity and table counts, artifact counts,
|
|
302
|
+
hashes, and any storage-object or sync-snapshot evidence.
|
|
303
|
+
4. Leave only a diagnostic tombstone at the old path.
|
|
304
|
+
5. Treat mismatched counts, hash failures, or SQLite integrity failures as
|
|
305
|
+
blockers.
|
|
306
|
+
|
|
307
|
+
Unattended automatic routes must fail closed when the configured sandbox cannot
|
|
308
|
+
be proven. Acceptable sandbox evidence includes a successful preflight receipt
|
|
309
|
+
that names the isolation provider, filesystem/network policy, writable roots,
|
|
310
|
+
tool allowlist, environment redaction result, and timestamp for the exact route
|
|
311
|
+
or run. `danger-full-access` plus a worktree is a manual break-glass mode, not a
|
|
312
|
+
safe auto-route default.
|
|
313
|
+
|
|
314
|
+
`WorkflowInvocation` is documented here as the architecture boundary used by
|
|
315
|
+
OpenLoops and neighboring packages. It is not yet a wire schema in the current
|
|
316
|
+
catalog; add a `hasna.workflow_invocation.v1` schema only when at least two
|
|
317
|
+
packages need to validate the object directly at a shared boundary.
|
|
318
|
+
|
|
209
319
|
## Enforcement Model
|
|
210
320
|
|
|
211
321
|
Validate at every boundary where another package, agent, process, or machine can
|
package/dist/cli/index.js
CHANGED
|
@@ -992,7 +992,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
992
992
|
this._exitCallback = (err) => {
|
|
993
993
|
if (err.code !== "commander.executeSubCommandAsync") {
|
|
994
994
|
throw err;
|
|
995
|
-
}
|
|
995
|
+
} else {}
|
|
996
996
|
};
|
|
997
997
|
}
|
|
998
998
|
return this;
|
|
@@ -6074,7 +6074,7 @@ var coerce = {
|
|
|
6074
6074
|
};
|
|
6075
6075
|
var NEVER = INVALID;
|
|
6076
6076
|
// src/schemas.ts
|
|
6077
|
-
var CONTRACTS_PACKAGE_VERSION = "0.
|
|
6077
|
+
var CONTRACTS_PACKAGE_VERSION = "0.2.0";
|
|
6078
6078
|
var SCHEMA_IDS = {
|
|
6079
6079
|
actorRef: "hasna.actor_ref.v1",
|
|
6080
6080
|
resourceRef: "hasna.resource_ref.v1",
|
|
@@ -6086,7 +6086,9 @@ var SCHEMA_IDS = {
|
|
|
6086
6086
|
contextPack: "hasna.context_pack.v1",
|
|
6087
6087
|
agentTrajectory: "hasna.agent_trajectory.v1",
|
|
6088
6088
|
validationPlan: "hasna.validation_plan.v1",
|
|
6089
|
-
proofBundle: "hasna.proof_bundle.v1"
|
|
6089
|
+
proofBundle: "hasna.proof_bundle.v1",
|
|
6090
|
+
scaffoldManifest: "hasna.scaffold_manifest.v1",
|
|
6091
|
+
scaffoldInstallRecord: "hasna.scaffold_install_record.v1"
|
|
6090
6092
|
};
|
|
6091
6093
|
var SchemaIdSchema = exports_external.string().regex(/^hasna\.[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*\.v[0-9]+$/);
|
|
6092
6094
|
var TimestampSchema = exports_external.string().datetime();
|
|
@@ -6390,6 +6392,144 @@ var ValidationPlanSchema = contractBaseSchema(SCHEMA_IDS.validationPlan).extend(
|
|
|
6390
6392
|
verifier: ActorPointerSchema.optional(),
|
|
6391
6393
|
requiredEvidenceKinds: exports_external.array(EvidenceKindSchema).default([])
|
|
6392
6394
|
}).strict();
|
|
6395
|
+
var ScaffoldTypeSchema = exports_external.enum([
|
|
6396
|
+
"open_source",
|
|
6397
|
+
"internal_app",
|
|
6398
|
+
"platform",
|
|
6399
|
+
"app",
|
|
6400
|
+
"agent",
|
|
6401
|
+
"content",
|
|
6402
|
+
"overlay",
|
|
6403
|
+
"other"
|
|
6404
|
+
]);
|
|
6405
|
+
var ScaffoldStatusSchema = exports_external.enum(["draft", "active", "deprecated", "archived"]);
|
|
6406
|
+
var ScaffoldCapabilitySchema = exports_external.enum([
|
|
6407
|
+
"cli",
|
|
6408
|
+
"mcp",
|
|
6409
|
+
"library",
|
|
6410
|
+
"sdk",
|
|
6411
|
+
"rest_api",
|
|
6412
|
+
"dashboard",
|
|
6413
|
+
"database",
|
|
6414
|
+
"auth",
|
|
6415
|
+
"billing",
|
|
6416
|
+
"worker",
|
|
6417
|
+
"daemon",
|
|
6418
|
+
"native",
|
|
6419
|
+
"browser_extension",
|
|
6420
|
+
"ai_provider",
|
|
6421
|
+
"media_pipeline",
|
|
6422
|
+
"data_pipeline",
|
|
6423
|
+
"tests",
|
|
6424
|
+
"ci",
|
|
6425
|
+
"deployment",
|
|
6426
|
+
"docs",
|
|
6427
|
+
"other"
|
|
6428
|
+
]);
|
|
6429
|
+
var ScaffoldEnvVarSchema = exports_external.object({
|
|
6430
|
+
key: exports_external.string().regex(/^[A-Z][A-Z0-9_]*$/),
|
|
6431
|
+
description: exports_external.string().min(1),
|
|
6432
|
+
required: exports_external.boolean().default(false),
|
|
6433
|
+
secret: exports_external.boolean().default(false),
|
|
6434
|
+
group: exports_external.string().min(1).optional(),
|
|
6435
|
+
default: exports_external.string().optional()
|
|
6436
|
+
}).strict().superRefine((value, ctx) => {
|
|
6437
|
+
if (value.secret && value.default !== undefined) {
|
|
6438
|
+
ctx.addIssue({
|
|
6439
|
+
code: exports_external.ZodIssueCode.custom,
|
|
6440
|
+
message: "Secret scaffold env vars cannot include defaults",
|
|
6441
|
+
path: ["default"]
|
|
6442
|
+
});
|
|
6443
|
+
}
|
|
6444
|
+
});
|
|
6445
|
+
var ScaffoldScriptSchema = exports_external.object({
|
|
6446
|
+
name: exports_external.string().min(1),
|
|
6447
|
+
command: exports_external.string().min(1),
|
|
6448
|
+
description: exports_external.string().min(1).optional(),
|
|
6449
|
+
required: exports_external.boolean().default(false)
|
|
6450
|
+
}).strict();
|
|
6451
|
+
var ScaffoldOutputShapeSchema = exports_external.object({
|
|
6452
|
+
packageManager: exports_external.enum(["bun", "npm", "pnpm", "yarn", "cargo", "pip", "other"]).optional(),
|
|
6453
|
+
languages: exports_external.array(exports_external.string().min(1)).default([]),
|
|
6454
|
+
requiredFiles: exports_external.array(exports_external.string().min(1)).default([]),
|
|
6455
|
+
requiredDirectories: exports_external.array(exports_external.string().min(1)).default([]),
|
|
6456
|
+
optionalDirectories: exports_external.array(exports_external.string().min(1)).default([])
|
|
6457
|
+
}).strict();
|
|
6458
|
+
var ScaffoldManifestSchema = contractBaseSchema(SCHEMA_IDS.scaffoldManifest).extend({
|
|
6459
|
+
name: exports_external.string().min(1),
|
|
6460
|
+
version: exports_external.string().min(1),
|
|
6461
|
+
summary: exports_external.string().min(1),
|
|
6462
|
+
type: ScaffoldTypeSchema,
|
|
6463
|
+
status: ScaffoldStatusSchema.default("draft"),
|
|
6464
|
+
capabilities: exports_external.array(ScaffoldCapabilitySchema).default([]),
|
|
6465
|
+
techStack: exports_external.array(exports_external.string().min(1)).default([]),
|
|
6466
|
+
tags: TagsSchema,
|
|
6467
|
+
source: ResourcePointerSchema.optional(),
|
|
6468
|
+
output: ScaffoldOutputShapeSchema,
|
|
6469
|
+
env: exports_external.array(ScaffoldEnvVarSchema).default([]),
|
|
6470
|
+
scripts: exports_external.array(ScaffoldScriptSchema).default([]),
|
|
6471
|
+
validationChecks: exports_external.array(ValidationCheckSchema).default([]),
|
|
6472
|
+
evidenceRefs: exports_external.array(EvidencePointerSchema).default([])
|
|
6473
|
+
}).strict().superRefine((value, ctx) => {
|
|
6474
|
+
if (value.source?.uri?.startsWith("file://")) {
|
|
6475
|
+
ctx.addIssue({
|
|
6476
|
+
code: exports_external.ZodIssueCode.custom,
|
|
6477
|
+
message: "Public scaffold manifest source refs cannot use local file:// URIs",
|
|
6478
|
+
path: ["source", "uri"]
|
|
6479
|
+
});
|
|
6480
|
+
}
|
|
6481
|
+
if (value.status === "active" && value.validationChecks.length === 0) {
|
|
6482
|
+
ctx.addIssue({
|
|
6483
|
+
code: exports_external.ZodIssueCode.custom,
|
|
6484
|
+
message: "Active scaffold manifests require validation checks",
|
|
6485
|
+
path: ["validationChecks"]
|
|
6486
|
+
});
|
|
6487
|
+
}
|
|
6488
|
+
if (value.status === "active" && value.output.requiredFiles.length === 0 && value.output.requiredDirectories.length === 0) {
|
|
6489
|
+
ctx.addIssue({
|
|
6490
|
+
code: exports_external.ZodIssueCode.custom,
|
|
6491
|
+
message: "Active scaffold manifests require at least one required file or directory",
|
|
6492
|
+
path: ["output"]
|
|
6493
|
+
});
|
|
6494
|
+
}
|
|
6495
|
+
});
|
|
6496
|
+
var ScaffoldInstallStatusSchema = exports_external.enum(["installed", "failed", "cancelled", "partial", "unknown"]);
|
|
6497
|
+
var ScaffoldInstallRecordSchema = contractBaseSchema(SCHEMA_IDS.scaffoldInstallRecord).extend({
|
|
6498
|
+
scaffoldId: exports_external.string().min(1),
|
|
6499
|
+
scaffoldVersion: exports_external.string().min(1).optional(),
|
|
6500
|
+
manifestRef: ResourcePointerSchema.optional(),
|
|
6501
|
+
target: ResourcePointerSchema,
|
|
6502
|
+
status: ScaffoldInstallStatusSchema,
|
|
6503
|
+
installedAt: TimestampSchema.optional(),
|
|
6504
|
+
installer: ActorPointerSchema.optional(),
|
|
6505
|
+
packageManager: exports_external.enum(["bun", "npm", "pnpm", "yarn", "cargo", "pip", "other"]).optional(),
|
|
6506
|
+
options: MetadataSchema.optional(),
|
|
6507
|
+
generatedFiles: exports_external.array(ResourcePointerSchema).default([]),
|
|
6508
|
+
evidenceRefs: exports_external.array(EvidencePointerSchema).default([]),
|
|
6509
|
+
proofBundleRefs: exports_external.array(ResourcePointerSchema).default([])
|
|
6510
|
+
}).strict().superRefine((value, ctx) => {
|
|
6511
|
+
if (value.status === "installed" && !value.installedAt) {
|
|
6512
|
+
ctx.addIssue({
|
|
6513
|
+
code: exports_external.ZodIssueCode.custom,
|
|
6514
|
+
message: "Installed scaffold records require installedAt",
|
|
6515
|
+
path: ["installedAt"]
|
|
6516
|
+
});
|
|
6517
|
+
}
|
|
6518
|
+
if (value.status === "installed" && value.generatedFiles.length === 0 && value.evidenceRefs.length === 0 && value.proofBundleRefs.length === 0) {
|
|
6519
|
+
ctx.addIssue({
|
|
6520
|
+
code: exports_external.ZodIssueCode.custom,
|
|
6521
|
+
message: "Installed scaffold records require generated files, evidence, or proof bundle refs",
|
|
6522
|
+
path: ["generatedFiles"]
|
|
6523
|
+
});
|
|
6524
|
+
}
|
|
6525
|
+
if ((value.status === "failed" || value.status === "partial") && value.evidenceRefs.length === 0 && value.proofBundleRefs.length === 0) {
|
|
6526
|
+
ctx.addIssue({
|
|
6527
|
+
code: exports_external.ZodIssueCode.custom,
|
|
6528
|
+
message: "Failed or partial scaffold records require evidence or proof bundle refs",
|
|
6529
|
+
path: ["evidenceRefs"]
|
|
6530
|
+
});
|
|
6531
|
+
}
|
|
6532
|
+
});
|
|
6393
6533
|
var ProofCheckResultSchema = exports_external.object({
|
|
6394
6534
|
checkId: exports_external.string().min(1),
|
|
6395
6535
|
status: ContractStatusSchema,
|
|
@@ -6536,7 +6676,9 @@ var ContractSchemaRegistry = {
|
|
|
6536
6676
|
[SCHEMA_IDS.contextPack]: ContextPackSchema,
|
|
6537
6677
|
[SCHEMA_IDS.agentTrajectory]: AgentTrajectorySchema,
|
|
6538
6678
|
[SCHEMA_IDS.validationPlan]: ValidationPlanSchema,
|
|
6539
|
-
[SCHEMA_IDS.proofBundle]: ProofBundleSchema
|
|
6679
|
+
[SCHEMA_IDS.proofBundle]: ProofBundleSchema,
|
|
6680
|
+
[SCHEMA_IDS.scaffoldManifest]: ScaffoldManifestSchema,
|
|
6681
|
+
[SCHEMA_IDS.scaffoldInstallRecord]: ScaffoldInstallRecordSchema
|
|
6540
6682
|
};
|
|
6541
6683
|
|
|
6542
6684
|
// src/validators.ts
|
package/dist/index.js
CHANGED
|
@@ -3989,7 +3989,7 @@ var coerce = {
|
|
|
3989
3989
|
var NEVER = INVALID;
|
|
3990
3990
|
// src/schemas.ts
|
|
3991
3991
|
var CONTRACTS_PACKAGE_NAME = "@hasna/contracts";
|
|
3992
|
-
var CONTRACTS_PACKAGE_VERSION = "0.
|
|
3992
|
+
var CONTRACTS_PACKAGE_VERSION = "0.2.0";
|
|
3993
3993
|
var SCHEMA_IDS = {
|
|
3994
3994
|
actorRef: "hasna.actor_ref.v1",
|
|
3995
3995
|
resourceRef: "hasna.resource_ref.v1",
|
|
@@ -4001,7 +4001,9 @@ var SCHEMA_IDS = {
|
|
|
4001
4001
|
contextPack: "hasna.context_pack.v1",
|
|
4002
4002
|
agentTrajectory: "hasna.agent_trajectory.v1",
|
|
4003
4003
|
validationPlan: "hasna.validation_plan.v1",
|
|
4004
|
-
proofBundle: "hasna.proof_bundle.v1"
|
|
4004
|
+
proofBundle: "hasna.proof_bundle.v1",
|
|
4005
|
+
scaffoldManifest: "hasna.scaffold_manifest.v1",
|
|
4006
|
+
scaffoldInstallRecord: "hasna.scaffold_install_record.v1"
|
|
4005
4007
|
};
|
|
4006
4008
|
var SchemaIdSchema = exports_external.string().regex(/^hasna\.[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*\.v[0-9]+$/);
|
|
4007
4009
|
var TimestampSchema = exports_external.string().datetime();
|
|
@@ -4305,6 +4307,144 @@ var ValidationPlanSchema = contractBaseSchema(SCHEMA_IDS.validationPlan).extend(
|
|
|
4305
4307
|
verifier: ActorPointerSchema.optional(),
|
|
4306
4308
|
requiredEvidenceKinds: exports_external.array(EvidenceKindSchema).default([])
|
|
4307
4309
|
}).strict();
|
|
4310
|
+
var ScaffoldTypeSchema = exports_external.enum([
|
|
4311
|
+
"open_source",
|
|
4312
|
+
"internal_app",
|
|
4313
|
+
"platform",
|
|
4314
|
+
"app",
|
|
4315
|
+
"agent",
|
|
4316
|
+
"content",
|
|
4317
|
+
"overlay",
|
|
4318
|
+
"other"
|
|
4319
|
+
]);
|
|
4320
|
+
var ScaffoldStatusSchema = exports_external.enum(["draft", "active", "deprecated", "archived"]);
|
|
4321
|
+
var ScaffoldCapabilitySchema = exports_external.enum([
|
|
4322
|
+
"cli",
|
|
4323
|
+
"mcp",
|
|
4324
|
+
"library",
|
|
4325
|
+
"sdk",
|
|
4326
|
+
"rest_api",
|
|
4327
|
+
"dashboard",
|
|
4328
|
+
"database",
|
|
4329
|
+
"auth",
|
|
4330
|
+
"billing",
|
|
4331
|
+
"worker",
|
|
4332
|
+
"daemon",
|
|
4333
|
+
"native",
|
|
4334
|
+
"browser_extension",
|
|
4335
|
+
"ai_provider",
|
|
4336
|
+
"media_pipeline",
|
|
4337
|
+
"data_pipeline",
|
|
4338
|
+
"tests",
|
|
4339
|
+
"ci",
|
|
4340
|
+
"deployment",
|
|
4341
|
+
"docs",
|
|
4342
|
+
"other"
|
|
4343
|
+
]);
|
|
4344
|
+
var ScaffoldEnvVarSchema = exports_external.object({
|
|
4345
|
+
key: exports_external.string().regex(/^[A-Z][A-Z0-9_]*$/),
|
|
4346
|
+
description: exports_external.string().min(1),
|
|
4347
|
+
required: exports_external.boolean().default(false),
|
|
4348
|
+
secret: exports_external.boolean().default(false),
|
|
4349
|
+
group: exports_external.string().min(1).optional(),
|
|
4350
|
+
default: exports_external.string().optional()
|
|
4351
|
+
}).strict().superRefine((value, ctx) => {
|
|
4352
|
+
if (value.secret && value.default !== undefined) {
|
|
4353
|
+
ctx.addIssue({
|
|
4354
|
+
code: exports_external.ZodIssueCode.custom,
|
|
4355
|
+
message: "Secret scaffold env vars cannot include defaults",
|
|
4356
|
+
path: ["default"]
|
|
4357
|
+
});
|
|
4358
|
+
}
|
|
4359
|
+
});
|
|
4360
|
+
var ScaffoldScriptSchema = exports_external.object({
|
|
4361
|
+
name: exports_external.string().min(1),
|
|
4362
|
+
command: exports_external.string().min(1),
|
|
4363
|
+
description: exports_external.string().min(1).optional(),
|
|
4364
|
+
required: exports_external.boolean().default(false)
|
|
4365
|
+
}).strict();
|
|
4366
|
+
var ScaffoldOutputShapeSchema = exports_external.object({
|
|
4367
|
+
packageManager: exports_external.enum(["bun", "npm", "pnpm", "yarn", "cargo", "pip", "other"]).optional(),
|
|
4368
|
+
languages: exports_external.array(exports_external.string().min(1)).default([]),
|
|
4369
|
+
requiredFiles: exports_external.array(exports_external.string().min(1)).default([]),
|
|
4370
|
+
requiredDirectories: exports_external.array(exports_external.string().min(1)).default([]),
|
|
4371
|
+
optionalDirectories: exports_external.array(exports_external.string().min(1)).default([])
|
|
4372
|
+
}).strict();
|
|
4373
|
+
var ScaffoldManifestSchema = contractBaseSchema(SCHEMA_IDS.scaffoldManifest).extend({
|
|
4374
|
+
name: exports_external.string().min(1),
|
|
4375
|
+
version: exports_external.string().min(1),
|
|
4376
|
+
summary: exports_external.string().min(1),
|
|
4377
|
+
type: ScaffoldTypeSchema,
|
|
4378
|
+
status: ScaffoldStatusSchema.default("draft"),
|
|
4379
|
+
capabilities: exports_external.array(ScaffoldCapabilitySchema).default([]),
|
|
4380
|
+
techStack: exports_external.array(exports_external.string().min(1)).default([]),
|
|
4381
|
+
tags: TagsSchema,
|
|
4382
|
+
source: ResourcePointerSchema.optional(),
|
|
4383
|
+
output: ScaffoldOutputShapeSchema,
|
|
4384
|
+
env: exports_external.array(ScaffoldEnvVarSchema).default([]),
|
|
4385
|
+
scripts: exports_external.array(ScaffoldScriptSchema).default([]),
|
|
4386
|
+
validationChecks: exports_external.array(ValidationCheckSchema).default([]),
|
|
4387
|
+
evidenceRefs: exports_external.array(EvidencePointerSchema).default([])
|
|
4388
|
+
}).strict().superRefine((value, ctx) => {
|
|
4389
|
+
if (value.source?.uri?.startsWith("file://")) {
|
|
4390
|
+
ctx.addIssue({
|
|
4391
|
+
code: exports_external.ZodIssueCode.custom,
|
|
4392
|
+
message: "Public scaffold manifest source refs cannot use local file:// URIs",
|
|
4393
|
+
path: ["source", "uri"]
|
|
4394
|
+
});
|
|
4395
|
+
}
|
|
4396
|
+
if (value.status === "active" && value.validationChecks.length === 0) {
|
|
4397
|
+
ctx.addIssue({
|
|
4398
|
+
code: exports_external.ZodIssueCode.custom,
|
|
4399
|
+
message: "Active scaffold manifests require validation checks",
|
|
4400
|
+
path: ["validationChecks"]
|
|
4401
|
+
});
|
|
4402
|
+
}
|
|
4403
|
+
if (value.status === "active" && value.output.requiredFiles.length === 0 && value.output.requiredDirectories.length === 0) {
|
|
4404
|
+
ctx.addIssue({
|
|
4405
|
+
code: exports_external.ZodIssueCode.custom,
|
|
4406
|
+
message: "Active scaffold manifests require at least one required file or directory",
|
|
4407
|
+
path: ["output"]
|
|
4408
|
+
});
|
|
4409
|
+
}
|
|
4410
|
+
});
|
|
4411
|
+
var ScaffoldInstallStatusSchema = exports_external.enum(["installed", "failed", "cancelled", "partial", "unknown"]);
|
|
4412
|
+
var ScaffoldInstallRecordSchema = contractBaseSchema(SCHEMA_IDS.scaffoldInstallRecord).extend({
|
|
4413
|
+
scaffoldId: exports_external.string().min(1),
|
|
4414
|
+
scaffoldVersion: exports_external.string().min(1).optional(),
|
|
4415
|
+
manifestRef: ResourcePointerSchema.optional(),
|
|
4416
|
+
target: ResourcePointerSchema,
|
|
4417
|
+
status: ScaffoldInstallStatusSchema,
|
|
4418
|
+
installedAt: TimestampSchema.optional(),
|
|
4419
|
+
installer: ActorPointerSchema.optional(),
|
|
4420
|
+
packageManager: exports_external.enum(["bun", "npm", "pnpm", "yarn", "cargo", "pip", "other"]).optional(),
|
|
4421
|
+
options: MetadataSchema.optional(),
|
|
4422
|
+
generatedFiles: exports_external.array(ResourcePointerSchema).default([]),
|
|
4423
|
+
evidenceRefs: exports_external.array(EvidencePointerSchema).default([]),
|
|
4424
|
+
proofBundleRefs: exports_external.array(ResourcePointerSchema).default([])
|
|
4425
|
+
}).strict().superRefine((value, ctx) => {
|
|
4426
|
+
if (value.status === "installed" && !value.installedAt) {
|
|
4427
|
+
ctx.addIssue({
|
|
4428
|
+
code: exports_external.ZodIssueCode.custom,
|
|
4429
|
+
message: "Installed scaffold records require installedAt",
|
|
4430
|
+
path: ["installedAt"]
|
|
4431
|
+
});
|
|
4432
|
+
}
|
|
4433
|
+
if (value.status === "installed" && value.generatedFiles.length === 0 && value.evidenceRefs.length === 0 && value.proofBundleRefs.length === 0) {
|
|
4434
|
+
ctx.addIssue({
|
|
4435
|
+
code: exports_external.ZodIssueCode.custom,
|
|
4436
|
+
message: "Installed scaffold records require generated files, evidence, or proof bundle refs",
|
|
4437
|
+
path: ["generatedFiles"]
|
|
4438
|
+
});
|
|
4439
|
+
}
|
|
4440
|
+
if ((value.status === "failed" || value.status === "partial") && value.evidenceRefs.length === 0 && value.proofBundleRefs.length === 0) {
|
|
4441
|
+
ctx.addIssue({
|
|
4442
|
+
code: exports_external.ZodIssueCode.custom,
|
|
4443
|
+
message: "Failed or partial scaffold records require evidence or proof bundle refs",
|
|
4444
|
+
path: ["evidenceRefs"]
|
|
4445
|
+
});
|
|
4446
|
+
}
|
|
4447
|
+
});
|
|
4308
4448
|
var ProofCheckResultSchema = exports_external.object({
|
|
4309
4449
|
checkId: exports_external.string().min(1),
|
|
4310
4450
|
status: ContractStatusSchema,
|
|
@@ -4451,7 +4591,9 @@ var ContractSchemaRegistry = {
|
|
|
4451
4591
|
[SCHEMA_IDS.contextPack]: ContextPackSchema,
|
|
4452
4592
|
[SCHEMA_IDS.agentTrajectory]: AgentTrajectorySchema,
|
|
4453
4593
|
[SCHEMA_IDS.validationPlan]: ValidationPlanSchema,
|
|
4454
|
-
[SCHEMA_IDS.proofBundle]: ProofBundleSchema
|
|
4594
|
+
[SCHEMA_IDS.proofBundle]: ProofBundleSchema,
|
|
4595
|
+
[SCHEMA_IDS.scaffoldManifest]: ScaffoldManifestSchema,
|
|
4596
|
+
[SCHEMA_IDS.scaffoldInstallRecord]: ScaffoldInstallRecordSchema
|
|
4455
4597
|
};
|
|
4456
4598
|
|
|
4457
4599
|
// src/validators.ts
|
|
@@ -4533,6 +4675,15 @@ export {
|
|
|
4533
4675
|
TagsSchema,
|
|
4534
4676
|
Sha256DigestSchema,
|
|
4535
4677
|
SchemaIdSchema,
|
|
4678
|
+
ScaffoldTypeSchema,
|
|
4679
|
+
ScaffoldStatusSchema,
|
|
4680
|
+
ScaffoldScriptSchema,
|
|
4681
|
+
ScaffoldOutputShapeSchema,
|
|
4682
|
+
ScaffoldManifestSchema,
|
|
4683
|
+
ScaffoldInstallStatusSchema,
|
|
4684
|
+
ScaffoldInstallRecordSchema,
|
|
4685
|
+
ScaffoldEnvVarSchema,
|
|
4686
|
+
ScaffoldCapabilitySchema,
|
|
4536
4687
|
SCHEMA_IDS,
|
|
4537
4688
|
ResourceRefSchema,
|
|
4538
4689
|
ResourcePointerSchema,
|