very-happy-cli 0.2.124 → 0.2.126

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 (49) hide show
  1. package/dist/{AcpBackend-CT9TOBEM.mjs → AcpBackend-BzGpBAZ0.mjs} +2 -1
  2. package/dist/{AcpBackend-au0veuIF.cjs → AcpBackend-C9eu6CDu.cjs} +30 -29
  3. package/dist/{AcpSessionManager-p1tj7FxF.mjs → AcpSessionManager-B223yT78.mjs} +1 -1
  4. package/dist/{AcpSessionManager-BCWeBKDd.cjs → AcpSessionManager-DQ1e_0gc.cjs} +9 -9
  5. package/dist/agentGuidance-BR0OFumQ.mjs +224 -0
  6. package/dist/agentGuidance-Tm8Z5HYp.cjs +237 -0
  7. package/dist/codex/happyMcpStdioBridge.cjs +29 -6
  8. package/dist/codex/happyMcpStdioBridge.mjs +25 -2
  9. package/dist/{config-DwMic6AC.mjs → config-Bjd1nG0P.mjs} +11 -11
  10. package/dist/{config-GzzqE5Ev.cjs → config-C0mofvCH.cjs} +11 -11
  11. package/dist/{index-B3-daYaX.mjs → index-BP56asuS.mjs} +8 -8
  12. package/dist/{index-DgN9P02i.cjs → index-CMbKpntk.cjs} +53 -19
  13. package/dist/{index-Ba6Fu6MJ.mjs → index-CV6sAa4a.mjs} +49 -15
  14. package/dist/{index-DI_VC3vJ.cjs → index-Cw9Zj1Zr.cjs} +2191 -1864
  15. package/dist/{index-SQKnWyz-.mjs → index-D4eCRu9x.mjs} +2046 -1719
  16. package/dist/{index-C69uF6Up.cjs → index-HW-KdG6W.cjs} +8 -8
  17. package/dist/index.cjs +5 -5
  18. package/dist/index.mjs +5 -5
  19. package/dist/{installTerminalHooks-CvMt8cBI.cjs → installTerminalHooks-CNp1LExn.cjs} +9 -9
  20. package/dist/{installTerminalHooks-Df4hzzdM.mjs → installTerminalHooks-D-CNSalI.mjs} +8 -8
  21. package/dist/lib.cjs +12 -12
  22. package/dist/lib.d.cts +3 -0
  23. package/dist/lib.d.mts +3 -0
  24. package/dist/lib.mjs +9 -9
  25. package/dist/limits-DG1OQnCb.cjs +1198 -0
  26. package/dist/limits-DlbYYtOw.mjs +1129 -0
  27. package/dist/{mcp-DnyLwSPq.cjs → mcp-BtZoIIIM.cjs} +11 -10
  28. package/dist/{mcp-C0oW5u-b.mjs → mcp-D3oV_dH-.mjs} +7 -6
  29. package/dist/resources-CVl7NdOB.cjs +83 -0
  30. package/dist/resources-D-mn7ptO.mjs +80 -0
  31. package/dist/{runGemini-mqLjz-M7.mjs → runGemini-BJ8bU1pP.mjs} +13 -13
  32. package/dist/{runGemini-_FHrxuHN.cjs → runGemini-BfCSOPL1.cjs} +30 -30
  33. package/dist/{runOpenClaw-C5VZQ6Na.cjs → runOpenClaw-CBlHXEAT.cjs} +24 -24
  34. package/dist/{runOpenClaw-Bs03yQHe.mjs → runOpenClaw-DTgOpJnO.mjs} +9 -9
  35. package/dist/{send-BaLjQPZQ.mjs → send-9duZlpGX.mjs} +10 -10
  36. package/dist/{send-BD2gTVoP.cjs → send-CDK1bZFj.cjs} +10 -10
  37. package/dist/{sessions-B108j_Xj.cjs → sessions-CNkLCorF.cjs} +11 -11
  38. package/dist/{sessions-ggBePfSY.mjs → sessions-jAFOkKvW.mjs} +10 -10
  39. package/dist/{spawn-CORFRb9D.mjs → spawn-BG5oHi_f.mjs} +21 -21
  40. package/dist/{spawn-iI8w8sD7.cjs → spawn-J-A5WGZ7.cjs} +21 -21
  41. package/dist/teams-Cuqsk7Ty.mjs +189 -0
  42. package/dist/teams-MgWeyutG.cjs +191 -0
  43. package/dist/{types-CZIwVSN2.cjs → types-P5deH8Ls.cjs} +464 -1571
  44. package/dist/{types-gDOmwOKw.mjs → types-n_VWu9qe.mjs} +78 -1148
  45. package/package.json +7 -7
  46. package/dist/agentGuidance-BifkGXdE.cjs +0 -46
  47. package/dist/agentGuidance-C2_pkgRI.mjs +0 -37
  48. package/dist/limits-CwFb5S2b.mjs +0 -22
  49. package/dist/limits-KdWKmwtH.cjs +0 -28
@@ -0,0 +1,189 @@
1
+ import { homedir } from 'node:os';
2
+ import { unlink, rmdir, mkdir, lstat, readFile, writeFile, rename } from 'node:fs/promises';
3
+ import { z } from 'zod';
4
+ import { createHash, randomUUID } from 'node:crypto';
5
+ import { t as teamRequest, c as createTeamsClient } from './agentGuidance-BR0OFumQ.mjs';
6
+ import { i as readCredentialsForConfiguredRelay } from './limits-DlbYYtOw.mjs';
7
+ import { join, resolve, dirname } from 'node:path';
8
+ import { T as TEAM_SKILL } from './resources-D-mn7ptO.mjs';
9
+ import 'node:fs';
10
+ import 'tweetnacl';
11
+ import 'chalk';
12
+ import 'node:util';
13
+
14
+ const legacyTask = z.object({
15
+ id: z.string().regex(/^T-\d{3,}$/),
16
+ goal: z.string().min(1),
17
+ cwd: z.string().min(1),
18
+ acceptance: z.array(z.string().min(1)).min(1),
19
+ status: z.enum(["queued", "running", "waiting", "review", "done", "stopped", "escalated"]),
20
+ sessionId: z.string().nullable().optional(),
21
+ agent: z.string().optional()
22
+ });
23
+ const ledger = z.object({ version: z.literal(1), tasks: z.array(legacyTask) });
24
+ function previewLegacyTeamsMigration(input) {
25
+ const parsed = ledger.parse(input);
26
+ if (new Set(parsed.tasks.map((t) => t.id)).size !== parsed.tasks.length) throw new Error("Duplicate legacy task ids");
27
+ return {
28
+ mode: "preview-only",
29
+ precondition: "Stop and verify the old dispatcher before creating any replacement assignment. Preserve the original ledger as an audit archive.",
30
+ tasks: parsed.tasks.map((task) => {
31
+ const assistant = task.agent === "pi" ? "pi-acp" : task.agent ?? "claude";
32
+ const supported = ["claude", "codex", "pi-acp"].includes(assistant);
33
+ const closed = ["done", "stopped"].includes(task.status);
34
+ return {
35
+ legacyId: task.id,
36
+ goal: task.goal,
37
+ legacyStatus: task.status,
38
+ sessionId: task.sessionId ?? null,
39
+ disposition: closed ? "retain-history" : task.sessionId ? "reconcile-existing-session" : supported ? "ready-after-dispatcher-stopped" : "unsupported-runner",
40
+ ...closed || task.sessionId || !supported ? {} : { proposedAction: { type: "delegate", goal: task.goal, acceptance: task.acceptance, directory: task.cwd, assistant } }
41
+ };
42
+ })
43
+ };
44
+ }
45
+
46
+ async function setTeamPermissionMode(teamId, mode, requestId) {
47
+ if (process.env.VH_TEAM_SCOPE_FILE || process.env.HAPPY_SESSION_ID) {
48
+ throw new Error("Change team execution mode from the owner Web UI or an independent CLI terminal");
49
+ }
50
+ if (!teamId?.trim() || !requestId?.trim()) throw new Error("Team and request ID are required");
51
+ if (mode !== "default" && mode !== "bypassPermissions") throw new Error("Mode must be default or bypassPermissions");
52
+ const credentials = await readCredentialsForConfiguredRelay();
53
+ if (!credentials) throw new Error("Sign in before changing team execution mode");
54
+ const result = await teamRequest(
55
+ `/v1/teams/${encodeURIComponent(teamId)}/actions`,
56
+ "POST",
57
+ credentials.token,
58
+ false,
59
+ { requestId, action: { type: "set-permission-mode", permissionMode: mode } }
60
+ );
61
+ const { credential: _credential, ...safe } = result;
62
+ return safe;
63
+ }
64
+
65
+ async function assertPrivateDestination(directory) {
66
+ for (let path = directory; ; path = dirname(path)) {
67
+ try {
68
+ const stat = await lstat(path);
69
+ if (stat.isSymbolicLink() || !stat.isDirectory()) throw new Error("Refusing symlink or non-directory in managed skill destination: " + path);
70
+ } catch (error) {
71
+ if (error.code !== "ENOENT") throw error;
72
+ }
73
+ if (dirname(path) === path) break;
74
+ }
75
+ }
76
+ const digest = (text) => createHash("sha256").update(text).digest("hex");
77
+ async function read(path) {
78
+ try {
79
+ const stat = await lstat(path);
80
+ if (!stat.isFile() || stat.isSymbolicLink()) throw new Error("Refusing non-regular managed file");
81
+ return await readFile(path, "utf8");
82
+ } catch (error) {
83
+ if (error.code === "ENOENT") return null;
84
+ throw error;
85
+ }
86
+ }
87
+ async function publish(path, content) {
88
+ const temporary = `${path}.${randomUUID()}.new`;
89
+ try {
90
+ await writeFile(temporary, content, { flag: "wx", mode: 384 });
91
+ await rename(temporary, path);
92
+ } finally {
93
+ await unlink(temporary).catch(() => {
94
+ });
95
+ }
96
+ }
97
+ async function installTeamSkill(options) {
98
+ const directory = join(resolve(options.home), ".local", "share", "very-happy", "skills", "very-happy-teams");
99
+ await assertPrivateDestination(directory);
100
+ const file = join(directory, "SKILL.md");
101
+ const manifest = join(directory, ".very-happy-managed.json");
102
+ const current = await read(file);
103
+ const managed = await read(manifest);
104
+ const previous = managed ? JSON.parse(managed) : null;
105
+ if (previous && previous.owner !== "very-happy") throw new Error("Existing manifest is not owned by Very Happy");
106
+ if (current !== null && (!previous || previous.owner !== "very-happy" || previous.sha256 !== digest(current) && previous.pendingSha256 !== digest(current))) {
107
+ throw new Error("Existing skill is not owned by Very Happy or was edited; preserve it and resolve manually");
108
+ }
109
+ const action = options.uninstall ? current === null && managed === null ? "unchanged" : "remove" : current === TEAM_SKILL && !previous?.pendingSha256 ? "unchanged" : "write";
110
+ if (options.apply && action !== "unchanged") {
111
+ await assertPrivateDestination(directory);
112
+ if (options.uninstall) {
113
+ if (current !== null) await unlink(file);
114
+ if (managed !== null) await unlink(manifest);
115
+ await rmdir(directory).catch(() => {
116
+ });
117
+ } else {
118
+ await mkdir(directory, { recursive: true });
119
+ const nextHash = digest(TEAM_SKILL);
120
+ await publish(manifest, JSON.stringify({ owner: "very-happy", sha256: current === null ? null : digest(current), pendingSha256: nextHash, version: 1 }));
121
+ await publish(file, TEAM_SKILL);
122
+ await publish(manifest, JSON.stringify({ owner: "very-happy", sha256: nextHash, version: 1 }));
123
+ }
124
+ }
125
+ return { host: options.host, path: file, action, applied: !!options.apply, discovery: "No host skill directories are modified. Read this absolute skill path in a managed session.", managedSessions: "Team tools are injected by Very Happy. Standalone agents require a managed session connection." };
126
+ }
127
+
128
+ async function handleTeamsCommand(args) {
129
+ const command = args[0];
130
+ const value = (flag) => {
131
+ const index = args.indexOf(flag);
132
+ return index < 0 ? void 0 : args[index + 1];
133
+ };
134
+ if (!command || command === "--help") {
135
+ console.log("very-happy teams install|uninstall --host claude|codex|pi [--home PATH] [--apply]\nvery-happy teams doctor --host pi\nvery-happy teams migration-preview --file LEDGER_JSON\nvery-happy teams inspect\nvery-happy teams permissions --team-id ID --mode default|bypassPermissions --request-id ID\nvery-happy teams create|join --name NAME [--machine-id ID | --team-id ID] [--session-id ID] [--request-id ID]\nvery-happy teams action --json ACTION_JSON --request-id ID\nInstallation previews changes unless --apply is supplied. Managed sessions receive tools automatically.");
136
+ return;
137
+ }
138
+ if (command === "install" || command === "uninstall") {
139
+ const host = value("--host");
140
+ if (!host || !["claude", "codex", "pi"].includes(host)) throw new Error("--host must be claude, codex, or pi");
141
+ console.log(JSON.stringify(await installTeamSkill({ host, home: value("--home") ?? homedir(), apply: args.includes("--apply"), uninstall: command === "uninstall" })));
142
+ return;
143
+ }
144
+ if (command === "doctor") {
145
+ if (value("--host") !== "pi") throw new Error("doctor currently requires --host pi");
146
+ console.log(JSON.stringify({
147
+ host: "pi",
148
+ entry: "very-happy pi",
149
+ commandSource: process.env.PI_ACP_PI_COMMAND ? "PI_ACP_PI_COMMAND override (preserved)" : "pi from PATH",
150
+ delegatedCommandSource: process.env.VH_TEAM_PI_COMMAND ? "VH_TEAM_PI_COMMAND is set" : "not set",
151
+ officialBridge: "Injected by Very Happy managed pi sessions through HAPPY_MCP_URL",
152
+ permissions: "Official permission gate; user extensions may enforce additional rules",
153
+ check: "Run in the daemon environment. Audit pi settings extensions and any wrapper before removing private bindings. This diagnostic does not verify binary availability or a live connection.",
154
+ standalone: "Bare pi skill loading does not establish Teams transport or wakeup"
155
+ }, null, 2));
156
+ return;
157
+ }
158
+ if (command === "migration-preview") {
159
+ const file = value("--file");
160
+ if (!file) throw new Error("--file is required");
161
+ console.log(JSON.stringify(previewLegacyTeamsMigration(JSON.parse(await readFile(file, "utf8"))), null, 2));
162
+ return;
163
+ }
164
+ if (command === "permissions") {
165
+ const teamId = value("--team-id"), mode = value("--mode"), requestId = value("--request-id");
166
+ if (!teamId || !mode || !requestId) throw new Error("--team-id, --mode and --request-id are required");
167
+ console.log(JSON.stringify(await setTeamPermissionMode(teamId, mode, requestId)));
168
+ return;
169
+ }
170
+ const client = createTeamsClient(value("--session-id"));
171
+ let result;
172
+ if (command === "inspect") result = await client.inspect();
173
+ else if (command === "create" || command === "join") {
174
+ const name = value("--name");
175
+ if (!name) throw new Error("--name is required");
176
+ if (command === "join" && !value("--team-id")) throw new Error("--team-id is required");
177
+ result = await client.initialize({ name, teamId: command === "join" ? value("--team-id") : void 0, machineId: value("--machine-id"), botId: value("--bot-id"), requestId: value("--request-id") ?? randomUUID() });
178
+ } else if (command === "action") {
179
+ const payload = value("--json");
180
+ const requestId = value("--request-id");
181
+ if (!payload || !requestId) throw new Error("--json and --request-id are required");
182
+ const action = JSON.parse(payload);
183
+ if (!["delegate", "message", "submit", "accept", "return", "cancel", "handoff", "schedule-create", "schedule-pause", "schedule-resume", "schedule-cancel"].includes(action.type)) throw new Error("Unsupported team action");
184
+ result = await client.action(action, requestId);
185
+ } else throw new Error("Unknown teams command; use teams --help");
186
+ console.log(JSON.stringify(result));
187
+ }
188
+
189
+ export { handleTeamsCommand };
@@ -0,0 +1,191 @@
1
+ 'use strict';
2
+
3
+ var os = require('node:os');
4
+ var promises = require('node:fs/promises');
5
+ var z = require('zod');
6
+ var node_crypto = require('node:crypto');
7
+ var agentGuidance = require('./agentGuidance-Tm8Z5HYp.cjs');
8
+ var persistence = require('./limits-DG1OQnCb.cjs');
9
+ var path = require('node:path');
10
+ var resources = require('./resources-CVl7NdOB.cjs');
11
+ require('node:fs');
12
+ require('tweetnacl');
13
+ require('chalk');
14
+ require('node:util');
15
+
16
+ const legacyTask = z.z.object({
17
+ id: z.z.string().regex(/^T-\d{3,}$/),
18
+ goal: z.z.string().min(1),
19
+ cwd: z.z.string().min(1),
20
+ acceptance: z.z.array(z.z.string().min(1)).min(1),
21
+ status: z.z.enum(["queued", "running", "waiting", "review", "done", "stopped", "escalated"]),
22
+ sessionId: z.z.string().nullable().optional(),
23
+ agent: z.z.string().optional()
24
+ });
25
+ const ledger = z.z.object({ version: z.z.literal(1), tasks: z.z.array(legacyTask) });
26
+ function previewLegacyTeamsMigration(input) {
27
+ const parsed = ledger.parse(input);
28
+ if (new Set(parsed.tasks.map((t) => t.id)).size !== parsed.tasks.length) throw new Error("Duplicate legacy task ids");
29
+ return {
30
+ mode: "preview-only",
31
+ precondition: "Stop and verify the old dispatcher before creating any replacement assignment. Preserve the original ledger as an audit archive.",
32
+ tasks: parsed.tasks.map((task) => {
33
+ const assistant = task.agent === "pi" ? "pi-acp" : task.agent ?? "claude";
34
+ const supported = ["claude", "codex", "pi-acp"].includes(assistant);
35
+ const closed = ["done", "stopped"].includes(task.status);
36
+ return {
37
+ legacyId: task.id,
38
+ goal: task.goal,
39
+ legacyStatus: task.status,
40
+ sessionId: task.sessionId ?? null,
41
+ disposition: closed ? "retain-history" : task.sessionId ? "reconcile-existing-session" : supported ? "ready-after-dispatcher-stopped" : "unsupported-runner",
42
+ ...closed || task.sessionId || !supported ? {} : { proposedAction: { type: "delegate", goal: task.goal, acceptance: task.acceptance, directory: task.cwd, assistant } }
43
+ };
44
+ })
45
+ };
46
+ }
47
+
48
+ async function setTeamPermissionMode(teamId, mode, requestId) {
49
+ if (process.env.VH_TEAM_SCOPE_FILE || process.env.HAPPY_SESSION_ID) {
50
+ throw new Error("Change team execution mode from the owner Web UI or an independent CLI terminal");
51
+ }
52
+ if (!teamId?.trim() || !requestId?.trim()) throw new Error("Team and request ID are required");
53
+ if (mode !== "default" && mode !== "bypassPermissions") throw new Error("Mode must be default or bypassPermissions");
54
+ const credentials = await persistence.readCredentialsForConfiguredRelay();
55
+ if (!credentials) throw new Error("Sign in before changing team execution mode");
56
+ const result = await agentGuidance.teamRequest(
57
+ `/v1/teams/${encodeURIComponent(teamId)}/actions`,
58
+ "POST",
59
+ credentials.token,
60
+ false,
61
+ { requestId, action: { type: "set-permission-mode", permissionMode: mode } }
62
+ );
63
+ const { credential: _credential, ...safe } = result;
64
+ return safe;
65
+ }
66
+
67
+ async function assertPrivateDestination(directory) {
68
+ for (let path$1 = directory; ; path$1 = path.dirname(path$1)) {
69
+ try {
70
+ const stat = await promises.lstat(path$1);
71
+ if (stat.isSymbolicLink() || !stat.isDirectory()) throw new Error("Refusing symlink or non-directory in managed skill destination: " + path$1);
72
+ } catch (error) {
73
+ if (error.code !== "ENOENT") throw error;
74
+ }
75
+ if (path.dirname(path$1) === path$1) break;
76
+ }
77
+ }
78
+ const digest = (text) => node_crypto.createHash("sha256").update(text).digest("hex");
79
+ async function read(path) {
80
+ try {
81
+ const stat = await promises.lstat(path);
82
+ if (!stat.isFile() || stat.isSymbolicLink()) throw new Error("Refusing non-regular managed file");
83
+ return await promises.readFile(path, "utf8");
84
+ } catch (error) {
85
+ if (error.code === "ENOENT") return null;
86
+ throw error;
87
+ }
88
+ }
89
+ async function publish(path, content) {
90
+ const temporary = `${path}.${node_crypto.randomUUID()}.new`;
91
+ try {
92
+ await promises.writeFile(temporary, content, { flag: "wx", mode: 384 });
93
+ await promises.rename(temporary, path);
94
+ } finally {
95
+ await promises.unlink(temporary).catch(() => {
96
+ });
97
+ }
98
+ }
99
+ async function installTeamSkill(options) {
100
+ const directory = path.join(path.resolve(options.home), ".local", "share", "very-happy", "skills", "very-happy-teams");
101
+ await assertPrivateDestination(directory);
102
+ const file = path.join(directory, "SKILL.md");
103
+ const manifest = path.join(directory, ".very-happy-managed.json");
104
+ const current = await read(file);
105
+ const managed = await read(manifest);
106
+ const previous = managed ? JSON.parse(managed) : null;
107
+ if (previous && previous.owner !== "very-happy") throw new Error("Existing manifest is not owned by Very Happy");
108
+ if (current !== null && (!previous || previous.owner !== "very-happy" || previous.sha256 !== digest(current) && previous.pendingSha256 !== digest(current))) {
109
+ throw new Error("Existing skill is not owned by Very Happy or was edited; preserve it and resolve manually");
110
+ }
111
+ const action = options.uninstall ? current === null && managed === null ? "unchanged" : "remove" : current === resources.TEAM_SKILL && !previous?.pendingSha256 ? "unchanged" : "write";
112
+ if (options.apply && action !== "unchanged") {
113
+ await assertPrivateDestination(directory);
114
+ if (options.uninstall) {
115
+ if (current !== null) await promises.unlink(file);
116
+ if (managed !== null) await promises.unlink(manifest);
117
+ await promises.rmdir(directory).catch(() => {
118
+ });
119
+ } else {
120
+ await promises.mkdir(directory, { recursive: true });
121
+ const nextHash = digest(resources.TEAM_SKILL);
122
+ await publish(manifest, JSON.stringify({ owner: "very-happy", sha256: current === null ? null : digest(current), pendingSha256: nextHash, version: 1 }));
123
+ await publish(file, resources.TEAM_SKILL);
124
+ await publish(manifest, JSON.stringify({ owner: "very-happy", sha256: nextHash, version: 1 }));
125
+ }
126
+ }
127
+ return { host: options.host, path: file, action, applied: !!options.apply, discovery: "No host skill directories are modified. Read this absolute skill path in a managed session.", managedSessions: "Team tools are injected by Very Happy. Standalone agents require a managed session connection." };
128
+ }
129
+
130
+ async function handleTeamsCommand(args) {
131
+ const command = args[0];
132
+ const value = (flag) => {
133
+ const index = args.indexOf(flag);
134
+ return index < 0 ? void 0 : args[index + 1];
135
+ };
136
+ if (!command || command === "--help") {
137
+ console.log("very-happy teams install|uninstall --host claude|codex|pi [--home PATH] [--apply]\nvery-happy teams doctor --host pi\nvery-happy teams migration-preview --file LEDGER_JSON\nvery-happy teams inspect\nvery-happy teams permissions --team-id ID --mode default|bypassPermissions --request-id ID\nvery-happy teams create|join --name NAME [--machine-id ID | --team-id ID] [--session-id ID] [--request-id ID]\nvery-happy teams action --json ACTION_JSON --request-id ID\nInstallation previews changes unless --apply is supplied. Managed sessions receive tools automatically.");
138
+ return;
139
+ }
140
+ if (command === "install" || command === "uninstall") {
141
+ const host = value("--host");
142
+ if (!host || !["claude", "codex", "pi"].includes(host)) throw new Error("--host must be claude, codex, or pi");
143
+ console.log(JSON.stringify(await installTeamSkill({ host, home: value("--home") ?? os.homedir(), apply: args.includes("--apply"), uninstall: command === "uninstall" })));
144
+ return;
145
+ }
146
+ if (command === "doctor") {
147
+ if (value("--host") !== "pi") throw new Error("doctor currently requires --host pi");
148
+ console.log(JSON.stringify({
149
+ host: "pi",
150
+ entry: "very-happy pi",
151
+ commandSource: process.env.PI_ACP_PI_COMMAND ? "PI_ACP_PI_COMMAND override (preserved)" : "pi from PATH",
152
+ delegatedCommandSource: process.env.VH_TEAM_PI_COMMAND ? "VH_TEAM_PI_COMMAND is set" : "not set",
153
+ officialBridge: "Injected by Very Happy managed pi sessions through HAPPY_MCP_URL",
154
+ permissions: "Official permission gate; user extensions may enforce additional rules",
155
+ check: "Run in the daemon environment. Audit pi settings extensions and any wrapper before removing private bindings. This diagnostic does not verify binary availability or a live connection.",
156
+ standalone: "Bare pi skill loading does not establish Teams transport or wakeup"
157
+ }, null, 2));
158
+ return;
159
+ }
160
+ if (command === "migration-preview") {
161
+ const file = value("--file");
162
+ if (!file) throw new Error("--file is required");
163
+ console.log(JSON.stringify(previewLegacyTeamsMigration(JSON.parse(await promises.readFile(file, "utf8"))), null, 2));
164
+ return;
165
+ }
166
+ if (command === "permissions") {
167
+ const teamId = value("--team-id"), mode = value("--mode"), requestId = value("--request-id");
168
+ if (!teamId || !mode || !requestId) throw new Error("--team-id, --mode and --request-id are required");
169
+ console.log(JSON.stringify(await setTeamPermissionMode(teamId, mode, requestId)));
170
+ return;
171
+ }
172
+ const client = agentGuidance.createTeamsClient(value("--session-id"));
173
+ let result;
174
+ if (command === "inspect") result = await client.inspect();
175
+ else if (command === "create" || command === "join") {
176
+ const name = value("--name");
177
+ if (!name) throw new Error("--name is required");
178
+ if (command === "join" && !value("--team-id")) throw new Error("--team-id is required");
179
+ result = await client.initialize({ name, teamId: command === "join" ? value("--team-id") : void 0, machineId: value("--machine-id"), botId: value("--bot-id"), requestId: value("--request-id") ?? node_crypto.randomUUID() });
180
+ } else if (command === "action") {
181
+ const payload = value("--json");
182
+ const requestId = value("--request-id");
183
+ if (!payload || !requestId) throw new Error("--json and --request-id are required");
184
+ const action = JSON.parse(payload);
185
+ if (!["delegate", "message", "submit", "accept", "return", "cancel", "handoff", "schedule-create", "schedule-pause", "schedule-resume", "schedule-cancel"].includes(action.type)) throw new Error("Unsupported team action");
186
+ result = await client.action(action, requestId);
187
+ } else throw new Error("Unknown teams command; use teams --help");
188
+ console.log(JSON.stringify(result));
189
+ }
190
+
191
+ exports.handleTeamsCommand = handleTeamsCommand;