@postman/postman-plugin 0.1.2-rc.0 → 0.2.0-rc.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.
package/README.md CHANGED
@@ -24,9 +24,9 @@ Install Postman in every compatible coding agent detected on your machine:
24
24
  npx @postman/postman-plugin
25
25
  ```
26
26
 
27
- One command configures **Claude Code, Codex, Cursor, Kimi Code, OpenCode and Pi**.
28
- Run it again to update, `status` to see what's installed, and `remove` to
29
- uninstall; `--agent <id>` limits any of them to one agent.
27
+ One command configures **Claude Code, Codex, Cursor, Factory Droid, Kimi Code,
28
+ OpenCode and Pi**. Run it again to update, `status` to see what's installed,
29
+ and `remove` to uninstall; `--agent <id>` limits any of them to one agent.
30
30
 
31
31
  You can also use the following commands to install individually:
32
32
 
@@ -54,6 +54,17 @@ claude plugin install postman@postman
54
54
  codex plugin add postman@postman
55
55
  ```
56
56
 
57
+ ### Factory Droid
58
+
59
+ ```bash
60
+ droid plugin marketplace add postmanlabs/postman-plugin
61
+ droid plugin install postman@postman-plugin --scope user
62
+ ```
63
+
64
+ `droid plugin marketplace update postman-plugin`, then
65
+ `droid plugin update postman@postman-plugin --scope user`, updates it. Sign in
66
+ to Postman's MCP server with `/mcp` inside a Droid session.
67
+
57
68
  ### Pi
58
69
 
59
70
  [View Postman in Pi's package gallery](https://pi.dev/packages/@postman/postman-plugin)
@@ -0,0 +1,67 @@
1
+ import { GIT_URL, REPO, isSameRepo, redact } from '../source.js';
2
+ import { blocked, guard, mustProbeText, mustRun } from './shared.js';
3
+ import { result } from './types.js';
4
+ const MARKETPLACE = 'postman-plugin', PLUGIN_ID = `postman@${MARKETPLACE}`, SCOPE = 'user', NEXT = 'Restart Droid for the change to take effect.';
5
+ function hasInstalledPlugin(text) {
6
+ return text.split('\n').some((line) => new RegExp(`^${PLUGIN_ID}\\s+\\[${SCOPE}\\]`).test(line.trimStart()));
7
+ }
8
+ function marketplaceSource(text) {
9
+ for (const line of text.split('\n')) {
10
+ const match = /^\s*(\S+)\s+\(\d+ plugins?\)\s+(.+?)(?:\s+"[^"]*")?\s*$/.exec(line);
11
+ if (match && match[1] === MARKETPLACE) {
12
+ return match[2];
13
+ }
14
+ }
15
+ return null;
16
+ }
17
+ function sourceWithoutFactoryPrefix(source) {
18
+ return source.replace(/^(?:github|url):/, '');
19
+ }
20
+ async function listPlugins(system) {
21
+ return mustProbeText(system, 'droid', ['plugin', 'list', '--scope', SCOPE]);
22
+ }
23
+ async function refreshMarketplace(system) {
24
+ const source = marketplaceSource(await mustProbeText(system, 'droid', ['plugin', 'marketplace', 'list']));
25
+ if (!source) {
26
+ await mustRun(system, 'droid', ['plugin', 'marketplace', 'add', GIT_URL]);
27
+ return;
28
+ }
29
+ if (!isSameRepo(sourceWithoutFactoryPrefix(source), REPO)) {
30
+ blocked(`marketplace ${MARKETPLACE} is registered from ${redact(source)}, not ${REPO}`);
31
+ }
32
+ await mustRun(system, 'droid', ['plugin', 'marketplace', 'update', MARKETPLACE]);
33
+ }
34
+ export const factory = {
35
+ id: 'factory',
36
+ name: 'Factory Droid',
37
+ route: '.factory-plugin',
38
+ async detect(system) {
39
+ return (await system.which('droid')) !== null;
40
+ },
41
+ async status(system) {
42
+ const exec = await system.probe('droid', ['plugin', 'list', '--scope', SCOPE]);
43
+ if (exec.code !== 0) {
44
+ return { installed: null, detail: 'could not read `droid plugin list --scope user`', notes: [] };
45
+ }
46
+ return hasInstalledPlugin(exec.stdout) ?
47
+ { installed: true, detail: PLUGIN_ID, notes: [] } :
48
+ { installed: false, detail: 'not installed', notes: [] };
49
+ },
50
+ install(system) {
51
+ return guard(async () => {
52
+ await refreshMarketplace(system);
53
+ const wasInstalled = hasInstalledPlugin(await listPlugins(system)), verb = wasInstalled ? 'update' : 'install';
54
+ await mustRun(system, 'droid', ['plugin', verb, PLUGIN_ID, '--scope', SCOPE]);
55
+ return result('done', `${wasInstalled ? 'updated' : 'installed'} ${PLUGIN_ID}`, NEXT);
56
+ });
57
+ },
58
+ remove(system) {
59
+ return guard(async () => {
60
+ if (!hasInstalledPlugin(await listPlugins(system))) {
61
+ return result('skipped', 'not installed');
62
+ }
63
+ await mustRun(system, 'droid', ['plugin', 'uninstall', PLUGIN_ID, '--scope', SCOPE]);
64
+ return result('done', `uninstalled ${PLUGIN_ID}`, NEXT);
65
+ });
66
+ }
67
+ };
@@ -1,7 +1,8 @@
1
1
  import { claudeCode } from './claude-code.js';
2
2
  import { codex } from './codex.js';
3
3
  import { cursor } from './cursor.js';
4
+ import { factory } from './factory.js';
4
5
  import { kimi } from './kimi.js';
5
6
  import { opencode } from './opencode.js';
6
7
  import { pi } from './pi.js';
7
- export const HOSTS = [claudeCode, codex, cursor, kimi, opencode, pi];
8
+ export const HOSTS = [claudeCode, codex, cursor, factory, kimi, opencode, pi];
@@ -41,6 +41,14 @@ export async function mustProbeJson(system, command, args) {
41
41
  }
42
42
  return parsed;
43
43
  }
44
+ /** Runs a read-only listing with no JSON mode; throws `StepFailed` if it fails. */
45
+ export async function mustProbeText(system, command, args) {
46
+ const exec = await system.probe(command, args);
47
+ if (exec.code !== 0) {
48
+ throw new StepFailed(result('failed', describeFailure(command, args, exec)));
49
+ }
50
+ return exec.stdout;
51
+ }
44
52
  export function blocked(message) {
45
53
  throw new StepFailed(result('blocked', message));
46
54
  }
package/mcp.pi.json CHANGED
@@ -6,8 +6,8 @@
6
6
  "description": "Postman workspaces, collections, specs, environments, mocks and monitors",
7
7
  "headers": {
8
8
  "X-Source": "postman-pi-plugin",
9
- "X-Plugin-Version": "0.1.2-rc.0",
10
- "User-Agent": "postman-pi-plugin/0.1.2-rc.0"
9
+ "X-Plugin-Version": "0.2.0-rc.0",
10
+ "User-Agent": "postman-pi-plugin/0.2.0-rc.0"
11
11
  }
12
12
  }
13
13
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postman/postman-plugin",
3
- "version": "0.1.2-rc.0",
3
+ "version": "0.2.0-rc.0",
4
4
  "description": "Postman's API engineering skills for coding agents: a Pi package, and an npx installer that sets up Claude Code, Codex, Cursor, Kimi Code, OpenCode and Pi.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -23,6 +23,7 @@
23
23
  "claude-code",
24
24
  "codex",
25
25
  "cursor",
26
+ "factory.ai",
26
27
  "kimi",
27
28
  "opencode",
28
29
  "agent-plugin"