@cleocode/contracts 2026.5.113 → 2026.5.120

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.
Files changed (37) hide show
  1. package/dist/__tests__/meta-tokens.test.d.ts +16 -0
  2. package/dist/__tests__/meta-tokens.test.d.ts.map +1 -0
  3. package/dist/__tests__/meta-tokens.test.js +99 -0
  4. package/dist/__tests__/meta-tokens.test.js.map +1 -0
  5. package/dist/boundary.js +3 -3
  6. package/dist/boundary.js.map +1 -1
  7. package/dist/dispatch/operations-registry.d.ts.map +1 -1
  8. package/dist/dispatch/operations-registry.js +119 -0
  9. package/dist/dispatch/operations-registry.js.map +1 -1
  10. package/dist/index.d.ts +2 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +4 -0
  13. package/dist/index.js.map +1 -1
  14. package/dist/operations/__tests__/tasks-input-contracts.test.d.ts +18 -0
  15. package/dist/operations/__tests__/tasks-input-contracts.test.d.ts.map +1 -0
  16. package/dist/operations/__tests__/tasks-input-contracts.test.js +80 -0
  17. package/dist/operations/__tests__/tasks-input-contracts.test.js.map +1 -0
  18. package/dist/operations/docs.d.ts +166 -8
  19. package/dist/operations/docs.d.ts.map +1 -1
  20. package/dist/operations/docs.js +9 -7
  21. package/dist/operations/docs.js.map +1 -1
  22. package/dist/operations/tasks.d.ts +109 -0
  23. package/dist/operations/tasks.d.ts.map +1 -1
  24. package/dist/operations/tasks.js +237 -1
  25. package/dist/operations/tasks.js.map +1 -1
  26. package/dist/task-record.d.ts +7 -0
  27. package/dist/task-record.d.ts.map +1 -1
  28. package/package.json +2 -2
  29. package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
  30. package/src/__tests__/meta-tokens.test.ts +107 -0
  31. package/src/boundary.ts +3 -3
  32. package/src/dispatch/operations-registry.ts +124 -0
  33. package/src/index.ts +12 -0
  34. package/src/operations/__tests__/tasks-input-contracts.test.ts +106 -0
  35. package/src/operations/docs.ts +187 -9
  36. package/src/operations/tasks.ts +321 -0
  37. package/src/task-record.ts +7 -0
@@ -36,6 +36,7 @@ import type {
36
36
  TaskView,
37
37
  } from '../tasks.js';
38
38
  import type { DocsType } from './docs.js';
39
+ import type { JsonSchema, OperationInputContract } from './input-contract.js';
39
40
 
40
41
  export type { TaskPriority, TaskStatus };
41
42
 
@@ -124,6 +125,19 @@ export interface TasksFindParams {
124
125
  * @task T9072
125
126
  */
126
127
  kind?: string;
128
+ /**
129
+ * Unified urgency surface (T9905).
130
+ *
131
+ * When `true`, the predicate is
132
+ *
133
+ * `priority IN ('critical','high') OR severity IN ('P0','P1')`
134
+ *
135
+ * combining the two orthogonal urgency axes (priority + severity) into a
136
+ * single filter. Composes with other filters via AND.
137
+ *
138
+ * @task T9905
139
+ */
140
+ urgent?: boolean;
127
141
  }
128
142
  export type TasksFindResult = MinimalTask[];
129
143
 
@@ -1352,3 +1366,310 @@ export type TasksOps = {
1352
1366
  /** T10121 — idempotent cron-safe auto-close repair (supersedes T10098 scope). */
1353
1367
  readonly 'saga.reconcile': readonly [TasksSagaReconcileParams, TasksSagaReconcileResult];
1354
1368
  };
1369
+
1370
+ // ---------------------------------------------------------------------------
1371
+ // OperationInputContract schemas (T9917 / Epic T9903 / Saga T9855)
1372
+ // ---------------------------------------------------------------------------
1373
+ //
1374
+ // JSON Schema documents that describe the accepted input shape for each
1375
+ // tasks.* mutate operation. The `tasks.add`, `tasks.add-batch`, and
1376
+ // `tasks.update` schemas back the schema-first `mutate(operation, input)`
1377
+ // DX surface introduced by T9914 and validated by T9915.
1378
+ //
1379
+ // Schemas live in `contracts/` because the CLI (`packages/cleo/`) and the
1380
+ // CORE registry (`packages/core/`) both depend on them — contracts is the
1381
+ // leaf package both packages already import from, so colocation avoids a
1382
+ // fan-out violation (T10074).
1383
+ //
1384
+ // Each schema sets `additionalProperties: false` to reject typo'd flags
1385
+ // outright instead of silently dropping them on the floor at the dispatch
1386
+ // boundary.
1387
+ // ---------------------------------------------------------------------------
1388
+
1389
+ /**
1390
+ * Per-task entry inside a `tasks.add-batch` payload.
1391
+ *
1392
+ * Mirrors the shape of {@link TasksAddBatchParams.tasks | TasksAddBatchParams.tasks[]}
1393
+ * exactly — every field is identical to a `tasks.add` spec EXCEPT `dryRun`,
1394
+ * which is hoisted to the batch level so a single dispatch can preview the
1395
+ * whole batch atomically.
1396
+ *
1397
+ * @task T9917
1398
+ */
1399
+ export interface TasksAddBatchEntry {
1400
+ /** Task title (3–500 characters). Required. */
1401
+ title: string;
1402
+ /** Detailed task description (must differ meaningfully from title). */
1403
+ description?: string;
1404
+ /** Parent task ID (makes this task a subtask). */
1405
+ parent?: string;
1406
+ /** Comma-separated dependency task IDs. */
1407
+ depends?: string[];
1408
+ /** Task priority (low | medium | high | critical). */
1409
+ priority?: string;
1410
+ /** Lowercase alphanumeric + hyphens + periods labels. */
1411
+ labels?: string[];
1412
+ /** Task type (saga | epic | task | subtask). */
1413
+ type?: TaskType; // SSoT-EXEMPT:kind≠type — same axis split as TasksAddBatchParams (T944) // ssot-exempt-ok: mirrors parent type
1414
+ /** Pipe-separated acceptance criteria, normalized to string[]. */
1415
+ acceptance?: string[];
1416
+ /** Phase slug to assign the task to. */
1417
+ phase?: string;
1418
+ /** Scope size estimate (small | medium | large). */
1419
+ size?: string;
1420
+ /** Initial note entry for the task. */
1421
+ notes?: string;
1422
+ /** Files touched by the task (relative paths). */
1423
+ files?: string[];
1424
+ /** Task kind / intent axis (work | research | experiment | bug | spike | release). */
1425
+ kind?: string;
1426
+ /** Task scope / granularity axis (project | feature | unit). */
1427
+ scope?: string;
1428
+ /** Severity level (P0 | P1 | P2 | P3). */
1429
+ severity?: string;
1430
+ /** Bypass BRAIN duplicate-task rejection (audited). */
1431
+ forceDuplicate?: boolean;
1432
+ }
1433
+
1434
+ /**
1435
+ * JSON Schema draft-07 document describing the accepted input shape for
1436
+ * the `tasks.add` mutate operation.
1437
+ *
1438
+ * Mirrors {@link TasksAddParams} field-for-field. Set
1439
+ * `additionalProperties: false` so a typo'd flag fails fast with a typed
1440
+ * `E_VAL_ADDITIONALPROPERTIES` error instead of being silently dropped.
1441
+ *
1442
+ * @task T9917
1443
+ */
1444
+ export const TASKS_ADD_INPUT_SCHEMA: JsonSchema = {
1445
+ type: 'object',
1446
+ required: ['title'],
1447
+ additionalProperties: false,
1448
+ properties: {
1449
+ title: { type: 'string', minLength: 1, maxLength: 500 },
1450
+ description: { type: 'string' },
1451
+ parent: { type: 'string' },
1452
+ depends: { type: 'array', items: { type: 'string' } },
1453
+ priority: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] },
1454
+ labels: { type: 'array', items: { type: 'string' } },
1455
+ type: { type: 'string', enum: ['saga', 'epic', 'task', 'subtask'] },
1456
+ acceptance: { type: 'array', items: { type: 'string' } },
1457
+ phase: { type: 'string' },
1458
+ size: { type: 'string', enum: ['small', 'medium', 'large'] },
1459
+ notes: { type: 'string' },
1460
+ files: { type: 'array', items: { type: 'string' } },
1461
+ dryRun: { type: 'boolean' },
1462
+ parentSearch: { type: 'string' },
1463
+ kind: {
1464
+ type: 'string',
1465
+ enum: ['work', 'research', 'experiment', 'bug', 'spike', 'release'],
1466
+ },
1467
+ scope: { type: 'string', enum: ['project', 'feature', 'unit'] },
1468
+ severity: { type: 'string', enum: ['P0', 'P1', 'P2', 'P3'] },
1469
+ forceDuplicate: { type: 'boolean' },
1470
+ },
1471
+ };
1472
+
1473
+ /**
1474
+ * Schema-first input contract for `tasks.add`.
1475
+ *
1476
+ * @task T9917
1477
+ */
1478
+ export const tasksAddInputContract: OperationInputContract<TasksAddParams> = {
1479
+ operation: 'tasks.add',
1480
+ schema: TASKS_ADD_INPUT_SCHEMA,
1481
+ examples: [
1482
+ {
1483
+ name: 'minimal',
1484
+ value: { title: 'Ship E7-MUTATE-DX-SCHEMA-FIRST' },
1485
+ description: 'Smallest valid input — title is the only required field.',
1486
+ },
1487
+ {
1488
+ name: 'subtask-with-acceptance',
1489
+ value: {
1490
+ title: 'Wire validator into add command',
1491
+ parent: 'T9903',
1492
+ priority: 'high',
1493
+ acceptance: ['validator runs before dispatch', 'errors surface in envelope'],
1494
+ },
1495
+ },
1496
+ ],
1497
+ };
1498
+
1499
+ /**
1500
+ * JSON Schema draft-07 document describing the accepted input shape for
1501
+ * the `tasks.add-batch` mutate operation.
1502
+ *
1503
+ * Wraps N `tasks.add` specs in a single atomic transaction. `dryRun` is
1504
+ * hoisted to the batch level (single rollback unit), so the per-entry
1505
+ * schema OMITS `dryRun` deliberately.
1506
+ *
1507
+ * @task T9917
1508
+ */
1509
+ export const TASKS_ADD_BATCH_INPUT_SCHEMA: JsonSchema = {
1510
+ type: 'object',
1511
+ required: ['tasks'],
1512
+ additionalProperties: false,
1513
+ properties: {
1514
+ tasks: {
1515
+ type: 'array',
1516
+ minItems: 1,
1517
+ items: {
1518
+ type: 'object',
1519
+ required: ['title'],
1520
+ additionalProperties: false,
1521
+ properties: {
1522
+ title: { type: 'string', minLength: 1, maxLength: 500 },
1523
+ description: { type: 'string' },
1524
+ parent: { type: 'string' },
1525
+ depends: { type: 'array', items: { type: 'string' } },
1526
+ priority: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] },
1527
+ labels: { type: 'array', items: { type: 'string' } },
1528
+ type: { type: 'string', enum: ['saga', 'epic', 'task', 'subtask'] },
1529
+ acceptance: { type: 'array', items: { type: 'string' } },
1530
+ phase: { type: 'string' },
1531
+ size: { type: 'string', enum: ['small', 'medium', 'large'] },
1532
+ notes: { type: 'string' },
1533
+ files: { type: 'array', items: { type: 'string' } },
1534
+ kind: {
1535
+ type: 'string',
1536
+ enum: ['work', 'research', 'experiment', 'bug', 'spike', 'release'],
1537
+ },
1538
+ scope: { type: 'string', enum: ['project', 'feature', 'unit'] },
1539
+ severity: { type: 'string', enum: ['P0', 'P1', 'P2', 'P3'] },
1540
+ forceDuplicate: { type: 'boolean' },
1541
+ },
1542
+ },
1543
+ },
1544
+ defaultParent: { type: 'string' },
1545
+ dryRun: { type: 'boolean' },
1546
+ },
1547
+ };
1548
+
1549
+ /**
1550
+ * Schema-first input contract for `tasks.add-batch`.
1551
+ *
1552
+ * @task T9917
1553
+ */
1554
+ export const tasksAddBatchInputContract: OperationInputContract<TasksAddBatchParams> = {
1555
+ operation: 'tasks.add-batch',
1556
+ schema: TASKS_ADD_BATCH_INPUT_SCHEMA,
1557
+ examples: [
1558
+ {
1559
+ name: 'two-tasks',
1560
+ value: {
1561
+ tasks: [{ title: 'first task' }, { title: 'second task' }],
1562
+ },
1563
+ description: 'Atomic insert of two tasks under no shared parent.',
1564
+ },
1565
+ {
1566
+ name: 'with-default-parent',
1567
+ value: {
1568
+ defaultParent: 'T9903',
1569
+ tasks: [{ title: 'a' }, { title: 'b', parent: 'T9914' }],
1570
+ },
1571
+ description: 'defaultParent applies to entries without an explicit parent.',
1572
+ },
1573
+ ],
1574
+ };
1575
+
1576
+ /**
1577
+ * JSON Schema draft-07 document describing the accepted input shape for
1578
+ * the `tasks.update` mutate operation.
1579
+ *
1580
+ * Mirrors {@link TasksUpdateQueryParams}. `taskId` is REQUIRED. All other
1581
+ * fields are optional — `tasks.update` is a partial update; only the
1582
+ * fields supplied are mutated.
1583
+ *
1584
+ * @task T9917
1585
+ */
1586
+ export const TASKS_UPDATE_INPUT_SCHEMA: JsonSchema = {
1587
+ type: 'object',
1588
+ required: ['taskId'],
1589
+ additionalProperties: false,
1590
+ properties: {
1591
+ taskId: { type: 'string', minLength: 1 },
1592
+ title: { type: 'string', minLength: 1, maxLength: 500 },
1593
+ description: { type: 'string' },
1594
+ status: {
1595
+ type: 'string',
1596
+ enum: ['pending', 'active', 'blocked', 'done', 'cancelled'],
1597
+ },
1598
+ priority: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] },
1599
+ notes: { type: 'string' },
1600
+ labels: { type: 'array', items: { type: 'string' } },
1601
+ addLabels: { type: 'array', items: { type: 'string' } },
1602
+ removeLabels: { type: 'array', items: { type: 'string' } },
1603
+ depends: { type: 'array', items: { type: 'string' } },
1604
+ addDepends: { type: 'array', items: { type: 'string' } },
1605
+ removeDepends: { type: 'array', items: { type: 'string' } },
1606
+ acceptance: { type: 'array', items: { type: 'string' } },
1607
+ parent: { type: ['string', 'null'] },
1608
+ type: { type: 'string', enum: ['saga', 'epic', 'task', 'subtask'] },
1609
+ size: { type: 'string', enum: ['small', 'medium', 'large'] },
1610
+ files: { type: 'array', items: { type: 'string' } },
1611
+ addFiles: { type: 'array', items: { type: 'string' } },
1612
+ removeFiles: { type: 'array', items: { type: 'string' } },
1613
+ pipelineStage: { type: 'string' },
1614
+ kind: {
1615
+ type: 'string',
1616
+ enum: ['work', 'research', 'experiment', 'bug', 'spike', 'release'],
1617
+ },
1618
+ scope: { type: 'string', enum: ['project', 'feature', 'unit'] },
1619
+ severity: { type: 'string', enum: ['P0', 'P1', 'P2', 'P3'] },
1620
+ reason: { type: 'string' },
1621
+ dependsWaiver: { type: 'string' },
1622
+ clearBlockedBy: { type: 'boolean' },
1623
+ relates: {
1624
+ type: 'array',
1625
+ items: {
1626
+ type: 'object',
1627
+ required: ['taskId', 'type'],
1628
+ additionalProperties: false,
1629
+ properties: {
1630
+ taskId: { type: 'string', minLength: 1 },
1631
+ type: { type: 'string', minLength: 1 },
1632
+ reason: { type: 'string' },
1633
+ },
1634
+ },
1635
+ },
1636
+ addRelates: {
1637
+ type: 'array',
1638
+ items: {
1639
+ type: 'object',
1640
+ required: ['taskId', 'type'],
1641
+ additionalProperties: false,
1642
+ properties: {
1643
+ taskId: { type: 'string', minLength: 1 },
1644
+ type: { type: 'string', minLength: 1 },
1645
+ reason: { type: 'string' },
1646
+ },
1647
+ },
1648
+ },
1649
+ removeRelates: { type: 'array', items: { type: 'string' } },
1650
+ },
1651
+ };
1652
+
1653
+ /**
1654
+ * Schema-first input contract for `tasks.update`.
1655
+ *
1656
+ * @task T9917
1657
+ */
1658
+ export const tasksUpdateInputContract: OperationInputContract<TasksUpdateQueryParams> = {
1659
+ operation: 'tasks.update',
1660
+ schema: TASKS_UPDATE_INPUT_SCHEMA,
1661
+ examples: [
1662
+ {
1663
+ name: 'set-status',
1664
+ value: { taskId: 'T9917', status: 'active' },
1665
+ description: 'Transition status to active.',
1666
+ },
1667
+ {
1668
+ name: 'add-labels-incrementally',
1669
+ value: {
1670
+ taskId: 'T9917',
1671
+ addLabels: ['saga.t9855', 'epic.t9903'],
1672
+ },
1673
+ },
1674
+ ],
1675
+ };
@@ -103,4 +103,11 @@ export interface MinimalTaskRecord {
103
103
  type?: string;
104
104
  /** Scope size estimate — helps agents decide if decomposition is needed. @task T091 */
105
105
  size?: string;
106
+ /**
107
+ * Bug severity axis — P0|P1|P2|P3 (string-widened). Surfaced so the unified
108
+ * urgency surface (`cleo find --urgent`) can identify P0/P1 rows without a
109
+ * follow-up `cleo show` per row.
110
+ * @task T9905
111
+ */
112
+ severity?: string | null;
106
113
  }