@cleocode/cant 2026.4.114 → 2026.4.115

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/dist/index.d.ts CHANGED
@@ -12,8 +12,8 @@ export type { ConsolidateOptions, MentalModel, MentalModelObservation, MentalMod
12
12
  export { consolidate, createEmptyModel, harvestObservations, renderMentalModel, } from './mental-model.js';
13
13
  export type { ConvertedFile, MigrationOptions, MigrationResult, UnconvertedSection, } from './migrate/index';
14
14
  export { migrateMarkdown, serializeCantDocument, showDiff, showSummary } from './migrate/index';
15
- export type { AgentProfile, NativeDiagnostic, NativeParseDocumentResult, NativeParseError, NativeParseResult, NativePipelineResult, NativePipelineStep, NativeValidateResult, } from './native-loader';
16
- export { cantClassifyDirectiveNative, cantExecutePipelineNative, cantExtractAgentProfilesNative, cantParseDocumentNative, cantParseNative, cantValidateDocumentNative, extractAgentProfilesTyped, extractAgentSkills, initWasm, isNativeAvailable, isWasmAvailable, validateAgentCantPath, } from './native-loader';
15
+ export type { AgentProfile, NativeDiagnostic, NativeParseDocumentResult, NativeParseError, NativeParseResult, NativePipelineResult, NativePipelineStep, NativeValidateResult, SeedPersonaId, } from './native-loader';
16
+ export { cantClassifyDirectiveNative, cantExecutePipelineNative, cantExtractAgentProfilesNative, cantParseDocumentNative, cantParseNative, cantValidateDocumentNative, extractAgentProfilesTyped, extractAgentSkills, initWasm, isNativeAvailable, isWasmAvailable, loadSeedAgentIdentities, SEED_PERSONA_IDS, validateAgentCantPath, } from './native-loader';
17
17
  export type { ParsedCANTMessage } from './parse';
18
18
  export { initCantParser, parseCANTMessage } from './parse';
19
19
  export type { CantAgentV3, CantContextSourceDef, CantContractBlock, CantContractClause, CantMentalModelRef, CantOverflowStrategy, CantPathPermissions, CantTier, DirectiveType, } from './types';
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // JIT Agent Composer (ULTRAPLAN Wave 5)
3
3
  // Wave 7a: BRAIN-backed ContextProvider (T432)
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.resolveWorktreeRoot = exports.mergeWorktree = exports.listWorktrees = exports.createWorktree = exports.isCantAgentV3 = exports.parseCANTMessage = exports.initCantParser = exports.validateAgentCantPath = exports.isWasmAvailable = exports.isNativeAvailable = exports.initWasm = exports.extractAgentSkills = exports.extractAgentProfilesTyped = exports.cantValidateDocumentNative = exports.cantParseNative = exports.cantParseDocumentNative = exports.cantExtractAgentProfilesNative = exports.cantExecutePipelineNative = exports.cantClassifyDirectiveNative = exports.showSummary = exports.showDiff = exports.serializeCantDocument = exports.migrateMarkdown = exports.renderMentalModel = exports.harvestObservations = exports.createEmptyModel = exports.consolidate = exports.WORKER_FORBIDDEN_SPAWN_TOOLS = exports.validateSpawnRequest = exports.THIN_AGENT_TOOLS_STRIPPED = exports.stripSpawnToolsForWorker = exports.ORCHESTRATOR_FORBIDDEN_TOOLS = exports.LEAD_FORBIDDEN_TOOLS = exports.filterToolsForRole = exports.validateDocument = exports.parseDocument = exports.listSections = exports.executePipeline = exports.brainContextProvider = exports.TIER_CAPS = exports.estimateTokens = exports.escalateTier = exports.composeSpawnPayload = exports.toCantAgentV3 = exports.compileBundle = void 0;
5
+ exports.resolveWorktreeRoot = exports.mergeWorktree = exports.listWorktrees = exports.createWorktree = exports.isCantAgentV3 = exports.parseCANTMessage = exports.initCantParser = exports.validateAgentCantPath = exports.SEED_PERSONA_IDS = exports.loadSeedAgentIdentities = exports.isWasmAvailable = exports.isNativeAvailable = exports.initWasm = exports.extractAgentSkills = exports.extractAgentProfilesTyped = exports.cantValidateDocumentNative = exports.cantParseNative = exports.cantParseDocumentNative = exports.cantExtractAgentProfilesNative = exports.cantExecutePipelineNative = exports.cantClassifyDirectiveNative = exports.showSummary = exports.showDiff = exports.serializeCantDocument = exports.migrateMarkdown = exports.renderMentalModel = exports.harvestObservations = exports.createEmptyModel = exports.consolidate = exports.WORKER_FORBIDDEN_SPAWN_TOOLS = exports.validateSpawnRequest = exports.THIN_AGENT_TOOLS_STRIPPED = exports.stripSpawnToolsForWorker = exports.ORCHESTRATOR_FORBIDDEN_TOOLS = exports.LEAD_FORBIDDEN_TOOLS = exports.filterToolsForRole = exports.validateDocument = exports.parseDocument = exports.listSections = exports.executePipeline = exports.brainContextProvider = exports.TIER_CAPS = exports.estimateTokens = exports.escalateTier = exports.composeSpawnPayload = exports.toCantAgentV3 = exports.compileBundle = void 0;
6
6
  // Bundle compiler
7
7
  var bundle_1 = require("./bundle");
8
8
  Object.defineProperty(exports, "compileBundle", { enumerable: true, get: function () { return bundle_1.compileBundle; } });
@@ -54,6 +54,9 @@ Object.defineProperty(exports, "extractAgentSkills", { enumerable: true, get: fu
54
54
  Object.defineProperty(exports, "initWasm", { enumerable: true, get: function () { return native_loader_1.initWasm; } });
55
55
  Object.defineProperty(exports, "isNativeAvailable", { enumerable: true, get: function () { return native_loader_1.isNativeAvailable; } });
56
56
  Object.defineProperty(exports, "isWasmAvailable", { enumerable: true, get: function () { return native_loader_1.isWasmAvailable; } });
57
+ // T1210 — PeerIdentity SDK surface
58
+ Object.defineProperty(exports, "loadSeedAgentIdentities", { enumerable: true, get: function () { return native_loader_1.loadSeedAgentIdentities; } });
59
+ Object.defineProperty(exports, "SEED_PERSONA_IDS", { enumerable: true, get: function () { return native_loader_1.SEED_PERSONA_IDS; } });
57
60
  Object.defineProperty(exports, "validateAgentCantPath", { enumerable: true, get: function () { return native_loader_1.validateAgentCantPath; } });
58
61
  // Parser
59
62
  var parse_1 = require("./parse");
@@ -10,6 +10,7 @@
10
10
  * Replaces the previous WASM loader. Follows the same pattern as
11
11
  * `packages/lafs/src/native-loader.ts`.
12
12
  */
13
+ import type { PeerIdentity } from '@cleocode/contracts';
13
14
  /** Shape of a parsed CANT message returned by the native binding. */
14
15
  export interface NativeParseResult {
15
16
  /** The directive verb if present (e.g., `"done"`), or `undefined`. */
@@ -229,6 +230,53 @@ export declare function validateAgentCantPath(cantPath: string, rootDir: string)
229
230
  * @param pipelineName - The name of the `pipeline { ... }` block to run.
230
231
  */
231
232
  export declare function cantExecutePipelineNative(filePath: string, pipelineName: string): Promise<NativePipelineResult>;
233
+ /**
234
+ * Canonical IDs of the 7 CLEO seed personas.
235
+ *
236
+ * Kept in declaration order: orchestrator first, then leads, then universal base.
237
+ * Used by the regression test and as documentation for the expected registry
238
+ * contents. Any persona on this list MUST be resolvable from the canonical
239
+ * seed-agents path (either `seed-agents/<id>.cant` or `cleo-subagent.cant`).
240
+ *
241
+ * @task T1210
242
+ */
243
+ export declare const SEED_PERSONA_IDS: readonly ["cleo-prime", "cleo-dev", "cleo-db-lead", "cleo-historian", "cleo-rust-lead", "cleo-subagent", "cleoos-opus-orchestrator"];
244
+ /** Type-safe union of the 7 canonical seed persona IDs. */
245
+ export type SeedPersonaId = (typeof SEED_PERSONA_IDS)[number];
246
+ /**
247
+ * Load all seed-agent {@link PeerIdentity} records from the canonical
248
+ * `packages/agents/` directory shipped with `@cleocode/agents`.
249
+ *
250
+ * Walk order:
251
+ * 1. All `.cant` files inside `packages/agents/seed-agents/` (generic templates
252
+ * + any project-specific personas installed there).
253
+ * 2. `packages/agents/cleo-subagent.cant` — the universal protocol base.
254
+ *
255
+ * Files that cannot be parsed (unreadable, missing `agent <id>:` block) are
256
+ * silently skipped.
257
+ *
258
+ * This function is intentionally pure-TS and does NOT require the native addon.
259
+ * It is safe to call in environments where `cant-napi` is absent (CI, test, etc.).
260
+ *
261
+ * @param agentsRoot - Optional override for the `packages/agents/` root. When
262
+ * omitted the path is resolved automatically relative to this file. Tests
263
+ * should pass an absolute path to an isolated fixture directory.
264
+ * @returns `PeerIdentity[]` for every successfully-parsed `.cant` file, in
265
+ * seed-agents-first, universal-base-last order.
266
+ *
267
+ * @example
268
+ * ```ts
269
+ * import { loadSeedAgentIdentities } from '@cleocode/cant';
270
+ *
271
+ * const peers = loadSeedAgentIdentities();
272
+ * console.log(peers.map((p) => p.peerId));
273
+ * // ['project-code-worker', 'project-dev-lead', ..., 'cleo-subagent']
274
+ * ```
275
+ *
276
+ * @task T1210
277
+ * @epic T1144
278
+ */
279
+ export declare function loadSeedAgentIdentities(agentsRoot?: string): PeerIdentity[];
232
280
  export declare const isWasmAvailable: typeof isNativeAvailable;
233
281
  /**
234
282
  * Backward-compatible no-op initializer.
@@ -12,7 +12,7 @@
12
12
  * `packages/lafs/src/native-loader.ts`.
13
13
  */
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.initWasm = exports.isWasmAvailable = void 0;
15
+ exports.initWasm = exports.isWasmAvailable = exports.SEED_PERSONA_IDS = void 0;
16
16
  exports.isNativeAvailable = isNativeAvailable;
17
17
  exports.cantParseNative = cantParseNative;
18
18
  exports.cantClassifyDirectiveNative = cantClassifyDirectiveNative;
@@ -23,7 +23,9 @@ exports.extractAgentProfilesTyped = extractAgentProfilesTyped;
23
23
  exports.extractAgentSkills = extractAgentSkills;
24
24
  exports.validateAgentCantPath = validateAgentCantPath;
25
25
  exports.cantExecutePipelineNative = cantExecutePipelineNative;
26
+ exports.loadSeedAgentIdentities = loadSeedAgentIdentities;
26
27
  /* eslint-disable @typescript-eslint/no-require-imports */
28
+ const node_fs_1 = require("node:fs");
27
29
  const node_path_1 = require("node:path");
28
30
  let nativeModule = null;
29
31
  let loadAttempted = false;
@@ -227,6 +229,240 @@ function validateAgentCantPath(cantPath, rootDir) {
227
229
  function cantExecutePipelineNative(filePath, pipelineName) {
228
230
  return requireNative().cantExecutePipeline(filePath, pipelineName);
229
231
  }
232
+ // ============================================================================
233
+ // Seed-agent identity loader (T1210 — PeerIdentity SDK surface)
234
+ // ============================================================================
235
+ /**
236
+ * Canonical IDs of the 7 CLEO seed personas.
237
+ *
238
+ * Kept in declaration order: orchestrator first, then leads, then universal base.
239
+ * Used by the regression test and as documentation for the expected registry
240
+ * contents. Any persona on this list MUST be resolvable from the canonical
241
+ * seed-agents path (either `seed-agents/<id>.cant` or `cleo-subagent.cant`).
242
+ *
243
+ * @task T1210
244
+ */
245
+ exports.SEED_PERSONA_IDS = [
246
+ 'cleo-prime',
247
+ 'cleo-dev',
248
+ 'cleo-db-lead',
249
+ 'cleo-historian',
250
+ 'cleo-rust-lead',
251
+ 'cleo-subagent',
252
+ 'cleoos-opus-orchestrator',
253
+ ];
254
+ /**
255
+ * Discover the `packages/agents/` root by walking up from the compiled
256
+ * `native-loader.js` / source `native-loader.ts` file.
257
+ *
258
+ * Walk candidates covering `src/` (dev), `dist/` (compiled), and the
259
+ * installed `node_modules/@cleocode/cant/dist/` layout.
260
+ *
261
+ * Uses `__dirname` (available in the CJS-compiled output) to resolve paths
262
+ * relative to this module, matching the pattern used by `ensureLoaded()`.
263
+ *
264
+ * @returns Absolute path to the `packages/agents/` directory, or `null` when
265
+ * none of the candidates resolves to an existing directory.
266
+ *
267
+ * @internal
268
+ */
269
+ function resolveAgentsPackageRoot() {
270
+ // __dirname is always available in the CJS-compiled output (packages/cant/dist/).
271
+ // In the TypeScript source tree (packages/cant/src/) tsc injects __dirname via
272
+ // the module-resolution helpers, so this is safe in both contexts.
273
+ const here = __dirname;
274
+ const candidates = [
275
+ // packages/cant/src/ → packages/agents/
276
+ (0, node_path_1.resolve)(here, '..', '..', 'agents'),
277
+ // packages/cant/dist/ → packages/agents/
278
+ (0, node_path_1.resolve)(here, '..', '..', '..', 'agents'),
279
+ // node_modules/@cleocode/cant/dist/ → @cleocode/agents (relative to node_modules)
280
+ (0, node_path_1.resolve)(here, '..', '..', '..', '..', 'agents'),
281
+ (0, node_path_1.resolve)(here, '..', '..', '..', '..', '@cleocode', 'agents'),
282
+ ];
283
+ return candidates.find((p) => (0, node_fs_1.existsSync)(p)) ?? null;
284
+ }
285
+ /**
286
+ * Extract the `role:` value from a raw `.cant` file body.
287
+ *
288
+ * Looks for a line matching ` role: <value>` within the `agent <id>:` block
289
+ * using a simple regex — intentionally avoids full CANT parsing to remove the
290
+ * native-addon dependency from this path (the addon may not be present in all
291
+ * environments where the loader runs).
292
+ *
293
+ * @param content - Raw `.cant` file text.
294
+ * @returns Extracted role string, or `null` when no `role:` line is found.
295
+ * @internal
296
+ */
297
+ function extractRoleFromCant(content) {
298
+ const match = /^\s{2}role:\s*(\S+)/m.exec(content);
299
+ return match ? (match[1] ?? null) : null;
300
+ }
301
+ /**
302
+ * Map a raw role string from a `.cant` file to a {@link PeerKind}.
303
+ *
304
+ * Unrecognised values default to `"subagent"` so the loader remains
305
+ * forward-compatible with new role names.
306
+ *
307
+ * @param rawRole - Raw role string extracted from the `.cant` file.
308
+ * @internal
309
+ */
310
+ function roleToPeerKind(rawRole) {
311
+ switch (rawRole) {
312
+ case 'orchestrator':
313
+ return 'orchestrator';
314
+ case 'lead':
315
+ return 'lead';
316
+ case 'worker':
317
+ return 'worker';
318
+ default:
319
+ return 'subagent';
320
+ }
321
+ }
322
+ /**
323
+ * Extract the `description:` value from a raw `.cant` file body.
324
+ *
325
+ * Handles single-line descriptions (`description: "..."`) and multiline
326
+ * block-scalar descriptions (`description: |`). Returns the first line of
327
+ * the block-scalar body for multiline values. Returns empty string when no
328
+ * `description:` field is found.
329
+ *
330
+ * @param content - Raw `.cant` file text.
331
+ * @internal
332
+ */
333
+ function extractDescriptionFromCant(content) {
334
+ // Single-line: ` description: "some text"` or ` description: some text`
335
+ const singleLine = /^\s{2}description:\s+"([^"]+)"/m.exec(content);
336
+ if (singleLine)
337
+ return singleLine[1] ?? '';
338
+ const singleLineUnquoted = /^\s{2}description:\s+(.+)/m.exec(content);
339
+ if (singleLineUnquoted) {
340
+ const raw = singleLineUnquoted[1] ?? '';
341
+ // Exclude multiline indicator '|'
342
+ if (raw.trim() !== '|')
343
+ return raw.trim();
344
+ }
345
+ // Multiline block scalar: grab first non-empty line after `description: |`
346
+ const blockScalar = /^\s{2}description:\s+\|\s*\n((?:\s+\S[^\n]*\n?)+)/m.exec(content);
347
+ if (blockScalar) {
348
+ const bodyLines = (blockScalar[1] ?? '').split('\n');
349
+ for (const line of bodyLines) {
350
+ const trimmed = line.trim();
351
+ if (trimmed.length > 0)
352
+ return trimmed;
353
+ }
354
+ }
355
+ return '';
356
+ }
357
+ /**
358
+ * Extract the agent business id from a raw `.cant` file body.
359
+ *
360
+ * Looks for the `agent <id>:` declaration line. Returns `null` when not found.
361
+ *
362
+ * @param content - Raw `.cant` file text.
363
+ * @internal
364
+ */
365
+ function extractAgentIdFromCant(content) {
366
+ const match = /^agent\s+([a-z][a-z0-9-]*):/m.exec(content);
367
+ return match ? (match[1] ?? null) : null;
368
+ }
369
+ /**
370
+ * Parse a single `.cant` file at `cantFile` into a {@link PeerIdentity}.
371
+ *
372
+ * Returns `null` when the file cannot be parsed (missing `agent <id>:` block
373
+ * or unreadable file). The caller is responsible for logging / skipping nulls.
374
+ *
375
+ * @param cantFile - Absolute path to the `.cant` file.
376
+ * @param fallbackId - Id to use when the `agent <id>:` block is absent (e.g.,
377
+ * when loading the universal base by a known filename).
378
+ * @internal
379
+ */
380
+ function parseCantFileToIdentity(cantFile, fallbackId) {
381
+ let content;
382
+ try {
383
+ content = (0, node_fs_1.readFileSync)(cantFile, 'utf-8');
384
+ }
385
+ catch {
386
+ return null;
387
+ }
388
+ const agentId = extractAgentIdFromCant(content) ?? fallbackId ?? null;
389
+ if (!agentId)
390
+ return null;
391
+ const rawRole = extractRoleFromCant(content);
392
+ const peerKind = roleToPeerKind(rawRole);
393
+ const description = extractDescriptionFromCant(content);
394
+ return {
395
+ peerId: agentId,
396
+ peerKind,
397
+ cantFile,
398
+ displayName: agentId,
399
+ description,
400
+ };
401
+ }
402
+ /**
403
+ * Load all seed-agent {@link PeerIdentity} records from the canonical
404
+ * `packages/agents/` directory shipped with `@cleocode/agents`.
405
+ *
406
+ * Walk order:
407
+ * 1. All `.cant` files inside `packages/agents/seed-agents/` (generic templates
408
+ * + any project-specific personas installed there).
409
+ * 2. `packages/agents/cleo-subagent.cant` — the universal protocol base.
410
+ *
411
+ * Files that cannot be parsed (unreadable, missing `agent <id>:` block) are
412
+ * silently skipped.
413
+ *
414
+ * This function is intentionally pure-TS and does NOT require the native addon.
415
+ * It is safe to call in environments where `cant-napi` is absent (CI, test, etc.).
416
+ *
417
+ * @param agentsRoot - Optional override for the `packages/agents/` root. When
418
+ * omitted the path is resolved automatically relative to this file. Tests
419
+ * should pass an absolute path to an isolated fixture directory.
420
+ * @returns `PeerIdentity[]` for every successfully-parsed `.cant` file, in
421
+ * seed-agents-first, universal-base-last order.
422
+ *
423
+ * @example
424
+ * ```ts
425
+ * import { loadSeedAgentIdentities } from '@cleocode/cant';
426
+ *
427
+ * const peers = loadSeedAgentIdentities();
428
+ * console.log(peers.map((p) => p.peerId));
429
+ * // ['project-code-worker', 'project-dev-lead', ..., 'cleo-subagent']
430
+ * ```
431
+ *
432
+ * @task T1210
433
+ * @epic T1144
434
+ */
435
+ function loadSeedAgentIdentities(agentsRoot) {
436
+ const root = agentsRoot ?? resolveAgentsPackageRoot();
437
+ if (!root)
438
+ return [];
439
+ const identities = [];
440
+ // 1. Walk seed-agents/ directory
441
+ const seedDir = (0, node_path_1.join)(root, 'seed-agents');
442
+ if ((0, node_fs_1.existsSync)(seedDir)) {
443
+ let entries = [];
444
+ try {
445
+ entries = (0, node_fs_1.readdirSync)(seedDir).filter((f) => f.endsWith('.cant'));
446
+ }
447
+ catch {
448
+ // unreadable — skip
449
+ }
450
+ for (const entry of entries) {
451
+ const cantFile = (0, node_path_1.join)(seedDir, entry);
452
+ const identity = parseCantFileToIdentity(cantFile);
453
+ if (identity)
454
+ identities.push(identity);
455
+ }
456
+ }
457
+ // 2. Universal base: packages/agents/cleo-subagent.cant
458
+ const universalBase = (0, node_path_1.join)(root, 'cleo-subagent.cant');
459
+ if ((0, node_fs_1.existsSync)(universalBase)) {
460
+ const identity = parseCantFileToIdentity(universalBase, 'cleo-subagent');
461
+ if (identity)
462
+ identities.push(identity);
463
+ }
464
+ return identities;
465
+ }
230
466
  // Backward compatibility aliases (kept so existing callers compile).
231
467
  exports.isWasmAvailable = isNativeAvailable;
232
468
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cleocode/cant",
3
- "version": "2026.4.114",
3
+ "version": "2026.4.115",
4
4
  "description": "CANT protocol parser and runtime for CLEO — wraps cant-core via napi-rs",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -9,9 +9,9 @@
9
9
  "napi/"
10
10
  ],
11
11
  "dependencies": {
12
- "@cleocode/lafs": "2026.4.114",
13
- "@cleocode/core": "2026.4.114",
14
- "@cleocode/contracts": "2026.4.114"
12
+ "@cleocode/lafs": "2026.4.115",
13
+ "@cleocode/core": "2026.4.115",
14
+ "@cleocode/contracts": "2026.4.115"
15
15
  },
16
16
  "devDependencies": {
17
17
  "typescript": "^6.0.2",