@ted-galago/wave-cli 0.1.18 → 0.1.20

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 CHANGED
@@ -120,6 +120,7 @@ wave markdown-tree resolve --tool-key projects --node-key tasks --parent-id 123
120
120
  wave markdown-tree children --tool-key directory --node-key members --record-id 67
121
121
  wave markdown-tree subtree --tool-key knowledge --node-key knowledge --content-type processes --depth 2
122
122
  wave osmd tree
123
+ wave osmd search "Wave Tools" --scope combined --limit 10
123
124
  wave osmd read "projects/Wave Tools"
124
125
  wave osmd children "projects/Wave Tools"
125
126
  wave osmd status "projects/Wave Tools/.agent/notes.md" --parent-ref "projects/Wave Tools"
@@ -307,6 +308,7 @@ The `osmd` command group is the write-capable agent interface for canonical OSMD
307
308
  Commands:
308
309
 
309
310
  - `wave osmd tree [--depth <n>] [--tree-view]`
311
+ - `wave osmd search "<query>" [--scope os-only|agent-overlay-only|agent-wiki-only|combined] [--limit <n>]`
310
312
  - `wave osmd read <path> [--parent-ref <canonicalPath>]`
311
313
  - `wave osmd children [path] [--parent-ref <canonicalPath>] [--source canonical_osmd|agent_overlay|agent_wiki]`
312
314
  - `wave osmd status <path> [--parent-ref <canonicalPath>]`
@@ -326,6 +328,7 @@ Commands:
326
328
  GraphQL mapping:
327
329
 
328
330
  - `osmd status` / `osmd agent status` / `osmd wiki status` -> `agentMarkdownStatus`
331
+ - `osmd search` -> `osMdSearch`
329
332
  - `osmd read` / `osmd agent read` / `osmd wiki read` -> `agentMarkdownFile`
330
333
  - `osmd children` / `osmd wiki children` -> `agentMarkdownChildren`
331
334
  - `osmd agent init` -> `initAgentMarkdown`
@@ -348,7 +351,9 @@ Path and permission rules:
348
351
  - Agent Wiki `create` and `update` support only `index.md`; `log.md` cannot be overwritten.
349
352
  - Agent Wiki `append-log` supports only `log.md` and calls status first before appending.
350
353
  - The CLI uses backend GraphQL metadata directly and does not derive S3 paths, SHA paths, or backend storage conventions.
351
- - Atlas should inspect `path`, `source`, `access`, `owner`, `parentRef`, `exists`, `canCreate`, `canUpdate`, `canAppend`, `suggestedAction`, and `errorCode`.
354
+ - Atlas should inspect `path`, `source`, `access`, `owner`, `parentRef`, `exists`, `canCreate`, `canUpdate`, `canAppend`, `wikiRole`, `formatVersion`, `suggestedAction`, and `errorCode`.
355
+ - `osmd search` scopes map to backend `source` values: `os-only` -> `canonical_osmd`, `agent-overlay-only` -> `agent_overlay`, `agent-wiki-only` -> `agent_wiki`, and `combined` -> backend merged search.
356
+ - `osmd search` returns backend candidates with `path`, `source`, `access`, `owner`, `wikiRole`, `formatVersion`, `parentRef`, `exists`, `agentChildrenAllowed`, `title`, `label`, `snippet`, `rank`, `matchReason`, `toolKey`, `nodeKey`, and `nodeKind` where the backend provides them.
352
357
  - Reads never create files.
353
358
  - Create/update/append-log flows call status first and inspect `exists`, `canCreate`, `canUpdate`, `canAppend`, `suggestedAction`, and `errorCode`.
354
359
  - `create` fails when `exists` is true.
@@ -357,6 +362,50 @@ Path and permission rules:
357
362
  - When `Agent Wiki/log.md` is missing and status reports `suggestedAction: "init"`, `append-log` returns a JSON error telling Atlas to run `wave osmd wiki init`.
358
363
  - Missing `Agent Wiki/index.md` is create-ready when status returns `exists: false`, `canCreate: true`, `canUpdate: false`, and `suggestedAction: "create"`.
359
364
 
365
+ Atlas Agent Wiki log flow:
366
+
367
+ 1. `status_log`: run `wave osmd wiki status log.md`.
368
+ 2. If `data.exists === false` and `data.suggestedAction === "init"`, run `wave osmd wiki init`.
369
+ 3. `status_log`: run `wave osmd wiki status log.md` again and require `data.canAppend === true`.
370
+ 4. `append_log`: run `wave osmd wiki append-log --content "<markdown log entry>"`.
371
+
372
+ Atlas must not skip the status checks. `append-log` never initializes files implicitly; backend `initAgentMarkdown` via `wave osmd wiki init` is the only supported initialization flow for Agent Wiki system files.
373
+
374
+ Atlas maintenance examples:
375
+
376
+ Update `Agent Wiki/index.md` after an entity `.agent/notes.md` change. Atlas should read the current index, compose the complete replacement markdown in memory, then update `index.md`; the CLI does not patch partial content:
377
+
378
+ ```bash
379
+ wave osmd agent update "directory/Wave Tools Team" notes.md --content "## Working notes\n\n- New durable entity note."
380
+ wave osmd wiki status index.md
381
+ wave osmd wiki read index.md
382
+ wave osmd wiki update index.md --content "# Agent Wiki\n\n## Entity Notes\n\n- directory/Wave Tools Team -> .agent/notes.md"
383
+ ```
384
+
385
+ Append a parseable log entry. Use a stable fenced block so Atlas or backend jobs can parse the chronology later:
386
+
387
+ ````bash
388
+ wave osmd wiki append-log --content "```yaml
389
+ event: entity_note_updated
390
+ parentRef: directory/Wave Tools Team
391
+ agentFile: .agent/notes.md
392
+ wikiPath: Agent Wiki/index.md
393
+ summary: Added durable working notes for the Wave Tools Team.
394
+ ```"
395
+ ````
396
+
397
+ `append-log` accepts multi-line markdown from `--content`, `--file`, or stdin. Use `--file` for larger structured entries:
398
+
399
+ ```bash
400
+ wave osmd wiki append-log --file ./agent-wiki-log-entry.md
401
+ ```
402
+
403
+ When not using `--token-stdin` or `--auth-json-stdin`, stdin may also provide the log body:
404
+
405
+ ````bash
406
+ printf '%s\n' '```yaml' 'event: wiki_maintenance' 'summary: Refreshed Agent Wiki index.' '```' | wave osmd wiki append-log
407
+ ````
408
+
360
409
  OSMD command envelopes keep the global CLI envelope and put the file metadata directly in `data`:
361
410
 
362
411
  ```json
@@ -373,7 +422,11 @@ OSMD command envelopes keep the global CLI envelope and put the file metadata di
373
422
  "canCreate": false,
374
423
  "canUpdate": true,
375
424
  "canAppend": false,
425
+ "wikiRole": "notes",
426
+ "formatVersion": "agent_markdown_v1",
376
427
  "parentRef": "projects/Wave Tools",
428
+ "suggestedAction": "update",
429
+ "errorCode": null,
377
430
  "content": "..."
378
431
  },
379
432
  "error": null,
@@ -381,6 +434,44 @@ OSMD command envelopes keep the global CLI envelope and put the file metadata di
381
434
  }
382
435
  ```
383
436
 
437
+ Merged OSMD search keeps the same envelope and returns backend-ranked candidates:
438
+
439
+ ```json
440
+ {
441
+ "ok": true,
442
+ "command": "osmd.search",
443
+ "status": 200,
444
+ "data": {
445
+ "query": "Wave Tools",
446
+ "scope": "combined",
447
+ "count": 3,
448
+ "candidates": [
449
+ {
450
+ "path": "directory/Wave Tools Team/.agent/notes.md",
451
+ "source": "agent_overlay",
452
+ "access": "read_write",
453
+ "owner": "atlas",
454
+ "wikiRole": "notes",
455
+ "formatVersion": "agent_markdown_v1",
456
+ "parentRef": "directory/Wave Tools Team",
457
+ "exists": true,
458
+ "agentChildrenAllowed": false,
459
+ "title": "notes.md",
460
+ "label": "notes.md",
461
+ "snippet": "...",
462
+ "rank": 1,
463
+ "matchReason": "content",
464
+ "toolKey": "agent_overlay",
465
+ "nodeKey": "notes",
466
+ "nodeKind": "agent_overlay_file"
467
+ }
468
+ ]
469
+ },
470
+ "error": null,
471
+ "meta": { "requestId": "req_125" }
472
+ }
473
+ ```
474
+
384
475
  On write preflight errors, `data` contains the status metadata and `error.suggestedAction` mirrors backend guidance:
385
476
 
386
477
  ```json
@@ -397,6 +488,8 @@ On write preflight errors, `data` contains the status metadata and `error.sugges
397
488
  "canCreate": true,
398
489
  "canUpdate": false,
399
490
  "canAppend": false,
491
+ "wikiRole": "index",
492
+ "formatVersion": "agent_markdown_v1",
400
493
  "parentRef": null,
401
494
  "suggestedAction": "create",
402
495
  "errorCode": null
@@ -432,6 +525,12 @@ These wrap backend-owned markdown-tree primitives:
432
525
  Discovery, ranking, canonical paths, and narrowing are backend-owned.
433
526
  An empty `find` result (`candidates: []`) means no evidence for that exact query/scope, not confirmed global absence.
434
527
  `markdownTreeFind` remains canonical-focused. Agent overlay and Agent Wiki files are discoverable through `osmd tree`, `osmd children`, and `osmd status`, not through `find`.
528
+ Use `wave osmd search "<query>" --scope combined` when Atlas needs merged canonical OSMD, `.agent`, and Agent Wiki search. Use narrower scopes for targeted memory lookup:
529
+
530
+ - `--scope os-only` searches canonical OSMD only.
531
+ - `--scope agent-overlay-only` searches entity-specific `.agent` files.
532
+ - `--scope agent-wiki-only` searches broad Agent Wiki files, including `index.md` and append-only `log.md`.
533
+ - `--scope combined` searches the backend merged OSMD surface.
435
534
 
436
535
  Ambiguity contract:
437
536
 
package/dist/index.cjs CHANGED
@@ -6143,10 +6143,17 @@ var agentMarkdownErrorCodeSchema = import_zod16.z.enum([
6143
6143
  var agentMarkdownErrorCodeFieldSchema = agentMarkdownErrorCodeSchema.nullable().catch(null);
6144
6144
  var nonEmptyString3 = import_zod16.z.string().min(1);
6145
6145
  var nonNegativeInt3 = import_zod16.z.coerce.number().int().min(0);
6146
+ var positiveInt = import_zod16.z.coerce.number().int().min(1);
6146
6147
  var supportedAgentOverlayFile = "notes.md";
6147
6148
  var supportedWikiIndexFile = "index.md";
6148
6149
  var supportedWikiLogFile = "log.md";
6149
6150
  var agentOverlayFileSchema = import_zod16.z.enum([supportedAgentOverlayFile]);
6151
+ var osmdSearchScopeSchema = import_zod16.z.enum([
6152
+ "os-only",
6153
+ "agent-overlay-only",
6154
+ "agent-wiki-only",
6155
+ "combined"
6156
+ ]);
6150
6157
  var agentMarkdownFileSchema = import_zod16.z.object({
6151
6158
  path: import_zod16.z.string(),
6152
6159
  source: sourceSchema,
@@ -6156,6 +6163,8 @@ var agentMarkdownFileSchema = import_zod16.z.object({
6156
6163
  canCreate: import_zod16.z.boolean(),
6157
6164
  canUpdate: import_zod16.z.boolean(),
6158
6165
  canAppend: import_zod16.z.boolean(),
6166
+ wikiRole: import_zod16.z.string().nullable().optional(),
6167
+ formatVersion: import_zod16.z.string().nullable().optional(),
6159
6168
  parentRef: import_zod16.z.string().nullable().optional(),
6160
6169
  agentChildrenAllowed: import_zod16.z.boolean(),
6161
6170
  suggestedAction: suggestedActionSchema,
@@ -6164,6 +6173,8 @@ var agentMarkdownFileSchema = import_zod16.z.object({
6164
6173
  url: import_zod16.z.string().nullable().optional()
6165
6174
  }).transform((value) => ({
6166
6175
  ...value,
6176
+ wikiRole: value.wikiRole ?? null,
6177
+ formatVersion: value.formatVersion ?? null,
6167
6178
  parentRef: value.parentRef ?? null,
6168
6179
  errorCode: value.errorCode ?? null,
6169
6180
  content: value.content ?? null,
@@ -6174,6 +6185,47 @@ var agentMarkdownMutationDataSchema = import_zod16.z.union([
6174
6185
  agentMarkdownFileSchema,
6175
6186
  import_zod16.z.object({ files: agentMarkdownFilesSchema })
6176
6187
  ]);
6188
+ var osmdSearchCandidateSchema = import_zod16.z.preprocess(
6189
+ normalizeAgentMarkdownJsonKeys,
6190
+ import_zod16.z.object({
6191
+ path: import_zod16.z.string(),
6192
+ source: sourceSchema,
6193
+ access: accessSchema,
6194
+ owner: ownerSchema,
6195
+ wikiRole: import_zod16.z.string().nullable().optional(),
6196
+ formatVersion: import_zod16.z.string().nullable().optional(),
6197
+ parentRef: import_zod16.z.string().nullable().optional(),
6198
+ exists: import_zod16.z.boolean(),
6199
+ agentChildrenAllowed: import_zod16.z.boolean(),
6200
+ title: import_zod16.z.string(),
6201
+ label: import_zod16.z.string(),
6202
+ snippet: import_zod16.z.string().nullable().optional(),
6203
+ rank: import_zod16.z.number().int(),
6204
+ matchReason: import_zod16.z.string().nullable().optional(),
6205
+ toolKey: import_zod16.z.string().nullable().optional(),
6206
+ nodeKey: import_zod16.z.string().nullable().optional(),
6207
+ nodeKind: import_zod16.z.string().nullable().optional()
6208
+ }).transform((value) => ({
6209
+ ...value,
6210
+ wikiRole: value.wikiRole ?? null,
6211
+ formatVersion: value.formatVersion ?? null,
6212
+ parentRef: value.parentRef ?? null,
6213
+ snippet: value.snippet ?? null,
6214
+ matchReason: value.matchReason ?? null,
6215
+ toolKey: value.toolKey ?? null,
6216
+ nodeKey: value.nodeKey ?? null,
6217
+ nodeKind: value.nodeKind ?? null
6218
+ }))
6219
+ );
6220
+ var osmdSearchResultSchema = import_zod16.z.preprocess(
6221
+ normalizeAgentMarkdownJsonKeys,
6222
+ import_zod16.z.object({
6223
+ query: import_zod16.z.string(),
6224
+ scope: import_zod16.z.string(),
6225
+ count: import_zod16.z.number().int().min(0),
6226
+ candidates: import_zod16.z.array(osmdSearchCandidateSchema)
6227
+ })
6228
+ );
6177
6229
  var mutationPayloadSchema = import_zod16.z.object({
6178
6230
  ok: import_zod16.z.boolean(),
6179
6231
  status: import_zod16.z.number(),
@@ -6216,6 +6268,8 @@ var AGENT_MARKDOWN_FILE_SELECTION = `{
6216
6268
  canCreate
6217
6269
  canUpdate
6218
6270
  canAppend
6271
+ wikiRole
6272
+ formatVersion
6219
6273
  parentRef
6220
6274
  agentChildrenAllowed
6221
6275
  suggestedAction
@@ -6223,15 +6277,45 @@ var AGENT_MARKDOWN_FILE_SELECTION = `{
6223
6277
  content
6224
6278
  url
6225
6279
  }`;
6280
+ var OSMD_SEARCH_SELECTION = `{
6281
+ query
6282
+ scope
6283
+ count
6284
+ candidates {
6285
+ path
6286
+ source
6287
+ access
6288
+ owner
6289
+ wikiRole
6290
+ formatVersion
6291
+ parentRef
6292
+ exists
6293
+ agentChildrenAllowed
6294
+ title
6295
+ label
6296
+ snippet
6297
+ rank
6298
+ matchReason
6299
+ toolKey
6300
+ nodeKey
6301
+ nodeKind
6302
+ }
6303
+ }`;
6226
6304
  var MUTATION_RESULT_SELECTION = "{ ok status errorCode data errors }";
6227
6305
  var AGENT_JSON_KEY_ALIASES = {
6228
6306
  can_create: "canCreate",
6229
6307
  can_update: "canUpdate",
6230
6308
  can_append: "canAppend",
6309
+ wiki_role: "wikiRole",
6310
+ format_version: "formatVersion",
6231
6311
  parent_ref: "parentRef",
6232
6312
  agent_children_allowed: "agentChildrenAllowed",
6233
6313
  suggested_action: "suggestedAction",
6234
- error_code: "errorCode"
6314
+ error_code: "errorCode",
6315
+ match_reason: "matchReason",
6316
+ tool_key: "toolKey",
6317
+ node_key: "nodeKey",
6318
+ node_kind: "nodeKind"
6235
6319
  };
6236
6320
  function isSupportedAgentMarkdownFile(file) {
6237
6321
  if (file.source !== "agent_overlay") {
@@ -6383,6 +6467,22 @@ async function requestAgentMarkdownChildren(params) {
6383
6467
  schema: agentMarkdownFilesSchema
6384
6468
  });
6385
6469
  }
6470
+ async function requestOsmdSearch(params) {
6471
+ return requestOsmdQuery({
6472
+ command: params.command,
6473
+ operationName: "OsMdSearch",
6474
+ runtimeOptions: params.runtimeOptions,
6475
+ field: "os_md_search",
6476
+ variables: {
6477
+ organization_id: params.organizationId,
6478
+ query: params.query,
6479
+ source: backendSearchSourceForScope(params.scope),
6480
+ limit: params.limit
6481
+ },
6482
+ selectionSet: OSMD_SEARCH_SELECTION,
6483
+ schema: osmdSearchResultSchema
6484
+ });
6485
+ }
6386
6486
  async function runAgentMarkdownMutation(params) {
6387
6487
  const result = await graphqlRequest({
6388
6488
  config: getConfig(params.runtimeOptions),
@@ -6495,6 +6595,46 @@ function parseOptionalSource(value) {
6495
6595
  }
6496
6596
  return parsed.data;
6497
6597
  }
6598
+ function parseOsmdSearchScope(value) {
6599
+ const raw = typeof value === "string" && value.trim() !== "" ? value.trim() : "combined";
6600
+ const parsed = osmdSearchScopeSchema.safeParse(raw);
6601
+ if (!parsed.success) {
6602
+ throw new CliError({
6603
+ message: "Invalid OSMD search scope. Use os-only, agent-overlay-only, agent-wiki-only, or combined.",
6604
+ kind: "invalid_args",
6605
+ status: 400,
6606
+ exitCode: EXIT_CODES.invalidArgs,
6607
+ details: { supportedScopes: osmdSearchScopeSchema.options }
6608
+ });
6609
+ }
6610
+ return parsed.data;
6611
+ }
6612
+ function backendSearchSourceForScope(scope) {
6613
+ if (scope === "os-only") {
6614
+ return "canonical_osmd";
6615
+ }
6616
+ if (scope === "agent-overlay-only") {
6617
+ return "agent_overlay";
6618
+ }
6619
+ if (scope === "agent-wiki-only") {
6620
+ return "agent_wiki";
6621
+ }
6622
+ return "combined";
6623
+ }
6624
+ function parseSearchLimit(value) {
6625
+ const raw = value === void 0 || value === null || value === "" ? "10" : value;
6626
+ const parsed = positiveInt.safeParse(raw);
6627
+ if (!parsed.success) {
6628
+ throw new CliError({
6629
+ message: "Invalid OSMD search limit. Use a positive integer.",
6630
+ kind: "invalid_args",
6631
+ status: 400,
6632
+ exitCode: EXIT_CODES.invalidArgs,
6633
+ details: { issues: parsed.error.issues }
6634
+ });
6635
+ }
6636
+ return parsed.data;
6637
+ }
6498
6638
  function parseDepth(value) {
6499
6639
  if (value === void 0 || value === null || value === "") {
6500
6640
  return 1;
@@ -6784,7 +6924,7 @@ function registerOsmdCommands(program) {
6784
6924
  })
6785
6925
  });
6786
6926
  });
6787
- osmd.command("children [path]").description("List backend-supported agent markdown children; search remains canonical-only").option("--parent-ref <parentRef>", "Canonical OSMD parent ref for .agent files").option("--source <source>", "Filter by canonical_osmd, agent_overlay, or agent_wiki").action(async (path, opts, cmd) => {
6927
+ osmd.command("children [path]").description("List backend-supported agent markdown children").option("--parent-ref <parentRef>", "Canonical OSMD parent ref for .agent files").option("--source <source>", "Filter by canonical_osmd, agent_overlay, or agent_wiki").action(async (path, opts, cmd) => {
6788
6928
  const { organizationId, runtimeOptions } = await resolveOsmdContext(cmd);
6789
6929
  const result = await requestAgentMarkdownChildren({
6790
6930
  command: "osmd.children",
@@ -6803,6 +6943,25 @@ function registerOsmdCommands(program) {
6803
6943
  })
6804
6944
  });
6805
6945
  });
6946
+ osmd.command("search <query>").description("Search merged OSMD, .agent overlays, and Agent Wiki through backend OSMD search").option("--scope <scope>", "os-only, agent-overlay-only, agent-wiki-only, or combined", "combined").option("--limit <limit>", "Maximum number of results", "10").action(async (query, opts, cmd) => {
6947
+ const { organizationId, runtimeOptions } = await resolveOsmdContext(cmd);
6948
+ const result = await requestOsmdSearch({
6949
+ command: "osmd.search",
6950
+ runtimeOptions,
6951
+ organizationId,
6952
+ query: nonEmptyString3.parse(query).trim(),
6953
+ scope: parseOsmdSearchScope(opts.scope),
6954
+ limit: parseSearchLimit(opts.limit)
6955
+ });
6956
+ return printEnvelopeAndExit({
6957
+ envelope: buildSuccessEnvelope({
6958
+ command: "osmd.search",
6959
+ status: result.status,
6960
+ data: result.data,
6961
+ requestId: result.requestId
6962
+ })
6963
+ });
6964
+ });
6806
6965
  const agent = osmd.command("agent").description(".agent overlay memory attached to canonical OSMD parents; supports notes.md");
6807
6966
  agent.command("status <parent-ref> <file>").description("Show .agent notes.md metadata without creating files").action(async (parentRef, file, _opts, cmd) => {
6808
6967
  const { organizationId, runtimeOptions } = await resolveOsmdContext(cmd);
package/dist/index.js CHANGED
@@ -6142,10 +6142,17 @@ var agentMarkdownErrorCodeSchema = z16.enum([
6142
6142
  var agentMarkdownErrorCodeFieldSchema = agentMarkdownErrorCodeSchema.nullable().catch(null);
6143
6143
  var nonEmptyString3 = z16.string().min(1);
6144
6144
  var nonNegativeInt3 = z16.coerce.number().int().min(0);
6145
+ var positiveInt = z16.coerce.number().int().min(1);
6145
6146
  var supportedAgentOverlayFile = "notes.md";
6146
6147
  var supportedWikiIndexFile = "index.md";
6147
6148
  var supportedWikiLogFile = "log.md";
6148
6149
  var agentOverlayFileSchema = z16.enum([supportedAgentOverlayFile]);
6150
+ var osmdSearchScopeSchema = z16.enum([
6151
+ "os-only",
6152
+ "agent-overlay-only",
6153
+ "agent-wiki-only",
6154
+ "combined"
6155
+ ]);
6149
6156
  var agentMarkdownFileSchema = z16.object({
6150
6157
  path: z16.string(),
6151
6158
  source: sourceSchema,
@@ -6155,6 +6162,8 @@ var agentMarkdownFileSchema = z16.object({
6155
6162
  canCreate: z16.boolean(),
6156
6163
  canUpdate: z16.boolean(),
6157
6164
  canAppend: z16.boolean(),
6165
+ wikiRole: z16.string().nullable().optional(),
6166
+ formatVersion: z16.string().nullable().optional(),
6158
6167
  parentRef: z16.string().nullable().optional(),
6159
6168
  agentChildrenAllowed: z16.boolean(),
6160
6169
  suggestedAction: suggestedActionSchema,
@@ -6163,6 +6172,8 @@ var agentMarkdownFileSchema = z16.object({
6163
6172
  url: z16.string().nullable().optional()
6164
6173
  }).transform((value) => ({
6165
6174
  ...value,
6175
+ wikiRole: value.wikiRole ?? null,
6176
+ formatVersion: value.formatVersion ?? null,
6166
6177
  parentRef: value.parentRef ?? null,
6167
6178
  errorCode: value.errorCode ?? null,
6168
6179
  content: value.content ?? null,
@@ -6173,6 +6184,47 @@ var agentMarkdownMutationDataSchema = z16.union([
6173
6184
  agentMarkdownFileSchema,
6174
6185
  z16.object({ files: agentMarkdownFilesSchema })
6175
6186
  ]);
6187
+ var osmdSearchCandidateSchema = z16.preprocess(
6188
+ normalizeAgentMarkdownJsonKeys,
6189
+ z16.object({
6190
+ path: z16.string(),
6191
+ source: sourceSchema,
6192
+ access: accessSchema,
6193
+ owner: ownerSchema,
6194
+ wikiRole: z16.string().nullable().optional(),
6195
+ formatVersion: z16.string().nullable().optional(),
6196
+ parentRef: z16.string().nullable().optional(),
6197
+ exists: z16.boolean(),
6198
+ agentChildrenAllowed: z16.boolean(),
6199
+ title: z16.string(),
6200
+ label: z16.string(),
6201
+ snippet: z16.string().nullable().optional(),
6202
+ rank: z16.number().int(),
6203
+ matchReason: z16.string().nullable().optional(),
6204
+ toolKey: z16.string().nullable().optional(),
6205
+ nodeKey: z16.string().nullable().optional(),
6206
+ nodeKind: z16.string().nullable().optional()
6207
+ }).transform((value) => ({
6208
+ ...value,
6209
+ wikiRole: value.wikiRole ?? null,
6210
+ formatVersion: value.formatVersion ?? null,
6211
+ parentRef: value.parentRef ?? null,
6212
+ snippet: value.snippet ?? null,
6213
+ matchReason: value.matchReason ?? null,
6214
+ toolKey: value.toolKey ?? null,
6215
+ nodeKey: value.nodeKey ?? null,
6216
+ nodeKind: value.nodeKind ?? null
6217
+ }))
6218
+ );
6219
+ var osmdSearchResultSchema = z16.preprocess(
6220
+ normalizeAgentMarkdownJsonKeys,
6221
+ z16.object({
6222
+ query: z16.string(),
6223
+ scope: z16.string(),
6224
+ count: z16.number().int().min(0),
6225
+ candidates: z16.array(osmdSearchCandidateSchema)
6226
+ })
6227
+ );
6176
6228
  var mutationPayloadSchema = z16.object({
6177
6229
  ok: z16.boolean(),
6178
6230
  status: z16.number(),
@@ -6215,6 +6267,8 @@ var AGENT_MARKDOWN_FILE_SELECTION = `{
6215
6267
  canCreate
6216
6268
  canUpdate
6217
6269
  canAppend
6270
+ wikiRole
6271
+ formatVersion
6218
6272
  parentRef
6219
6273
  agentChildrenAllowed
6220
6274
  suggestedAction
@@ -6222,15 +6276,45 @@ var AGENT_MARKDOWN_FILE_SELECTION = `{
6222
6276
  content
6223
6277
  url
6224
6278
  }`;
6279
+ var OSMD_SEARCH_SELECTION = `{
6280
+ query
6281
+ scope
6282
+ count
6283
+ candidates {
6284
+ path
6285
+ source
6286
+ access
6287
+ owner
6288
+ wikiRole
6289
+ formatVersion
6290
+ parentRef
6291
+ exists
6292
+ agentChildrenAllowed
6293
+ title
6294
+ label
6295
+ snippet
6296
+ rank
6297
+ matchReason
6298
+ toolKey
6299
+ nodeKey
6300
+ nodeKind
6301
+ }
6302
+ }`;
6225
6303
  var MUTATION_RESULT_SELECTION = "{ ok status errorCode data errors }";
6226
6304
  var AGENT_JSON_KEY_ALIASES = {
6227
6305
  can_create: "canCreate",
6228
6306
  can_update: "canUpdate",
6229
6307
  can_append: "canAppend",
6308
+ wiki_role: "wikiRole",
6309
+ format_version: "formatVersion",
6230
6310
  parent_ref: "parentRef",
6231
6311
  agent_children_allowed: "agentChildrenAllowed",
6232
6312
  suggested_action: "suggestedAction",
6233
- error_code: "errorCode"
6313
+ error_code: "errorCode",
6314
+ match_reason: "matchReason",
6315
+ tool_key: "toolKey",
6316
+ node_key: "nodeKey",
6317
+ node_kind: "nodeKind"
6234
6318
  };
6235
6319
  function isSupportedAgentMarkdownFile(file) {
6236
6320
  if (file.source !== "agent_overlay") {
@@ -6382,6 +6466,22 @@ async function requestAgentMarkdownChildren(params) {
6382
6466
  schema: agentMarkdownFilesSchema
6383
6467
  });
6384
6468
  }
6469
+ async function requestOsmdSearch(params) {
6470
+ return requestOsmdQuery({
6471
+ command: params.command,
6472
+ operationName: "OsMdSearch",
6473
+ runtimeOptions: params.runtimeOptions,
6474
+ field: "os_md_search",
6475
+ variables: {
6476
+ organization_id: params.organizationId,
6477
+ query: params.query,
6478
+ source: backendSearchSourceForScope(params.scope),
6479
+ limit: params.limit
6480
+ },
6481
+ selectionSet: OSMD_SEARCH_SELECTION,
6482
+ schema: osmdSearchResultSchema
6483
+ });
6484
+ }
6385
6485
  async function runAgentMarkdownMutation(params) {
6386
6486
  const result = await graphqlRequest({
6387
6487
  config: getConfig(params.runtimeOptions),
@@ -6494,6 +6594,46 @@ function parseOptionalSource(value) {
6494
6594
  }
6495
6595
  return parsed.data;
6496
6596
  }
6597
+ function parseOsmdSearchScope(value) {
6598
+ const raw = typeof value === "string" && value.trim() !== "" ? value.trim() : "combined";
6599
+ const parsed = osmdSearchScopeSchema.safeParse(raw);
6600
+ if (!parsed.success) {
6601
+ throw new CliError({
6602
+ message: "Invalid OSMD search scope. Use os-only, agent-overlay-only, agent-wiki-only, or combined.",
6603
+ kind: "invalid_args",
6604
+ status: 400,
6605
+ exitCode: EXIT_CODES.invalidArgs,
6606
+ details: { supportedScopes: osmdSearchScopeSchema.options }
6607
+ });
6608
+ }
6609
+ return parsed.data;
6610
+ }
6611
+ function backendSearchSourceForScope(scope) {
6612
+ if (scope === "os-only") {
6613
+ return "canonical_osmd";
6614
+ }
6615
+ if (scope === "agent-overlay-only") {
6616
+ return "agent_overlay";
6617
+ }
6618
+ if (scope === "agent-wiki-only") {
6619
+ return "agent_wiki";
6620
+ }
6621
+ return "combined";
6622
+ }
6623
+ function parseSearchLimit(value) {
6624
+ const raw = value === void 0 || value === null || value === "" ? "10" : value;
6625
+ const parsed = positiveInt.safeParse(raw);
6626
+ if (!parsed.success) {
6627
+ throw new CliError({
6628
+ message: "Invalid OSMD search limit. Use a positive integer.",
6629
+ kind: "invalid_args",
6630
+ status: 400,
6631
+ exitCode: EXIT_CODES.invalidArgs,
6632
+ details: { issues: parsed.error.issues }
6633
+ });
6634
+ }
6635
+ return parsed.data;
6636
+ }
6497
6637
  function parseDepth(value) {
6498
6638
  if (value === void 0 || value === null || value === "") {
6499
6639
  return 1;
@@ -6783,7 +6923,7 @@ function registerOsmdCommands(program) {
6783
6923
  })
6784
6924
  });
6785
6925
  });
6786
- osmd.command("children [path]").description("List backend-supported agent markdown children; search remains canonical-only").option("--parent-ref <parentRef>", "Canonical OSMD parent ref for .agent files").option("--source <source>", "Filter by canonical_osmd, agent_overlay, or agent_wiki").action(async (path, opts, cmd) => {
6926
+ osmd.command("children [path]").description("List backend-supported agent markdown children").option("--parent-ref <parentRef>", "Canonical OSMD parent ref for .agent files").option("--source <source>", "Filter by canonical_osmd, agent_overlay, or agent_wiki").action(async (path, opts, cmd) => {
6787
6927
  const { organizationId, runtimeOptions } = await resolveOsmdContext(cmd);
6788
6928
  const result = await requestAgentMarkdownChildren({
6789
6929
  command: "osmd.children",
@@ -6802,6 +6942,25 @@ function registerOsmdCommands(program) {
6802
6942
  })
6803
6943
  });
6804
6944
  });
6945
+ osmd.command("search <query>").description("Search merged OSMD, .agent overlays, and Agent Wiki through backend OSMD search").option("--scope <scope>", "os-only, agent-overlay-only, agent-wiki-only, or combined", "combined").option("--limit <limit>", "Maximum number of results", "10").action(async (query, opts, cmd) => {
6946
+ const { organizationId, runtimeOptions } = await resolveOsmdContext(cmd);
6947
+ const result = await requestOsmdSearch({
6948
+ command: "osmd.search",
6949
+ runtimeOptions,
6950
+ organizationId,
6951
+ query: nonEmptyString3.parse(query).trim(),
6952
+ scope: parseOsmdSearchScope(opts.scope),
6953
+ limit: parseSearchLimit(opts.limit)
6954
+ });
6955
+ return printEnvelopeAndExit({
6956
+ envelope: buildSuccessEnvelope({
6957
+ command: "osmd.search",
6958
+ status: result.status,
6959
+ data: result.data,
6960
+ requestId: result.requestId
6961
+ })
6962
+ });
6963
+ });
6805
6964
  const agent = osmd.command("agent").description(".agent overlay memory attached to canonical OSMD parents; supports notes.md");
6806
6965
  agent.command("status <parent-ref> <file>").description("Show .agent notes.md metadata without creating files").action(async (parentRef, file, _opts, cmd) => {
6807
6966
  const { organizationId, runtimeOptions } = await resolveOsmdContext(cmd);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ted-galago/wave-cli",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "wave": "dist/index.js"
@@ -1182,6 +1182,8 @@ function runOsmdLiveVerification() {
1182
1182
  wikiStatus.parsed?.ok === true &&
1183
1183
  wikiStatus.parsed?.data?.path === "Agent Wiki/index.md" &&
1184
1184
  wikiStatus.parsed?.data?.source === "agent_wiki" &&
1185
+ wikiStatus.parsed?.data?.wikiRole === "index" &&
1186
+ typeof wikiStatus.parsed?.data?.formatVersion === "string" &&
1185
1187
  (wikiStatus.parsed?.data?.exists !== false ||
1186
1188
  (wikiStatus.parsed?.data?.canCreate === true &&
1187
1189
  wikiStatus.parsed?.data?.canUpdate === false &&
@@ -1210,6 +1212,8 @@ function runOsmdLiveVerification() {
1210
1212
  wikiLogStatus.parsed?.data?.path === "Agent Wiki/log.md" &&
1211
1213
  wikiLogStatus.parsed?.data?.source === "agent_wiki" &&
1212
1214
  wikiLogStatus.parsed?.data?.access === "append_only" &&
1215
+ wikiLogStatus.parsed?.data?.wikiRole === "log" &&
1216
+ typeof wikiLogStatus.parsed?.data?.formatVersion === "string" &&
1213
1217
  typeof wikiLogStatus.parsed?.data?.canAppend === "boolean",
1214
1218
  reason: "agent_wiki_log_status"
1215
1219
  });
@@ -1224,6 +1228,8 @@ function runOsmdLiveVerification() {
1224
1228
  wikiLogRead.parsed?.ok === true &&
1225
1229
  wikiLogRead.parsed?.data?.path === "Agent Wiki/log.md" &&
1226
1230
  wikiLogRead.parsed?.data?.access === "append_only" &&
1231
+ wikiLogRead.parsed?.data?.wikiRole === "log" &&
1232
+ typeof wikiLogRead.parsed?.data?.formatVersion === "string" &&
1227
1233
  wikiLogRead.parsed?.data?.exists === wikiLogStatus.parsed?.data?.exists,
1228
1234
  reason: "agent_wiki_log_read"
1229
1235
  });
@@ -1245,6 +1251,8 @@ function runOsmdLiveVerification() {
1245
1251
  missingWikiLogAppend.parsed?.error?.suggestedAction === "init" &&
1246
1252
  String(missingWikiLogAppend.parsed?.error?.message ?? "").includes("wave osmd wiki init") &&
1247
1253
  missingWikiLogAppend.parsed?.data?.path === "Agent Wiki/log.md" &&
1254
+ missingWikiLogAppend.parsed?.data?.wikiRole === "log" &&
1255
+ typeof missingWikiLogAppend.parsed?.data?.formatVersion === "string" &&
1248
1256
  missingWikiLogAppend.parsed?.data?.canAppend === false,
1249
1257
  reason: "agent_wiki_log_missing_init_guidance"
1250
1258
  });
@@ -1267,6 +1275,8 @@ function runOsmdLiveVerification() {
1267
1275
  (file) =>
1268
1276
  file?.path === "Agent Wiki/log.md" &&
1269
1277
  file?.access === "append_only" &&
1278
+ file?.wikiRole === "log" &&
1279
+ typeof file?.formatVersion === "string" &&
1270
1280
  file?.exists === true &&
1271
1281
  file?.canAppend === true
1272
1282
  ),
@@ -1286,6 +1296,8 @@ function runOsmdLiveVerification() {
1286
1296
  wikiLogAppend.parsed?.ok === true &&
1287
1297
  wikiLogAppend.parsed?.data?.path === "Agent Wiki/log.md" &&
1288
1298
  wikiLogAppend.parsed?.data?.access === "append_only" &&
1299
+ wikiLogAppend.parsed?.data?.wikiRole === "log" &&
1300
+ typeof wikiLogAppend.parsed?.data?.formatVersion === "string" &&
1289
1301
  wikiLogAppend.parsed?.data?.canAppend === true,
1290
1302
  reason: "agent_wiki_log_append_after_init"
1291
1303
  });
@@ -1336,6 +1348,8 @@ function runOsmdLiveVerification() {
1336
1348
  ok:
1337
1349
  agentStatus.parsed?.ok === true &&
1338
1350
  agentStatus.parsed?.data?.source === "agent_overlay" &&
1351
+ agentStatus.parsed?.data?.wikiRole === "notes" &&
1352
+ typeof agentStatus.parsed?.data?.formatVersion === "string" &&
1339
1353
  agentStatus.parsed?.data?.parentRef === parentRef,
1340
1354
  reason: "agent_overlay_status"
1341
1355
  });
@@ -1349,7 +1363,12 @@ function runOsmdLiveVerification() {
1349
1363
  result: agentInit,
1350
1364
  ok:
1351
1365
  agentInit.parsed?.ok === true &&
1352
- (initFiles.some((file) => file?.path?.endsWith("/.agent/notes.md")) ||
1366
+ (initFiles.some(
1367
+ (file) =>
1368
+ file?.path?.endsWith("/.agent/notes.md") &&
1369
+ file?.wikiRole === "notes" &&
1370
+ typeof file?.formatVersion === "string"
1371
+ ) ||
1353
1372
  agentInit.parsed?.data?.path?.endsWith("/.agent/notes.md")),
1354
1373
  reason: "agent_overlay_init"
1355
1374
  });
@@ -1367,10 +1386,131 @@ function runOsmdLiveVerification() {
1367
1386
  ok:
1368
1387
  agentUpdate.parsed?.ok === true &&
1369
1388
  agentUpdate.parsed?.data?.access === "read_write" &&
1389
+ agentUpdate.parsed?.data?.wikiRole === "notes" &&
1390
+ typeof agentUpdate.parsed?.data?.formatVersion === "string" &&
1370
1391
  agentUpdate.parsed?.data?.content === notesContent,
1371
1392
  reason: "agent_overlay_update"
1372
1393
  });
1373
1394
 
1395
+ const searchCandidates = (result) => firstArrayValue(result.parsed, [["data", "candidates"]]);
1396
+ const hasOwn = (candidate, key) => Object.prototype.hasOwnProperty.call(candidate ?? {}, key);
1397
+ const hasSearchMetadata = (candidate, expectedSource) =>
1398
+ candidate &&
1399
+ typeof candidate.path === "string" &&
1400
+ candidate.source === expectedSource &&
1401
+ typeof candidate.access === "string" &&
1402
+ typeof candidate.owner === "string" &&
1403
+ hasOwn(candidate, "wikiRole") &&
1404
+ hasOwn(candidate, "formatVersion") &&
1405
+ hasOwn(candidate, "parentRef") &&
1406
+ typeof candidate.exists === "boolean";
1407
+
1408
+ const canonicalSearch = runWave(["osmd", "search", "Wave Tools", "--scope", "os-only", "--limit", "5"], env);
1409
+ results.push(canonicalSearch);
1410
+ const canonicalSearchCandidates = searchCandidates(canonicalSearch);
1411
+ osmdVerificationFailures += recordExactCheck({
1412
+ lines: osmdVerificationLines,
1413
+ label: "osmd.search canonical results include OS metadata",
1414
+ result: canonicalSearch,
1415
+ ok:
1416
+ canonicalSearch.parsed?.ok === true &&
1417
+ canonicalSearch.parsed?.command === "osmd.search" &&
1418
+ typeof canonicalSearch.parsed?.meta?.requestId === "string" &&
1419
+ canonicalSearch.parsed?.data?.scope === "canonical_osmd" &&
1420
+ canonicalSearchCandidates.some(
1421
+ (candidate) =>
1422
+ hasSearchMetadata(candidate, "canonical_osmd") &&
1423
+ candidate.access === "read_only" &&
1424
+ candidate.owner === "system"
1425
+ ),
1426
+ reason: "osmd_search_canonical"
1427
+ });
1428
+
1429
+ const wikiSearch = runWave(["osmd", "search", "Agent Wiki", "--scope", "agent-wiki-only", "--limit", "10"], env);
1430
+ results.push(wikiSearch);
1431
+ const wikiSearchCandidates = searchCandidates(wikiSearch);
1432
+ osmdVerificationFailures += recordExactCheck({
1433
+ lines: osmdVerificationLines,
1434
+ label: "osmd.search Agent Wiki results include index and log metadata",
1435
+ result: wikiSearch,
1436
+ ok:
1437
+ wikiSearch.parsed?.ok === true &&
1438
+ wikiSearch.parsed?.data?.scope === "agent_wiki" &&
1439
+ wikiSearchCandidates.some(
1440
+ (candidate) =>
1441
+ hasSearchMetadata(candidate, "agent_wiki") &&
1442
+ candidate.path === "Agent Wiki/index.md" &&
1443
+ candidate.wikiRole === "index"
1444
+ ) &&
1445
+ wikiSearchCandidates.some(
1446
+ (candidate) =>
1447
+ hasSearchMetadata(candidate, "agent_wiki") &&
1448
+ candidate.path === "Agent Wiki/log.md" &&
1449
+ candidate.wikiRole === "log" &&
1450
+ candidate.access === "append_only"
1451
+ ),
1452
+ reason: "osmd_search_agent_wiki"
1453
+ });
1454
+
1455
+ const logSearch = runWave(
1456
+ ["osmd", "search", `CLI live verify log ${verifyStamp}`, "--scope", "agent-wiki-only", "--limit", "5"],
1457
+ env
1458
+ );
1459
+ results.push(logSearch);
1460
+ const logSearchCandidates = searchCandidates(logSearch);
1461
+ osmdVerificationFailures += recordExactCheck({
1462
+ lines: osmdVerificationLines,
1463
+ label: "osmd.search Agent Wiki log content result",
1464
+ result: logSearch,
1465
+ ok:
1466
+ logSearch.parsed?.ok === true &&
1467
+ logSearchCandidates.some(
1468
+ (candidate) =>
1469
+ hasSearchMetadata(candidate, "agent_wiki") &&
1470
+ candidate.path === "Agent Wiki/log.md" &&
1471
+ candidate.wikiRole === "log"
1472
+ ),
1473
+ reason: "osmd_search_agent_wiki_log"
1474
+ });
1475
+
1476
+ const notesSearch = runWave(
1477
+ ["osmd", "search", notesContent, "--scope", "agent-overlay-only", "--limit", "5"],
1478
+ env
1479
+ );
1480
+ results.push(notesSearch);
1481
+ const notesSearchCandidates = searchCandidates(notesSearch);
1482
+ osmdVerificationFailures += recordExactCheck({
1483
+ lines: osmdVerificationLines,
1484
+ label: "osmd.search agent overlay notes content result",
1485
+ result: notesSearch,
1486
+ ok:
1487
+ notesSearch.parsed?.ok === true &&
1488
+ notesSearch.parsed?.data?.scope === "agent_overlay" &&
1489
+ notesSearchCandidates.some(
1490
+ (candidate) =>
1491
+ hasSearchMetadata(candidate, "agent_overlay") &&
1492
+ candidate.path.endsWith("/.agent/notes.md") &&
1493
+ candidate.wikiRole === "notes" &&
1494
+ candidate.parentRef === parentRef
1495
+ ),
1496
+ reason: "osmd_search_agent_overlay_notes"
1497
+ });
1498
+
1499
+ const combinedSearch = runWave(["osmd", "search", "Wave", "--scope", "combined", "--limit", "3"], env);
1500
+ results.push(combinedSearch);
1501
+ osmdVerificationFailures += recordExactCheck({
1502
+ lines: osmdVerificationLines,
1503
+ label: "osmd.search combined scope returns stable envelope",
1504
+ result: combinedSearch,
1505
+ ok:
1506
+ combinedSearch.parsed?.ok === true &&
1507
+ combinedSearch.parsed?.command === "osmd.search" &&
1508
+ combinedSearch.parsed?.data?.scope === "combined" &&
1509
+ Array.isArray(combinedSearch.parsed?.data?.candidates) &&
1510
+ typeof combinedSearch.parsed?.meta?.requestId === "string",
1511
+ reason: "osmd_search_combined"
1512
+ });
1513
+
1374
1514
  }
1375
1515
 
1376
1516
  runOsmdLiveVerification();