@aiwg/cli 2026.8.0 → 2026.8.2

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 (70) hide show
  1. package/README.md +33 -0
  2. package/agentic/code/providers/capability-matrix.yaml +511 -0
  3. package/agentic/code/providers/model-capabilities.v1.json +120 -0
  4. package/agentic/code/providers/model-catalog.v1.json +96 -0
  5. package/agentic/code/providers/model-policy-evaluations.v1.json +50 -0
  6. package/agentic/code/providers/premium-model-allowlist.v1.json +36 -0
  7. package/bin/aiwg.mjs +14 -10
  8. package/dist/src/api/index.d.ts +1 -0
  9. package/dist/src/api/index.js +1 -0
  10. package/dist/src/artifacts/cli.js +2 -0
  11. package/dist/src/artifacts/types.js +4 -0
  12. package/dist/src/auth/client.js +209 -0
  13. package/dist/src/auth/config.js +38 -0
  14. package/dist/src/auth/credential-store.js +141 -0
  15. package/dist/src/auth/resource-credentials.js +25 -0
  16. package/dist/src/auth/types.js +2 -0
  17. package/dist/src/channel/manager.mjs +5 -5
  18. package/dist/src/cli/handlers/auth.js +125 -0
  19. package/dist/src/cli/handlers/help.js +1 -0
  20. package/dist/src/cli/handlers/index.js +3 -1
  21. package/dist/src/cli/handlers/install.js +42 -4
  22. package/dist/src/cli/handlers/marketplace.js +375 -122
  23. package/dist/src/cli/handlers/resource-versions.js +2 -0
  24. package/dist/src/cli/handlers/sessions.js +23 -5
  25. package/dist/src/cli/handlers/subcommands.js +10 -1
  26. package/dist/src/cli/handlers/use.js +342 -43
  27. package/dist/src/config/gitignore.js +1 -0
  28. package/dist/src/extensions/commands/definitions.js +19 -0
  29. package/dist/src/marketplace/exchange.js +602 -0
  30. package/dist/src/marketplace/provenance-types.js +19 -0
  31. package/dist/src/marketplace/provenance.js +834 -0
  32. package/dist/src/memory/canonical-context.js +342 -0
  33. package/dist/src/memory/context-pack.js +282 -0
  34. package/dist/src/memory/index.js +4 -0
  35. package/dist/src/memory/intake.js +118 -0
  36. package/dist/src/packages/adapters/git.js +79 -29
  37. package/dist/src/packages/package-discovery.js +81 -0
  38. package/dist/src/packages/package-registry.js +2 -0
  39. package/dist/src/packages/registry.js +119 -20
  40. package/dist/src/resources/resolver.js +1 -0
  41. package/dist/src/resources/web-release.d.ts +3 -1
  42. package/dist/src/resources/web-release.js +14 -6
  43. package/dist/src/serve/agentic-sandbox-fleet-client.js +213 -0
  44. package/dist/src/serve/fleet-mission-conductor.js +293 -0
  45. package/dist/src/sessions/index.js +1 -0
  46. package/dist/src/sessions/output-registration.js +338 -0
  47. package/dist/src/sessions/promotion.js +73 -2
  48. package/dist/src/sessions/repository.js +2 -1
  49. package/dist/src/update/notifier.mjs +13 -2
  50. package/package.json +8 -1
  51. package/tools/_resolve-impl.mjs +74 -0
  52. package/tools/agents/deploy-agents.mjs +962 -0
  53. package/tools/agents/providers/base.mjs +2954 -0
  54. package/tools/agents/providers/claude.mjs +711 -0
  55. package/tools/agents/providers/codex.mjs +699 -0
  56. package/tools/agents/providers/copilot.mjs +659 -0
  57. package/tools/agents/providers/cursor.mjs +714 -0
  58. package/tools/agents/providers/factory.mjs +1130 -0
  59. package/tools/agents/providers/hermes.mjs +663 -0
  60. package/tools/agents/providers/hook-capabilities.mjs +85 -0
  61. package/tools/agents/providers/model-role.mjs +56 -0
  62. package/tools/agents/providers/openclaw-translator.mjs +348 -0
  63. package/tools/agents/providers/openclaw.mjs +680 -0
  64. package/tools/agents/providers/opencode.mjs +675 -0
  65. package/tools/agents/providers/openhuman.mjs +292 -0
  66. package/tools/agents/providers/warp.mjs +413 -0
  67. package/tools/agents/providers/windsurf.mjs +748 -0
  68. package/tools/commands/deploy-prompts-codex.mjs +336 -0
  69. package/tools/plugin/package-plugins.mjs +1013 -0
  70. package/tools/skills/deploy-skills-codex.mjs +571 -0
@@ -0,0 +1,141 @@
1
+ import { spawn } from "node:child_process";
2
+ import fs from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ export const defaultCommandRunner = (command, args, stdin = "") => new Promise((resolve, reject) => {
6
+ const child = spawn(command, args, { stdio: ["pipe", "pipe", "pipe"], windowsHide: true });
7
+ const stdout = [];
8
+ const stderr = [];
9
+ let outputBytes = 0;
10
+ const collect = (target, chunk) => {
11
+ outputBytes += chunk.length;
12
+ if (outputBytes > 1024 * 1024)
13
+ child.kill();
14
+ else
15
+ target.push(chunk);
16
+ };
17
+ child.stdout.on("data", (chunk) => collect(stdout, chunk));
18
+ child.stderr.on("data", (chunk) => collect(stderr, chunk));
19
+ child.once("error", reject);
20
+ child.once("close", (code) => resolve({
21
+ stdout: Buffer.concat(stdout).toString("utf8"),
22
+ stderr: Buffer.concat(stderr).toString("utf8"),
23
+ exitCode: code ?? 1,
24
+ }));
25
+ child.stdin.end(stdin);
26
+ });
27
+ function parseCredentials(raw) {
28
+ const value = JSON.parse(raw);
29
+ if (!value.accessToken?.startsWith("aiwg_at_") || !value.refreshToken?.startsWith("aiwg_rt_")
30
+ || value.tokenType !== "Bearer" || !Array.isArray(value.scope) || !value.expiresAt) {
31
+ throw new Error("stored AIWG credentials are invalid");
32
+ }
33
+ return value;
34
+ }
35
+ const SERVICE = "releases.aiwg.io";
36
+ const ACCOUNT = "aiwg-cli";
37
+ class NativeCredentialStore {
38
+ run;
39
+ constructor(run = defaultCommandRunner) {
40
+ this.run = run;
41
+ }
42
+ parse(raw) { return parseCredentials(raw.trim()); }
43
+ }
44
+ export class MacOsKeychainStore extends NativeCredentialStore {
45
+ metadata = { provider: "macos-keychain", location: `Keychain:${SERVICE}/${ACCOUNT}` };
46
+ async load() {
47
+ const result = await this.run("security", ["find-generic-password", "-a", ACCOUNT, "-s", SERVICE, "-w"]);
48
+ return result.exitCode === 44 ? null : result.exitCode === 0 ? this.parse(result.stdout) : Promise.reject(new Error("macOS Keychain read failed"));
49
+ }
50
+ async save(credentials) {
51
+ const result = await this.run("security", ["add-generic-password", "-U", "-a", ACCOUNT, "-s", SERVICE, "-w"], JSON.stringify(credentials));
52
+ if (result.exitCode !== 0)
53
+ throw new Error("macOS Keychain write failed");
54
+ }
55
+ async delete() { await this.run("security", ["delete-generic-password", "-a", ACCOUNT, "-s", SERVICE]); }
56
+ }
57
+ export class LinuxSecretServiceStore extends NativeCredentialStore {
58
+ metadata = { provider: "linux-secret-service", location: `SecretService:${SERVICE}/${ACCOUNT}` };
59
+ async load() {
60
+ const result = await this.run("secret-tool", ["lookup", "service", SERVICE, "account", ACCOUNT]);
61
+ return result.exitCode === 1 ? null : result.exitCode === 0 ? this.parse(result.stdout) : Promise.reject(new Error("Linux Secret Service read failed"));
62
+ }
63
+ async save(credentials) {
64
+ const result = await this.run("secret-tool", ["store", `--label=AIWG ${SERVICE}`, "service", SERVICE, "account", ACCOUNT], JSON.stringify(credentials));
65
+ if (result.exitCode !== 0)
66
+ throw new Error("Linux Secret Service write failed");
67
+ }
68
+ async delete() { await this.run("secret-tool", ["clear", "service", SERVICE, "account", ACCOUNT]); }
69
+ }
70
+ const WINDOWS_READ = "$v=New-Object Windows.Security.Credentials.PasswordVault;try{$c=$v.Retrieve('releases.aiwg.io','aiwg-cli');$c.RetrievePassword();[Console]::Out.Write($c.Password)}catch{exit 1}";
71
+ const WINDOWS_WRITE = "$s=[Console]::In.ReadToEnd();$v=New-Object Windows.Security.Credentials.PasswordVault;$v.Add((New-Object Windows.Security.Credentials.PasswordCredential('releases.aiwg.io','aiwg-cli',$s)))";
72
+ const WINDOWS_DELETE = "$v=New-Object Windows.Security.Credentials.PasswordVault;try{$c=$v.Retrieve('releases.aiwg.io','aiwg-cli');$v.Remove($c)}catch{}";
73
+ export class WindowsCredentialManagerStore extends NativeCredentialStore {
74
+ metadata = { provider: "windows-credential-manager", location: `CredentialManager:${SERVICE}/${ACCOUNT}` };
75
+ execute(script, stdin = "") { return this.run("powershell.exe", ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", script], stdin); }
76
+ async load() { const result = await this.execute(WINDOWS_READ); return result.exitCode === 1 ? null : result.exitCode === 0 ? this.parse(result.stdout) : Promise.reject(new Error("Windows Credential Manager read failed")); }
77
+ async save(credentials) { if ((await this.execute(WINDOWS_WRITE, JSON.stringify(credentials))).exitCode !== 0)
78
+ throw new Error("Windows Credential Manager write failed"); }
79
+ async delete() { await this.execute(WINDOWS_DELETE); }
80
+ }
81
+ export class FileCredentialStore {
82
+ pathname;
83
+ explicitlyAllowed;
84
+ metadata;
85
+ constructor(pathname, explicitlyAllowed) {
86
+ this.pathname = pathname;
87
+ this.explicitlyAllowed = explicitlyAllowed;
88
+ this.pathname = path.resolve(pathname);
89
+ this.metadata = { provider: "file", location: this.pathname };
90
+ }
91
+ assertAllowed() { if (!this.explicitlyAllowed)
92
+ throw new Error("credential file fallback requires --allow-file-store or AIWG_AUTH_ALLOW_FILE_STORE=1"); }
93
+ async load() {
94
+ this.assertAllowed();
95
+ try {
96
+ const stat = await fs.lstat(this.pathname);
97
+ if (!stat.isFile() || stat.isSymbolicLink() || (stat.mode & 0o077) !== 0)
98
+ throw new Error("credential file must be a non-symlink mode-0600 regular file");
99
+ return parseCredentials(await fs.readFile(this.pathname, "utf8"));
100
+ }
101
+ catch (error) {
102
+ if (error.code === "ENOENT")
103
+ return null;
104
+ throw error;
105
+ }
106
+ }
107
+ async save(credentials) {
108
+ this.assertAllowed();
109
+ await fs.mkdir(path.dirname(this.pathname), { recursive: true, mode: 0o700 });
110
+ const temporary = `${this.pathname}.${process.pid}.tmp`;
111
+ await fs.writeFile(temporary, `${JSON.stringify(credentials)}\n`, { mode: 0o600, flag: "wx" });
112
+ await fs.rename(temporary, this.pathname);
113
+ await fs.chmod(this.pathname, 0o600);
114
+ }
115
+ async delete() { this.assertAllowed(); await fs.unlink(this.pathname).catch((error) => { if (error.code !== "ENOENT")
116
+ throw error; }); }
117
+ }
118
+ export class MemoryCredentialStore {
119
+ metadata = { provider: "memory", location: "injected-memory-store" };
120
+ value = null;
121
+ async load() { return this.value ? structuredClone(this.value) : null; }
122
+ async save(value) { this.value = structuredClone(value); }
123
+ async delete() { this.value = null; }
124
+ }
125
+ export function defaultCredentialFile() {
126
+ const root = process.env.XDG_CONFIG_HOME || (process.platform === "win32" ? process.env.APPDATA : undefined) || path.join(os.homedir(), ".config");
127
+ return path.join(root, "aiwg", "credentials", "resource-auth.json");
128
+ }
129
+ export function createCredentialStore(options = {}) {
130
+ if (options.useFile)
131
+ return new FileCredentialStore(options.pathname || defaultCredentialFile(), options.allowFile === true);
132
+ const platform = options.platform || process.platform;
133
+ if (platform === "darwin")
134
+ return new MacOsKeychainStore(options.runner);
135
+ if (platform === "win32")
136
+ return new WindowsCredentialManagerStore(options.runner);
137
+ if (platform === "linux")
138
+ return new LinuxSecretServiceStore(options.runner);
139
+ throw new Error("no native credential store is available; explicitly opt in to the mode-0600 file fallback");
140
+ }
141
+ //# sourceMappingURL=credential-store.js.map
@@ -0,0 +1,25 @@
1
+ import { explicitResourceToken } from "./config.js";
2
+ import { createCredentialStore } from "./credential-store.js";
3
+ /**
4
+ * Resolve credentials for protected release downloads. Explicit compatibility
5
+ * inputs take precedence over interactive-login credentials.
6
+ */
7
+ export function createResourceCredentialProvider(env = process.env, store) {
8
+ return async () => {
9
+ const explicit = explicitResourceToken(env);
10
+ if (explicit)
11
+ return explicit;
12
+ const selected = store ?? createCredentialStore();
13
+ try {
14
+ return (await selected.load())?.accessToken ?? null;
15
+ }
16
+ catch (error) {
17
+ // A workstation without the platform keychain helper must retain access
18
+ // to public releases. Invalid/corrupt stored credentials still fail loud.
19
+ if (error.code === "ENOENT")
20
+ return null;
21
+ throw error;
22
+ }
23
+ };
24
+ }
25
+ //# sourceMappingURL=resource-credentials.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -99,10 +99,10 @@ const DEFAULT_CONFIG = {
99
99
  * Get the package root directory.
100
100
  *
101
101
  * Walks up from this file's directory looking for the nearest package.json
102
- * that names "aiwg". This works whether this module runs from its source
103
- * location (`src/channel/manager.mjs`) or from its compiled-build copy
104
- * (`dist/src/channel/manager.mjs`), both of which have package.json at
105
- * the repo root.
102
+ * that names either the full `aiwg` distribution or the lightweight
103
+ * `@aiwg/cli` distribution. This works whether this module runs from its
104
+ * source location (`src/channel/manager.mjs`) or from its compiled-build copy
105
+ * (`dist/src/channel/manager.mjs`).
106
106
  *
107
107
  * The walk is bounded to 10 levels as a safety cap.
108
108
  *
@@ -115,7 +115,7 @@ export function getPackageRoot() {
115
115
  if (existsSync(pkg)) {
116
116
  try {
117
117
  const content = JSON.parse(readFileSync(pkg, 'utf8'));
118
- if (content.name === 'aiwg') return dir;
118
+ if (content.name === 'aiwg' || content.name === '@aiwg/cli') return dir;
119
119
  } catch {
120
120
  // keep walking
121
121
  }
@@ -0,0 +1,125 @@
1
+ import { AuthClient, defaultBrowserOpener } from "../../auth/client.js";
2
+ import { authConfigFromEnvironment } from "../../auth/config.js";
3
+ import { createCredentialStore } from "../../auth/credential-store.js";
4
+ function usage() {
5
+ return [
6
+ "Usage:",
7
+ " aiwg auth login [--device] [--device-label <label>] [--store native|file] [--allow-file-store]",
8
+ " aiwg auth status [--json] [--store native|file] [--allow-file-store]",
9
+ " aiwg auth logout [--all] [--store native|file] [--allow-file-store]",
10
+ "",
11
+ "Exit codes: 0 success; 2 invalid usage; 3 not authenticated; 4 authorization denied/expired; 5 credential store unavailable; 6 network/protocol failure.",
12
+ ].join("\n");
13
+ }
14
+ function value(args, flag) {
15
+ const index = args.indexOf(flag);
16
+ if (index < 0)
17
+ return undefined;
18
+ const result = args[index + 1];
19
+ if (!result || result.startsWith("--"))
20
+ throw new Error(`${flag} requires a value`);
21
+ return result;
22
+ }
23
+ function classify(error) {
24
+ const message = error instanceof Error ? error.message : String(error);
25
+ if (message === "not_authenticated")
26
+ return 3;
27
+ if (/access_denied|expired_token|authorization canceled/.test(message))
28
+ return 4;
29
+ if (/credential|Keychain|Secret Service|Credential Manager/.test(message))
30
+ return 5;
31
+ return 6;
32
+ }
33
+ export function createAuthHandler(dependencies = {}) {
34
+ return {
35
+ id: "auth",
36
+ name: "Authentication",
37
+ description: "Log in, inspect access, and log out of paid AIWG web resources",
38
+ category: "maintenance",
39
+ aliases: [],
40
+ async execute(ctx) {
41
+ if (!ctx.args.length || ["help", "--help", "-h"].includes(ctx.args[0])) {
42
+ console.log(usage());
43
+ return { exitCode: 0 };
44
+ }
45
+ const [subcommand, ...args] = ctx.args;
46
+ if (!["login", "status", "logout"].includes(subcommand))
47
+ return { exitCode: 2, message: usage() };
48
+ try {
49
+ const storeMode = value(args, "--store") || "native";
50
+ if (!["native", "file"].includes(storeMode))
51
+ return { exitCode: 2, message: "--store must be native or file" };
52
+ const allowFile = args.includes("--allow-file-store") || dependencies.env?.AIWG_AUTH_ALLOW_FILE_STORE === "1" || process.env.AIWG_AUTH_ALLOW_FILE_STORE === "1";
53
+ const store = dependencies.store || createCredentialStore({
54
+ platform: dependencies.platform,
55
+ useFile: storeMode === "file",
56
+ allowFile,
57
+ runner: dependencies.runner,
58
+ });
59
+ if (store.metadata.provider === "file")
60
+ console.error("Warning: using explicitly opted-in mode-0600 credential file fallback.");
61
+ const config = dependencies.config || authConfigFromEnvironment(dependencies.env);
62
+ const client = new AuthClient(config, store, dependencies.fetcher, dependencies.openBrowser, dependencies.now);
63
+ if (subcommand === "login") {
64
+ const deviceLabel = value(args, "--device-label");
65
+ if (args.includes("--device")) {
66
+ await client.loginDevice({
67
+ signal: ctx.signal,
68
+ deviceLabel,
69
+ onCode(info) {
70
+ console.log(`Open: ${String(info.verification_uri)}`);
71
+ console.log(`Code: ${String(info.user_code)}`);
72
+ },
73
+ });
74
+ }
75
+ else {
76
+ await client.loginBrowser({ signal: ctx.signal, deviceLabel });
77
+ }
78
+ console.log(`Authenticated. Credentials stored in ${store.metadata.location}.`);
79
+ return { exitCode: 0 };
80
+ }
81
+ if (subcommand === "status") {
82
+ const { profile, credentials } = await client.status(ctx.signal);
83
+ const output = {
84
+ authenticated: true,
85
+ subject: profile.sub,
86
+ account: profile.email || null,
87
+ organization: profile.organization_id || null,
88
+ scopes: profile.scope?.split(/\s+/).filter(Boolean) || credentials.scope,
89
+ plan: profile.plan || null,
90
+ accessReason: profile.access_reason || null,
91
+ accessValidUntil: profile.access_valid_until || credentials.expiresAt,
92
+ credentialStore: store.metadata,
93
+ };
94
+ if (args.includes("--json"))
95
+ console.log(JSON.stringify(output));
96
+ else {
97
+ console.log(`subject: ${output.subject}`);
98
+ console.log(`account: ${output.account || "(not supplied)"}`);
99
+ console.log(`organization: ${output.organization || "(none)"}`);
100
+ console.log(`scopes: ${output.scopes.join(" ")}`);
101
+ console.log(`plan: ${output.plan || "(none)"}`);
102
+ console.log(`access_reason: ${output.accessReason || "(unknown)"}`);
103
+ console.log(`access_valid_until: ${output.accessValidUntil}`);
104
+ console.log(`credential_location: ${store.metadata.location}`);
105
+ }
106
+ return { exitCode: 0 };
107
+ }
108
+ if (args.includes("--all")) {
109
+ const opener = dependencies.openBrowser || defaultBrowserOpener;
110
+ await opener(`${config.baseUrl}/account/security?revoke=all`);
111
+ }
112
+ await client.logout(ctx.signal);
113
+ console.log(args.includes("--all")
114
+ ? "Local credentials removed. Complete revoke-all in the opened account security page."
115
+ : "Logged out and removed local credentials.");
116
+ return { exitCode: 0 };
117
+ }
118
+ catch (error) {
119
+ return { exitCode: classify(error), message: error instanceof Error ? error.message : String(error) };
120
+ }
121
+ },
122
+ };
123
+ }
124
+ export const authHandler = createAuthHandler();
125
+ //# sourceMappingURL=auth.js.map
@@ -81,6 +81,7 @@ function displayHelp() {
81
81
  ['discover "<phrase>"', 'Find skills/agents/commands/rules by capability'],
82
82
  ['show <type> <name>', 'Stream the body of an indexed artifact'],
83
83
  ['versions <list|resolve|show>', 'Browse and resolve signed AIWG web resource releases'],
84
+ ['auth <login|status|logout>', 'Authenticate for paid AIWG web resources'],
84
85
  ['index <subcommand>', 'Manage the artifact index (build/query/discover/deps/stats)'],
85
86
  ['artifacts move --to <path>', 'Move/rename the project AIWG artifact root and reindex'],
86
87
  ]);
@@ -13,6 +13,7 @@ export { createScriptRunner, DefaultScriptRunner } from './script-runner.js';
13
13
  // Import all handlers
14
14
  import { helpHandler } from './help.js';
15
15
  import { versionHandler } from './version.js';
16
+ import { authHandler } from './auth.js';
16
17
  import { useHandler } from './use.js';
17
18
  import { statusHandler, wizardHandler, migrateWorkspaceHandler, rollbackWorkspaceHandler, workspaceHandlers, } from './workspace.js';
18
19
  import { prefillCardsHandler, contributeStartHandler, validateMetadataHandler, doctorHandler, updateHandler, utilityHandlers, } from './utilities.js';
@@ -61,7 +62,7 @@ import { jobHandler } from './job.js';
61
62
  // Re-export individual handlers
62
63
  export {
63
64
  // Maintenance
64
- helpHandler, versionHandler, doctorHandler, updateHandler, refreshHandler, regenerateHandler, workspaceContextHandler,
65
+ helpHandler, versionHandler, authHandler, doctorHandler, updateHandler, refreshHandler, regenerateHandler, workspaceContextHandler,
65
66
  // Framework management
66
67
  useHandler, listHandler, removeHandler, promoteHandler, installHandler, packagesHandler, marketplaceHandler, initHandler, setupHandler, setupGenerateHandler, setupRunHandler, setupValidateHandler, issueHandler, issueAuditHandler, runHandler, jobHandler,
67
68
  // Project
@@ -115,6 +116,7 @@ export const allHandlers = [
115
116
  // Maintenance (shown first in help)
116
117
  helpHandler,
117
118
  versionHandler,
119
+ authHandler,
118
120
  doctorHandler,
119
121
  updateHandler,
120
122
  refreshHandler,
@@ -20,6 +20,7 @@
20
20
  import path from 'path';
21
21
  import { installPackage } from '../../packages/registry.js';
22
22
  import { recordDeployment } from '../../packages/package-registry.js';
23
+ import { marketplaceConfigDir, resolveVerificationPolicy } from '../../marketplace/exchange.js';
23
24
  import { createScriptRunner } from './script-runner.js';
24
25
  import { handlerResultFromError } from '../errors.js';
25
26
  import * as ui from '../ui.js';
@@ -59,6 +60,12 @@ export const installHandler = {
59
60
  ' --provider <name> Target provider (claude, copilot, cursor...)',
60
61
  ' --target <dir> Project directory to deploy into',
61
62
  ' --refresh Force re-pull even if cached',
63
+ ' --ref <tag-or-sha> Resolve this ref and lock its immutable commit',
64
+ ' --package <id> Select one wrapper when a repository contains several',
65
+ ' --verify Require a publisher signature trusted by local policy',
66
+ ' --policy <name|path> Named trust policy or JSON policy file',
67
+ ' --project-local Store registry, lock, receipts, and index under <target>/.aiwg',
68
+ ' --global Store package state in the user AIWG directory (default)',
62
69
  ].join('\n'),
63
70
  };
64
71
  }
@@ -66,6 +73,15 @@ export const installHandler = {
66
73
  const refresh = hasFlag(ctx.args, '--refresh');
67
74
  const provider = parseFlag(ctx.args, '--provider') ?? 'claude';
68
75
  const target = parseFlag(ctx.args, '--target') ?? ctx.cwd;
76
+ const projectLocal = hasFlag(ctx.args, '--project-local');
77
+ const global = hasFlag(ctx.args, '--global');
78
+ if (projectLocal && global) {
79
+ return { exitCode: 1, message: 'Error: Choose either --project-local or --global, not both' };
80
+ }
81
+ const verify = hasFlag(ctx.args, '--verify');
82
+ const policyName = parseFlag(ctx.args, '--policy');
83
+ const scope = { projectLocal, projectDir: target };
84
+ const configDir = marketplaceConfigDir(scope);
69
85
  ui.blank();
70
86
  console.log(` ${ui.brandMark()} ${ui.bold('aiwg install')} ${ui.dimText(rawRef)}`);
71
87
  ui.rule();
@@ -75,8 +91,23 @@ export const installHandler = {
75
91
  let key;
76
92
  let type;
77
93
  let namespace;
94
+ let lockId;
95
+ let verificationStatus;
78
96
  try {
79
- ({ cachePath, key, type, namespace } = await installPackage(rawRef, { refresh }));
97
+ const resolvedPolicy = await resolveVerificationPolicy(policyName, scope);
98
+ const installed = await installPackage(rawRef, {
99
+ refresh,
100
+ ref: parseFlag(ctx.args, '--ref'),
101
+ packageSelector: parseFlag(ctx.args, '--package'),
102
+ verify,
103
+ verificationPolicy: resolvedPolicy.policy,
104
+ trustStore: resolvedPolicy.trustStore,
105
+ configDir,
106
+ actor: 'local-user',
107
+ });
108
+ ({ cachePath, key, type, namespace } = installed);
109
+ lockId = installed.lock.lockId;
110
+ verificationStatus = installed.verification.status;
80
111
  }
81
112
  catch (error) {
82
113
  // Preserve AiwgError.exitCode while keeping the "Error: " prefix users
@@ -85,9 +116,12 @@ export const installHandler = {
85
116
  return { ...result, message: `Error: ${result.message}` };
86
117
  }
87
118
  ui.success(`Installed: ${key} (${type})`);
88
- ui.dimText(` Cache: ${cachePath}`);
119
+ ui.dim(` Cache: ${cachePath}`);
120
+ ui.dim(` Lock: ${lockId}`);
121
+ ui.dim(` Verification: ${verificationStatus}`);
122
+ ui.dim(` Scope: ${projectLocal ? 'project-local' : 'global'}`);
89
123
  if (namespace !== 'aiwg') {
90
- ui.dimText(` Namespace: ${namespace}`);
124
+ ui.dim(` Namespace: ${namespace}`);
91
125
  }
92
126
  // Optionally deploy
93
127
  if (deploy) {
@@ -98,6 +132,10 @@ export const installHandler = {
98
132
  '--deploy-commands',
99
133
  '--deploy-skills',
100
134
  '--deploy-rules',
135
+ // External packages do not participate in AIWG's global artifact
136
+ // index. Copy their complete skill payload into the target so a
137
+ // successful install cannot silently deploy agents/rules only.
138
+ '--copy-all',
101
139
  '--provider', provider,
102
140
  '--target', target,
103
141
  '--namespace', namespace,
@@ -116,7 +154,7 @@ export const installHandler = {
116
154
  projectPath: target,
117
155
  provider,
118
156
  deployedAt: new Date().toISOString(),
119
- });
157
+ }, configDir);
120
158
  }
121
159
  }
122
160
  ui.blank();