@pptb/types 1.2.2-beta.0 → 1.2.2-beta.1

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
@@ -8,6 +8,7 @@ TypeScript type definitions for Power Platform ToolBox APIs, plus a built-in CLI
8
8
  - [Quick start](#quick-start)
9
9
  - [CLI options](#cli-options)
10
10
  - [What is validated](#what-is-validated)
11
+ - [pptb.config.json (optional)](#pptbconfigjson-optional)
11
12
  - [Overview](#overview)
12
13
  - [Usage](#usage)
13
14
  - [Include all type definitions](#include-all-type-definitions)
@@ -17,6 +18,7 @@ TypeScript type definitions for Power Platform ToolBox APIs, plus a built-in CLI
17
18
  - [Utilities](#utilities)
18
19
  - [Terminal Operations](#terminal-operations)
19
20
  - [Events](#events)
21
+ - [Inter-Tool Invocation](#inter-tool-invocation)
20
22
  - [Dataverse API Examples](#dataverse-api-examples)
21
23
  - [CRUD Operations](#crud-operations)
22
24
  - [FetchXML Queries](#fetchxml-queries)
@@ -29,6 +31,7 @@ TypeScript type definitions for Power Platform ToolBox APIs, plus a built-in CLI
29
31
  - [Utils](#utils)
30
32
  - [Terminal](#terminal)
31
33
  - [Events](#events-1)
34
+ - [Invocation](#invocation)
32
35
  - [Dataverse API (`window.dataverseAPI`)](#dataverse-api-windowdataverseapi)
33
36
  - [CRUD Operations](#crud-operations-1)
34
37
  - [Query Operations](#query-operations)
@@ -109,6 +112,43 @@ The validator checks every field that the official review pipeline inspects:
109
112
 
110
113
  > \* Required only when the `features` object is present.
111
114
 
115
+ #### pptb.config.json (optional)
116
+
117
+ In addition to `package.json`, the validator automatically checks a `pptb.config.json` file if one is present in the same directory. This file declares tool-to-tool communication contracts and other PPTB-specific metadata.
118
+
119
+ | Field | Required | Rules |
120
+ | --------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------- |
121
+ | `invocation.version` | ✅\*\* | Must be a valid **semantic version** string (e.g. `"1.0.0"`). Tool developers own this version and bump it when the invocation contract changes. |
122
+ | `invocation.prefill` | ❌ | JSON-schema-style object describing data callers can pre-populate |
123
+ | `invocation.prefill.properties` | ❌ | Map of property names to `{ type?, enum?, items? }` descriptors |
124
+ | `invocation.returnTopic` | ❌ | JSON-schema-style object describing the data this tool returns to its caller |
125
+ | `invocation.returnTopic.properties` | ❌ | Map of property names to `{ type?, enum?, items? }` descriptors |
126
+
127
+ > \*\* Required only when the `invocation` object is present.
128
+
129
+ **Example `pptb.config.json`:**
130
+
131
+ ```json
132
+ {
133
+ "invocation": {
134
+ "version": "1.0.0",
135
+ "prefill": {
136
+ "properties": {
137
+ "entityName": { "type": "string" },
138
+ "attributes": { "type": "array", "items": { "type": "string" } }
139
+ }
140
+ },
141
+ "returnTopic": {
142
+ "properties": {
143
+ "result": { "type": "object" },
144
+ "status": { "type": "string", "enum": ["success", "cancelled", "error"] },
145
+ "error": { "type": "string" }
146
+ }
147
+ }
148
+ }
149
+ }
150
+ ```
151
+
112
152
  ## Overview
113
153
 
114
154
  The `@pptb/types` package provides TypeScript definitions for two main APIs:
@@ -248,6 +288,67 @@ toolboxAPI.events.on((event, payload) => {
248
288
  const history = await toolboxAPI.events.getHistory(10); // Last 10 events
249
289
  ```
250
290
 
291
+ ### Inter-Tool Invocation
292
+
293
+ Tools can launch one another and pass data between them using the `invocation` namespace.
294
+
295
+ #### Caller: launching another tool with prefill data
296
+
297
+ ```typescript
298
+ // Tool A – launches the entity-picker tool and waits for a selection
299
+ const result = await toolboxAPI.invocation.launchTool(
300
+ "@my-org/entity-picker",
301
+ { entityName: "account", allowMultiSelect: false },
302
+ );
303
+
304
+ if (result) {
305
+ console.log("Selected record id:", (result as { selectedId: string }).selectedId);
306
+ }
307
+ ```
308
+
309
+ #### Callee: reading prefill data and returning a result
310
+
311
+ ```typescript
312
+ // Tool B (@my-org/entity-picker) – reads the context provided by Tool A
313
+ const ctx = await toolboxAPI.invocation.getLaunchContext();
314
+ if (ctx) {
315
+ const entityName = ctx.entityName as string; // "account"
316
+ // … show records from entityName …
317
+
318
+ // When the user makes their selection:
319
+ await toolboxAPI.invocation.returnData({ selectedId: "a1b2c3...", selectedName: "Contoso" });
320
+ }
321
+ ```
322
+
323
+ > **Tip:** A tool that was *not* launched by another tool receives `null` from `getLaunchContext()`.
324
+ > Use this to show a standalone UI or redirect accordingly.
325
+
326
+ #### Declaring your invocation contract
327
+
328
+ Add a `pptb.config.json` alongside your `package.json` to tell callers what data you expect and return:
329
+
330
+ ```json
331
+ {
332
+ "invocation": {
333
+ "version": "1.0.0",
334
+ "prefill": {
335
+ "properties": {
336
+ "entityName": { "type": "string" },
337
+ "allowMultiSelect": { "type": "boolean" }
338
+ }
339
+ },
340
+ "returnTopic": {
341
+ "properties": {
342
+ "selectedId": { "type": "string" },
343
+ "selectedName": { "type": "string" }
344
+ }
345
+ }
346
+ }
347
+ }
348
+ ```
349
+
350
+ Run `pptb-validate` to validate both `package.json` and `pptb.config.json` at once.
351
+
251
352
  ## Dataverse API Examples
252
353
 
253
354
  The Dataverse API provides direct access to Microsoft Dataverse operations:
@@ -495,6 +596,19 @@ Core platform features organized into namespaces:
495
596
  - **off(callback: (event: any, payload: ToolBoxEventPayload) => void)**: void
496
597
  - Removes a previously registered event listener
497
598
 
599
+ #### Invocation
600
+
601
+ - **getLaunchContext()**: Promise\<Record\<string, unknown\> | null\>
602
+ - Returns the prefill data passed by the tool that launched this tool, or `null` when not launched via inter-tool invocation
603
+
604
+ - **returnData(returnData: Record\<string, unknown\>)**: Promise\<void\>
605
+ - Sends data back to the caller tool and signals completion; no-op if not launched by another tool
606
+
607
+ - **launchTool(targetToolId, prefillData?, options?)**: Promise\<unknown\>
608
+ - Launches the specified tool, optionally with prefill data
609
+ - Returns a Promise that resolves with the data returned by the callee (or `null` if it closes without returning)
610
+ - `options.primaryConnectionId` / `options.secondaryConnectionId` – override connection for the callee
611
+
498
612
  ### Dataverse API (`window.dataverseAPI`)
499
613
 
500
614
  Complete HTTP client for interacting with Microsoft Dataverse:
@@ -16,7 +16,7 @@
16
16
 
17
17
  const fs = require("fs");
18
18
  const path = require("path");
19
- const { validatePackageJson } = require("../lib/validate");
19
+ const { validatePackageJson, validatePPTBConfig } = require("../lib/validate");
20
20
 
21
21
  // ANSI colour helpers – gracefully degrade when colours are unsupported
22
22
  const NO_COLOR = !process.stdout.isTTY || process.env.NO_COLOR;
@@ -37,7 +37,8 @@ ${c.bold("USAGE")}
37
37
  pptb-validate [options] [path/to/package.json]
38
38
 
39
39
  When no path is given the tool looks for ${c.cyan("package.json")} in the current
40
- working directory.
40
+ working directory. If a ${c.cyan("pptb.config.json")} file exists in the same directory
41
+ it is automatically validated as well.
41
42
 
42
43
  ${c.bold("OPTIONS")}
43
44
  ${c.cyan("--skip-url-checks")} Skip URL reachability checks (faster, works offline)
@@ -79,6 +80,10 @@ async function main() {
79
80
  packageJsonPath = path.resolve(process.cwd(), packageJsonPath);
80
81
  }
81
82
 
83
+ // Derive pptb.config.json path from the same directory as package.json
84
+ const toolDir = path.dirname(packageJsonPath);
85
+ const pptbConfigPath = path.join(toolDir, "pptb.config.json");
86
+
82
87
  // --- Load package.json ---
83
88
  if (!fs.existsSync(packageJsonPath)) {
84
89
  if (jsonOutput) {
@@ -102,21 +107,35 @@ async function main() {
102
107
  process.exit(1);
103
108
  }
104
109
 
110
+ // --- Load pptb.config.json (optional) ---
111
+ let pptbConfig = null;
112
+ let pptbConfigParseError = null;
113
+ if (fs.existsSync(pptbConfigPath)) {
114
+ try {
115
+ pptbConfig = JSON.parse(fs.readFileSync(pptbConfigPath, "utf8"));
116
+ } catch (err) {
117
+ pptbConfigParseError = err instanceof Error ? err.message : String(err);
118
+ }
119
+ }
120
+
105
121
  // --- Run validation ---
106
122
  if (!jsonOutput) {
107
123
  console.log();
108
124
  console.log(c.bold("Power Platform ToolBox – Tool Validator"));
109
125
  console.log(c.dim("─".repeat(45)));
110
126
  console.log(c.dim(`File: ${packageJsonPath}`));
127
+ if (pptbConfig !== null) {
128
+ console.log(c.dim(`Config: ${pptbConfigPath}`));
129
+ }
111
130
  if (skipUrlChecks) {
112
131
  console.log(c.yellow("⚠ URL reachability checks are skipped"));
113
132
  }
114
133
  console.log();
115
134
  }
116
135
 
117
- let result;
136
+ let packageResult;
118
137
  try {
119
- result = await validatePackageJson(packageJson, { skipUrlChecks });
138
+ packageResult = await validatePackageJson(packageJson, { skipUrlChecks });
120
139
  } catch (err) {
121
140
  const message = err instanceof Error ? err.message : String(err);
122
141
  if (jsonOutput) {
@@ -127,27 +146,62 @@ async function main() {
127
146
  process.exit(1);
128
147
  }
129
148
 
149
+ // --- Validate pptb.config.json if present ---
150
+ let configResult = null;
151
+ if (pptbConfigParseError !== null) {
152
+ configResult = { valid: false, errors: [`Failed to parse pptb.config.json: ${pptbConfigParseError}`], warnings: [] };
153
+ } else if (pptbConfig !== null) {
154
+ configResult = validatePPTBConfig(pptbConfig);
155
+ }
156
+
157
+ // Merge results for overall pass/fail
158
+ const allErrors = [...packageResult.errors, ...(configResult ? configResult.errors : [])];
159
+ const allWarnings = [...packageResult.warnings, ...(configResult ? configResult.warnings : [])];
160
+ const overallValid = packageResult.valid && (configResult === null || configResult.valid);
161
+
130
162
  // --- Output results ---
131
163
  if (jsonOutput) {
132
- console.log(JSON.stringify(result, null, 2));
133
- process.exit(result.valid ? 0 : 1);
164
+ const output = {
165
+ valid: overallValid,
166
+ errors: allErrors,
167
+ warnings: allWarnings,
168
+ packageInfo: packageResult.packageInfo,
169
+ configInfo: configResult ? configResult.packageInfo : undefined,
170
+ };
171
+ console.log(JSON.stringify(output, null, 2));
172
+ process.exit(overallValid ? 0 : 1);
134
173
  }
135
174
 
136
- // Human-readable output
137
- if (result.errors.length > 0) {
138
- console.log(c.bold(c.red(`Errors (${result.errors.length})`)));
139
- result.errors.forEach((e) => console.log(` ${c.red("✖")} ${e}`));
175
+ // Human-readable output – package.json section
176
+ if (packageResult.errors.length > 0) {
177
+ console.log(c.bold(c.red(`package.json Errors (${packageResult.errors.length})`)));
178
+ packageResult.errors.forEach((e) => console.log(` ${c.red("✖")} ${e}`));
140
179
  console.log();
141
180
  }
142
181
 
143
- if (result.warnings.length > 0) {
144
- console.log(c.bold(c.yellow(`Warnings (${result.warnings.length})`)));
145
- result.warnings.forEach((w) => console.log(` ${c.yellow("⚠")} ${w}`));
182
+ if (packageResult.warnings.length > 0) {
183
+ console.log(c.bold(c.yellow(`package.json Warnings (${packageResult.warnings.length})`)));
184
+ packageResult.warnings.forEach((w) => console.log(` ${c.yellow("⚠")} ${w}`));
146
185
  console.log();
147
186
  }
148
187
 
149
- if (result.valid) {
150
- const info = result.packageInfo;
188
+ // Human-readable output – pptb.config.json section
189
+ if (configResult !== null) {
190
+ if (configResult.errors.length > 0) {
191
+ console.log(c.bold(c.red(`pptb.config.json Errors (${configResult.errors.length})`)));
192
+ configResult.errors.forEach((e) => console.log(` ${c.red("✖")} ${e}`));
193
+ console.log();
194
+ }
195
+
196
+ if (configResult.warnings.length > 0) {
197
+ console.log(c.bold(c.yellow(`pptb.config.json Warnings (${configResult.warnings.length})`)));
198
+ configResult.warnings.forEach((w) => console.log(` ${c.yellow("⚠")} ${w}`));
199
+ console.log();
200
+ }
201
+ }
202
+
203
+ if (overallValid) {
204
+ const info = packageResult.packageInfo;
151
205
  console.log(c.green(c.bold("✔ Validation passed")));
152
206
  console.log();
153
207
  console.log(c.bold("Package summary"));
@@ -157,13 +211,16 @@ async function main() {
157
211
  console.log(` Display name: ${info.displayName}`);
158
212
  console.log(` Description : ${info.description}`);
159
213
  console.log(` License : ${info.license}`);
160
- console.log(` Contributors: ${info.contributors.map((c) => c.name).join(", ")}`);
214
+ console.log(` Contributors: ${info.contributors.map((contributor) => contributor.name).join(", ")}`);
161
215
  if (info.icon) {
162
216
  console.log(` Icon : ${info.icon}`);
163
217
  }
164
218
  if (info.features) {
165
219
  console.log(` Features : multiConnection=${info.features.multiConnection}${info.features.minAPI ? `, minAPI=${info.features.minAPI}` : ""}`);
166
220
  }
221
+ if (configResult !== null && configResult.packageInfo && configResult.packageInfo.invocation) {
222
+ console.log(` Invocation : version=${configResult.packageInfo.invocation.version}`);
223
+ }
167
224
  console.log();
168
225
  } else {
169
226
  console.log(c.red(c.bold("✖ Validation failed")));
@@ -172,7 +229,7 @@ async function main() {
172
229
  console.log();
173
230
  }
174
231
 
175
- process.exit(result.valid ? 0 : 1);
232
+ process.exit(overallValid ? 0 : 1);
176
233
  }
177
234
 
178
235
  main().catch((err) => {
package/index.d.ts CHANGED
@@ -16,7 +16,9 @@
16
16
 
17
17
  /// <reference path="./toolboxAPI.d.ts" />
18
18
  /// <reference path="./dataverseAPI.d.ts" />
19
+ /// <reference path="./pptbConfig.d.ts" />
19
20
 
20
21
  // Re-export all namespaces for convenience
21
22
  export * from "./dataverseAPI";
22
23
  export * from "./toolboxAPI";
24
+ export * from "./pptbConfig";
package/lib/validate.js CHANGED
@@ -33,6 +33,19 @@
33
33
  * }} ValidationResult
34
34
  */
35
35
 
36
+ /**
37
+ * @typedef {{ type?: string; enum?: string[]; items?: object }} JsonSchemaProperty
38
+ * @typedef {{ properties?: Record<string, JsonSchemaProperty> }} JsonSchemaObject
39
+ * @typedef {{
40
+ * version: string;
41
+ * prefill?: JsonSchemaObject;
42
+ * returnTopic?: JsonSchemaObject;
43
+ * }} InvocationConfig
44
+ * @typedef {{
45
+ * invocation?: InvocationConfig;
46
+ * }} PPTBConfig
47
+ */
48
+
36
49
  // List of approved open source licenses
37
50
  const APPROVED_LICENSES = ["MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "GPL-2.0", "GPL-3.0", "LGPL-3.0", "ISC", "AGPL-3.0-only"];
38
51
 
@@ -321,4 +334,110 @@ async function validatePackageJson(packageJson, options = {}) {
321
334
  };
322
335
  }
323
336
 
324
- module.exports = { validatePackageJson, isValidUrl, APPROVED_LICENSES };
337
+ module.exports = { validatePackageJson, validatePPTBConfig, isValidUrl, APPROVED_LICENSES };
338
+
339
+ /**
340
+ * Validates a tool's pptb.config.json against the official review criteria.
341
+ *
342
+ * @param {PPTBConfig} config - The parsed pptb.config.json object.
343
+ * @returns {ValidationResult}
344
+ */
345
+ function validatePPTBConfig(config) {
346
+ const errors = /** @type {string[]} */ ([]);
347
+ const warnings = /** @type {string[]} */ ([]);
348
+
349
+ if (config === null || typeof config !== "object" || Array.isArray(config)) {
350
+ errors.push("pptb.config.json must be a JSON object");
351
+ return { valid: false, errors, warnings };
352
+ }
353
+
354
+ const VALID_ROOT_KEYS = ["invocation"];
355
+ const unknownRootKeys = Object.keys(config).filter((k) => !VALID_ROOT_KEYS.includes(k));
356
+ if (unknownRootKeys.length > 0) {
357
+ warnings.push(`pptb.config.json contains unrecognised root keys: ${unknownRootKeys.join(", ")}`);
358
+ }
359
+
360
+ // Invocation section
361
+ if (config.invocation !== undefined) {
362
+ const inv = config.invocation;
363
+
364
+ if (inv === null || typeof inv !== "object" || Array.isArray(inv)) {
365
+ errors.push("invocation must be a non-array object");
366
+ } else {
367
+ // invocation.version – required, must be a valid semver string
368
+ if (inv.version === undefined || inv.version === null) {
369
+ errors.push("invocation.version is required");
370
+ } else if (typeof inv.version !== "string") {
371
+ errors.push("invocation.version must be a string");
372
+ } else if (!SEMVER_REGEX.test(inv.version)) {
373
+ errors.push(`invocation.version "${inv.version}" is not a valid semantic version string (e.g. "1.0.0")`);
374
+ }
375
+
376
+ // invocation.prefill – optional JSON-schema-like object
377
+ if (inv.prefill !== undefined) {
378
+ if (inv.prefill === null || typeof inv.prefill !== "object" || Array.isArray(inv.prefill)) {
379
+ errors.push("invocation.prefill must be a non-array object");
380
+ } else if (inv.prefill.properties !== undefined) {
381
+ validateJsonSchemaProperties("invocation.prefill", inv.prefill.properties, errors);
382
+ }
383
+ }
384
+
385
+ // invocation.returnTopic – optional JSON-schema-like object
386
+ if (inv.returnTopic !== undefined) {
387
+ if (inv.returnTopic === null || typeof inv.returnTopic !== "object" || Array.isArray(inv.returnTopic)) {
388
+ errors.push("invocation.returnTopic must be a non-array object");
389
+ } else if (inv.returnTopic.properties !== undefined) {
390
+ validateJsonSchemaProperties("invocation.returnTopic", inv.returnTopic.properties, errors);
391
+ }
392
+ }
393
+ }
394
+ }
395
+
396
+ const valid = errors.length === 0;
397
+
398
+ return {
399
+ valid,
400
+ errors,
401
+ warnings,
402
+ packageInfo: valid
403
+ ? {
404
+ invocation: config.invocation,
405
+ }
406
+ : undefined,
407
+ };
408
+ }
409
+
410
+ /**
411
+ * Validates a JSON-schema-style `properties` map used inside invocation sections.
412
+ * Only performs basic structural validation; full JSON Schema validation is not required.
413
+ *
414
+ * @param {string} fieldName
415
+ * @param {unknown} properties
416
+ * @param {string[]} errors
417
+ */
418
+ function validateJsonSchemaProperties(fieldName, properties, errors) {
419
+ if (properties === null || typeof properties !== "object" || Array.isArray(properties)) {
420
+ errors.push(`${fieldName}.properties must be a non-array object`);
421
+ return;
422
+ }
423
+
424
+ const propsRecord = /** @type {Record<string, unknown>} */ (properties);
425
+
426
+ for (const [key, value] of Object.entries(propsRecord)) {
427
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
428
+ errors.push(`${fieldName}.properties.${key} must be an object`);
429
+ continue;
430
+ }
431
+ const prop = /** @type {Record<string, unknown>} */ (value);
432
+ if (prop.type !== undefined && typeof prop.type !== "string") {
433
+ errors.push(`${fieldName}.properties.${key}.type must be a string`);
434
+ }
435
+ if (prop.enum !== undefined) {
436
+ if (!Array.isArray(prop.enum)) {
437
+ errors.push(`${fieldName}.properties.${key}.enum must be an array`);
438
+ } else if (prop.enum.length === 0) {
439
+ errors.push(`${fieldName}.properties.${key}.enum must not be empty`);
440
+ }
441
+ }
442
+ }
443
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pptb/types",
3
- "version": "1.2.2-beta.0",
3
+ "version": "1.2.2-beta.1",
4
4
  "description": "Type definitions for Power Platform ToolBox APIs and validity checks for tool packages",
5
5
  "main": "index.d.ts",
6
6
  "types": "index.d.ts",
@@ -26,6 +26,7 @@
26
26
  "index.d.ts",
27
27
  "toolboxAPI.d.ts",
28
28
  "dataverseAPI.d.ts",
29
+ "pptbConfig.d.ts",
29
30
  "bin/",
30
31
  "lib/",
31
32
  "README.md"
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Type definitions for pptb.config.json – the optional configuration file that
3
+ * tools can place alongside their package.json to declare invocation contracts
4
+ * and other Power Platform ToolBox-specific metadata.
5
+ *
6
+ * Tool developers should place this file in the root of their tool package so
7
+ * that `pptb-validate` can automatically discover and validate it.
8
+ *
9
+ * Example pptb.config.json:
10
+ * ```json
11
+ * {
12
+ * "invocation": {
13
+ * "version": "1.0.0",
14
+ * "prefill": {
15
+ * "properties": {
16
+ * "entityName": { "type": "string" },
17
+ * "attributes": { "type": "array", "items": { "type": "string" } }
18
+ * }
19
+ * },
20
+ * "returnTopic": {
21
+ * "properties": {
22
+ * "result": { "type": "object" },
23
+ * "status": { "type": "string", "enum": ["success", "cancelled", "error"] },
24
+ * "error": { "type": "string" }
25
+ * }
26
+ * }
27
+ * }
28
+ * }
29
+ * ```
30
+ */
31
+
32
+ /** A JSON-schema-style property descriptor used inside invocation definitions. */
33
+ export interface JsonSchemaProperty {
34
+ /** The JSON type of the value (e.g. "string", "number", "boolean", "object", "array"). */
35
+ type?: string;
36
+ /** Restricts the value to one of the listed literals. */
37
+ enum?: string[];
38
+ /** Describes the items of an array property. */
39
+ items?: JsonSchemaProperty;
40
+ }
41
+
42
+ /** A JSON-schema-style object definition: a map of named property descriptors. */
43
+ export interface JsonSchemaObject {
44
+ properties?: Record<string, JsonSchemaProperty>;
45
+ }
46
+
47
+ /**
48
+ * The invocation contract for a tool.
49
+ *
50
+ * - `version` controls which revision of this contract is in effect. It must
51
+ * follow **semantic versioning** (`MAJOR.MINOR.PATCH[-prerelease][+build]`).
52
+ * Tool developers own this version and should bump it whenever the shape of
53
+ * `prefill` or `returnTopic` changes in a meaningful way.
54
+ * - `prefill` describes the data that callers can pre-populate when opening
55
+ * this tool programmatically.
56
+ * - `returnTopic` describes the data this tool will resolve back to its caller
57
+ * when it finishes.
58
+ */
59
+ export interface InvocationConfig {
60
+ /**
61
+ * Semantic version of this invocation contract (e.g. "1.0.0").
62
+ * Tool developers control this version so they can evolve the prefill or
63
+ * return shape independently of the tool's npm package version.
64
+ */
65
+ version: string;
66
+ /** Schema of the data the caller can pass in when invoking this tool. */
67
+ prefill?: JsonSchemaObject;
68
+ /** Schema of the data this tool returns to its caller on completion. */
69
+ returnTopic?: JsonSchemaObject;
70
+ }
71
+
72
+ /**
73
+ * The shape of a tool's `pptb.config.json` file.
74
+ *
75
+ * This file lives alongside `package.json` in the tool's package root.
76
+ * All sections are optional; the file itself is optional. When present it
77
+ * is validated by `pptb-validate` in addition to `package.json`.
78
+ */
79
+ export interface PPTBConfig {
80
+ /** Invocation contract – how this tool can be called by other tools. */
81
+ invocation?: InvocationConfig;
82
+ }
package/toolboxAPI.d.ts CHANGED
@@ -397,6 +397,14 @@ declare namespace ToolBoxAPI {
397
397
  */
398
398
  events: EventsAPI;
399
399
 
400
+ /**
401
+ * Inter-tool launch context API.
402
+ *
403
+ * Allows one tool to launch another, pass prefill data to it, and receive
404
+ * a return value when the callee finishes.
405
+ */
406
+ invocation: InvocationAPI;
407
+
400
408
  /**
401
409
  * Get the current tool context
402
410
  * @internal Used internally by the framework
@@ -404,6 +412,76 @@ declare namespace ToolBoxAPI {
404
412
  getToolContext: () => Promise<ToolContext>;
405
413
  }
406
414
 
415
+ /**
416
+ * Inter-tool launch context API.
417
+ *
418
+ * Tools use this namespace to:
419
+ * 1. **Launch another tool** with prefill data (`invocation.launchTool`).
420
+ * 2. **Read their own launch context** when they were launched by another tool (`invocation.getLaunchContext`).
421
+ * 3. **Return data** back to the tool that launched them (`invocation.returnData`).
422
+ *
423
+ * @example Caller (Tool A)
424
+ * ```ts
425
+ * const result = await toolboxAPI.invocation.launchTool(
426
+ * "@my-org/entity-picker",
427
+ * { entityName: "account" },
428
+ * );
429
+ * console.log(result); // { selectedId: "...", selectedName: "..." }
430
+ * ```
431
+ *
432
+ * @example Callee (Tool B)
433
+ * ```ts
434
+ * const ctx = await toolboxAPI.invocation.getLaunchContext();
435
+ * if (ctx) {
436
+ * console.log(ctx.entityName); // "account"
437
+ * }
438
+ *
439
+ * // After user picks something...
440
+ * await toolboxAPI.invocation.returnData({ selectedId, selectedName });
441
+ * ```
442
+ */
443
+ export interface InvocationAPI {
444
+ /**
445
+ * Returns the prefill data that was passed by the caller tool when it launched
446
+ * this tool, or `null` if this tool was not launched via an inter-tool invocation.
447
+ */
448
+ getLaunchContext: () => Promise<Record<string, unknown> | null>;
449
+
450
+ /**
451
+ * Returns data back to the caller tool that launched this tool.
452
+ *
453
+ * The value resolves the `Promise` returned by the caller's
454
+ * `invocation.launchTool()` call. After calling `returnData`, the PPTB host
455
+ * will notify the caller; it is the callee's responsibility to close itself (or
456
+ * update its UI) after the return.
457
+ *
458
+ * If this tool was not launched by another tool, the call is a no-op.
459
+ *
460
+ * @param returnData The data to pass back to the caller
461
+ */
462
+ returnData: (returnData: Record<string, unknown>) => Promise<void>;
463
+
464
+ /**
465
+ * Launch another tool from within this tool and (optionally) pass prefill data.
466
+ *
467
+ * Returns a Promise that resolves with the data the target tool sends via
468
+ * `invocation.returnData()`, or `null` if the target tool closes without
469
+ * returning any data.
470
+ *
471
+ * The target tool must be installed and its `pptb.config.json` must declare an
472
+ * `invocation.prefill` schema that matches the shape of `prefillData`.
473
+ *
474
+ * @param targetToolId The npm package name (toolId) of the tool to launch
475
+ * @param prefillData Data to pre-populate the target tool's state
476
+ * @param options Optional connection overrides for the target tool
477
+ */
478
+ launchTool: (
479
+ targetToolId: string,
480
+ prefillData?: Record<string, unknown>,
481
+ options?: { primaryConnectionId?: string | null; secondaryConnectionId?: string | null },
482
+ ) => Promise<unknown>;
483
+ }
484
+
407
485
  /**
408
486
  * Auto-update event handlers
409
487
  */