@ted-galago/wave-cli 0.1.20 → 0.1.22
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 +23 -3
- package/dist/index.cjs +112 -31
- package/dist/index.js +112 -31
- package/package.json +1 -1
- package/scripts/verify-dev-api.mjs +167 -0
package/README.md
CHANGED
|
@@ -133,6 +133,8 @@ wave osmd wiki read log.md
|
|
|
133
133
|
wave osmd wiki init
|
|
134
134
|
wave osmd wiki create index.md --content "# Agent Wiki"
|
|
135
135
|
wave osmd wiki update "Agent Wiki/index.md" --file ./agent-wiki-index.md
|
|
136
|
+
wave osmd wiki create "concepts/customer-health.md" --content "# Customer Health"
|
|
137
|
+
wave osmd wiki update "decisions/use-agent-wiki.md" --content "# Use Agent Wiki"
|
|
136
138
|
wave osmd wiki append-log --content "Observed durable event"
|
|
137
139
|
wave find "Ted"
|
|
138
140
|
wave open "Ted Martinez"
|
|
@@ -345,10 +347,11 @@ Path and permission rules:
|
|
|
345
347
|
- `.agent` first slice supports only `notes.md`.
|
|
346
348
|
- `osmd agent init <parent-ref>` is idempotent for default `.agent` files.
|
|
347
349
|
- Agent Wiki index paths may be `index.md` or `Agent Wiki/index.md`; the CLI normalizes these to `Agent Wiki/index.md`.
|
|
350
|
+
- Controlled Agent Wiki page paths may be `concepts/<name>.md`, `playbooks/<name>.md`, `decisions/<name>.md`, `org-summaries/<name>.md`, or the same forms prefixed with `Agent Wiki/`.
|
|
348
351
|
- Agent Wiki log paths may be `log.md` or `Agent Wiki/log.md`; the CLI normalizes these to `Agent Wiki/log.md`.
|
|
349
|
-
- Agent Wiki
|
|
352
|
+
- Agent Wiki agents should use `index.md` for broad writable wiki memory, controlled folders for durable typed pages, and `log.md` for append-only event memory.
|
|
350
353
|
- Agent Wiki `init` initializes backend-owned system files, including append-only `log.md`, through `initAgentMarkdown` at path `Agent Wiki`.
|
|
351
|
-
- Agent Wiki `create` and `update` support
|
|
354
|
+
- Agent Wiki `create` and `update` support `index.md`, `concepts/*.md`, `playbooks/*.md`, `decisions/*.md`, and `org-summaries/*.md`; `log.md` cannot be created or overwritten by these commands.
|
|
352
355
|
- Agent Wiki `append-log` supports only `log.md` and calls status first before appending.
|
|
353
356
|
- The CLI uses backend GraphQL metadata directly and does not derive S3 paths, SHA paths, or backend storage conventions.
|
|
354
357
|
- Atlas should inspect `path`, `source`, `access`, `owner`, `parentRef`, `exists`, `canCreate`, `canUpdate`, `canAppend`, `wikiRole`, `formatVersion`, `suggestedAction`, and `errorCode`.
|
|
@@ -361,6 +364,7 @@ Path and permission rules:
|
|
|
361
364
|
- `append-log` fails unless status reports `exists: true`, `access: "append_only"`, and `canAppend: true`.
|
|
362
365
|
- 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`.
|
|
363
366
|
- Missing `Agent Wiki/index.md` is create-ready when status returns `exists: false`, `canCreate: true`, `canUpdate: false`, and `suggestedAction: "create"`.
|
|
367
|
+
- Missing controlled pages are create-ready when backend status returns `exists: false`, `canCreate: true`, `canUpdate: false`, and `suggestedAction: "create"`.
|
|
364
368
|
|
|
365
369
|
Atlas Agent Wiki log flow:
|
|
366
370
|
|
|
@@ -382,6 +386,22 @@ wave osmd wiki read index.md
|
|
|
382
386
|
wave osmd wiki update index.md --content "# Agent Wiki\n\n## Entity Notes\n\n- directory/Wave Tools Team -> .agent/notes.md"
|
|
383
387
|
```
|
|
384
388
|
|
|
389
|
+
Create or update controlled Agent Wiki pages. Atlas should call `status` first, then choose `create` or `update` from backend `canCreate`, `canUpdate`, and `suggestedAction`:
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
wave osmd wiki status concepts/customer-health.md
|
|
393
|
+
wave osmd wiki create concepts/customer-health.md --content "# Customer Health\n\nDurable definition and usage notes."
|
|
394
|
+
|
|
395
|
+
wave osmd wiki status decisions/use-agent-wiki.md
|
|
396
|
+
wave osmd wiki update decisions/use-agent-wiki.md --content "# Use Agent Wiki\n\nDecision: store broad agent memory in controlled Agent Wiki pages."
|
|
397
|
+
|
|
398
|
+
wave osmd wiki status playbooks/customer-review.md
|
|
399
|
+
wave osmd wiki create playbooks/customer-review.md --content "# Customer Review\n\n1. Read the customer summary.\n2. Review recent notes.\n3. Append the maintenance log."
|
|
400
|
+
|
|
401
|
+
wave osmd wiki status org-summaries/galago.md
|
|
402
|
+
wave osmd wiki update org-summaries/galago.md --content "# Galago\n\nCurrent durable organization summary."
|
|
403
|
+
```
|
|
404
|
+
|
|
385
405
|
Append a parseable log entry. Use a stable fenced block so Atlas or backend jobs can parse the chronology later:
|
|
386
406
|
|
|
387
407
|
````bash
|
|
@@ -529,7 +549,7 @@ Use `wave osmd search "<query>" --scope combined` when Atlas needs merged canoni
|
|
|
529
549
|
|
|
530
550
|
- `--scope os-only` searches canonical OSMD only.
|
|
531
551
|
- `--scope agent-overlay-only` searches entity-specific `.agent` files.
|
|
532
|
-
- `--scope agent-wiki-only` searches broad Agent Wiki files, including `index.md
|
|
552
|
+
- `--scope agent-wiki-only` searches broad Agent Wiki files, including `index.md`, controlled pages, and append-only `log.md`.
|
|
533
553
|
- `--scope combined` searches the backend merged OSMD surface.
|
|
534
554
|
|
|
535
555
|
Ambiguity contract:
|
package/dist/index.cjs
CHANGED
|
@@ -6147,6 +6147,15 @@ var positiveInt = import_zod16.z.coerce.number().int().min(1);
|
|
|
6147
6147
|
var supportedAgentOverlayFile = "notes.md";
|
|
6148
6148
|
var supportedWikiIndexFile = "index.md";
|
|
6149
6149
|
var supportedWikiLogFile = "log.md";
|
|
6150
|
+
var supportedWikiControlledFolders = [
|
|
6151
|
+
"concepts",
|
|
6152
|
+
"playbooks",
|
|
6153
|
+
"decisions",
|
|
6154
|
+
"org-summaries"
|
|
6155
|
+
];
|
|
6156
|
+
var supportedWikiControlledPatterns = supportedWikiControlledFolders.map(
|
|
6157
|
+
(folder) => `${folder}/*.md`
|
|
6158
|
+
);
|
|
6150
6159
|
var agentOverlayFileSchema = import_zod16.z.enum([supportedAgentOverlayFile]);
|
|
6151
6160
|
var osmdSearchScopeSchema = import_zod16.z.enum([
|
|
6152
6161
|
"os-only",
|
|
@@ -6540,41 +6549,113 @@ function normalizeAgentFilePath(file) {
|
|
|
6540
6549
|
}
|
|
6541
6550
|
return `.agent/${parsed.data}`;
|
|
6542
6551
|
}
|
|
6543
|
-
function
|
|
6544
|
-
|
|
6552
|
+
function formatHumanList(items) {
|
|
6553
|
+
if (items.length <= 1) {
|
|
6554
|
+
return items[0] ?? "";
|
|
6555
|
+
}
|
|
6556
|
+
if (items.length === 2) {
|
|
6557
|
+
return `${items[0]} and ${items[1]}`;
|
|
6558
|
+
}
|
|
6559
|
+
return `${items.slice(0, -1).join(", ")}, and ${items[items.length - 1]}`;
|
|
6560
|
+
}
|
|
6561
|
+
function supportedWikiPathsMessage(options = {}) {
|
|
6562
|
+
const allowed = allowedWikiPathLabels(options);
|
|
6563
|
+
return `Agent Wiki file commands support only ${formatHumanList(allowed)} in this CLI slice.`;
|
|
6564
|
+
}
|
|
6565
|
+
function allowedWikiPathLabels(options = {}) {
|
|
6566
|
+
const allowIndex = options.allowIndex ?? true;
|
|
6567
|
+
const allowLog = options.allowLog ?? true;
|
|
6568
|
+
const allowControlledPages = options.allowControlledPages ?? true;
|
|
6569
|
+
const labels = [];
|
|
6570
|
+
if (options.allowRoot) {
|
|
6571
|
+
labels.push("Agent Wiki");
|
|
6572
|
+
}
|
|
6573
|
+
if (allowIndex) {
|
|
6574
|
+
labels.push(supportedWikiIndexFile);
|
|
6575
|
+
}
|
|
6576
|
+
if (allowLog) {
|
|
6577
|
+
labels.push(supportedWikiLogFile);
|
|
6578
|
+
}
|
|
6579
|
+
if (allowControlledPages) {
|
|
6580
|
+
labels.push(...supportedWikiControlledPatterns);
|
|
6581
|
+
}
|
|
6582
|
+
if (options.allowControlledFolders) {
|
|
6583
|
+
labels.push(...supportedWikiControlledFolders);
|
|
6584
|
+
}
|
|
6585
|
+
return labels;
|
|
6586
|
+
}
|
|
6587
|
+
function rejectUnsupportedWikiPath(options) {
|
|
6588
|
+
throw new CliError({
|
|
6589
|
+
message: supportedWikiPathsMessage(options),
|
|
6590
|
+
kind: "invalid_args",
|
|
6591
|
+
status: 400,
|
|
6592
|
+
exitCode: EXIT_CODES.invalidArgs,
|
|
6593
|
+
details: { supportedPaths: allowedWikiPathLabels(options) }
|
|
6594
|
+
});
|
|
6595
|
+
}
|
|
6596
|
+
function isControlledWikiFolder(value) {
|
|
6597
|
+
return supportedWikiControlledFolders.includes(
|
|
6598
|
+
value
|
|
6599
|
+
);
|
|
6600
|
+
}
|
|
6601
|
+
function isMarkdownLeafFileName(value) {
|
|
6602
|
+
return value.endsWith(".md") && value.length > ".md".length;
|
|
6545
6603
|
}
|
|
6546
6604
|
function normalizeWikiPath(path, options = {}) {
|
|
6547
|
-
const
|
|
6605
|
+
const normalizedOptions = {
|
|
6606
|
+
allowIndex: options.allowIndex ?? true,
|
|
6607
|
+
allowLog: options.allowLog ?? true,
|
|
6608
|
+
allowControlledPages: options.allowControlledPages ?? true,
|
|
6609
|
+
allowRoot: options.allowRoot ?? false,
|
|
6610
|
+
allowControlledFolders: options.allowControlledFolders ?? false
|
|
6611
|
+
};
|
|
6548
6612
|
const trimmed = nonEmptyString3.parse(path).trim().replace(/^\/+/, "");
|
|
6549
6613
|
if (trimmed.localeCompare("Agent Wiki", void 0, { sensitivity: "accent" }) === 0) {
|
|
6550
|
-
if (
|
|
6614
|
+
if (normalizedOptions.allowRoot) {
|
|
6551
6615
|
return "Agent Wiki";
|
|
6552
6616
|
}
|
|
6553
|
-
|
|
6554
|
-
message: supportedWikiFilesMessage(supportedFiles),
|
|
6555
|
-
kind: "invalid_args",
|
|
6556
|
-
status: 400,
|
|
6557
|
-
exitCode: EXIT_CODES.invalidArgs,
|
|
6558
|
-
details: { supportedFiles }
|
|
6559
|
-
});
|
|
6617
|
+
return rejectUnsupportedWikiPath(normalizedOptions);
|
|
6560
6618
|
}
|
|
6561
6619
|
const fileName = trimmed.toLowerCase().startsWith("agent wiki/") ? trimmed.slice("Agent Wiki/".length) : trimmed;
|
|
6562
|
-
if (
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6620
|
+
if (fileName.includes("\\") || fileName.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
6621
|
+
return rejectUnsupportedWikiPath(normalizedOptions);
|
|
6622
|
+
}
|
|
6623
|
+
if (fileName === supportedWikiIndexFile) {
|
|
6624
|
+
if (normalizedOptions.allowIndex) {
|
|
6625
|
+
return `Agent Wiki/${fileName}`;
|
|
6626
|
+
}
|
|
6627
|
+
return rejectUnsupportedWikiPath(normalizedOptions);
|
|
6628
|
+
}
|
|
6629
|
+
if (fileName === supportedWikiLogFile) {
|
|
6630
|
+
if (normalizedOptions.allowLog) {
|
|
6631
|
+
return `Agent Wiki/${fileName}`;
|
|
6632
|
+
}
|
|
6633
|
+
return rejectUnsupportedWikiPath(normalizedOptions);
|
|
6570
6634
|
}
|
|
6571
|
-
|
|
6635
|
+
if (isControlledWikiFolder(fileName)) {
|
|
6636
|
+
if (normalizedOptions.allowControlledFolders) {
|
|
6637
|
+
return `Agent Wiki/${fileName}`;
|
|
6638
|
+
}
|
|
6639
|
+
return rejectUnsupportedWikiPath(normalizedOptions);
|
|
6640
|
+
}
|
|
6641
|
+
const parts = fileName.split("/");
|
|
6642
|
+
if (parts.length === 2 && isControlledWikiFolder(parts[0] ?? "") && isMarkdownLeafFileName(parts[1] ?? "")) {
|
|
6643
|
+
if (normalizedOptions.allowControlledPages) {
|
|
6644
|
+
return `Agent Wiki/${fileName}`;
|
|
6645
|
+
}
|
|
6646
|
+
return rejectUnsupportedWikiPath(normalizedOptions);
|
|
6647
|
+
}
|
|
6648
|
+
return rejectUnsupportedWikiPath(normalizedOptions);
|
|
6572
6649
|
}
|
|
6573
|
-
function
|
|
6574
|
-
return normalizeWikiPath(path, {
|
|
6650
|
+
function normalizeWikiWritablePath(path) {
|
|
6651
|
+
return normalizeWikiPath(path, { allowLog: false });
|
|
6575
6652
|
}
|
|
6576
6653
|
function normalizeWikiLogPath(path = supportedWikiLogFile) {
|
|
6577
|
-
return normalizeWikiPath(path, {
|
|
6654
|
+
return normalizeWikiPath(path, {
|
|
6655
|
+
allowIndex: false,
|
|
6656
|
+
allowLog: true,
|
|
6657
|
+
allowControlledPages: false
|
|
6658
|
+
});
|
|
6578
6659
|
}
|
|
6579
6660
|
function parseOptionalParentRef(value) {
|
|
6580
6661
|
return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
|
|
@@ -7049,7 +7130,7 @@ function registerOsmdCommands(program) {
|
|
|
7049
7130
|
});
|
|
7050
7131
|
}
|
|
7051
7132
|
);
|
|
7052
|
-
const wiki = osmd.command("wiki").description("Agent Wiki files writable by agents; supports index.md and append-only log.md");
|
|
7133
|
+
const wiki = osmd.command("wiki").description("Agent Wiki files writable by agents; supports index.md, controlled pages, and append-only log.md");
|
|
7053
7134
|
wiki.command("init").description("Idempotently initialize Agent Wiki system files").action(async function() {
|
|
7054
7135
|
const { organizationId, runtimeOptions } = await resolveOsmdContext(this);
|
|
7055
7136
|
return runAgentMarkdownMutation({
|
|
@@ -7063,7 +7144,7 @@ function registerOsmdCommands(program) {
|
|
|
7063
7144
|
}
|
|
7064
7145
|
});
|
|
7065
7146
|
});
|
|
7066
|
-
wiki.command("status <path>").description("Show Agent Wiki index.md
|
|
7147
|
+
wiki.command("status <path>").description("Show Agent Wiki index.md, log.md, or controlled page metadata without creating files").action(async (path, _opts, cmd) => {
|
|
7067
7148
|
const { organizationId, runtimeOptions } = await resolveOsmdContext(cmd);
|
|
7068
7149
|
const result = await requestAgentMarkdownStatus({
|
|
7069
7150
|
command: "osmd.wiki.status",
|
|
@@ -7080,7 +7161,7 @@ function registerOsmdCommands(program) {
|
|
|
7080
7161
|
})
|
|
7081
7162
|
});
|
|
7082
7163
|
});
|
|
7083
|
-
wiki.command("read <path>").description("Read Agent Wiki index.md
|
|
7164
|
+
wiki.command("read <path>").description("Read Agent Wiki index.md, log.md, or controlled pages without creating files").action(async (path, _opts, cmd) => {
|
|
7084
7165
|
const { organizationId, runtimeOptions } = await resolveOsmdContext(cmd);
|
|
7085
7166
|
const result = await requestAgentMarkdownFile({
|
|
7086
7167
|
command: "osmd.wiki.read",
|
|
@@ -7103,7 +7184,7 @@ function registerOsmdCommands(program) {
|
|
|
7103
7184
|
command: "osmd.wiki.children",
|
|
7104
7185
|
runtimeOptions,
|
|
7105
7186
|
organizationId,
|
|
7106
|
-
path: typeof path === "string" && path.trim() !== "" ? normalizeWikiPath(path, { allowRoot: true }) : "Agent Wiki",
|
|
7187
|
+
path: typeof path === "string" && path.trim() !== "" ? normalizeWikiPath(path, { allowRoot: true, allowControlledFolders: true }) : "Agent Wiki",
|
|
7107
7188
|
source: "agent_wiki"
|
|
7108
7189
|
});
|
|
7109
7190
|
return printEnvelopeAndExit({
|
|
@@ -7116,7 +7197,7 @@ function registerOsmdCommands(program) {
|
|
|
7116
7197
|
});
|
|
7117
7198
|
});
|
|
7118
7199
|
addContentOptions(
|
|
7119
|
-
wiki.command("create <path>").description("Create Agent Wiki index.md after status/permission preflight")
|
|
7200
|
+
wiki.command("create <path>").description("Create Agent Wiki index.md or controlled pages after status/permission preflight")
|
|
7120
7201
|
).action(async (path, opts, cmd) => {
|
|
7121
7202
|
const globals = cmd.optsWithGlobals();
|
|
7122
7203
|
const content = await resolveContentInput(opts, globals);
|
|
@@ -7126,12 +7207,12 @@ function registerOsmdCommands(program) {
|
|
|
7126
7207
|
action: "create",
|
|
7127
7208
|
runtimeOptions,
|
|
7128
7209
|
organizationId,
|
|
7129
|
-
path:
|
|
7210
|
+
path: normalizeWikiWritablePath(path),
|
|
7130
7211
|
content
|
|
7131
7212
|
});
|
|
7132
7213
|
});
|
|
7133
7214
|
addContentOptions(
|
|
7134
|
-
wiki.command("update <path>").description("Update Agent Wiki index.md after status/permission preflight")
|
|
7215
|
+
wiki.command("update <path>").description("Update Agent Wiki index.md or controlled pages after status/permission preflight")
|
|
7135
7216
|
).action(async (path, opts, cmd) => {
|
|
7136
7217
|
const globals = cmd.optsWithGlobals();
|
|
7137
7218
|
const content = await resolveContentInput(opts, globals);
|
|
@@ -7141,7 +7222,7 @@ function registerOsmdCommands(program) {
|
|
|
7141
7222
|
action: "update",
|
|
7142
7223
|
runtimeOptions,
|
|
7143
7224
|
organizationId,
|
|
7144
|
-
path:
|
|
7225
|
+
path: normalizeWikiWritablePath(path),
|
|
7145
7226
|
content
|
|
7146
7227
|
});
|
|
7147
7228
|
});
|
package/dist/index.js
CHANGED
|
@@ -6146,6 +6146,15 @@ var positiveInt = z16.coerce.number().int().min(1);
|
|
|
6146
6146
|
var supportedAgentOverlayFile = "notes.md";
|
|
6147
6147
|
var supportedWikiIndexFile = "index.md";
|
|
6148
6148
|
var supportedWikiLogFile = "log.md";
|
|
6149
|
+
var supportedWikiControlledFolders = [
|
|
6150
|
+
"concepts",
|
|
6151
|
+
"playbooks",
|
|
6152
|
+
"decisions",
|
|
6153
|
+
"org-summaries"
|
|
6154
|
+
];
|
|
6155
|
+
var supportedWikiControlledPatterns = supportedWikiControlledFolders.map(
|
|
6156
|
+
(folder) => `${folder}/*.md`
|
|
6157
|
+
);
|
|
6149
6158
|
var agentOverlayFileSchema = z16.enum([supportedAgentOverlayFile]);
|
|
6150
6159
|
var osmdSearchScopeSchema = z16.enum([
|
|
6151
6160
|
"os-only",
|
|
@@ -6539,41 +6548,113 @@ function normalizeAgentFilePath(file) {
|
|
|
6539
6548
|
}
|
|
6540
6549
|
return `.agent/${parsed.data}`;
|
|
6541
6550
|
}
|
|
6542
|
-
function
|
|
6543
|
-
|
|
6551
|
+
function formatHumanList(items) {
|
|
6552
|
+
if (items.length <= 1) {
|
|
6553
|
+
return items[0] ?? "";
|
|
6554
|
+
}
|
|
6555
|
+
if (items.length === 2) {
|
|
6556
|
+
return `${items[0]} and ${items[1]}`;
|
|
6557
|
+
}
|
|
6558
|
+
return `${items.slice(0, -1).join(", ")}, and ${items[items.length - 1]}`;
|
|
6559
|
+
}
|
|
6560
|
+
function supportedWikiPathsMessage(options = {}) {
|
|
6561
|
+
const allowed = allowedWikiPathLabels(options);
|
|
6562
|
+
return `Agent Wiki file commands support only ${formatHumanList(allowed)} in this CLI slice.`;
|
|
6563
|
+
}
|
|
6564
|
+
function allowedWikiPathLabels(options = {}) {
|
|
6565
|
+
const allowIndex = options.allowIndex ?? true;
|
|
6566
|
+
const allowLog = options.allowLog ?? true;
|
|
6567
|
+
const allowControlledPages = options.allowControlledPages ?? true;
|
|
6568
|
+
const labels = [];
|
|
6569
|
+
if (options.allowRoot) {
|
|
6570
|
+
labels.push("Agent Wiki");
|
|
6571
|
+
}
|
|
6572
|
+
if (allowIndex) {
|
|
6573
|
+
labels.push(supportedWikiIndexFile);
|
|
6574
|
+
}
|
|
6575
|
+
if (allowLog) {
|
|
6576
|
+
labels.push(supportedWikiLogFile);
|
|
6577
|
+
}
|
|
6578
|
+
if (allowControlledPages) {
|
|
6579
|
+
labels.push(...supportedWikiControlledPatterns);
|
|
6580
|
+
}
|
|
6581
|
+
if (options.allowControlledFolders) {
|
|
6582
|
+
labels.push(...supportedWikiControlledFolders);
|
|
6583
|
+
}
|
|
6584
|
+
return labels;
|
|
6585
|
+
}
|
|
6586
|
+
function rejectUnsupportedWikiPath(options) {
|
|
6587
|
+
throw new CliError({
|
|
6588
|
+
message: supportedWikiPathsMessage(options),
|
|
6589
|
+
kind: "invalid_args",
|
|
6590
|
+
status: 400,
|
|
6591
|
+
exitCode: EXIT_CODES.invalidArgs,
|
|
6592
|
+
details: { supportedPaths: allowedWikiPathLabels(options) }
|
|
6593
|
+
});
|
|
6594
|
+
}
|
|
6595
|
+
function isControlledWikiFolder(value) {
|
|
6596
|
+
return supportedWikiControlledFolders.includes(
|
|
6597
|
+
value
|
|
6598
|
+
);
|
|
6599
|
+
}
|
|
6600
|
+
function isMarkdownLeafFileName(value) {
|
|
6601
|
+
return value.endsWith(".md") && value.length > ".md".length;
|
|
6544
6602
|
}
|
|
6545
6603
|
function normalizeWikiPath(path, options = {}) {
|
|
6546
|
-
const
|
|
6604
|
+
const normalizedOptions = {
|
|
6605
|
+
allowIndex: options.allowIndex ?? true,
|
|
6606
|
+
allowLog: options.allowLog ?? true,
|
|
6607
|
+
allowControlledPages: options.allowControlledPages ?? true,
|
|
6608
|
+
allowRoot: options.allowRoot ?? false,
|
|
6609
|
+
allowControlledFolders: options.allowControlledFolders ?? false
|
|
6610
|
+
};
|
|
6547
6611
|
const trimmed = nonEmptyString3.parse(path).trim().replace(/^\/+/, "");
|
|
6548
6612
|
if (trimmed.localeCompare("Agent Wiki", void 0, { sensitivity: "accent" }) === 0) {
|
|
6549
|
-
if (
|
|
6613
|
+
if (normalizedOptions.allowRoot) {
|
|
6550
6614
|
return "Agent Wiki";
|
|
6551
6615
|
}
|
|
6552
|
-
|
|
6553
|
-
message: supportedWikiFilesMessage(supportedFiles),
|
|
6554
|
-
kind: "invalid_args",
|
|
6555
|
-
status: 400,
|
|
6556
|
-
exitCode: EXIT_CODES.invalidArgs,
|
|
6557
|
-
details: { supportedFiles }
|
|
6558
|
-
});
|
|
6616
|
+
return rejectUnsupportedWikiPath(normalizedOptions);
|
|
6559
6617
|
}
|
|
6560
6618
|
const fileName = trimmed.toLowerCase().startsWith("agent wiki/") ? trimmed.slice("Agent Wiki/".length) : trimmed;
|
|
6561
|
-
if (
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6619
|
+
if (fileName.includes("\\") || fileName.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
6620
|
+
return rejectUnsupportedWikiPath(normalizedOptions);
|
|
6621
|
+
}
|
|
6622
|
+
if (fileName === supportedWikiIndexFile) {
|
|
6623
|
+
if (normalizedOptions.allowIndex) {
|
|
6624
|
+
return `Agent Wiki/${fileName}`;
|
|
6625
|
+
}
|
|
6626
|
+
return rejectUnsupportedWikiPath(normalizedOptions);
|
|
6627
|
+
}
|
|
6628
|
+
if (fileName === supportedWikiLogFile) {
|
|
6629
|
+
if (normalizedOptions.allowLog) {
|
|
6630
|
+
return `Agent Wiki/${fileName}`;
|
|
6631
|
+
}
|
|
6632
|
+
return rejectUnsupportedWikiPath(normalizedOptions);
|
|
6569
6633
|
}
|
|
6570
|
-
|
|
6634
|
+
if (isControlledWikiFolder(fileName)) {
|
|
6635
|
+
if (normalizedOptions.allowControlledFolders) {
|
|
6636
|
+
return `Agent Wiki/${fileName}`;
|
|
6637
|
+
}
|
|
6638
|
+
return rejectUnsupportedWikiPath(normalizedOptions);
|
|
6639
|
+
}
|
|
6640
|
+
const parts = fileName.split("/");
|
|
6641
|
+
if (parts.length === 2 && isControlledWikiFolder(parts[0] ?? "") && isMarkdownLeafFileName(parts[1] ?? "")) {
|
|
6642
|
+
if (normalizedOptions.allowControlledPages) {
|
|
6643
|
+
return `Agent Wiki/${fileName}`;
|
|
6644
|
+
}
|
|
6645
|
+
return rejectUnsupportedWikiPath(normalizedOptions);
|
|
6646
|
+
}
|
|
6647
|
+
return rejectUnsupportedWikiPath(normalizedOptions);
|
|
6571
6648
|
}
|
|
6572
|
-
function
|
|
6573
|
-
return normalizeWikiPath(path, {
|
|
6649
|
+
function normalizeWikiWritablePath(path) {
|
|
6650
|
+
return normalizeWikiPath(path, { allowLog: false });
|
|
6574
6651
|
}
|
|
6575
6652
|
function normalizeWikiLogPath(path = supportedWikiLogFile) {
|
|
6576
|
-
return normalizeWikiPath(path, {
|
|
6653
|
+
return normalizeWikiPath(path, {
|
|
6654
|
+
allowIndex: false,
|
|
6655
|
+
allowLog: true,
|
|
6656
|
+
allowControlledPages: false
|
|
6657
|
+
});
|
|
6577
6658
|
}
|
|
6578
6659
|
function parseOptionalParentRef(value) {
|
|
6579
6660
|
return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
|
|
@@ -7048,7 +7129,7 @@ function registerOsmdCommands(program) {
|
|
|
7048
7129
|
});
|
|
7049
7130
|
}
|
|
7050
7131
|
);
|
|
7051
|
-
const wiki = osmd.command("wiki").description("Agent Wiki files writable by agents; supports index.md and append-only log.md");
|
|
7132
|
+
const wiki = osmd.command("wiki").description("Agent Wiki files writable by agents; supports index.md, controlled pages, and append-only log.md");
|
|
7052
7133
|
wiki.command("init").description("Idempotently initialize Agent Wiki system files").action(async function() {
|
|
7053
7134
|
const { organizationId, runtimeOptions } = await resolveOsmdContext(this);
|
|
7054
7135
|
return runAgentMarkdownMutation({
|
|
@@ -7062,7 +7143,7 @@ function registerOsmdCommands(program) {
|
|
|
7062
7143
|
}
|
|
7063
7144
|
});
|
|
7064
7145
|
});
|
|
7065
|
-
wiki.command("status <path>").description("Show Agent Wiki index.md
|
|
7146
|
+
wiki.command("status <path>").description("Show Agent Wiki index.md, log.md, or controlled page metadata without creating files").action(async (path, _opts, cmd) => {
|
|
7066
7147
|
const { organizationId, runtimeOptions } = await resolveOsmdContext(cmd);
|
|
7067
7148
|
const result = await requestAgentMarkdownStatus({
|
|
7068
7149
|
command: "osmd.wiki.status",
|
|
@@ -7079,7 +7160,7 @@ function registerOsmdCommands(program) {
|
|
|
7079
7160
|
})
|
|
7080
7161
|
});
|
|
7081
7162
|
});
|
|
7082
|
-
wiki.command("read <path>").description("Read Agent Wiki index.md
|
|
7163
|
+
wiki.command("read <path>").description("Read Agent Wiki index.md, log.md, or controlled pages without creating files").action(async (path, _opts, cmd) => {
|
|
7083
7164
|
const { organizationId, runtimeOptions } = await resolveOsmdContext(cmd);
|
|
7084
7165
|
const result = await requestAgentMarkdownFile({
|
|
7085
7166
|
command: "osmd.wiki.read",
|
|
@@ -7102,7 +7183,7 @@ function registerOsmdCommands(program) {
|
|
|
7102
7183
|
command: "osmd.wiki.children",
|
|
7103
7184
|
runtimeOptions,
|
|
7104
7185
|
organizationId,
|
|
7105
|
-
path: typeof path === "string" && path.trim() !== "" ? normalizeWikiPath(path, { allowRoot: true }) : "Agent Wiki",
|
|
7186
|
+
path: typeof path === "string" && path.trim() !== "" ? normalizeWikiPath(path, { allowRoot: true, allowControlledFolders: true }) : "Agent Wiki",
|
|
7106
7187
|
source: "agent_wiki"
|
|
7107
7188
|
});
|
|
7108
7189
|
return printEnvelopeAndExit({
|
|
@@ -7115,7 +7196,7 @@ function registerOsmdCommands(program) {
|
|
|
7115
7196
|
});
|
|
7116
7197
|
});
|
|
7117
7198
|
addContentOptions(
|
|
7118
|
-
wiki.command("create <path>").description("Create Agent Wiki index.md after status/permission preflight")
|
|
7199
|
+
wiki.command("create <path>").description("Create Agent Wiki index.md or controlled pages after status/permission preflight")
|
|
7119
7200
|
).action(async (path, opts, cmd) => {
|
|
7120
7201
|
const globals = cmd.optsWithGlobals();
|
|
7121
7202
|
const content = await resolveContentInput(opts, globals);
|
|
@@ -7125,12 +7206,12 @@ function registerOsmdCommands(program) {
|
|
|
7125
7206
|
action: "create",
|
|
7126
7207
|
runtimeOptions,
|
|
7127
7208
|
organizationId,
|
|
7128
|
-
path:
|
|
7209
|
+
path: normalizeWikiWritablePath(path),
|
|
7129
7210
|
content
|
|
7130
7211
|
});
|
|
7131
7212
|
});
|
|
7132
7213
|
addContentOptions(
|
|
7133
|
-
wiki.command("update <path>").description("Update Agent Wiki index.md after status/permission preflight")
|
|
7214
|
+
wiki.command("update <path>").description("Update Agent Wiki index.md or controlled pages after status/permission preflight")
|
|
7134
7215
|
).action(async (path, opts, cmd) => {
|
|
7135
7216
|
const globals = cmd.optsWithGlobals();
|
|
7136
7217
|
const content = await resolveContentInput(opts, globals);
|
|
@@ -7140,7 +7221,7 @@ function registerOsmdCommands(program) {
|
|
|
7140
7221
|
action: "update",
|
|
7141
7222
|
runtimeOptions,
|
|
7142
7223
|
organizationId,
|
|
7143
|
-
path:
|
|
7224
|
+
path: normalizeWikiWritablePath(path),
|
|
7144
7225
|
content
|
|
7145
7226
|
});
|
|
7146
7227
|
});
|
package/package.json
CHANGED
|
@@ -1330,6 +1330,124 @@ function runOsmdLiveVerification() {
|
|
|
1330
1330
|
);
|
|
1331
1331
|
}
|
|
1332
1332
|
|
|
1333
|
+
const controlledWikiSearchTerm = `CLI live controlled wiki ${verifyStamp}`;
|
|
1334
|
+
const controlledWikiPages = [
|
|
1335
|
+
{
|
|
1336
|
+
path: `concepts/cli-live-concept-${verifyStamp}.md`,
|
|
1337
|
+
fullPath: `Agent Wiki/concepts/cli-live-concept-${verifyStamp}.md`,
|
|
1338
|
+
wikiRole: "concept",
|
|
1339
|
+
title: "concept"
|
|
1340
|
+
},
|
|
1341
|
+
{
|
|
1342
|
+
path: `playbooks/cli-live-playbook-${verifyStamp}.md`,
|
|
1343
|
+
fullPath: `Agent Wiki/playbooks/cli-live-playbook-${verifyStamp}.md`,
|
|
1344
|
+
wikiRole: "playbook",
|
|
1345
|
+
title: "playbook"
|
|
1346
|
+
},
|
|
1347
|
+
{
|
|
1348
|
+
path: `decisions/cli-live-decision-${verifyStamp}.md`,
|
|
1349
|
+
fullPath: `Agent Wiki/decisions/cli-live-decision-${verifyStamp}.md`,
|
|
1350
|
+
wikiRole: "decision",
|
|
1351
|
+
title: "decision"
|
|
1352
|
+
},
|
|
1353
|
+
{
|
|
1354
|
+
path: `org-summaries/cli-live-org-summary-${verifyStamp}.md`,
|
|
1355
|
+
fullPath: `Agent Wiki/org-summaries/cli-live-org-summary-${verifyStamp}.md`,
|
|
1356
|
+
wikiRole: "org_summary",
|
|
1357
|
+
title: "org_summary"
|
|
1358
|
+
}
|
|
1359
|
+
];
|
|
1360
|
+
|
|
1361
|
+
for (const page of controlledWikiPages) {
|
|
1362
|
+
const controlledStatus = runWave(["osmd", "wiki", "status", page.path], env);
|
|
1363
|
+
results.push(controlledStatus);
|
|
1364
|
+
osmdVerificationFailures += recordExactCheck({
|
|
1365
|
+
lines: osmdVerificationLines,
|
|
1366
|
+
label: `osmd.wiki status controlled ${page.title}`,
|
|
1367
|
+
result: controlledStatus,
|
|
1368
|
+
ok:
|
|
1369
|
+
controlledStatus.parsed?.ok === true &&
|
|
1370
|
+
controlledStatus.parsed?.data?.path === page.fullPath &&
|
|
1371
|
+
controlledStatus.parsed?.data?.source === "agent_wiki" &&
|
|
1372
|
+
controlledStatus.parsed?.data?.access === "read_write" &&
|
|
1373
|
+
controlledStatus.parsed?.data?.wikiRole === page.wikiRole &&
|
|
1374
|
+
controlledStatus.parsed?.data?.formatVersion === "agent_markdown_v1" &&
|
|
1375
|
+
controlledStatus.parsed?.data?.exists === false &&
|
|
1376
|
+
controlledStatus.parsed?.data?.canCreate === true &&
|
|
1377
|
+
controlledStatus.parsed?.data?.canUpdate === false &&
|
|
1378
|
+
controlledStatus.parsed?.data?.canAppend === false &&
|
|
1379
|
+
controlledStatus.parsed?.data?.suggestedAction === "create",
|
|
1380
|
+
reason: "agent_wiki_controlled_status"
|
|
1381
|
+
});
|
|
1382
|
+
|
|
1383
|
+
const createContent = `# CLI Live ${page.title}\n\n${controlledWikiSearchTerm} create ${page.title}`;
|
|
1384
|
+
const controlledCreate = runWave(["osmd", "wiki", "create", page.path, "--content", createContent], env);
|
|
1385
|
+
results.push(controlledCreate);
|
|
1386
|
+
osmdVerificationFailures += recordExactCheck({
|
|
1387
|
+
lines: osmdVerificationLines,
|
|
1388
|
+
label: `osmd.wiki create controlled ${page.title}`,
|
|
1389
|
+
result: controlledCreate,
|
|
1390
|
+
ok:
|
|
1391
|
+
controlledCreate.parsed?.ok === true &&
|
|
1392
|
+
controlledCreate.parsed?.data?.path === page.fullPath &&
|
|
1393
|
+
controlledCreate.parsed?.data?.source === "agent_wiki" &&
|
|
1394
|
+
controlledCreate.parsed?.data?.wikiRole === page.wikiRole &&
|
|
1395
|
+
controlledCreate.parsed?.data?.formatVersion === "agent_markdown_v1" &&
|
|
1396
|
+
controlledCreate.parsed?.data?.exists === true &&
|
|
1397
|
+
controlledCreate.parsed?.data?.canUpdate === true &&
|
|
1398
|
+
controlledCreate.parsed?.data?.canAppend === false &&
|
|
1399
|
+
controlledCreate.parsed?.data?.content === createContent,
|
|
1400
|
+
reason: "agent_wiki_controlled_create"
|
|
1401
|
+
});
|
|
1402
|
+
|
|
1403
|
+
const updateContent = `# CLI Live ${page.title}\n\n${controlledWikiSearchTerm} update ${page.title}`;
|
|
1404
|
+
const controlledUpdate = runWave(["osmd", "wiki", "update", page.path, "--content", updateContent], env);
|
|
1405
|
+
results.push(controlledUpdate);
|
|
1406
|
+
osmdVerificationFailures += recordExactCheck({
|
|
1407
|
+
lines: osmdVerificationLines,
|
|
1408
|
+
label: `osmd.wiki update controlled ${page.title}`,
|
|
1409
|
+
result: controlledUpdate,
|
|
1410
|
+
ok:
|
|
1411
|
+
controlledUpdate.parsed?.ok === true &&
|
|
1412
|
+
controlledUpdate.parsed?.data?.path === page.fullPath &&
|
|
1413
|
+
controlledUpdate.parsed?.data?.source === "agent_wiki" &&
|
|
1414
|
+
controlledUpdate.parsed?.data?.wikiRole === page.wikiRole &&
|
|
1415
|
+
controlledUpdate.parsed?.data?.formatVersion === "agent_markdown_v1" &&
|
|
1416
|
+
controlledUpdate.parsed?.data?.exists === true &&
|
|
1417
|
+
controlledUpdate.parsed?.data?.canUpdate === true &&
|
|
1418
|
+
controlledUpdate.parsed?.data?.canAppend === false &&
|
|
1419
|
+
controlledUpdate.parsed?.data?.content === updateContent,
|
|
1420
|
+
reason: "agent_wiki_controlled_update"
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
const logUpdateRejected = runWave(["osmd", "wiki", "update", "log.md", "--content", "verify forbidden"], env);
|
|
1425
|
+
osmdVerificationFailures += recordExactCheck({
|
|
1426
|
+
lines: osmdVerificationLines,
|
|
1427
|
+
label: "osmd.wiki update rejects log locally",
|
|
1428
|
+
result: logUpdateRejected,
|
|
1429
|
+
ok:
|
|
1430
|
+
logUpdateRejected.parsed?.ok === false &&
|
|
1431
|
+
logUpdateRejected.parsed?.status === 400 &&
|
|
1432
|
+
logUpdateRejected.parsed?.error?.code === "invalid_args",
|
|
1433
|
+
reason: "agent_wiki_log_update_local_reject"
|
|
1434
|
+
});
|
|
1435
|
+
|
|
1436
|
+
const arbitraryWikiRejected = runWave(
|
|
1437
|
+
["osmd", "wiki", "create", "random/cli-live-random.md", "--content", "verify forbidden"],
|
|
1438
|
+
env
|
|
1439
|
+
);
|
|
1440
|
+
osmdVerificationFailures += recordExactCheck({
|
|
1441
|
+
lines: osmdVerificationLines,
|
|
1442
|
+
label: "osmd.wiki create rejects arbitrary wiki path locally",
|
|
1443
|
+
result: arbitraryWikiRejected,
|
|
1444
|
+
ok:
|
|
1445
|
+
arbitraryWikiRejected.parsed?.ok === false &&
|
|
1446
|
+
arbitraryWikiRejected.parsed?.status === 400 &&
|
|
1447
|
+
arbitraryWikiRejected.parsed?.error?.code === "invalid_args",
|
|
1448
|
+
reason: "agent_wiki_arbitrary_path_local_reject"
|
|
1449
|
+
});
|
|
1450
|
+
|
|
1333
1451
|
const parentRef = resolveOsmdAgentParentRef();
|
|
1334
1452
|
if (!parentRef) {
|
|
1335
1453
|
osmdVerificationLines.push(
|
|
@@ -1452,6 +1570,55 @@ function runOsmdLiveVerification() {
|
|
|
1452
1570
|
reason: "osmd_search_agent_wiki"
|
|
1453
1571
|
});
|
|
1454
1572
|
|
|
1573
|
+
const controlledWikiSearch = runWave(
|
|
1574
|
+
["osmd", "search", controlledWikiSearchTerm, "--scope", "agent-wiki-only", "--limit", "10"],
|
|
1575
|
+
env
|
|
1576
|
+
);
|
|
1577
|
+
results.push(controlledWikiSearch);
|
|
1578
|
+
const controlledWikiSearchCandidates = searchCandidates(controlledWikiSearch);
|
|
1579
|
+
osmdVerificationFailures += recordExactCheck({
|
|
1580
|
+
lines: osmdVerificationLines,
|
|
1581
|
+
label: "osmd.search Agent Wiki controlled pages",
|
|
1582
|
+
result: controlledWikiSearch,
|
|
1583
|
+
ok:
|
|
1584
|
+
controlledWikiSearch.parsed?.ok === true &&
|
|
1585
|
+
controlledWikiSearch.parsed?.data?.scope === "agent_wiki" &&
|
|
1586
|
+
controlledWikiPages.every((page) =>
|
|
1587
|
+
controlledWikiSearchCandidates.some(
|
|
1588
|
+
(candidate) =>
|
|
1589
|
+
hasSearchMetadata(candidate, "agent_wiki") &&
|
|
1590
|
+
candidate.path === page.fullPath &&
|
|
1591
|
+
candidate.wikiRole === page.wikiRole &&
|
|
1592
|
+
candidate.access === "read_write"
|
|
1593
|
+
)
|
|
1594
|
+
),
|
|
1595
|
+
reason: "osmd_search_agent_wiki_controlled_pages"
|
|
1596
|
+
});
|
|
1597
|
+
|
|
1598
|
+
const controlledCombinedSearch = runWave(
|
|
1599
|
+
["osmd", "search", controlledWikiSearchTerm, "--scope", "combined", "--limit", "10"],
|
|
1600
|
+
env
|
|
1601
|
+
);
|
|
1602
|
+
results.push(controlledCombinedSearch);
|
|
1603
|
+
const controlledCombinedSearchCandidates = searchCandidates(controlledCombinedSearch);
|
|
1604
|
+
osmdVerificationFailures += recordExactCheck({
|
|
1605
|
+
lines: osmdVerificationLines,
|
|
1606
|
+
label: "osmd.search combined includes controlled Agent Wiki pages",
|
|
1607
|
+
result: controlledCombinedSearch,
|
|
1608
|
+
ok:
|
|
1609
|
+
controlledCombinedSearch.parsed?.ok === true &&
|
|
1610
|
+
controlledCombinedSearch.parsed?.data?.scope === "combined" &&
|
|
1611
|
+
controlledWikiPages.some((page) =>
|
|
1612
|
+
controlledCombinedSearchCandidates.some(
|
|
1613
|
+
(candidate) =>
|
|
1614
|
+
hasSearchMetadata(candidate, "agent_wiki") &&
|
|
1615
|
+
candidate.path === page.fullPath &&
|
|
1616
|
+
candidate.wikiRole === page.wikiRole
|
|
1617
|
+
)
|
|
1618
|
+
),
|
|
1619
|
+
reason: "osmd_search_combined_controlled_pages"
|
|
1620
|
+
});
|
|
1621
|
+
|
|
1455
1622
|
const logSearch = runWave(
|
|
1456
1623
|
["osmd", "search", `CLI live verify log ${verifyStamp}`, "--scope", "agent-wiki-only", "--limit", "5"],
|
|
1457
1624
|
env
|