@aws/agentcore 0.22.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap +2 -2
  2. package/dist/assets/agents/AGENTS.md +1 -1
  3. package/dist/assets/python/http/strands/base/model/load.py +1 -1
  4. package/dist/cli/index.mjs +557 -530
  5. package/dist/lib/constants.d.ts +8 -4
  6. package/dist/lib/constants.d.ts.map +1 -1
  7. package/dist/lib/constants.js +13 -7
  8. package/dist/lib/constants.js.map +1 -1
  9. package/dist/lib/packaging/build-args.d.ts +6 -0
  10. package/dist/lib/packaging/build-args.d.ts.map +1 -1
  11. package/dist/lib/packaging/build-args.js +9 -0
  12. package/dist/lib/packaging/build-args.js.map +1 -1
  13. package/dist/lib/packaging/build-context-dockerignore.d.ts +23 -0
  14. package/dist/lib/packaging/build-context-dockerignore.d.ts.map +1 -0
  15. package/dist/lib/packaging/build-context-dockerignore.js +63 -0
  16. package/dist/lib/packaging/build-context-dockerignore.js.map +1 -0
  17. package/dist/lib/packaging/build-context.d.ts +21 -0
  18. package/dist/lib/packaging/build-context.d.ts.map +1 -0
  19. package/dist/lib/packaging/build-context.js +21 -0
  20. package/dist/lib/packaging/build-context.js.map +1 -0
  21. package/dist/lib/packaging/container.d.ts.map +1 -1
  22. package/dist/lib/packaging/container.js +15 -4
  23. package/dist/lib/packaging/container.js.map +1 -1
  24. package/dist/lib/packaging/index.d.ts +2 -0
  25. package/dist/lib/packaging/index.d.ts.map +1 -1
  26. package/dist/lib/packaging/index.js +5 -1
  27. package/dist/lib/packaging/index.js.map +1 -1
  28. package/dist/lib/schemas/io/config-io.d.ts +8 -0
  29. package/dist/lib/schemas/io/config-io.d.ts.map +1 -1
  30. package/dist/lib/schemas/io/config-io.js +12 -0
  31. package/dist/lib/schemas/io/config-io.js.map +1 -1
  32. package/dist/schema/schemas/agent-env.d.ts +22 -0
  33. package/dist/schema/schemas/agent-env.d.ts.map +1 -1
  34. package/dist/schema/schemas/agent-env.js +117 -15
  35. package/dist/schema/schemas/agent-env.js.map +1 -1
  36. package/dist/schema/schemas/agentcore-project.d.ts +24 -10
  37. package/dist/schema/schemas/agentcore-project.d.ts.map +1 -1
  38. package/dist/schema/schemas/agentcore-project.js +19 -6
  39. package/dist/schema/schemas/agentcore-project.js.map +1 -1
  40. package/dist/schema/schemas/aws-targets.d.ts +12 -0
  41. package/dist/schema/schemas/aws-targets.d.ts.map +1 -1
  42. package/dist/schema/schemas/aws-targets.js +4 -0
  43. package/dist/schema/schemas/aws-targets.js.map +1 -1
  44. package/dist/schema/schemas/mcp.d.ts +29 -18
  45. package/dist/schema/schemas/mcp.d.ts.map +1 -1
  46. package/dist/schema/schemas/mcp.js +29 -175
  47. package/dist/schema/schemas/mcp.js.map +1 -1
  48. package/npm-shrinkwrap.json +2 -2
  49. package/package.json +1 -1
  50. package/scripts/extract-cli-model.mjs +228 -0
  51. package/scripts/render_adoc.py +274 -0
@@ -0,0 +1,228 @@
1
+ #!/usr/bin/env node
2
+ // =============================================================================
3
+ // extract-cli-model.mjs — agentcore CLI -> doc-model JSON
4
+ // =============================================================================
5
+ // Runs `agentcore <cmd> --help` for every command, parses the Commander.js help
6
+ // output, and emits the SAME shared doc-model schema (v1) as the SDK extractors
7
+ // so the one shared renderer (_shared/render_adoc.py) produces consistent .adoc.
8
+ //
9
+ // Why --help scraping (not AST): it is 1:1 with what users actually see, and it
10
+ // survives refactors of the command source. Commander.js help is
11
+ // stable and easy to parse (Usage / Arguments / Options blocks).
12
+ //
13
+ // Decision: ALL ~30 commands, arranged into groups (one group == one .adoc).
14
+ //
15
+ // NOTE: if these workflows are later consolidated into a single shared reusable
16
+ // workflow, this script is vendored there and selected via `language: cli`.
17
+ // Standalone here for the draft.
18
+ // =============================================================================
19
+ import { execFileSync } from 'node:child_process';
20
+ import { writeFileSync } from 'node:fs';
21
+ import { argv } from 'node:process';
22
+
23
+ // Command grouping (arranged properly, per the request). Mirrors the sections
24
+ // in agentcore-cli/docs/commands.md. Any command discovered from the binary but
25
+ // not listed here lands in the "Other" group so nothing is silently dropped.
26
+ const GROUPS = [
27
+ {
28
+ id: 'project-lifecycle',
29
+ title: 'Project Lifecycle',
30
+ commands: ['create', 'deploy', 'dev', 'package', 'export', 'update', 'validate'],
31
+ },
32
+ {
33
+ id: 'invocation',
34
+ title: 'Invocation & Runtime',
35
+ commands: ['invoke', 'exec', 'run', 'logs', 'traces', 'status', 'fetch', 'view'],
36
+ },
37
+ {
38
+ id: 'resources',
39
+ title: 'Resource Management',
40
+ commands: ['add', 'remove', 'import'],
41
+ },
42
+ {
43
+ id: 'evaluation',
44
+ title: 'Evaluation & Datasets',
45
+ commands: ['evals', 'batch-evaluations', 'dataset'],
46
+ },
47
+ {
48
+ id: 'optimization',
49
+ title: 'Optimization & Config Bundles',
50
+ commands: ['config-bundle', 'promote', 'archive'],
51
+ },
52
+ {
53
+ id: 'operations',
54
+ title: 'Operations & Settings',
55
+ commands: ['pause', 'resume', 'stop', 'config', 'telemetry', 'feedback'],
56
+ },
57
+ ];
58
+
59
+ // AGENTCORE_BIN may be a single command ("agentcore") OR a multi-token
60
+ // invocation ("node /path/to/index.mjs"). Split into [executable, ...prefixArgs]
61
+ // so execFileSync gets a real executable and forwards the rest as args —
62
+ // passing the whole string as argv[0] would make execFileSync look for an
63
+ // executable literally named "node /path/...", which fails silently to empty.
64
+ const BIN_TOKENS = (process.env.AGENTCORE_BIN || 'agentcore').split(/\s+/);
65
+ const BIN = BIN_TOKENS[0];
66
+ const BIN_PREFIX_ARGS = BIN_TOKENS.slice(1);
67
+
68
+ function getArg(flag) {
69
+ const i = argv.indexOf(flag);
70
+ return i >= 0 ? argv[i + 1] : undefined;
71
+ }
72
+
73
+ function help(args) {
74
+ try {
75
+ return execFileSync(BIN, [...BIN_PREFIX_ARGS, ...args, '--help'], {
76
+ encoding: 'utf8',
77
+ // CLI launches a TUI without args; --help forces non-interactive text.
78
+ env: { ...process.env, NO_COLOR: '1', CI: '1' },
79
+ stdio: ['ignore', 'pipe', 'pipe'],
80
+ });
81
+ } catch (e) {
82
+ // Commander exits non-zero for some help paths; stdout still holds text.
83
+ return (e.stdout && e.stdout.toString()) || '';
84
+ }
85
+ }
86
+
87
+ // Parse a Commander.js help blob into { summary, signature, params, options }.
88
+ function parseHelp(text, name) {
89
+ const lines = text.split('\n');
90
+ const out = { summary: '', signature: '', args: [], options: [] };
91
+ let section = 'head';
92
+ const descLines = [];
93
+
94
+ for (const raw of lines) {
95
+ const line = raw.replace(/\s+$/, '');
96
+ if (/^Usage:/.test(line)) {
97
+ out.signature = line.replace(/^Usage:\s*/, '').trim();
98
+ section = 'desc';
99
+ continue;
100
+ }
101
+ if (/^Arguments:/.test(line)) {
102
+ section = 'args';
103
+ continue;
104
+ }
105
+ if (/^Options:/.test(line)) {
106
+ section = 'options';
107
+ continue;
108
+ }
109
+ if (/^Commands:/.test(line)) {
110
+ section = 'commands';
111
+ continue;
112
+ }
113
+
114
+ if (section === 'desc') {
115
+ if (line.trim()) descLines.push(line.trim());
116
+ } else if (section === 'args') {
117
+ const m = line.match(/^\s+(\S+)\s{2,}(.*)$/);
118
+ if (m) out.args.push({ name: m[1], type: null, required: true, description: m[2].trim() });
119
+ } else if (section === 'options') {
120
+ const m = line.match(/^\s+(-[^\s].*?)\s{2,}(.*)$/);
121
+ if (m) out.options.push({ name: m[1].trim(), type: null, required: false, description: m[2].trim() });
122
+ }
123
+ }
124
+ out.summary = descLines.join(' ');
125
+ return out;
126
+ }
127
+
128
+ function entryForCommand(name) {
129
+ const raw = help([name]);
130
+ // Fail loudly on phantom commands / drift. A real command's help names itself
131
+ // in the usage line (`Usage: agentcore <name> ...`); an unknown command falls
132
+ // back to the root usage (`Usage: agentcore [options] [command]`), which does
133
+ // NOT contain the name. Without this guard such commands would silently render
134
+ // as empty stubs (synthesized signature, no description/params).
135
+ if (!new RegExp(`^Usage:\\s+agentcore\\s+${name}\\b`, 'm').test(raw)) {
136
+ throw new Error(
137
+ `Command "${name}" produced no self-describing help output — it is likely ` +
138
+ `not a real CLI command (phantom/renamed). Remove it from GROUPS or fix the name.`
139
+ );
140
+ }
141
+ const parsed = parseHelp(raw, name);
142
+ // subcommands (e.g. `add agent`, `remove tool`) show under "Commands:"—
143
+ // we surface the top-level command; nested ones can be expanded later.
144
+ return {
145
+ kind: 'command',
146
+ name: `agentcore ${name}`,
147
+ signature: parsed.signature || `agentcore ${name} [options]`,
148
+ summary: parsed.summary,
149
+ description: '',
150
+ // reuse params for both positional args and flags, flagged by required.
151
+ // The renderer already wraps param names in backticks, so don't add our
152
+ // own (that produced double-backticks). Drop the ubiquitous help flag.
153
+ params: [...parsed.args, ...parsed.options.filter(o => !/^-h,?\s|--help\b/.test(o.name))],
154
+ returns: null,
155
+ raises: [],
156
+ examples: [],
157
+ members: [],
158
+ };
159
+ }
160
+
161
+ function discoverCommands() {
162
+ // Parse the root help "Commands:" block so we don't miss anything new.
163
+ // In Commander output, a command entry starts at EXACTLY 2 spaces of indent
164
+ // (e.g. " deploy|dp [options] ...") while wrapped description lines are
165
+ // indented much deeper (~36 spaces). Matching only the 2-space indent avoids
166
+ // scraping the first word of a wrapped description ("locally", "past", ...).
167
+ // We also strip the "|alias" and trailing "[options]"/"<arg>" tokens.
168
+ const text = help([]);
169
+ const found = [];
170
+ let inCmds = false;
171
+ for (const line of text.split('\n')) {
172
+ if (/^Commands:/.test(line)) {
173
+ inCmds = true;
174
+ continue;
175
+ }
176
+ if (!inCmds) continue;
177
+ // stop if we hit a new top-level section (e.g. a footer) — non-indented text
178
+ if (line.trim() && !/^ {2}\S/.test(line) && !/^ {3,}/.test(line)) break;
179
+ const m = line.match(/^ {2}([a-z][a-z0-9-]*)(?:\|[a-z0-9-]+)?\b/);
180
+ if (m) found.push(m[1]);
181
+ }
182
+ return found;
183
+ }
184
+
185
+ function main() {
186
+ const outPath = getArg('--out');
187
+ const version = getArg('--version') || 'unknown';
188
+
189
+ const discovered = new Set(discoverCommands());
190
+ const placed = new Set();
191
+ const groups = [];
192
+
193
+ for (const g of GROUPS) {
194
+ const entries = [];
195
+ for (const cmd of g.commands) {
196
+ entries.push(entryForCommand(cmd));
197
+ placed.add(cmd);
198
+ }
199
+ groups.push({ id: g.id, title: g.title, summary: '', entries });
200
+ }
201
+
202
+ // Built-in meta-commands we intentionally don't document as API surface.
203
+ const IGNORED = new Set(['help']);
204
+
205
+ // Catch anything the binary exposes that we didn't group — no silent drops.
206
+ const leftovers = [...discovered].filter(c => !placed.has(c) && !IGNORED.has(c));
207
+ if (leftovers.length) {
208
+ process.stderr.write(`WARNING: ungrouped commands -> "Other": ${leftovers.join(', ')}\n`);
209
+ groups.push({
210
+ id: 'other',
211
+ title: 'Other Commands',
212
+ summary: '',
213
+ entries: leftovers.map(entryForCommand),
214
+ });
215
+ }
216
+
217
+ const model = {
218
+ source: 'cli',
219
+ package: '@aws/agentcore',
220
+ version,
221
+ language: 'cli',
222
+ groups,
223
+ };
224
+ writeFileSync(outPath, JSON.stringify(model, null, 2));
225
+ process.stderr.write(`Wrote doc-model: ${groups.length} groups, version ${version}\n`);
226
+ }
227
+
228
+ main();
@@ -0,0 +1,274 @@
1
+ #!/usr/bin/env python3
2
+ # =============================================================================
3
+ # render_adoc.py — shared doc-model -> AsciiDoc renderer
4
+ # =============================================================================
5
+ # Renders a normalized "doc-model" JSON (produced by any of the three
6
+ # extractors) into .adoc files for the documentation repository.
7
+ #
8
+ # It is deliberately source-agnostic: the Python extractor, the TypeScript
9
+ # TypeDoc extractor, and the CLI --help extractor all emit the SAME doc-model
10
+ # schema, so this one renderer produces consistent output for all three.
11
+ #
12
+ # NOTE: if these workflows are later consolidated into a single shared reusable
13
+ # workflow, this file is vendored there ONCE and every source repo's caller
14
+ # invokes it. Keep it dependency-free (stdlib only) so it drops cleanly into any
15
+ # runner.
16
+ #
17
+ # -----------------------------------------------------------------------------
18
+ # doc-model schema (v1) — the contract every extractor must emit:
19
+ # {
20
+ # "source": "python-sdk" | "ts-sdk" | "cli",
21
+ # "package": "bedrock-agentcore",
22
+ # "version": "1.16.0",
23
+ # "language": "python" | "typescript" | "cli",
24
+ # "groups": [ # a group -> one .adoc file
25
+ # {
26
+ # "id": "runtime", # -> <prefix>-runtime.adoc, and anchor id
27
+ # "title": "Runtime",
28
+ # "summary": "Runtime management and application context.",
29
+ # "entries": [ # classes / functions / commands
30
+ # {
31
+ # "kind": "class" | "function" | "command",
32
+ # "name": "BedrockAgentCoreApp",
33
+ # "signature": "BedrockAgentCoreApp(params)",
34
+ # "summary": "one-line summary",
35
+ # "description": "longer prose (optional)",
36
+ # "params": [ {"name","type","required","description"} ],
37
+ # "returns": {"type","description"} | null,
38
+ # "raises": [ {"type","description"} ],
39
+ # "examples": [ {"lang","code"} ],
40
+ # "members": [ <entry>, ... ] # methods on a class (recursive)
41
+ # }
42
+ # ]
43
+ # }
44
+ # ]
45
+ # }
46
+ # -----------------------------------------------------------------------------
47
+
48
+ import argparse
49
+ import json
50
+ import os
51
+ import re
52
+ import sys
53
+ import textwrap
54
+
55
+ SCHEMA_VERSION = 1
56
+
57
+
58
+ def esc(text):
59
+ """Escape AsciiDoc-significant characters in inline text."""
60
+ if not text:
61
+ return ""
62
+ # Guard the couple of chars that start AsciiDoc markup in running prose.
63
+ return (
64
+ text.replace("|", "\\|")
65
+ .replace("{", "\\{")
66
+ )
67
+
68
+
69
+ # Match markdown code fences that may be indented (reST/Google docstrings often
70
+ # indent example blocks). `re.MULTILINE` lets ^ match each line start; the
71
+ # leading-whitespace groups are stripped from the captured code.
72
+ _FENCE_RE = re.compile(r"^[ \t]*```(\w*)[ \t]*\n(.*?)\n[ \t]*```[ \t]*$", re.DOTALL | re.MULTILINE)
73
+
74
+
75
+ def render_prose(text):
76
+ """Render description prose that may contain markdown ``` code fences.
77
+
78
+ Docstrings/TSDoc frequently embed fenced code blocks in the description
79
+ (not just in @example). Left alone they leak literal backticks into the
80
+ AsciiDoc. Split the prose on fences: escape the prose spans, and convert
81
+ each fenced block into an AsciiDoc [source] block (verbatim, not escaped).
82
+ """
83
+ if not text:
84
+ return []
85
+ out = []
86
+ pos = 0
87
+ for m in _FENCE_RE.finditer(text):
88
+ before = text[pos:m.start()].strip()
89
+ if before:
90
+ out.append(esc(before))
91
+ out.append("")
92
+ lang = m.group(1) or ""
93
+ out.append(f"[source,{lang}]" if lang else "[source]")
94
+ out.append("----")
95
+ # Dedent the captured code (fences are often indented in docstrings).
96
+ out.append(textwrap.dedent(m.group(2)).rstrip())
97
+ out.append("----")
98
+ out.append("")
99
+ pos = m.end()
100
+ tail = text[pos:].strip()
101
+ if tail:
102
+ out.append(esc(tail))
103
+ return out
104
+
105
+
106
+ def block(lines):
107
+ return "\n".join(lines)
108
+
109
+
110
+ def render_params(params, out):
111
+ if not params:
112
+ return
113
+ out.append("*Parameters*")
114
+ out.append("")
115
+ for p in params:
116
+ req = "" if p.get("required") else " _(optional)_"
117
+ typ = f"`{p['type']}`" if p.get("type") else ""
118
+ out.append(f"`{p['name']}`{req} {typ}::")
119
+ out.append(esc(p.get("description", "")) or "_No description._")
120
+ out.append("")
121
+
122
+
123
+ def render_returns(returns, out):
124
+ if not returns:
125
+ return
126
+ typ = f"`{returns['type']}` — " if returns.get("type") else ""
127
+ out.append("*Returns*")
128
+ out.append("")
129
+ out.append(f"{typ}{esc(returns.get('description', ''))}".strip())
130
+ out.append("")
131
+
132
+
133
+ def render_raises(raises, out):
134
+ if not raises:
135
+ return
136
+ out.append("*Raises*")
137
+ out.append("")
138
+ for r in raises:
139
+ out.append(f"`{r.get('type', 'Error')}`:: {esc(r.get('description', ''))}")
140
+ out.append("")
141
+
142
+
143
+ def clean_example_code(code):
144
+ """Strip stray markdown fence lines from example code.
145
+
146
+ Extractors try to remove ``` fences, but real docstrings put them mid-buffer
147
+ (e.g. a fence followed by extra "Notes:"/"Thread Safety:" prose swept into
148
+ the example). Since this text is already going inside an AsciiDoc [source]
149
+ block, any line that is just a fence is spurious — drop it, and drop trailing
150
+ non-code prose that follows a closing fence.
151
+ """
152
+ lines = code.split("\n")
153
+ kept = []
154
+ closed = False
155
+ for line in lines:
156
+ if re.match(r"^[ \t]*```", line):
157
+ # A closing fence marks the end of the real code; ignore the fence
158
+ # line itself and stop taking subsequent prose.
159
+ if kept:
160
+ closed = True
161
+ continue
162
+ if closed and line.strip() == "":
163
+ continue
164
+ if closed and line.strip():
165
+ break # prose after the closing fence — not part of the example
166
+ kept.append(line)
167
+ return textwrap.dedent("\n".join(kept)).strip()
168
+
169
+
170
+ def render_examples(examples, out):
171
+ for ex in examples or []:
172
+ lang = ex.get("lang", "text")
173
+ code = clean_example_code(ex.get("code", ""))
174
+ if not code:
175
+ continue
176
+ out.append(f"[source,{lang}]")
177
+ out.append("----")
178
+ out.append(code)
179
+ out.append("----")
180
+ out.append("")
181
+
182
+
183
+ def render_entry(entry, level, out):
184
+ """Render a single class/function/command as an AsciiDoc section."""
185
+ heading = "=" * level
186
+ name = entry.get("name", "")
187
+ out.append(f"{heading} {name}")
188
+ out.append("")
189
+
190
+ sig = entry.get("signature")
191
+ if sig:
192
+ out.append("[source]")
193
+ out.append("----")
194
+ out.append(sig)
195
+ out.append("----")
196
+ out.append("")
197
+
198
+ if entry.get("summary"):
199
+ out.extend(render_prose(entry["summary"]))
200
+ out.append("")
201
+ if entry.get("description"):
202
+ out.extend(render_prose(entry["description"]))
203
+ out.append("")
204
+
205
+ render_params(entry.get("params"), out)
206
+ render_returns(entry.get("returns"), out)
207
+ render_raises(entry.get("raises"), out)
208
+ render_examples(entry.get("examples"), out)
209
+
210
+ # methods / subcommands nest one heading level deeper
211
+ for member in entry.get("members", []):
212
+ render_entry(member, level + 1, out)
213
+
214
+
215
+ def render_group(group, model, prefix):
216
+ """Render one group -> one .adoc file body (string)."""
217
+ out = []
218
+ gid = group["id"]
219
+ # AsciiDoc anchor so the TOC / other pages can xref into it.
220
+ out.append(f"[[{prefix}-{gid}]]")
221
+ out.append(f"= {group['title']}")
222
+ out.append("")
223
+ out.append(
224
+ f"_Auto-generated from `{model['package']}` "
225
+ f"v{model['version']} — do not edit by hand._"
226
+ )
227
+ out.append("")
228
+ if group.get("summary"):
229
+ out.extend(render_prose(group["summary"]))
230
+ out.append("")
231
+
232
+ for entry in group.get("entries", []):
233
+ render_entry(entry, level=2, out=out)
234
+
235
+ return block(out).rstrip() + "\n"
236
+
237
+
238
+ def main():
239
+ ap = argparse.ArgumentParser(description="Render doc-model JSON to .adoc")
240
+ ap.add_argument("--model", required=True, help="path to doc-model JSON")
241
+ ap.add_argument("--out-dir", required=True, help="output dir for .adoc files")
242
+ ap.add_argument(
243
+ "--prefix",
244
+ required=True,
245
+ help="filename + anchor prefix, e.g. 'python-sdk', 'ts-sdk', 'cli'",
246
+ )
247
+ args = ap.parse_args()
248
+
249
+ with open(args.model) as f:
250
+ model = json.load(f)
251
+
252
+ os.makedirs(args.out_dir, exist_ok=True)
253
+ written = []
254
+ for group in model.get("groups", []):
255
+ body = render_group(group, model, args.prefix)
256
+ fname = f"{args.prefix}-{group['id']}.adoc"
257
+ path = os.path.join(args.out_dir, fname)
258
+ with open(path, "w") as f:
259
+ f.write(body)
260
+ written.append(fname)
261
+
262
+ # Emit the list of includes the caller can splice into the docs TOC file.
263
+ manifest = os.path.join(args.out_dir, f"{args.prefix}-includes.txt")
264
+ with open(manifest, "w") as f:
265
+ for fname in written:
266
+ f.write(f"include::{args.prefix}/{fname}[leveloffset=+1]\n")
267
+
268
+ print(f"Rendered {len(written)} .adoc files to {args.out_dir}", file=sys.stderr)
269
+ for fname in written:
270
+ print(f" - {fname}", file=sys.stderr)
271
+
272
+
273
+ if __name__ == "__main__":
274
+ main()