@vm0/cli 9.238.2 → 9.238.4
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/{agent-232YB3UW.js → agent-DY657IHK.js} +6 -8
- package/{agent-232YB3UW.js.map → agent-DY657IHK.js.map} +1 -1
- package/{banking-W4YOUOGR.js → banking-WZ5ZXNHW.js} +4 -6
- package/{banking-W4YOUOGR.js.map → banking-WZ5ZXNHW.js.map} +1 -1
- package/{chat-U7IY4EFM.js → chat-ORHRUMSC.js} +5 -7
- package/{chat-U7IY4EFM.js.map → chat-ORHRUMSC.js.map} +1 -1
- package/{chunk-TDHY3N5U.js → chunk-6TXV6T6G.js} +2 -2
- package/{chunk-QRWCZFSW.js → chunk-APIZB5CD.js} +5 -7
- package/{chunk-QRWCZFSW.js.map → chunk-APIZB5CD.js.map} +1 -1
- package/{chunk-LSV2VNTU.js → chunk-CYF7PHDS.js} +2832 -1327
- package/chunk-CYF7PHDS.js.map +1 -0
- package/{chunk-63SY7N6Y.js → chunk-EH4MVCB3.js} +2 -2
- package/{chunk-5IL2HDF6.js → chunk-GA7UX3FL.js} +1408 -32
- package/chunk-GA7UX3FL.js.map +1 -0
- package/{chunk-OJDPK7NK.js → chunk-GU4IPLKQ.js} +2 -2
- package/{chunk-OJDPK7NK.js.map → chunk-GU4IPLKQ.js.map} +1 -1
- package/{chunk-LKJRJF2G.js → chunk-JH5O3APS.js} +3 -3
- package/{chunk-PT3JWQPE.js → chunk-MZTSDUUX.js} +2 -2
- package/{chunk-HVKP7UPZ.js → chunk-XVW5RA46.js} +23 -1051
- package/chunk-XVW5RA46.js.map +1 -0
- package/{chunk-V2OYP5BZ.js → chunk-Z4SU5SW5.js} +227 -200
- package/chunk-Z4SU5SW5.js.map +1 -0
- package/{chunk-H3PJLBYQ.js → chunk-ZRG2A3OV.js} +4 -4
- package/{computer-use-FMWOZUIP.js → computer-use-NKBLGFEQ.js} +3 -4
- package/{computer-use-FMWOZUIP.js.map → computer-use-NKBLGFEQ.js.map} +1 -1
- package/{connector-YOH3JOKV.js → connector-7AIQZYTK.js} +5 -7
- package/{connector-YOH3JOKV.js.map → connector-7AIQZYTK.js.map} +1 -1
- package/{credit-BSKBYVKJ.js → credit-TIOONK33.js} +5 -7
- package/{credit-BSKBYVKJ.js.map → credit-TIOONK33.js.map} +1 -1
- package/{developer-support-MLHK3AS5.js → developer-support-IM7P3PNY.js} +3 -4
- package/{developer-support-MLHK3AS5.js.map → developer-support-IM7P3PNY.js.map} +1 -1
- package/{doctor-AXSIJ2XY.js → doctor-UG5O6IF2.js} +32 -18
- package/doctor-UG5O6IF2.js.map +1 -0
- package/{generate-IX7Y7HZH.js → generate-FFZOGVVZ.js} +6 -8
- package/{generate-IX7Y7HZH.js.map → generate-FFZOGVVZ.js.map} +1 -1
- package/{github-DLJEXA4P.js → github-B4A2NYZE.js} +3 -4
- package/{github-DLJEXA4P.js.map → github-B4A2NYZE.js.map} +1 -1
- package/{goal-R6NDTIHJ.js → goal-MQVOVTDO.js} +3 -4
- package/{goal-R6NDTIHJ.js.map → goal-MQVOVTDO.js.map} +1 -1
- package/google-contacts.generated-FL6Z7MTD.js +16 -0
- package/google-contacts.generated-FL6Z7MTD.js.map +1 -0
- package/google-contacts.generated-Q67YBTPW.js +16 -0
- package/google-contacts.generated-Q67YBTPW.js.map +1 -0
- package/google-forms.generated-AOKO24AB.js +16 -0
- package/google-forms.generated-AOKO24AB.js.map +1 -0
- package/google-forms.generated-KDCHIV43.js +16 -0
- package/google-forms.generated-KDCHIV43.js.map +1 -0
- package/{host-VD5GWO4T.js → host-OP2HJH6Y.js} +4 -6
- package/{host-VD5GWO4T.js.map → host-OP2HJH6Y.js.map} +1 -1
- package/index.js +17 -20
- package/index.js.map +1 -1
- package/{logs-NQI3ITVT.js → logs-CA6HKKD7.js} +8 -11
- package/{logs-NQI3ITVT.js.map → logs-CA6HKKD7.js.map} +1 -1
- package/{maps-XLAARX76.js → maps-IR4XLNKS.js} +4 -6
- package/{maps-XLAARX76.js.map → maps-IR4XLNKS.js.map} +1 -1
- package/{memory-UUNI5B2C.js → memory-KRW4WNNT.js} +4 -6
- package/{memory-UUNI5B2C.js.map → memory-KRW4WNNT.js.map} +1 -1
- package/{model-LMW4L5P6.js → model-N4ZX7CTX.js} +6 -8
- package/{model-LMW4L5P6.js.map → model-N4ZX7CTX.js.map} +1 -1
- package/{model-provider-2FCSBI3H.js → model-provider-U4P563EL.js} +5 -7
- package/{model-provider-2FCSBI3H.js.map → model-provider-U4P563EL.js.map} +1 -1
- package/{org-N6CEZGPY.js → org-IESFCHFN.js} +10 -12
- package/{org-N6CEZGPY.js.map → org-IESFCHFN.js.map} +1 -1
- package/package.json +1 -1
- package/{phone-LZ5VKEA5.js → phone-EBV43OF4.js} +4 -6
- package/{phone-LZ5VKEA5.js.map → phone-EBV43OF4.js.map} +1 -1
- package/{preference-F2IDGWK3.js → preference-ZBNLMRLI.js} +4 -6
- package/{preference-F2IDGWK3.js.map → preference-ZBNLMRLI.js.map} +1 -1
- package/{relationship-7EV3WLB3.js → relationship-TP2F7LLQ.js} +4 -6
- package/{relationship-7EV3WLB3.js.map → relationship-TP2F7LLQ.js.map} +1 -1
- package/{resource-MJISJ52Q.js → resource-OTHN2AGX.js} +5 -7
- package/{resource-MJISJ52Q.js.map → resource-OTHN2AGX.js.map} +1 -1
- package/{search-SEXZVPOC.js → search-4JZ5XQIQ.js} +8 -11
- package/{search-SEXZVPOC.js.map → search-4JZ5XQIQ.js.map} +1 -1
- package/{secret-Z3CACK36.js → secret-73Y3IETU.js} +12 -26
- package/secret-73Y3IETU.js.map +1 -0
- package/{slack-QDZZZ2AV.js → slack-5NXJ5HF5.js} +4 -6
- package/{slack-QDZZZ2AV.js.map → slack-5NXJ5HF5.js.map} +1 -1
- package/{teams-LG4URJER.js → teams-DXT4NI2S.js} +4 -6
- package/{teams-LG4URJER.js.map → teams-DXT4NI2S.js.map} +1 -1
- package/{telegram-GLGHTNGM.js → telegram-DRWWXQNJ.js} +4 -6
- package/{telegram-GLGHTNGM.js.map → telegram-DRWWXQNJ.js.map} +1 -1
- package/{variable-TXYIWD3G.js → variable-LP5GN2VJ.js} +4 -6
- package/{variable-TXYIWD3G.js.map → variable-LP5GN2VJ.js.map} +1 -1
- package/{video-E56LX44R.js → video-TNA6D37U.js} +2 -3
- package/{video-E56LX44R.js.map → video-TNA6D37U.js.map} +1 -1
- package/{web-Q3NRMNK3.js → web-KNGVOG6B.js} +3 -4
- package/{web-Q3NRMNK3.js.map → web-KNGVOG6B.js.map} +1 -1
- package/{whoami-HRHU43T7.js → whoami-O7ZRGGC7.js} +6 -8
- package/{whoami-HRHU43T7.js.map → whoami-O7ZRGGC7.js.map} +1 -1
- package/{workflow-S46MZV7Z.js → workflow-FYC7N3RU.js} +5 -7
- package/workflow-FYC7N3RU.js.map +1 -0
- package/zero.js +34 -51
- package/zero.js.map +1 -1
- package/automation-7MAK66QT.js +0 -31
- package/automation-7MAK66QT.js.map +0 -1
- package/chunk-5BTPFZG2.js +0 -1301
- package/chunk-5BTPFZG2.js.map +0 -1
- package/chunk-5IL2HDF6.js.map +0 -1
- package/chunk-HVKP7UPZ.js.map +0 -1
- package/chunk-JUTUEPIR.js +0 -512
- package/chunk-JUTUEPIR.js.map +0 -1
- package/chunk-LSV2VNTU.js.map +0 -1
- package/chunk-V2OYP5BZ.js.map +0 -1
- package/doctor-AXSIJ2XY.js.map +0 -1
- package/schedule-OSHL7HWT.js +0 -33
- package/schedule-OSHL7HWT.js.map +0 -1
- package/secret-Z3CACK36.js.map +0 -1
- package/workflow-S46MZV7Z.js.map +0 -1
- /package/{chunk-TDHY3N5U.js.map → chunk-6TXV6T6G.js.map} +0 -0
- /package/{chunk-63SY7N6Y.js.map → chunk-EH4MVCB3.js.map} +0 -0
- /package/{chunk-LKJRJF2G.js.map → chunk-JH5O3APS.js.map} +0 -0
- /package/{chunk-PT3JWQPE.js.map → chunk-MZTSDUUX.js.map} +0 -0
- /package/{chunk-H3PJLBYQ.js.map → chunk-ZRG2A3OV.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/zero/relationship/index.ts","../src/commands/zero/relationship/get.ts","../src/commands/zero/relationship/format.ts","../src/commands/zero/relationship/search.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { getCommand } from \"./get\";\nimport { searchCommand } from \"./search\";\n\nexport const zeroRelationshipCommand = new Command()\n .name(\"relationship\")\n .description(\"Query relationship memory\")\n .addCommand(getCommand)\n .addCommand(searchCommand);\n","import chalk from \"chalk\";\nimport { Command } from \"commander\";\n\nimport { resolveZeroRelationship } from \"../../../lib/api\";\nimport { withErrorHandler } from \"../../../lib/command\";\nimport { printRelationship } from \"./format\";\n\ninterface GetOptions {\n readonly id?: string;\n readonly email?: string;\n readonly domain?: string;\n readonly json?: boolean;\n}\n\nfunction selectedLookupCount(options: GetOptions): number {\n return [options.id, options.email, options.domain].filter((value) => {\n return Boolean(value);\n }).length;\n}\n\nfunction printUsageError(message: string, hint: string): never {\n console.error(chalk.red(`✗ ${message}`));\n console.error(chalk.dim(` ${hint}`));\n process.exit(1);\n}\n\nexport const getCommand = new Command()\n .name(\"get\")\n .description(\"Resolve a relationship by id, email, or domain\")\n .option(\"--id <id>\", \"Resolve by relationship id\")\n .option(\"--email <email>\", \"Resolve by primary email\")\n .option(\"--domain <domain>\", \"Resolve by domain\")\n .option(\"--json\", \"Print machine-readable JSON\")\n .addHelpText(\n \"after\",\n `\nExamples:\n Resolve by email: zero relationship get --email alice@acme.com\n Resolve by domain: zero relationship get --domain acme.com\n Resolve by id: zero relationship get --id <relationship-id>\n Print JSON: zero relationship get --email alice@acme.com --json\n\nNotes:\n - Uses the authenticated user's active organization\n - Does not support cross-organization lookup\n - This command is read-only`,\n )\n .action(\n withErrorHandler(async (options: GetOptions) => {\n if (selectedLookupCount(options) !== 1) {\n printUsageError(\n \"Choose exactly one lookup\",\n \"Pass one of --id, --email, or --domain.\",\n );\n }\n\n const response = await resolveZeroRelationship(\n options.id\n ? { id: options.id }\n : options.email\n ? { email: options.email }\n : { domain: options.domain! },\n );\n\n if (options.json) {\n console.log(JSON.stringify(response));\n return;\n }\n\n if (!response.relationship) {\n console.log(\"No relationship found\");\n return;\n }\n\n printRelationship(response.relationship);\n }),\n );\n","import chalk from \"chalk\";\nimport type { RelationshipRecord } from \"@vm0/api-contracts/contracts/zero-relationships\";\n\nfunction formatDate(value: string | null): string {\n if (!value) {\n return \"never\";\n }\n return new Intl.DateTimeFormat(undefined, {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n }).format(new Date(value));\n}\n\nfunction itemsOfKind(\n relationship: RelationshipRecord,\n kind: RelationshipRecord[\"items\"][number][\"kind\"],\n) {\n return relationship.items.filter((item) => {\n return item.kind === kind;\n });\n}\n\nfunction printItems(\n title: string,\n items: readonly RelationshipRecord[\"items\"][number][],\n): void {\n if (items.length === 0) {\n return;\n }\n console.log(\"\");\n console.log(chalk.bold(title));\n for (const item of items) {\n const source = item.sources[0];\n const sourceText = source\n ? chalk.dim(` (${source.provider}, ${formatDate(source.occurredAt)})`)\n : \"\";\n console.log(` - ${item.text}${sourceText}`);\n }\n}\n\nexport function printRelationship(relationship: RelationshipRecord): void {\n console.log(chalk.green(\"✓ Relationship loaded\"));\n console.log(chalk.bold(relationship.entity.displayName));\n if (relationship.entity.primaryEmail) {\n console.log(chalk.dim(` Email: ${relationship.entity.primaryEmail}`));\n }\n if (relationship.entity.domain) {\n console.log(chalk.dim(` Domain: ${relationship.entity.domain}`));\n }\n console.log(chalk.dim(` Type: ${relationship.relationshipType}`));\n console.log(chalk.dim(` Status: ${relationship.status}`));\n console.log(\n chalk.dim(` Last touch: ${formatDate(relationship.lastInteractionAt)}`),\n );\n\n if (relationship.summary) {\n console.log(\"\");\n console.log(relationship.summary);\n }\n\n printItems(\"Key facts\", itemsOfKind(relationship, \"key_fact\"));\n printItems(\"Preferences\", itemsOfKind(relationship, \"preference\"));\n printItems(\"Open loops\", itemsOfKind(relationship, \"open_loop\"));\n}\n\nexport function printRelationshipSearch(\n relationships: readonly RelationshipRecord[],\n): void {\n if (relationships.length === 0) {\n console.log(\"No relationships found\");\n return;\n }\n\n console.log(chalk.green(`✓ Found ${relationships.length} relationships`));\n for (const relationship of relationships) {\n const primary =\n relationship.entity.primaryEmail ?? relationship.entity.domain ?? \"\";\n const suffix = primary ? chalk.dim(` - ${primary}`) : \"\";\n console.log(\n `${relationship.entity.displayName}${suffix} ${chalk.dim(\n `(${relationship.relationshipType}, ${formatDate(\n relationship.lastInteractionAt,\n )})`,\n )}`,\n );\n if (relationship.summary) {\n console.log(chalk.dim(` ${relationship.summary}`));\n }\n }\n}\n","import { Command } from \"commander\";\n\nimport { searchZeroRelationships } from \"../../../lib/api\";\nimport { withErrorHandler } from \"../../../lib/command\";\nimport { printRelationshipSearch } from \"./format\";\n\ninterface SearchOptions {\n readonly json?: boolean;\n readonly limit?: string;\n}\n\nfunction parseLimit(value: string | undefined): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n const parsed = Number(value);\n return Number.isInteger(parsed) ? parsed : undefined;\n}\n\nexport const searchCommand = new Command()\n .name(\"search\")\n .description(\"Search relationship memory\")\n .argument(\"<query>\", \"Search query\")\n .option(\"--limit <limit>\", \"Maximum relationships to return\")\n .option(\"--json\", \"Print machine-readable JSON\")\n .addHelpText(\n \"after\",\n `\nExamples:\n Search relationships: zero relationship search \"acme pricing\"\n Print JSON: zero relationship search \"security review\" --json\n\nNotes:\n - Uses the authenticated user's active organization\n - Does not support cross-organization search\n - This command is read-only`,\n )\n .action(\n withErrorHandler(async (query: string, options: SearchOptions) => {\n const response = await searchZeroRelationships({\n q: query,\n limit: parseLimit(options.limit),\n });\n\n if (options.json) {\n console.log(JSON.stringify(response));\n return;\n }\n\n printRelationshipSearch(response.relationships);\n }),\n );\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/commands/zero/relationship/index.ts","../src/commands/zero/relationship/get.ts","../src/commands/zero/relationship/format.ts","../src/commands/zero/relationship/search.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { getCommand } from \"./get\";\nimport { searchCommand } from \"./search\";\n\nexport const zeroRelationshipCommand = new Command()\n .name(\"relationship\")\n .description(\"Query relationship memory\")\n .addCommand(getCommand)\n .addCommand(searchCommand);\n","import chalk from \"chalk\";\nimport { Command } from \"commander\";\n\nimport { resolveZeroRelationship } from \"../../../lib/api\";\nimport { withErrorHandler } from \"../../../lib/command\";\nimport { printRelationship } from \"./format\";\n\ninterface GetOptions {\n readonly id?: string;\n readonly email?: string;\n readonly domain?: string;\n readonly json?: boolean;\n}\n\nfunction selectedLookupCount(options: GetOptions): number {\n return [options.id, options.email, options.domain].filter((value) => {\n return Boolean(value);\n }).length;\n}\n\nfunction printUsageError(message: string, hint: string): never {\n console.error(chalk.red(`✗ ${message}`));\n console.error(chalk.dim(` ${hint}`));\n process.exit(1);\n}\n\nexport const getCommand = new Command()\n .name(\"get\")\n .description(\"Resolve a relationship by id, email, or domain\")\n .option(\"--id <id>\", \"Resolve by relationship id\")\n .option(\"--email <email>\", \"Resolve by primary email\")\n .option(\"--domain <domain>\", \"Resolve by domain\")\n .option(\"--json\", \"Print machine-readable JSON\")\n .addHelpText(\n \"after\",\n `\nExamples:\n Resolve by email: zero relationship get --email alice@acme.com\n Resolve by domain: zero relationship get --domain acme.com\n Resolve by id: zero relationship get --id <relationship-id>\n Print JSON: zero relationship get --email alice@acme.com --json\n\nNotes:\n - Uses the authenticated user's active organization\n - Does not support cross-organization lookup\n - This command is read-only`,\n )\n .action(\n withErrorHandler(async (options: GetOptions) => {\n if (selectedLookupCount(options) !== 1) {\n printUsageError(\n \"Choose exactly one lookup\",\n \"Pass one of --id, --email, or --domain.\",\n );\n }\n\n const response = await resolveZeroRelationship(\n options.id\n ? { id: options.id }\n : options.email\n ? { email: options.email }\n : { domain: options.domain! },\n );\n\n if (options.json) {\n console.log(JSON.stringify(response));\n return;\n }\n\n if (!response.relationship) {\n console.log(\"No relationship found\");\n return;\n }\n\n printRelationship(response.relationship);\n }),\n );\n","import chalk from \"chalk\";\nimport type { RelationshipRecord } from \"@vm0/api-contracts/contracts/zero-relationships\";\n\nfunction formatDate(value: string | null): string {\n if (!value) {\n return \"never\";\n }\n return new Intl.DateTimeFormat(undefined, {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n }).format(new Date(value));\n}\n\nfunction itemsOfKind(\n relationship: RelationshipRecord,\n kind: RelationshipRecord[\"items\"][number][\"kind\"],\n) {\n return relationship.items.filter((item) => {\n return item.kind === kind;\n });\n}\n\nfunction printItems(\n title: string,\n items: readonly RelationshipRecord[\"items\"][number][],\n): void {\n if (items.length === 0) {\n return;\n }\n console.log(\"\");\n console.log(chalk.bold(title));\n for (const item of items) {\n const source = item.sources[0];\n const sourceText = source\n ? chalk.dim(` (${source.provider}, ${formatDate(source.occurredAt)})`)\n : \"\";\n console.log(` - ${item.text}${sourceText}`);\n }\n}\n\nexport function printRelationship(relationship: RelationshipRecord): void {\n console.log(chalk.green(\"✓ Relationship loaded\"));\n console.log(chalk.bold(relationship.entity.displayName));\n if (relationship.entity.primaryEmail) {\n console.log(chalk.dim(` Email: ${relationship.entity.primaryEmail}`));\n }\n if (relationship.entity.domain) {\n console.log(chalk.dim(` Domain: ${relationship.entity.domain}`));\n }\n console.log(chalk.dim(` Type: ${relationship.relationshipType}`));\n console.log(chalk.dim(` Status: ${relationship.status}`));\n console.log(\n chalk.dim(` Last touch: ${formatDate(relationship.lastInteractionAt)}`),\n );\n\n if (relationship.summary) {\n console.log(\"\");\n console.log(relationship.summary);\n }\n\n printItems(\"Key facts\", itemsOfKind(relationship, \"key_fact\"));\n printItems(\"Preferences\", itemsOfKind(relationship, \"preference\"));\n printItems(\"Open loops\", itemsOfKind(relationship, \"open_loop\"));\n}\n\nexport function printRelationshipSearch(\n relationships: readonly RelationshipRecord[],\n): void {\n if (relationships.length === 0) {\n console.log(\"No relationships found\");\n return;\n }\n\n console.log(chalk.green(`✓ Found ${relationships.length} relationships`));\n for (const relationship of relationships) {\n const primary =\n relationship.entity.primaryEmail ?? relationship.entity.domain ?? \"\";\n const suffix = primary ? chalk.dim(` - ${primary}`) : \"\";\n console.log(\n `${relationship.entity.displayName}${suffix} ${chalk.dim(\n `(${relationship.relationshipType}, ${formatDate(\n relationship.lastInteractionAt,\n )})`,\n )}`,\n );\n if (relationship.summary) {\n console.log(chalk.dim(` ${relationship.summary}`));\n }\n }\n}\n","import { Command } from \"commander\";\n\nimport { searchZeroRelationships } from \"../../../lib/api\";\nimport { withErrorHandler } from \"../../../lib/command\";\nimport { printRelationshipSearch } from \"./format\";\n\ninterface SearchOptions {\n readonly json?: boolean;\n readonly limit?: string;\n}\n\nfunction parseLimit(value: string | undefined): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n const parsed = Number(value);\n return Number.isInteger(parsed) ? parsed : undefined;\n}\n\nexport const searchCommand = new Command()\n .name(\"search\")\n .description(\"Search relationship memory\")\n .argument(\"<query>\", \"Search query\")\n .option(\"--limit <limit>\", \"Maximum relationships to return\")\n .option(\"--json\", \"Print machine-readable JSON\")\n .addHelpText(\n \"after\",\n `\nExamples:\n Search relationships: zero relationship search \"acme pricing\"\n Print JSON: zero relationship search \"security review\" --json\n\nNotes:\n - Uses the authenticated user's active organization\n - Does not support cross-organization search\n - This command is read-only`,\n )\n .action(\n withErrorHandler(async (query: string, options: SearchOptions) => {\n const response = await searchZeroRelationships({\n q: query,\n limit: parseLimit(options.limit),\n });\n\n if (options.json) {\n console.log(JSON.stringify(response));\n return;\n }\n\n printRelationshipSearch(response.relationships);\n }),\n );\n"],"mappings":"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","names":[]}
|
|
@@ -13,17 +13,15 @@ import {
|
|
|
13
13
|
findTool,
|
|
14
14
|
findVideoTemplate,
|
|
15
15
|
findWebsiteTemplateResource
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-GU4IPLKQ.js";
|
|
17
17
|
import {
|
|
18
18
|
getRegistryResourceDownload
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-XVW5RA46.js";
|
|
20
20
|
import "./chunk-LTDQISD7.js";
|
|
21
21
|
import {
|
|
22
|
+
source_default,
|
|
22
23
|
withErrorHandler
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import {
|
|
25
|
-
source_default
|
|
26
|
-
} from "./chunk-JUTUEPIR.js";
|
|
24
|
+
} from "./chunk-CYF7PHDS.js";
|
|
27
25
|
import "./chunk-LRHXR7JT.js";
|
|
28
26
|
import {
|
|
29
27
|
Command
|
|
@@ -139,4 +137,4 @@ export {
|
|
|
139
137
|
findRegistryResourceForPull,
|
|
140
138
|
zeroResourceCommand
|
|
141
139
|
};
|
|
142
|
-
//# sourceMappingURL=resource-
|
|
140
|
+
//# sourceMappingURL=resource-OTHN2AGX.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/zero/resource/index.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { mkdir, mkdtemp, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\n\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport * as tar from \"tar\";\nimport {\n findColorSystem,\n findDesignSystem,\n findImageStyle,\n findPresentationRunbookResource,\n findTool,\n findTemplate,\n findVideoTemplate,\n findWebsiteTemplateResource,\n type RegistryEntry,\n type VideoTemplateRegistryEntry,\n} from \"@vm0/core/resource-registry\";\n\nimport { getRegistryResourceDownload } from \"../../../lib/api\";\nimport { withErrorHandler } from \"../../../lib/command\";\n\ntype PullableRegistryEntry = RegistryEntry | VideoTemplateRegistryEntry;\n\ninterface PullOptions {\n readonly dir: string;\n}\n\nfunction candidateIds(id: string): readonly string[] {\n if (id.includes(\":\")) {\n return [id];\n }\n return [\n `template:${id}`,\n `design-system:${id}`,\n `color-system:${id}`,\n `tool:${id}`,\n `image-style:${id}`,\n `video-template:${id}`,\n ];\n}\n\nexport function findRegistryResourceForPull(\n id: string,\n): PullableRegistryEntry | undefined {\n for (const candidate of candidateIds(id)) {\n const entry =\n findTemplate(candidate) ??\n findDesignSystem(candidate) ??\n findColorSystem(candidate) ??\n findTool(candidate) ??\n findImageStyle(candidate) ??\n findVideoTemplate(candidate) ??\n findPresentationRunbookResource(candidate) ??\n findWebsiteTemplateResource(candidate);\n if (entry) {\n return entry;\n }\n }\n return undefined;\n}\n\nfunction isSafeTarPath(entryPath: string): boolean {\n const normalized = entryPath.replace(/\\\\/gu, \"/\");\n return (\n !path.isAbsolute(normalized) &&\n !normalized.split(\"/\").some((segment) => {\n return segment === \"..\";\n })\n );\n}\n\nasync function downloadArchive(url: string): Promise<Buffer> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Resource archive download failed: ${response.status}`);\n }\n return Buffer.from(await response.arrayBuffer());\n}\n\nfunction verifyArchive(buffer: Buffer, expectedSha256: string): void {\n const actual = createHash(\"sha256\").update(buffer).digest(\"hex\");\n if (actual !== expectedSha256) {\n throw new Error(\n `Resource archive digest mismatch: expected ${expectedSha256}, got ${actual}`,\n );\n }\n}\n\nexport const zeroResourceCommand = new Command()\n .name(\"resource\")\n .description(\"Pull registry resources from private R2-backed archives\")\n .addCommand(\n new Command()\n .name(\"pull\")\n .description(\"Download and extract a private registry resource archive\")\n .argument(\n \"<id>\",\n \"Registry resource id, such as template:html-ppt-playful-launch-runbook\",\n )\n .option(\n \"--dir <path>\",\n \"Directory to extract into\",\n \"./generated/resources\",\n )\n .action(\n withErrorHandler(async (id: string, options: PullOptions) => {\n const entry = findRegistryResourceForPull(id);\n if (!entry) {\n throw new Error(`Unknown registry resource: ${id}`);\n }\n\n const archive = entry.source.archive;\n if (!archive) {\n throw new Error(\n `Registry resource ${entry.id} does not provide an R2 archive source`,\n );\n }\n\n console.log(chalk.dim(`Pulling ${entry.id}...`));\n const download = await getRegistryResourceDownload({ id: entry.id });\n if (download.sha256 !== archive.sha256) {\n throw new Error(\n `Resource archive digest metadata mismatch: expected ${archive.sha256}, got ${download.sha256}`,\n );\n }\n\n const buffer = await downloadArchive(download.url);\n verifyArchive(buffer, archive.sha256);\n\n const outputDir = path.resolve(options.dir);\n const tmpDir = await mkdtemp(path.join(tmpdir(), \"zero-resource-\"));\n const archivePath = path.join(tmpDir, \"resource.tar.gz\");\n await mkdir(outputDir, { recursive: true });\n await writeFile(archivePath, buffer);\n\n try {\n await tar.extract({\n file: archivePath,\n cwd: outputDir,\n gzip: true,\n filter: isSafeTarPath,\n });\n } finally {\n await rm(tmpDir, { recursive: true, force: true });\n }\n\n console.log(chalk.green(`✓ Pulled ${entry.id}`));\n console.log(chalk.dim(` Extracted to: ${outputDir}`));\n console.log(\n chalk.dim(\n ` Source path: ${path.join(outputDir, entry.source.path)}`,\n ),\n );\n }),\n ),\n );\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/commands/zero/resource/index.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { mkdir, mkdtemp, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\n\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport * as tar from \"tar\";\nimport {\n findColorSystem,\n findDesignSystem,\n findImageStyle,\n findPresentationRunbookResource,\n findTool,\n findTemplate,\n findVideoTemplate,\n findWebsiteTemplateResource,\n type RegistryEntry,\n type VideoTemplateRegistryEntry,\n} from \"@vm0/core/resource-registry\";\n\nimport { getRegistryResourceDownload } from \"../../../lib/api\";\nimport { withErrorHandler } from \"../../../lib/command\";\n\ntype PullableRegistryEntry = RegistryEntry | VideoTemplateRegistryEntry;\n\ninterface PullOptions {\n readonly dir: string;\n}\n\nfunction candidateIds(id: string): readonly string[] {\n if (id.includes(\":\")) {\n return [id];\n }\n return [\n `template:${id}`,\n `design-system:${id}`,\n `color-system:${id}`,\n `tool:${id}`,\n `image-style:${id}`,\n `video-template:${id}`,\n ];\n}\n\nexport function findRegistryResourceForPull(\n id: string,\n): PullableRegistryEntry | undefined {\n for (const candidate of candidateIds(id)) {\n const entry =\n findTemplate(candidate) ??\n findDesignSystem(candidate) ??\n findColorSystem(candidate) ??\n findTool(candidate) ??\n findImageStyle(candidate) ??\n findVideoTemplate(candidate) ??\n findPresentationRunbookResource(candidate) ??\n findWebsiteTemplateResource(candidate);\n if (entry) {\n return entry;\n }\n }\n return undefined;\n}\n\nfunction isSafeTarPath(entryPath: string): boolean {\n const normalized = entryPath.replace(/\\\\/gu, \"/\");\n return (\n !path.isAbsolute(normalized) &&\n !normalized.split(\"/\").some((segment) => {\n return segment === \"..\";\n })\n );\n}\n\nasync function downloadArchive(url: string): Promise<Buffer> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Resource archive download failed: ${response.status}`);\n }\n return Buffer.from(await response.arrayBuffer());\n}\n\nfunction verifyArchive(buffer: Buffer, expectedSha256: string): void {\n const actual = createHash(\"sha256\").update(buffer).digest(\"hex\");\n if (actual !== expectedSha256) {\n throw new Error(\n `Resource archive digest mismatch: expected ${expectedSha256}, got ${actual}`,\n );\n }\n}\n\nexport const zeroResourceCommand = new Command()\n .name(\"resource\")\n .description(\"Pull registry resources from private R2-backed archives\")\n .addCommand(\n new Command()\n .name(\"pull\")\n .description(\"Download and extract a private registry resource archive\")\n .argument(\n \"<id>\",\n \"Registry resource id, such as template:html-ppt-playful-launch-runbook\",\n )\n .option(\n \"--dir <path>\",\n \"Directory to extract into\",\n \"./generated/resources\",\n )\n .action(\n withErrorHandler(async (id: string, options: PullOptions) => {\n const entry = findRegistryResourceForPull(id);\n if (!entry) {\n throw new Error(`Unknown registry resource: ${id}`);\n }\n\n const archive = entry.source.archive;\n if (!archive) {\n throw new Error(\n `Registry resource ${entry.id} does not provide an R2 archive source`,\n );\n }\n\n console.log(chalk.dim(`Pulling ${entry.id}...`));\n const download = await getRegistryResourceDownload({ id: entry.id });\n if (download.sha256 !== archive.sha256) {\n throw new Error(\n `Resource archive digest metadata mismatch: expected ${archive.sha256}, got ${download.sha256}`,\n );\n }\n\n const buffer = await downloadArchive(download.url);\n verifyArchive(buffer, archive.sha256);\n\n const outputDir = path.resolve(options.dir);\n const tmpDir = await mkdtemp(path.join(tmpdir(), \"zero-resource-\"));\n const archivePath = path.join(tmpDir, \"resource.tar.gz\");\n await mkdir(outputDir, { recursive: true });\n await writeFile(archivePath, buffer);\n\n try {\n await tar.extract({\n file: archivePath,\n cwd: outputDir,\n gzip: true,\n filter: isSafeTarPath,\n });\n } finally {\n await rm(tmpDir, { recursive: true, force: true });\n }\n\n console.log(chalk.green(`✓ Pulled ${entry.id}`));\n console.log(chalk.dim(` Extracted to: ${outputDir}`));\n console.log(\n chalk.dim(\n ` Source path: ${path.join(outputDir, entry.source.path)}`,\n ),\n );\n }),\n ),\n );\n"],"mappings":"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","names":[]}
|
|
@@ -3,27 +3,24 @@ import { createRequire as __createRequire } from "node:module";
|
|
|
3
3
|
const require = __createRequire(import.meta.url);
|
|
4
4
|
import {
|
|
5
5
|
runLogsSearch
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-APIZB5CD.js";
|
|
7
7
|
import {
|
|
8
8
|
formatIsoTimestamp,
|
|
9
9
|
isUUID,
|
|
10
10
|
parseBoundedLogCount,
|
|
11
11
|
parseSearchQuery,
|
|
12
12
|
parseTime
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-5IL2HDF6.js";
|
|
13
|
+
} from "./chunk-Z4SU5SW5.js";
|
|
14
|
+
import "./chunk-GU4IPLKQ.js";
|
|
15
|
+
import "./chunk-GA7UX3FL.js";
|
|
17
16
|
import {
|
|
18
17
|
searchZeroChat
|
|
19
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-XVW5RA46.js";
|
|
20
19
|
import "./chunk-LTDQISD7.js";
|
|
21
20
|
import {
|
|
21
|
+
source_default,
|
|
22
22
|
withErrorHandler
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import {
|
|
25
|
-
source_default
|
|
26
|
-
} from "./chunk-JUTUEPIR.js";
|
|
23
|
+
} from "./chunk-CYF7PHDS.js";
|
|
27
24
|
import "./chunk-LRHXR7JT.js";
|
|
28
25
|
import {
|
|
29
26
|
Command
|
|
@@ -201,4 +198,4 @@ export {
|
|
|
201
198
|
buildSlackRecipe,
|
|
202
199
|
zeroSearchCommand
|
|
203
200
|
};
|
|
204
|
-
//# sourceMappingURL=search-
|
|
201
|
+
//# sourceMappingURL=search-4JZ5XQIQ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/zero/search/index.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { withErrorHandler } from \"../../../lib/command\";\nimport { runLogsSearch, type LogsSearchCliOptions } from \"../logs/search\";\nimport { searchZeroChat } from \"../../../lib/api\";\nimport type {\n ChatSearchMessage,\n ChatSearchResponse,\n} from \"@vm0/api-contracts/contracts/chat-threads\";\nimport { parseTime } from \"../../../lib/utils/time-parser\";\nimport { formatIsoTimestamp } from \"../../../lib/utils/time-format\";\nimport { parseBoundedLogCount } from \"../../../lib/utils/log-pagination\";\nimport { parseSearchQuery } from \"../../../lib/utils/search-query\";\nimport { isUUID } from \"../../run/shared\";\n\nconst SUPPORTED_SOURCES = [\"logs\", \"chat\", \"slack\"] as const;\ntype Source = (typeof SUPPORTED_SOURCES)[number];\n\nconst SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;\n\nexport const SEARCH_EXPLAINER = `\nAvailable sources:\n logs full agent event stream (tool calls, tokens, system events) from agent runs\n chat user/assistant text messages as shown in the web chat UI\n slack returns a recipe for calling the Slack API directly; requires the Slack connector\n\nUsage: zero search <query> --source <logs|chat|slack> [flags]\nRun 'zero search --help' for all flags.`;\n\nexport function buildSlackRecipe(query: string): string {\n const encoded = encodeURIComponent(query);\n return `The \\`slack\\` source does not call Slack from this CLI. Run the\nfollowing inside an agent sandbox that has $SLACK_TOKEN available:\n\n curl -H \"Authorization: Bearer $SLACK_TOKEN\" \\\\\n \"https://slack.com/api/search.messages?query=${encoded}\"\n\nIf you don't have $SLACK_TOKEN, check the connector status:\n zero connector status slack\n\nTo verify the token and network policy end-to-end:\n zero doctor check-connector --env-name SLACK_TOKEN\n\nSlack API docs: https://api.slack.com/methods/search.messages\n\nNote: CLI-local flags (--limit, --since, -A/-B/-C) are ignored for the\nslack source. Pass equivalents to Slack's API via count= / highlight=\nquery parameters instead.`;\n}\n\ninterface SearchOptions {\n source: string[];\n agent?: string;\n run?: string;\n since?: string;\n limit?: string;\n afterContext?: string;\n beforeContext?: string;\n context?: string;\n}\n\nfunction collectSource(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\nfunction parseContextOptions(options: SearchOptions): {\n before: number;\n after: number;\n} {\n const contextN =\n options.context !== undefined\n ? parseBoundedLogCount(options.context, \"--context\", 0, 10)\n : 0;\n const before =\n options.beforeContext !== undefined\n ? parseBoundedLogCount(options.beforeContext, \"--before-context\", 0, 10)\n : contextN;\n const after =\n options.afterContext !== undefined\n ? parseBoundedLogCount(options.afterContext, \"--after-context\", 0, 10)\n : contextN;\n\n return { before, after };\n}\n\nfunction parseLimit(value: string | undefined): number | undefined {\n if (value === undefined) return undefined;\n return parseBoundedLogCount(value, \"--limit\", 1, 50);\n}\n\nasync function runLogsSource(\n query: string,\n options: SearchOptions,\n): Promise<void> {\n const logsOptions: LogsSearchCliOptions = {\n afterContext: options.afterContext,\n beforeContext: options.beforeContext,\n context: options.context,\n agentId: options.agent,\n run: options.run,\n since: options.since,\n limit: options.limit,\n };\n await runLogsSearch(query, logsOptions);\n}\n\nfunction formatTimestamp(iso: string): string {\n return formatIsoTimestamp(iso);\n}\n\nfunction renderChatMessage(msg: ChatSearchMessage, isMatch: boolean): void {\n const marker = isMatch ? chalk.yellow(\"▸\") : chalk.dim(\"·\");\n const header = `${marker} ${chalk.dim(msg.role)} ${chalk.dim(formatTimestamp(msg.createdAt))}`;\n console.log(header);\n console.log(isMatch ? msg.content : chalk.dim(msg.content));\n}\n\nfunction renderChatResults(response: ChatSearchResponse): void {\n let isFirst = true;\n for (const result of response.results) {\n if (!isFirst) console.log();\n isFirst = false;\n\n console.log(\n chalk.bold(\n `── Thread ${result.chatThreadId} (${result.agentName}) ──────────`,\n ),\n );\n for (const msg of result.contextBefore) {\n renderChatMessage(msg, false);\n }\n renderChatMessage(result.matchedMessage, true);\n for (const msg of result.contextAfter) {\n renderChatMessage(msg, false);\n }\n }\n\n if (response.hasMore) {\n console.log();\n console.log(\n chalk.dim(\n ` Showing first ${response.results.length} matches. Use --limit to see more.`,\n ),\n );\n }\n}\n\nasync function runChatSource(\n query: string,\n options: SearchOptions,\n): Promise<void> {\n if (options.run !== undefined) {\n throw new Error(\"--run is not supported with --source chat\");\n }\n if (options.agent !== undefined && !isUUID(options.agent)) {\n console.error(\n chalk.red(`✗ Invalid agent ID \"${options.agent}\" — expected a UUID`),\n );\n console.error(chalk.dim(\" Run: zero logs list to find agent IDs\"));\n process.exit(1);\n }\n\n const { before, after } = parseContextOptions(options);\n const limit = parseLimit(options.limit);\n const since =\n options.since !== undefined\n ? parseTime(options.since)\n : Date.now() - SEVEN_DAYS_MS;\n\n const response = await searchZeroChat({\n keyword: query,\n agentId: options.agent,\n since,\n limit,\n before,\n after,\n });\n\n if (response.results.length === 0) {\n console.log(chalk.dim(\"No matches found\"));\n console.log(\n chalk.dim(\n \" Try a broader search with --since 30d or a different keyword\",\n ),\n );\n return;\n }\n\n renderChatResults(response);\n}\n\nasync function runSlackSource(\n query: string,\n _options: SearchOptions,\n): Promise<void> {\n console.log(buildSlackRecipe(query));\n}\n\nexport const zeroSearchCommand = new Command()\n .name(\"search\")\n .description(\"Search logs, chat, or get a recipe for external sources\")\n .argument(\"<query>\", \"Search query\")\n .option(\n \"--source <type>\",\n \"Source to search: logs | chat | slack (pass once)\",\n collectSource,\n [] as string[],\n )\n .option(\"--agent <id>\", \"Filter by Zero agent ID\")\n .option(\"--run <id>\", \"Filter by run ID\")\n .option(\"--since <time>\", \"Time window (e.g., 7d, 2h)\")\n .option(\"--limit <n>\", \"Maximum number of matches\")\n .option(\"-A, --after-context <n>\", \"Show n items after each match\")\n .option(\"-B, --before-context <n>\", \"Show n items before each match\")\n .option(\"-C, --context <n>\", \"Show n items before and after each match\")\n .addHelpText(\"after\", SEARCH_EXPLAINER)\n .action(\n withErrorHandler(async (query: string, options: SearchOptions) => {\n const searchQuery = parseSearchQuery(query, \"Query\");\n const sources = options.source;\n\n if (sources.length === 0) {\n console.log(SEARCH_EXPLAINER);\n return;\n }\n\n if (sources.length > 1) {\n throw new Error(\"Only one --source is allowed.\");\n }\n\n const source = sources[0]!;\n if (!SUPPORTED_SOURCES.includes(source as Source)) {\n throw new Error(\n `Unknown --source \"${source}\". Expected one of: ${SUPPORTED_SOURCES.join(\", \")}`,\n );\n }\n\n switch (source as Source) {\n case \"logs\":\n await runLogsSource(searchQuery, options);\n return;\n case \"chat\":\n await runChatSource(searchQuery, options);\n return;\n case \"slack\":\n await runSlackSource(searchQuery, options);\n return;\n }\n }),\n );\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/commands/zero/search/index.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { withErrorHandler } from \"../../../lib/command\";\nimport { runLogsSearch, type LogsSearchCliOptions } from \"../logs/search\";\nimport { searchZeroChat } from \"../../../lib/api\";\nimport type {\n ChatSearchMessage,\n ChatSearchResponse,\n} from \"@vm0/api-contracts/contracts/chat-threads\";\nimport { parseTime } from \"../../../lib/utils/time-parser\";\nimport { formatIsoTimestamp } from \"../../../lib/utils/time-format\";\nimport { parseBoundedLogCount } from \"../../../lib/utils/log-pagination\";\nimport { parseSearchQuery } from \"../../../lib/utils/search-query\";\nimport { isUUID } from \"../../run/shared\";\n\nconst SUPPORTED_SOURCES = [\"logs\", \"chat\", \"slack\"] as const;\ntype Source = (typeof SUPPORTED_SOURCES)[number];\n\nconst SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;\n\nexport const SEARCH_EXPLAINER = `\nAvailable sources:\n logs full agent event stream (tool calls, tokens, system events) from agent runs\n chat user/assistant text messages as shown in the web chat UI\n slack returns a recipe for calling the Slack API directly; requires the Slack connector\n\nUsage: zero search <query> --source <logs|chat|slack> [flags]\nRun 'zero search --help' for all flags.`;\n\nexport function buildSlackRecipe(query: string): string {\n const encoded = encodeURIComponent(query);\n return `The \\`slack\\` source does not call Slack from this CLI. Run the\nfollowing inside an agent sandbox that has $SLACK_TOKEN available:\n\n curl -H \"Authorization: Bearer $SLACK_TOKEN\" \\\\\n \"https://slack.com/api/search.messages?query=${encoded}\"\n\nIf you don't have $SLACK_TOKEN, check the connector status:\n zero connector status slack\n\nTo verify the token and network policy end-to-end:\n zero doctor check-connector --env-name SLACK_TOKEN\n\nSlack API docs: https://api.slack.com/methods/search.messages\n\nNote: CLI-local flags (--limit, --since, -A/-B/-C) are ignored for the\nslack source. Pass equivalents to Slack's API via count= / highlight=\nquery parameters instead.`;\n}\n\ninterface SearchOptions {\n source: string[];\n agent?: string;\n run?: string;\n since?: string;\n limit?: string;\n afterContext?: string;\n beforeContext?: string;\n context?: string;\n}\n\nfunction collectSource(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\nfunction parseContextOptions(options: SearchOptions): {\n before: number;\n after: number;\n} {\n const contextN =\n options.context !== undefined\n ? parseBoundedLogCount(options.context, \"--context\", 0, 10)\n : 0;\n const before =\n options.beforeContext !== undefined\n ? parseBoundedLogCount(options.beforeContext, \"--before-context\", 0, 10)\n : contextN;\n const after =\n options.afterContext !== undefined\n ? parseBoundedLogCount(options.afterContext, \"--after-context\", 0, 10)\n : contextN;\n\n return { before, after };\n}\n\nfunction parseLimit(value: string | undefined): number | undefined {\n if (value === undefined) return undefined;\n return parseBoundedLogCount(value, \"--limit\", 1, 50);\n}\n\nasync function runLogsSource(\n query: string,\n options: SearchOptions,\n): Promise<void> {\n const logsOptions: LogsSearchCliOptions = {\n afterContext: options.afterContext,\n beforeContext: options.beforeContext,\n context: options.context,\n agentId: options.agent,\n run: options.run,\n since: options.since,\n limit: options.limit,\n };\n await runLogsSearch(query, logsOptions);\n}\n\nfunction formatTimestamp(iso: string): string {\n return formatIsoTimestamp(iso);\n}\n\nfunction renderChatMessage(msg: ChatSearchMessage, isMatch: boolean): void {\n const marker = isMatch ? chalk.yellow(\"▸\") : chalk.dim(\"·\");\n const header = `${marker} ${chalk.dim(msg.role)} ${chalk.dim(formatTimestamp(msg.createdAt))}`;\n console.log(header);\n console.log(isMatch ? msg.content : chalk.dim(msg.content));\n}\n\nfunction renderChatResults(response: ChatSearchResponse): void {\n let isFirst = true;\n for (const result of response.results) {\n if (!isFirst) console.log();\n isFirst = false;\n\n console.log(\n chalk.bold(\n `── Thread ${result.chatThreadId} (${result.agentName}) ──────────`,\n ),\n );\n for (const msg of result.contextBefore) {\n renderChatMessage(msg, false);\n }\n renderChatMessage(result.matchedMessage, true);\n for (const msg of result.contextAfter) {\n renderChatMessage(msg, false);\n }\n }\n\n if (response.hasMore) {\n console.log();\n console.log(\n chalk.dim(\n ` Showing first ${response.results.length} matches. Use --limit to see more.`,\n ),\n );\n }\n}\n\nasync function runChatSource(\n query: string,\n options: SearchOptions,\n): Promise<void> {\n if (options.run !== undefined) {\n throw new Error(\"--run is not supported with --source chat\");\n }\n if (options.agent !== undefined && !isUUID(options.agent)) {\n console.error(\n chalk.red(`✗ Invalid agent ID \"${options.agent}\" — expected a UUID`),\n );\n console.error(chalk.dim(\" Run: zero logs list to find agent IDs\"));\n process.exit(1);\n }\n\n const { before, after } = parseContextOptions(options);\n const limit = parseLimit(options.limit);\n const since =\n options.since !== undefined\n ? parseTime(options.since)\n : Date.now() - SEVEN_DAYS_MS;\n\n const response = await searchZeroChat({\n keyword: query,\n agentId: options.agent,\n since,\n limit,\n before,\n after,\n });\n\n if (response.results.length === 0) {\n console.log(chalk.dim(\"No matches found\"));\n console.log(\n chalk.dim(\n \" Try a broader search with --since 30d or a different keyword\",\n ),\n );\n return;\n }\n\n renderChatResults(response);\n}\n\nasync function runSlackSource(\n query: string,\n _options: SearchOptions,\n): Promise<void> {\n console.log(buildSlackRecipe(query));\n}\n\nexport const zeroSearchCommand = new Command()\n .name(\"search\")\n .description(\"Search logs, chat, or get a recipe for external sources\")\n .argument(\"<query>\", \"Search query\")\n .option(\n \"--source <type>\",\n \"Source to search: logs | chat | slack (pass once)\",\n collectSource,\n [] as string[],\n )\n .option(\"--agent <id>\", \"Filter by Zero agent ID\")\n .option(\"--run <id>\", \"Filter by run ID\")\n .option(\"--since <time>\", \"Time window (e.g., 7d, 2h)\")\n .option(\"--limit <n>\", \"Maximum number of matches\")\n .option(\"-A, --after-context <n>\", \"Show n items after each match\")\n .option(\"-B, --before-context <n>\", \"Show n items before each match\")\n .option(\"-C, --context <n>\", \"Show n items before and after each match\")\n .addHelpText(\"after\", SEARCH_EXPLAINER)\n .action(\n withErrorHandler(async (query: string, options: SearchOptions) => {\n const searchQuery = parseSearchQuery(query, \"Query\");\n const sources = options.source;\n\n if (sources.length === 0) {\n console.log(SEARCH_EXPLAINER);\n return;\n }\n\n if (sources.length > 1) {\n throw new Error(\"Only one --source is allowed.\");\n }\n\n const source = sources[0]!;\n if (!SUPPORTED_SOURCES.includes(source as Source)) {\n throw new Error(\n `Unknown --source \"${source}\". Expected one of: ${SUPPORTED_SOURCES.join(\", \")}`,\n );\n }\n\n switch (source as Source) {\n case \"logs\":\n await runLogsSource(searchQuery, options);\n return;\n case \"chat\":\n await runChatSource(searchQuery, options);\n return;\n case \"slack\":\n await runSlackSource(searchQuery, options);\n return;\n }\n }),\n );\n"],"mappings":"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","names":[]}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __createRequire } from "node:module";
|
|
3
3
|
const require = __createRequire(import.meta.url);
|
|
4
|
-
import {
|
|
5
|
-
getConnectorStoredSecretDisplayInfo
|
|
6
|
-
} from "./chunk-5IL2HDF6.js";
|
|
7
4
|
import {
|
|
8
5
|
isInteractive,
|
|
9
6
|
promptConfirm,
|
|
@@ -13,14 +10,12 @@ import {
|
|
|
13
10
|
deleteZeroSecret,
|
|
14
11
|
listZeroSecrets,
|
|
15
12
|
setZeroSecret
|
|
16
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-XVW5RA46.js";
|
|
17
14
|
import "./chunk-LTDQISD7.js";
|
|
18
15
|
import {
|
|
16
|
+
source_default,
|
|
19
17
|
withErrorHandler
|
|
20
|
-
} from "./chunk-
|
|
21
|
-
import {
|
|
22
|
-
source_default
|
|
23
|
-
} from "./chunk-JUTUEPIR.js";
|
|
18
|
+
} from "./chunk-CYF7PHDS.js";
|
|
24
19
|
import "./chunk-LRHXR7JT.js";
|
|
25
20
|
import {
|
|
26
21
|
Command
|
|
@@ -51,24 +46,15 @@ var listCommand = new Command().name("list").alias("ls").description("List all s
|
|
|
51
46
|
let derivedLine = null;
|
|
52
47
|
if (secret.type === "model-provider") {
|
|
53
48
|
typeIndicator = source_default.dim(" [model-provider]");
|
|
49
|
+
} else if (secret.connectorDisplay) {
|
|
50
|
+
typeIndicator = source_default.dim(
|
|
51
|
+
` [${secret.connectorDisplay.label} connector]`
|
|
52
|
+
);
|
|
53
|
+
derivedLine = source_default.dim(
|
|
54
|
+
`Available as: ${secret.connectorDisplay.environmentNames.join(", ")}`
|
|
55
|
+
);
|
|
54
56
|
} else if (secret.type === "connector") {
|
|
55
|
-
|
|
56
|
-
if (derived) {
|
|
57
|
-
typeIndicator = source_default.dim(` [${derived.connectorLabel} connector]`);
|
|
58
|
-
derivedLine = source_default.dim(
|
|
59
|
-
`Available as: ${derived.envNames.join(", ")}`
|
|
60
|
-
);
|
|
61
|
-
} else {
|
|
62
|
-
typeIndicator = source_default.dim(" [connector]");
|
|
63
|
-
}
|
|
64
|
-
} else if (secret.type === "user") {
|
|
65
|
-
const derived = getConnectorStoredSecretDisplayInfo(secret.name);
|
|
66
|
-
if (derived) {
|
|
67
|
-
typeIndicator = source_default.dim(` [${derived.connectorLabel} connector]`);
|
|
68
|
-
derivedLine = source_default.dim(
|
|
69
|
-
`Available as: ${derived.envNames.join(", ")}`
|
|
70
|
-
);
|
|
71
|
-
}
|
|
57
|
+
typeIndicator = source_default.dim(" [connector]");
|
|
72
58
|
}
|
|
73
59
|
console.log(` ${source_default.cyan(secret.name)}${typeIndicator}`);
|
|
74
60
|
if (derivedLine) {
|
|
@@ -160,4 +146,4 @@ var zeroSecretCommand = new Command().name("secret").description("Read or write
|
|
|
160
146
|
export {
|
|
161
147
|
zeroSecretCommand
|
|
162
148
|
};
|
|
163
|
-
//# sourceMappingURL=secret-
|
|
149
|
+
//# sourceMappingURL=secret-73Y3IETU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/zero/secret/index.ts","../src/commands/zero/secret/list.ts","../src/commands/zero/secret/set.ts","../src/commands/zero/secret/delete.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { listCommand } from \"./list\";\nimport { setCommand } from \"./set\";\nimport { deleteCommand } from \"./delete\";\n\nexport const zeroSecretCommand = new Command()\n .name(\"secret\")\n .description(\"Read or write secrets (API keys, tokens)\")\n .addCommand(listCommand)\n .addCommand(setCommand)\n .addCommand(deleteCommand);\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { listZeroSecrets } from \"../../../lib/api\";\nimport { withErrorHandler } from \"../../../lib/command\";\n\nexport const listCommand = new Command()\n .name(\"list\")\n .alias(\"ls\")\n .description(\"List all secrets\")\n .action(\n withErrorHandler(async () => {\n const result = await listZeroSecrets();\n\n if (result.secrets.length === 0) {\n console.log(chalk.dim(\"No secrets found\"));\n console.log();\n console.log(\"To add a secret:\");\n console.log(chalk.cyan(\" zero secret set MY_API_KEY --body <value>\"));\n return;\n }\n\n console.log(chalk.bold(\"Secrets:\"));\n console.log();\n\n for (const secret of result.secrets) {\n let typeIndicator = \"\";\n let derivedLine: string | null = null;\n\n if (secret.type === \"model-provider\") {\n typeIndicator = chalk.dim(\" [model-provider]\");\n } else if (secret.connectorDisplay) {\n typeIndicator = chalk.dim(\n ` [${secret.connectorDisplay.label} connector]`,\n );\n derivedLine = chalk.dim(\n `Available as: ${secret.connectorDisplay.environmentNames.join(\", \")}`,\n );\n } else if (secret.type === \"connector\") {\n typeIndicator = chalk.dim(\" [connector]\");\n }\n\n console.log(` ${chalk.cyan(secret.name)}${typeIndicator}`);\n if (derivedLine) {\n console.log(` ${derivedLine}`);\n }\n if (secret.description) {\n console.log(` ${chalk.dim(secret.description)}`);\n }\n console.log(\n ` ${chalk.dim(`Updated: ${new Date(secret.updatedAt).toLocaleString()}`)}`,\n );\n console.log();\n }\n\n console.log(chalk.dim(`Total: ${result.secrets.length} secret(s)`));\n }),\n );\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { setZeroSecret } from \"../../../lib/api\";\nimport { isInteractive, promptPassword } from \"../../../lib/utils/prompt-utils\";\nimport { withErrorHandler } from \"../../../lib/command\";\n\nexport const setCommand = new Command()\n .name(\"set\")\n .description(\"Create or update a secret\")\n .argument(\"<name>\", \"Secret name (uppercase, e.g., MY_API_KEY)\")\n .option(\n \"-b, --body <value>\",\n \"Secret value (required in non-interactive mode)\",\n )\n .option(\"-d, --description <description>\", \"Optional description\")\n .action(\n withErrorHandler(\n async (\n name: string,\n options: { body?: string; description?: string },\n ) => {\n let value: string;\n\n if (options.body !== undefined) {\n value = options.body;\n } else if (isInteractive()) {\n const prompted = await promptPassword(\"Enter secret value:\");\n if (prompted === undefined) {\n console.log(chalk.dim(\"Cancelled\"));\n return;\n }\n value = prompted;\n } else {\n throw new Error(\"--body is required in non-interactive mode\", {\n cause: new Error(\n `Usage: zero secret set ${name} --body \"your-secret-value\"`,\n ),\n });\n }\n\n let secret;\n try {\n secret = await setZeroSecret({\n name,\n value,\n description: options.description,\n });\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes(\"must contain only uppercase\")\n ) {\n throw new Error(error.message, {\n cause: new Error(\n \"Examples of valid secret names: MY_API_KEY, GITHUB_TOKEN, AWS_ACCESS_KEY_ID\",\n ),\n });\n }\n throw error;\n }\n\n console.log(chalk.green(`✓ Secret \"${secret.name}\" saved`));\n },\n ),\n );\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { deleteZeroSecret } from \"../../../lib/api\";\nimport { isInteractive, promptConfirm } from \"../../../lib/utils/prompt-utils\";\nimport { withErrorHandler } from \"../../../lib/command\";\n\nexport const deleteCommand = new Command()\n .name(\"delete\")\n .description(\"Delete a secret\")\n .argument(\"<name>\", \"Secret name to delete\")\n .option(\"-y, --yes\", \"Skip confirmation prompt\")\n .action(\n withErrorHandler(async (name: string, options: { yes?: boolean }) => {\n if (!options.yes) {\n if (!isInteractive()) {\n throw new Error(\"--yes flag is required in non-interactive mode\");\n }\n\n const confirmed = await promptConfirm(\n `Are you sure you want to delete secret \"${name}\"?`,\n false,\n );\n\n if (!confirmed) {\n console.log(chalk.dim(\"Cancelled\"));\n return;\n }\n }\n\n await deleteZeroSecret(name);\n console.log(chalk.green(`✓ Secret \"${name}\" deleted`));\n }),\n );\n"],"mappings":"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","names":[]}
|
|
@@ -6,14 +6,12 @@ import {
|
|
|
6
6
|
downloadSlackFile,
|
|
7
7
|
initSlackFileUpload,
|
|
8
8
|
sendSlackMessage
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-XVW5RA46.js";
|
|
10
10
|
import "./chunk-LTDQISD7.js";
|
|
11
11
|
import {
|
|
12
|
+
source_default,
|
|
12
13
|
withErrorHandler
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import {
|
|
15
|
-
source_default
|
|
16
|
-
} from "./chunk-JUTUEPIR.js";
|
|
14
|
+
} from "./chunk-CYF7PHDS.js";
|
|
17
15
|
import "./chunk-LRHXR7JT.js";
|
|
18
16
|
import {
|
|
19
17
|
Command
|
|
@@ -220,4 +218,4 @@ Examples:
|
|
|
220
218
|
export {
|
|
221
219
|
zeroSlackCommand
|
|
222
220
|
};
|
|
223
|
-
//# sourceMappingURL=slack-
|
|
221
|
+
//# sourceMappingURL=slack-5NXJ5HF5.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/zero/slack/index.ts","../src/commands/zero/slack/message/index.ts","../src/commands/zero/slack/message/send.ts","../src/commands/zero/slack/upload-file.ts","../src/commands/zero/slack/download-file.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { zeroSlackMessageCommand } from \"./message\";\nimport { uploadFileCommand } from \"./upload-file\";\nimport { downloadFileCommand } from \"./download-file\";\n\nexport const zeroSlackCommand = new Command()\n .name(\"slack\")\n .description(\n \"Send messages, upload files, and download files from Slack as the bot\",\n )\n .addCommand(zeroSlackMessageCommand)\n .addCommand(uploadFileCommand)\n .addCommand(downloadFileCommand)\n .addHelpText(\n \"after\",\n `\nExamples:\n Send a message: zero slack message send -c <channel-id> -t \"Hello!\"\n Reply in a thread: zero slack message send -c <channel-id> --thread <ts> -t \"reply\"\n Upload a file: zero slack upload-file -f /tmp/report.pdf -c <channel-id>\n Download a file: zero slack download-file <file-id> -o /tmp/out.png`,\n );\n","import { Command } from \"commander\";\nimport { sendCommand } from \"./send\";\n\nexport const zeroSlackMessageCommand = new Command()\n .name(\"message\")\n .description(\"Manage Slack messages\")\n .addCommand(sendCommand)\n .addHelpText(\n \"after\",\n `\nExamples:\n zero slack message send -c <channel-id> -t \"Hello!\"`,\n );\n","import { readFileSync } from \"fs\";\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { sendSlackMessage } from \"../../../../lib/api\";\nimport { withErrorHandler } from \"../../../../lib/command\";\n\nexport const sendCommand = new Command()\n .name(\"send\")\n .description(\"Send a message to a Slack channel or DM a user\")\n .option(\"-c, --channel <id>\", \"Channel ID\")\n .option(\"-u, --user <id>\", 'Slack user ID for DM (use \"me\" for yourself)')\n .option(\"-t, --text <message>\", \"Message text\")\n .option(\"--thread <ts>\", \"Thread timestamp for replies\")\n .option(\"--blocks <json>\", \"Block Kit JSON string\")\n .addHelpText(\n \"after\",\n `\nExamples:\n Simple message: zero slack message send -c C01234 -t \"Hello!\"\n DM a user: zero slack message send -u U0A8V9X98QJ -t \"Hello!\"\n DM yourself: zero slack message send -u me -t \"Hello!\"\n Reply in thread: zero slack message send -c C01234 --thread 1234567890.123456 -t \"reply\"\n Rich blocks: zero slack message send -c C01234 --blocks '[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"*Bold*\"}}]'\n\nNotes:\n - Either --channel or --user is required; they are mutually exclusive\n - Either --text or --blocks is required; both can be used together`,\n )\n .action(\n withErrorHandler(\n async (options: {\n channel?: string;\n user?: string;\n text?: string;\n thread?: string;\n blocks?: string;\n }) => {\n let text = options.text;\n const { channel, user, thread, blocks: blocksStr } = options;\n\n // Validate mutual exclusion: exactly one of --channel or --user\n if (!channel && !user) {\n throw new Error(\"Either --channel or --user must be provided\", {\n cause: new Error(\n 'Usage: zero slack message send -c CHANNEL_ID -t \"your message\"\\n zero slack message send -u USER_ID -t \"your message\"',\n ),\n });\n }\n if (channel && user) {\n throw new Error(\"--channel and --user are mutually exclusive\", {\n cause: new Error(\n \"Provide either --channel to send to a channel or --user to DM a user, not both\",\n ),\n });\n }\n\n // Read from stdin if text not provided and stdin is not a TTY\n // (isTTY is true only for an interactive terminal, undefined when piped).\n if (!text && !process.stdin.isTTY) {\n try {\n text = readFileSync(\"/dev/stdin\", \"utf8\").trim();\n } catch {\n // stdin not readable (e.g. test runner with no piped input);\n // fall through to the missing-text validation below.\n }\n }\n\n // Parse blocks JSON if provided\n let blocks: Array<{ type: string; [key: string]: unknown }> | undefined;\n if (blocksStr) {\n try {\n blocks = JSON.parse(blocksStr) as Array<{\n type: string;\n [key: string]: unknown;\n }>;\n } catch {\n throw new Error(\"Invalid JSON for --blocks flag\", {\n cause: new Error(\n \"Provide a valid JSON array of Block Kit blocks\",\n ),\n });\n }\n }\n\n // Validate at least one of text or blocks\n if (!text && !blocks) {\n throw new Error(\"Either --text or --blocks must be provided\", {\n cause: new Error(\n 'Usage: zero slack message send -c CHANNEL_ID -t \"your message\"',\n ),\n });\n }\n\n const result = await sendSlackMessage({\n channel: channel || undefined,\n user: user || undefined,\n text: text || undefined,\n threadTs: thread,\n blocks,\n });\n\n const tsInfo = result.ts ? ` (ts: ${result.ts})` : \"\";\n console.log(chalk.green(`✓ Message sent${tsInfo}`));\n },\n ),\n );\n","import { statSync, readFileSync } from \"fs\";\nimport { basename } from \"path\";\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { initSlackFileUpload, completeSlackFileUpload } from \"../../../lib/api\";\nimport { withErrorHandler } from \"../../../lib/command\";\n\nexport const uploadFileCommand = new Command()\n .name(\"upload-file\")\n .description(\"Upload a file to a Slack channel as the bot\")\n .requiredOption(\"-f, --file <path>\", \"Local file path to upload\")\n .requiredOption(\"-c, --channel <id>\", \"Slack channel ID\")\n .option(\"--thread <ts>\", \"Thread timestamp to post as a reply\")\n .option(\"--title <title>\", \"Display title for the file\")\n .option(\"--comment <text>\", \"Initial comment to accompany the file\")\n .addHelpText(\n \"after\",\n `\nExamples:\n Upload a file: zero slack upload-file -f /tmp/report.pdf -c C01234\n Upload to thread: zero slack upload-file -f /tmp/log.txt -c C01234 --thread 1234567890.123456\n With title and comment: zero slack upload-file -f /tmp/data.csv -c C01234 --title \"Daily Report\" --comment \"Here's the report\"\n\nNotes:\n - Uses the bot token (not user SLACK_TOKEN), so no files:write permission is needed\n - Returns file_id and permalink for reference`,\n )\n .action(\n withErrorHandler(\n async (options: {\n file: string;\n channel: string;\n thread?: string;\n title?: string;\n comment?: string;\n }) => {\n // Validate file exists and get size\n let fileSize: number;\n try {\n const stat = statSync(options.file);\n fileSize = stat.size;\n } catch {\n throw new Error(`File not found: ${options.file}`);\n }\n\n if (fileSize === 0) {\n throw new Error(\"File is empty\");\n }\n\n const filename = basename(options.file);\n\n // Step 1: Get pre-signed upload URL from server\n const { uploadUrl, fileId } = await initSlackFileUpload({\n filename,\n length: fileSize,\n });\n\n // Step 2: Upload file directly to Slack's pre-signed URL\n const fileContent = readFileSync(options.file);\n const uploadResponse = await fetch(uploadUrl, {\n method: \"POST\",\n body: fileContent,\n });\n\n if (!uploadResponse.ok) {\n throw new Error(\n `File upload failed: ${uploadResponse.status} ${uploadResponse.statusText}`,\n );\n }\n\n // Step 3: Complete the upload and share to channel/thread\n const result = await completeSlackFileUpload({\n fileId,\n channel: options.channel,\n threadTs: options.thread,\n title: options.title,\n initialComment: options.comment,\n });\n\n console.log(chalk.green(`✓ File uploaded (file_id: ${result.fileId})`));\n console.log(chalk.dim(` permalink: ${result.permalink}`));\n },\n ),\n );\n","import { basename, join } from \"path\";\nimport { tmpdir } from \"os\";\nimport { Command } from \"commander\";\nimport { downloadSlackFile } from \"../../../lib/api\";\nimport { withErrorHandler } from \"../../../lib/command\";\n\n/**\n * Derive a local output path for a Slack file id.\n * Uses the system temp directory; extension is appended later once the\n * mimetype is known.\n *\n * `basename` strips any path separators from `fileId` so a hostile id like\n * `../etc/passwd` cannot escape `tmpdir()`.\n */\nfunction defaultOutPath(fileId: string): string {\n return join(tmpdir(), `slack-${basename(fileId)}`);\n}\n\nexport const downloadFileCommand = new Command()\n .name(\"download-file\")\n .description(\"Download a Slack file by id using the bot token\")\n .argument(\"<file-id>\", \"Slack file id (e.g. F01234ABCD)\")\n .option(\n \"-o, --out <path>\",\n \"Output path for the downloaded file (default: /tmp/slack-<file-id>)\",\n )\n .addHelpText(\n \"after\",\n `\nExamples:\n Download to default temp path: zero slack download-file F01234ABCD\n Download to explicit path: zero slack download-file F01234ABCD -o /tmp/image.png\n\nOutput:\n Prints a JSON object to stdout on success:\n {\"path\":\"/tmp/slack-F01234ABCD\",\"mimetype\":\"image/png\",\"size\":12345}\n\nHow to read the downloaded file:\n - Images (png/jpg/gif/webp/svg): open the file path with your image viewing tool\n - Videos (mp4/mov/webm): transcribe audio first with\n zero video transcribe --url <download-url>\n or extract frames with\n ffmpeg -i <path> -vf \"fps=1\" -q:v 2 /tmp/<file-id>_frame_%03d.jpg\n - PDF/text/csv/json/markdown: read the file directly\n\nNotes:\n - Uses the bot token on the server side; no user Slack token is needed\n - Streams the file bytes directly to disk`,\n )\n .action(\n withErrorHandler(async (fileId: string, options: { out?: string }) => {\n const outPath = options.out ?? defaultOutPath(fileId);\n const result = await downloadSlackFile(fileId, outPath);\n console.log(JSON.stringify(result));\n }),\n );\n"],"mappings":"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","names":["readFileSync","readFileSync","basename","basename"]}
|
|
1
|
+
{"version":3,"sources":["../src/commands/zero/slack/index.ts","../src/commands/zero/slack/message/index.ts","../src/commands/zero/slack/message/send.ts","../src/commands/zero/slack/upload-file.ts","../src/commands/zero/slack/download-file.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { zeroSlackMessageCommand } from \"./message\";\nimport { uploadFileCommand } from \"./upload-file\";\nimport { downloadFileCommand } from \"./download-file\";\n\nexport const zeroSlackCommand = new Command()\n .name(\"slack\")\n .description(\n \"Send messages, upload files, and download files from Slack as the bot\",\n )\n .addCommand(zeroSlackMessageCommand)\n .addCommand(uploadFileCommand)\n .addCommand(downloadFileCommand)\n .addHelpText(\n \"after\",\n `\nExamples:\n Send a message: zero slack message send -c <channel-id> -t \"Hello!\"\n Reply in a thread: zero slack message send -c <channel-id> --thread <ts> -t \"reply\"\n Upload a file: zero slack upload-file -f /tmp/report.pdf -c <channel-id>\n Download a file: zero slack download-file <file-id> -o /tmp/out.png`,\n );\n","import { Command } from \"commander\";\nimport { sendCommand } from \"./send\";\n\nexport const zeroSlackMessageCommand = new Command()\n .name(\"message\")\n .description(\"Manage Slack messages\")\n .addCommand(sendCommand)\n .addHelpText(\n \"after\",\n `\nExamples:\n zero slack message send -c <channel-id> -t \"Hello!\"`,\n );\n","import { readFileSync } from \"fs\";\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { sendSlackMessage } from \"../../../../lib/api\";\nimport { withErrorHandler } from \"../../../../lib/command\";\n\nexport const sendCommand = new Command()\n .name(\"send\")\n .description(\"Send a message to a Slack channel or DM a user\")\n .option(\"-c, --channel <id>\", \"Channel ID\")\n .option(\"-u, --user <id>\", 'Slack user ID for DM (use \"me\" for yourself)')\n .option(\"-t, --text <message>\", \"Message text\")\n .option(\"--thread <ts>\", \"Thread timestamp for replies\")\n .option(\"--blocks <json>\", \"Block Kit JSON string\")\n .addHelpText(\n \"after\",\n `\nExamples:\n Simple message: zero slack message send -c C01234 -t \"Hello!\"\n DM a user: zero slack message send -u U0A8V9X98QJ -t \"Hello!\"\n DM yourself: zero slack message send -u me -t \"Hello!\"\n Reply in thread: zero slack message send -c C01234 --thread 1234567890.123456 -t \"reply\"\n Rich blocks: zero slack message send -c C01234 --blocks '[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"*Bold*\"}}]'\n\nNotes:\n - Either --channel or --user is required; they are mutually exclusive\n - Either --text or --blocks is required; both can be used together`,\n )\n .action(\n withErrorHandler(\n async (options: {\n channel?: string;\n user?: string;\n text?: string;\n thread?: string;\n blocks?: string;\n }) => {\n let text = options.text;\n const { channel, user, thread, blocks: blocksStr } = options;\n\n // Validate mutual exclusion: exactly one of --channel or --user\n if (!channel && !user) {\n throw new Error(\"Either --channel or --user must be provided\", {\n cause: new Error(\n 'Usage: zero slack message send -c CHANNEL_ID -t \"your message\"\\n zero slack message send -u USER_ID -t \"your message\"',\n ),\n });\n }\n if (channel && user) {\n throw new Error(\"--channel and --user are mutually exclusive\", {\n cause: new Error(\n \"Provide either --channel to send to a channel or --user to DM a user, not both\",\n ),\n });\n }\n\n // Read from stdin if text not provided and stdin is not a TTY\n // (isTTY is true only for an interactive terminal, undefined when piped).\n if (!text && !process.stdin.isTTY) {\n try {\n text = readFileSync(\"/dev/stdin\", \"utf8\").trim();\n } catch {\n // stdin not readable (e.g. test runner with no piped input);\n // fall through to the missing-text validation below.\n }\n }\n\n // Parse blocks JSON if provided\n let blocks: Array<{ type: string; [key: string]: unknown }> | undefined;\n if (blocksStr) {\n try {\n blocks = JSON.parse(blocksStr) as Array<{\n type: string;\n [key: string]: unknown;\n }>;\n } catch {\n throw new Error(\"Invalid JSON for --blocks flag\", {\n cause: new Error(\n \"Provide a valid JSON array of Block Kit blocks\",\n ),\n });\n }\n }\n\n // Validate at least one of text or blocks\n if (!text && !blocks) {\n throw new Error(\"Either --text or --blocks must be provided\", {\n cause: new Error(\n 'Usage: zero slack message send -c CHANNEL_ID -t \"your message\"',\n ),\n });\n }\n\n const result = await sendSlackMessage({\n channel: channel || undefined,\n user: user || undefined,\n text: text || undefined,\n threadTs: thread,\n blocks,\n });\n\n const tsInfo = result.ts ? ` (ts: ${result.ts})` : \"\";\n console.log(chalk.green(`✓ Message sent${tsInfo}`));\n },\n ),\n );\n","import { statSync, readFileSync } from \"fs\";\nimport { basename } from \"path\";\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { initSlackFileUpload, completeSlackFileUpload } from \"../../../lib/api\";\nimport { withErrorHandler } from \"../../../lib/command\";\n\nexport const uploadFileCommand = new Command()\n .name(\"upload-file\")\n .description(\"Upload a file to a Slack channel as the bot\")\n .requiredOption(\"-f, --file <path>\", \"Local file path to upload\")\n .requiredOption(\"-c, --channel <id>\", \"Slack channel ID\")\n .option(\"--thread <ts>\", \"Thread timestamp to post as a reply\")\n .option(\"--title <title>\", \"Display title for the file\")\n .option(\"--comment <text>\", \"Initial comment to accompany the file\")\n .addHelpText(\n \"after\",\n `\nExamples:\n Upload a file: zero slack upload-file -f /tmp/report.pdf -c C01234\n Upload to thread: zero slack upload-file -f /tmp/log.txt -c C01234 --thread 1234567890.123456\n With title and comment: zero slack upload-file -f /tmp/data.csv -c C01234 --title \"Daily Report\" --comment \"Here's the report\"\n\nNotes:\n - Uses the bot token (not user SLACK_TOKEN), so no files:write permission is needed\n - Returns file_id and permalink for reference`,\n )\n .action(\n withErrorHandler(\n async (options: {\n file: string;\n channel: string;\n thread?: string;\n title?: string;\n comment?: string;\n }) => {\n // Validate file exists and get size\n let fileSize: number;\n try {\n const stat = statSync(options.file);\n fileSize = stat.size;\n } catch {\n throw new Error(`File not found: ${options.file}`);\n }\n\n if (fileSize === 0) {\n throw new Error(\"File is empty\");\n }\n\n const filename = basename(options.file);\n\n // Step 1: Get pre-signed upload URL from server\n const { uploadUrl, fileId } = await initSlackFileUpload({\n filename,\n length: fileSize,\n });\n\n // Step 2: Upload file directly to Slack's pre-signed URL\n const fileContent = readFileSync(options.file);\n const uploadResponse = await fetch(uploadUrl, {\n method: \"POST\",\n body: fileContent,\n });\n\n if (!uploadResponse.ok) {\n throw new Error(\n `File upload failed: ${uploadResponse.status} ${uploadResponse.statusText}`,\n );\n }\n\n // Step 3: Complete the upload and share to channel/thread\n const result = await completeSlackFileUpload({\n fileId,\n channel: options.channel,\n threadTs: options.thread,\n title: options.title,\n initialComment: options.comment,\n });\n\n console.log(chalk.green(`✓ File uploaded (file_id: ${result.fileId})`));\n console.log(chalk.dim(` permalink: ${result.permalink}`));\n },\n ),\n );\n","import { basename, join } from \"path\";\nimport { tmpdir } from \"os\";\nimport { Command } from \"commander\";\nimport { downloadSlackFile } from \"../../../lib/api\";\nimport { withErrorHandler } from \"../../../lib/command\";\n\n/**\n * Derive a local output path for a Slack file id.\n * Uses the system temp directory; extension is appended later once the\n * mimetype is known.\n *\n * `basename` strips any path separators from `fileId` so a hostile id like\n * `../etc/passwd` cannot escape `tmpdir()`.\n */\nfunction defaultOutPath(fileId: string): string {\n return join(tmpdir(), `slack-${basename(fileId)}`);\n}\n\nexport const downloadFileCommand = new Command()\n .name(\"download-file\")\n .description(\"Download a Slack file by id using the bot token\")\n .argument(\"<file-id>\", \"Slack file id (e.g. F01234ABCD)\")\n .option(\n \"-o, --out <path>\",\n \"Output path for the downloaded file (default: /tmp/slack-<file-id>)\",\n )\n .addHelpText(\n \"after\",\n `\nExamples:\n Download to default temp path: zero slack download-file F01234ABCD\n Download to explicit path: zero slack download-file F01234ABCD -o /tmp/image.png\n\nOutput:\n Prints a JSON object to stdout on success:\n {\"path\":\"/tmp/slack-F01234ABCD\",\"mimetype\":\"image/png\",\"size\":12345}\n\nHow to read the downloaded file:\n - Images (png/jpg/gif/webp/svg): open the file path with your image viewing tool\n - Videos (mp4/mov/webm): transcribe audio first with\n zero video transcribe --url <download-url>\n or extract frames with\n ffmpeg -i <path> -vf \"fps=1\" -q:v 2 /tmp/<file-id>_frame_%03d.jpg\n - PDF/text/csv/json/markdown: read the file directly\n\nNotes:\n - Uses the bot token on the server side; no user Slack token is needed\n - Streams the file bytes directly to disk`,\n )\n .action(\n withErrorHandler(async (fileId: string, options: { out?: string }) => {\n const outPath = options.out ?? defaultOutPath(fileId);\n const result = await downloadSlackFile(fileId, outPath);\n console.log(JSON.stringify(result));\n }),\n );\n"],"mappings":"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","names":["readFileSync","readFileSync","basename","basename"]}
|
|
@@ -6,14 +6,12 @@ import {
|
|
|
6
6
|
downloadTeamsFile,
|
|
7
7
|
initTeamsFileUpload,
|
|
8
8
|
sendTeamsMessage
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-XVW5RA46.js";
|
|
10
10
|
import "./chunk-LTDQISD7.js";
|
|
11
11
|
import {
|
|
12
|
+
source_default,
|
|
12
13
|
withErrorHandler
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import {
|
|
15
|
-
source_default
|
|
16
|
-
} from "./chunk-JUTUEPIR.js";
|
|
14
|
+
} from "./chunk-CYF7PHDS.js";
|
|
17
15
|
import "./chunk-LRHXR7JT.js";
|
|
18
16
|
import {
|
|
19
17
|
Command
|
|
@@ -281,4 +279,4 @@ Examples:
|
|
|
281
279
|
export {
|
|
282
280
|
zeroTeamsCommand
|
|
283
281
|
};
|
|
284
|
-
//# sourceMappingURL=teams-
|
|
282
|
+
//# sourceMappingURL=teams-DXT4NI2S.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/zero/teams/index.ts","../src/commands/zero/teams/message/index.ts","../src/commands/zero/teams/message/send.ts","../src/commands/zero/teams/upload-file.ts","../src/commands/zero/teams/download-file.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { zeroTeamsMessageCommand } from \"./message\";\nimport { uploadFileCommand } from \"./upload-file\";\nimport { downloadFileCommand } from \"./download-file\";\n\nexport const zeroTeamsCommand = new Command()\n .name(\"teams\")\n .description(\n \"Send messages, upload files, and download files from Microsoft Teams as the bot\",\n )\n .addCommand(zeroTeamsMessageCommand)\n .addCommand(uploadFileCommand)\n .addCommand(downloadFileCommand)\n .addHelpText(\n \"after\",\n `\nExamples:\n Send a message: zero teams message send -c <conversation-id> -t \"Hello!\"\n DM a user: zero teams message send -u me -t \"Hello!\"\n Reply in a thread: zero teams message send -c <conversation-id> --thread <activity-id> -t \"reply\"\n Upload a file: zero teams upload-file -f /tmp/report.pdf -c <conversation-id>\n Download a file: zero teams download-file <file-id> -o /tmp/out.png`,\n );\n","import { Command } from \"commander\";\nimport { sendCommand } from \"./send\";\n\nexport const zeroTeamsMessageCommand = new Command()\n .name(\"message\")\n .description(\"Manage Microsoft Teams messages\")\n .addCommand(sendCommand)\n .addHelpText(\n \"after\",\n `\nExamples:\n zero teams message send -c <conversation-id> -t \"Hello!\"\n zero teams message send -u me -t \"Hello!\"`,\n );\n","import { readFileSync } from \"fs\";\nimport { Command } from \"commander\";\nimport type { SendTeamsMessageBody } from \"@vm0/api-contracts/contracts/integrations\";\nimport chalk from \"chalk\";\nimport { sendTeamsMessage } from \"../../../../lib/api\";\nimport { withErrorHandler } from \"../../../../lib/command\";\n\ntype TeamsCardInput = NonNullable<SendTeamsMessageBody[\"card\"]>;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction parseTeamsCard(value: string): TeamsCardInput {\n let parsed: unknown;\n try {\n parsed = JSON.parse(value);\n } catch {\n throw new Error(\"Invalid JSON for --card flag\", {\n cause: new Error(\"Provide a valid Adaptive Card JSON object\"),\n });\n }\n\n if (\n !isRecord(parsed) ||\n parsed.type !== \"AdaptiveCard\" ||\n typeof parsed.version !== \"string\"\n ) {\n throw new Error(\"Invalid Adaptive Card for --card flag\", {\n cause: new Error(\n 'Provide a JSON object with \"type\": \"AdaptiveCard\" and a version',\n ),\n });\n }\n\n return parsed as TeamsCardInput;\n}\n\nexport const sendCommand = new Command()\n .name(\"send\")\n .description(\"Send a message to a Microsoft Teams conversation or DM a user\")\n .option(\"-c, --conversation-id <id>\", \"Teams conversation ID\")\n .option(\"-u, --user <id>\", 'Teams user ID for DM (use \"me\" for yourself)')\n .option(\"-t, --text <message>\", \"Message text\")\n .option(\"--activity-id <id>\", \"Activity ID to reply to\")\n .option(\"--thread <id>\", \"Alias for --activity-id\")\n .option(\"--card <json>\", \"Adaptive Card JSON string\")\n .addHelpText(\n \"after\",\n `\nExamples:\n Simple message: zero teams message send -c 19:thread@thread.tacv2 -t \"Hello!\"\n DM a user: zero teams message send -u 29:user-id -t \"Hello!\"\n DM yourself: zero teams message send -u me -t \"Hello!\"\n Thread reply: zero teams message send -c 19:thread@thread.tacv2 --thread root-activity -t \"reply\"\n Adaptive Card: zero teams message send -c 19:thread@thread.tacv2 --card '{\"type\":\"AdaptiveCard\",\"version\":\"1.4\",\"body\":[{\"type\":\"TextBlock\",\"text\":\"Hello\",\"wrap\":true}]}'\n\nNotes:\n - Either --conversation-id or --user is required; they are mutually exclusive\n - Either --text or --card is required; text can be provided with --text or piped on stdin\n - Use the Conversation ID and Activity ID from the current Teams run prompt`,\n )\n .action(\n withErrorHandler(\n async (options: {\n conversationId?: string;\n user?: string;\n text?: string;\n activityId?: string;\n thread?: string;\n card?: string;\n }) => {\n let text = options.text;\n const { conversationId, user, card: cardJson } = options;\n\n if (!conversationId && !user) {\n throw new Error(\n \"Either --conversation-id or --user must be provided\",\n {\n cause: new Error(\n 'Usage: zero teams message send -c CONVERSATION_ID -t \"your message\"\\n zero teams message send -u USER_ID -t \"your message\"',\n ),\n },\n );\n }\n if (conversationId && user) {\n throw new Error(\n \"--conversation-id and --user are mutually exclusive\",\n {\n cause: new Error(\n \"Provide either --conversation-id to send to a conversation or --user to DM a user, not both\",\n ),\n },\n );\n }\n\n const activityId = options.activityId ?? options.thread;\n if (user && activityId) {\n throw new Error(\n \"--activity-id and --thread can only be used with --conversation-id\",\n {\n cause: new Error(\n \"Thread replies require an existing Teams conversation\",\n ),\n },\n );\n }\n\n if (!text && !process.stdin.isTTY) {\n try {\n text = readFileSync(\"/dev/stdin\", \"utf8\").trim();\n } catch {\n // stdin not readable; fall through to the missing-text validation.\n }\n }\n\n const card = cardJson ? parseTeamsCard(cardJson) : undefined;\n\n if (!text && !card) {\n throw new Error(\n \"Either --text, --card, or piped stdin must be provided\",\n {\n cause: new Error(\n 'Usage: zero teams message send -c CONVERSATION_ID -t \"your message\"',\n ),\n },\n );\n }\n\n const body: SendTeamsMessageBody = {\n ...(conversationId ? { conversationId } : { user }),\n ...(activityId ? { activityId } : {}),\n ...(text ? { text } : {}),\n ...(card ? { card } : {}),\n };\n const result = await sendTeamsMessage({\n ...body,\n });\n\n const activityInfo = result.activityId\n ? ` (activity_id: ${result.activityId})`\n : \"\";\n console.log(chalk.green(`✓ Message sent${activityInfo}`));\n },\n ),\n );\n","import { readFileSync, statSync } from \"fs\";\nimport { basename, extname } from \"path\";\nimport { Command } from \"commander\";\nimport { completeTeamsFileUpload, initTeamsFileUpload } from \"../../../lib/api\";\nimport { withErrorHandler } from \"../../../lib/command\";\n\nconst MIME_BY_EXTENSION: Record<string, string> = {\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".svg\": \"image/svg+xml\",\n \".mp4\": \"video/mp4\",\n \".webm\": \"video/webm\",\n \".mov\": \"video/quicktime\",\n \".pdf\": \"application/pdf\",\n \".txt\": \"text/plain\",\n \".csv\": \"text/csv\",\n \".md\": \"text/markdown\",\n \".json\": \"application/json\",\n};\n\nfunction inferContentType(localPath: string): string {\n const ext = extname(localPath).toLowerCase();\n return MIME_BY_EXTENSION[ext] ?? \"application/octet-stream\";\n}\n\nexport const uploadFileCommand = new Command()\n .name(\"upload-file\")\n .description(\n \"Upload a local file to a Microsoft Teams conversation as the bot\",\n )\n .requiredOption(\"-f, --file <path>\", \"Local file path to upload\")\n .requiredOption(\"-c, --conversation-id <id>\", \"Teams conversation ID\")\n .option(\"--activity-id <id>\", \"Activity ID to reply to\")\n .option(\"-t, --text <message>\", \"Message text to accompany the file\")\n .option(\"--content-type <mime>\", \"Override inferred content type\")\n .addHelpText(\n \"after\",\n `\nExamples:\n Upload a file: zero teams upload-file -f /tmp/report.pdf -c 19:thread@thread.tacv2\n Upload to thread: zero teams upload-file -f /tmp/log.txt -c 19:thread@thread.tacv2 --activity-id root-activity\n With message text: zero teams upload-file -f /tmp/data.csv -c 19:thread@thread.tacv2 -t \"Daily report\"\n\nOutput:\n Prints a JSON object to stdout on success:\n {\"activityId\":\"...\",\"conversationId\":\"19:...\",\"filename\":\"report.pdf\",\"mimetype\":\"application/pdf\",\"size\":12345,\"url\":\"https://...\"}\n\nNotes:\n - Uploads through VM0 storage first, then sends the Teams message with the file URL\n - Use the Conversation ID and Activity ID from the current Teams run prompt`,\n )\n .action(\n withErrorHandler(\n async (options: {\n file: string;\n conversationId: string;\n activityId?: string;\n text?: string;\n contentType?: string;\n }) => {\n let fileSize: number;\n try {\n const stat = statSync(options.file);\n if (!stat.isFile()) {\n throw new Error(`Not a regular file: ${options.file}`);\n }\n fileSize = stat.size;\n } catch (error) {\n if (error instanceof Error && error.message.startsWith(\"Not \")) {\n throw error;\n }\n throw new Error(`File not found: ${options.file}`);\n }\n\n if (fileSize === 0) {\n throw new Error(\"File is empty\");\n }\n\n const filename = basename(options.file);\n const contentType =\n options.contentType ?? inferContentType(options.file);\n const prepared = await initTeamsFileUpload({\n filename,\n contentType,\n length: fileSize,\n });\n\n const fileContent = readFileSync(options.file);\n const uploadResponse = await fetch(prepared.uploadUrl, {\n method: \"PUT\",\n headers: { \"Content-Type\": prepared.contentType },\n body: new Uint8Array(fileContent),\n });\n\n if (!uploadResponse.ok) {\n throw new Error(\n `File upload failed: ${uploadResponse.status} ${uploadResponse.statusText}`,\n );\n }\n\n const result = await completeTeamsFileUpload({\n uploadId: prepared.uploadId,\n conversationId: options.conversationId,\n activityId: options.activityId,\n contentType: prepared.contentType,\n text: options.text,\n });\n\n console.log(JSON.stringify(result));\n },\n ),\n );\n","import { basename, join } from \"path\";\nimport { tmpdir } from \"os\";\nimport { Command } from \"commander\";\nimport { downloadTeamsFile } from \"../../../lib/api\";\nimport { withErrorHandler } from \"../../../lib/command\";\n\nfunction defaultOutPath(fileId: string): string {\n return join(tmpdir(), `teams-${basename(fileId).slice(0, 48)}`);\n}\n\nexport const downloadFileCommand = new Command()\n .name(\"download-file\")\n .description(\"Download a Microsoft Teams file by signed file id\")\n .argument(\"<file-id>\", \"Microsoft Teams file id from a [Teams file] block\")\n .option(\n \"-o, --out <path>\",\n \"Output path for the downloaded file (default: /tmp/teams-<file-id>)\",\n )\n .addHelpText(\n \"after\",\n `\nExamples:\n Download to default temp path: zero teams download-file <file-id>\n Download to explicit path: zero teams download-file <file-id> -o /tmp/file.png\n\nOutput:\n Prints a JSON object to stdout on success:\n {\"path\":\"/tmp/teams-...\",\"mimetype\":\"image/png\",\"size\":12345}\n\nNotes:\n - Use the file id from a [Teams file] block in the prompt\n - Streams the file bytes directly to disk`,\n )\n .action(\n withErrorHandler(async (fileId: string, options: { out?: string }) => {\n const outPath = options.out ?? defaultOutPath(fileId);\n const result = await downloadTeamsFile(fileId, outPath);\n console.log(JSON.stringify(result));\n }),\n );\n"],"mappings":"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","names":["readFileSync","readFileSync","basename","basename"]}
|
|
1
|
+
{"version":3,"sources":["../src/commands/zero/teams/index.ts","../src/commands/zero/teams/message/index.ts","../src/commands/zero/teams/message/send.ts","../src/commands/zero/teams/upload-file.ts","../src/commands/zero/teams/download-file.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { zeroTeamsMessageCommand } from \"./message\";\nimport { uploadFileCommand } from \"./upload-file\";\nimport { downloadFileCommand } from \"./download-file\";\n\nexport const zeroTeamsCommand = new Command()\n .name(\"teams\")\n .description(\n \"Send messages, upload files, and download files from Microsoft Teams as the bot\",\n )\n .addCommand(zeroTeamsMessageCommand)\n .addCommand(uploadFileCommand)\n .addCommand(downloadFileCommand)\n .addHelpText(\n \"after\",\n `\nExamples:\n Send a message: zero teams message send -c <conversation-id> -t \"Hello!\"\n DM a user: zero teams message send -u me -t \"Hello!\"\n Reply in a thread: zero teams message send -c <conversation-id> --thread <activity-id> -t \"reply\"\n Upload a file: zero teams upload-file -f /tmp/report.pdf -c <conversation-id>\n Download a file: zero teams download-file <file-id> -o /tmp/out.png`,\n );\n","import { Command } from \"commander\";\nimport { sendCommand } from \"./send\";\n\nexport const zeroTeamsMessageCommand = new Command()\n .name(\"message\")\n .description(\"Manage Microsoft Teams messages\")\n .addCommand(sendCommand)\n .addHelpText(\n \"after\",\n `\nExamples:\n zero teams message send -c <conversation-id> -t \"Hello!\"\n zero teams message send -u me -t \"Hello!\"`,\n );\n","import { readFileSync } from \"fs\";\nimport { Command } from \"commander\";\nimport type { SendTeamsMessageBody } from \"@vm0/api-contracts/contracts/integrations\";\nimport chalk from \"chalk\";\nimport { sendTeamsMessage } from \"../../../../lib/api\";\nimport { withErrorHandler } from \"../../../../lib/command\";\n\ntype TeamsCardInput = NonNullable<SendTeamsMessageBody[\"card\"]>;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction parseTeamsCard(value: string): TeamsCardInput {\n let parsed: unknown;\n try {\n parsed = JSON.parse(value);\n } catch {\n throw new Error(\"Invalid JSON for --card flag\", {\n cause: new Error(\"Provide a valid Adaptive Card JSON object\"),\n });\n }\n\n if (\n !isRecord(parsed) ||\n parsed.type !== \"AdaptiveCard\" ||\n typeof parsed.version !== \"string\"\n ) {\n throw new Error(\"Invalid Adaptive Card for --card flag\", {\n cause: new Error(\n 'Provide a JSON object with \"type\": \"AdaptiveCard\" and a version',\n ),\n });\n }\n\n return parsed as TeamsCardInput;\n}\n\nexport const sendCommand = new Command()\n .name(\"send\")\n .description(\"Send a message to a Microsoft Teams conversation or DM a user\")\n .option(\"-c, --conversation-id <id>\", \"Teams conversation ID\")\n .option(\"-u, --user <id>\", 'Teams user ID for DM (use \"me\" for yourself)')\n .option(\"-t, --text <message>\", \"Message text\")\n .option(\"--activity-id <id>\", \"Activity ID to reply to\")\n .option(\"--thread <id>\", \"Alias for --activity-id\")\n .option(\"--card <json>\", \"Adaptive Card JSON string\")\n .addHelpText(\n \"after\",\n `\nExamples:\n Simple message: zero teams message send -c 19:thread@thread.tacv2 -t \"Hello!\"\n DM a user: zero teams message send -u 29:user-id -t \"Hello!\"\n DM yourself: zero teams message send -u me -t \"Hello!\"\n Thread reply: zero teams message send -c 19:thread@thread.tacv2 --thread root-activity -t \"reply\"\n Adaptive Card: zero teams message send -c 19:thread@thread.tacv2 --card '{\"type\":\"AdaptiveCard\",\"version\":\"1.4\",\"body\":[{\"type\":\"TextBlock\",\"text\":\"Hello\",\"wrap\":true}]}'\n\nNotes:\n - Either --conversation-id or --user is required; they are mutually exclusive\n - Either --text or --card is required; text can be provided with --text or piped on stdin\n - Use the Conversation ID and Activity ID from the current Teams run prompt`,\n )\n .action(\n withErrorHandler(\n async (options: {\n conversationId?: string;\n user?: string;\n text?: string;\n activityId?: string;\n thread?: string;\n card?: string;\n }) => {\n let text = options.text;\n const { conversationId, user, card: cardJson } = options;\n\n if (!conversationId && !user) {\n throw new Error(\n \"Either --conversation-id or --user must be provided\",\n {\n cause: new Error(\n 'Usage: zero teams message send -c CONVERSATION_ID -t \"your message\"\\n zero teams message send -u USER_ID -t \"your message\"',\n ),\n },\n );\n }\n if (conversationId && user) {\n throw new Error(\n \"--conversation-id and --user are mutually exclusive\",\n {\n cause: new Error(\n \"Provide either --conversation-id to send to a conversation or --user to DM a user, not both\",\n ),\n },\n );\n }\n\n const activityId = options.activityId ?? options.thread;\n if (user && activityId) {\n throw new Error(\n \"--activity-id and --thread can only be used with --conversation-id\",\n {\n cause: new Error(\n \"Thread replies require an existing Teams conversation\",\n ),\n },\n );\n }\n\n if (!text && !process.stdin.isTTY) {\n try {\n text = readFileSync(\"/dev/stdin\", \"utf8\").trim();\n } catch {\n // stdin not readable; fall through to the missing-text validation.\n }\n }\n\n const card = cardJson ? parseTeamsCard(cardJson) : undefined;\n\n if (!text && !card) {\n throw new Error(\n \"Either --text, --card, or piped stdin must be provided\",\n {\n cause: new Error(\n 'Usage: zero teams message send -c CONVERSATION_ID -t \"your message\"',\n ),\n },\n );\n }\n\n const body: SendTeamsMessageBody = {\n ...(conversationId ? { conversationId } : { user }),\n ...(activityId ? { activityId } : {}),\n ...(text ? { text } : {}),\n ...(card ? { card } : {}),\n };\n const result = await sendTeamsMessage({\n ...body,\n });\n\n const activityInfo = result.activityId\n ? ` (activity_id: ${result.activityId})`\n : \"\";\n console.log(chalk.green(`✓ Message sent${activityInfo}`));\n },\n ),\n );\n","import { readFileSync, statSync } from \"fs\";\nimport { basename, extname } from \"path\";\nimport { Command } from \"commander\";\nimport { completeTeamsFileUpload, initTeamsFileUpload } from \"../../../lib/api\";\nimport { withErrorHandler } from \"../../../lib/command\";\n\nconst MIME_BY_EXTENSION: Record<string, string> = {\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".svg\": \"image/svg+xml\",\n \".mp4\": \"video/mp4\",\n \".webm\": \"video/webm\",\n \".mov\": \"video/quicktime\",\n \".pdf\": \"application/pdf\",\n \".txt\": \"text/plain\",\n \".csv\": \"text/csv\",\n \".md\": \"text/markdown\",\n \".json\": \"application/json\",\n};\n\nfunction inferContentType(localPath: string): string {\n const ext = extname(localPath).toLowerCase();\n return MIME_BY_EXTENSION[ext] ?? \"application/octet-stream\";\n}\n\nexport const uploadFileCommand = new Command()\n .name(\"upload-file\")\n .description(\n \"Upload a local file to a Microsoft Teams conversation as the bot\",\n )\n .requiredOption(\"-f, --file <path>\", \"Local file path to upload\")\n .requiredOption(\"-c, --conversation-id <id>\", \"Teams conversation ID\")\n .option(\"--activity-id <id>\", \"Activity ID to reply to\")\n .option(\"-t, --text <message>\", \"Message text to accompany the file\")\n .option(\"--content-type <mime>\", \"Override inferred content type\")\n .addHelpText(\n \"after\",\n `\nExamples:\n Upload a file: zero teams upload-file -f /tmp/report.pdf -c 19:thread@thread.tacv2\n Upload to thread: zero teams upload-file -f /tmp/log.txt -c 19:thread@thread.tacv2 --activity-id root-activity\n With message text: zero teams upload-file -f /tmp/data.csv -c 19:thread@thread.tacv2 -t \"Daily report\"\n\nOutput:\n Prints a JSON object to stdout on success:\n {\"activityId\":\"...\",\"conversationId\":\"19:...\",\"filename\":\"report.pdf\",\"mimetype\":\"application/pdf\",\"size\":12345,\"url\":\"https://...\"}\n\nNotes:\n - Uploads through VM0 storage first, then sends the Teams message with the file URL\n - Use the Conversation ID and Activity ID from the current Teams run prompt`,\n )\n .action(\n withErrorHandler(\n async (options: {\n file: string;\n conversationId: string;\n activityId?: string;\n text?: string;\n contentType?: string;\n }) => {\n let fileSize: number;\n try {\n const stat = statSync(options.file);\n if (!stat.isFile()) {\n throw new Error(`Not a regular file: ${options.file}`);\n }\n fileSize = stat.size;\n } catch (error) {\n if (error instanceof Error && error.message.startsWith(\"Not \")) {\n throw error;\n }\n throw new Error(`File not found: ${options.file}`);\n }\n\n if (fileSize === 0) {\n throw new Error(\"File is empty\");\n }\n\n const filename = basename(options.file);\n const contentType =\n options.contentType ?? inferContentType(options.file);\n const prepared = await initTeamsFileUpload({\n filename,\n contentType,\n length: fileSize,\n });\n\n const fileContent = readFileSync(options.file);\n const uploadResponse = await fetch(prepared.uploadUrl, {\n method: \"PUT\",\n headers: { \"Content-Type\": prepared.contentType },\n body: new Uint8Array(fileContent),\n });\n\n if (!uploadResponse.ok) {\n throw new Error(\n `File upload failed: ${uploadResponse.status} ${uploadResponse.statusText}`,\n );\n }\n\n const result = await completeTeamsFileUpload({\n uploadId: prepared.uploadId,\n conversationId: options.conversationId,\n activityId: options.activityId,\n contentType: prepared.contentType,\n text: options.text,\n });\n\n console.log(JSON.stringify(result));\n },\n ),\n );\n","import { basename, join } from \"path\";\nimport { tmpdir } from \"os\";\nimport { Command } from \"commander\";\nimport { downloadTeamsFile } from \"../../../lib/api\";\nimport { withErrorHandler } from \"../../../lib/command\";\n\nfunction defaultOutPath(fileId: string): string {\n return join(tmpdir(), `teams-${basename(fileId).slice(0, 48)}`);\n}\n\nexport const downloadFileCommand = new Command()\n .name(\"download-file\")\n .description(\"Download a Microsoft Teams file by signed file id\")\n .argument(\"<file-id>\", \"Microsoft Teams file id from a [Teams file] block\")\n .option(\n \"-o, --out <path>\",\n \"Output path for the downloaded file (default: /tmp/teams-<file-id>)\",\n )\n .addHelpText(\n \"after\",\n `\nExamples:\n Download to default temp path: zero teams download-file <file-id>\n Download to explicit path: zero teams download-file <file-id> -o /tmp/file.png\n\nOutput:\n Prints a JSON object to stdout on success:\n {\"path\":\"/tmp/teams-...\",\"mimetype\":\"image/png\",\"size\":12345}\n\nNotes:\n - Use the file id from a [Teams file] block in the prompt\n - Streams the file bytes directly to disk`,\n )\n .action(\n withErrorHandler(async (fileId: string, options: { out?: string }) => {\n const outPath = options.out ?? defaultOutPath(fileId);\n const result = await downloadTeamsFile(fileId, outPath);\n console.log(JSON.stringify(result));\n }),\n );\n"],"mappings":"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","names":["readFileSync","readFileSync","basename","basename"]}
|
|
@@ -7,14 +7,12 @@ import {
|
|
|
7
7
|
initTelegramFileUpload,
|
|
8
8
|
listTelegramBots,
|
|
9
9
|
sendTelegramMessage
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-XVW5RA46.js";
|
|
11
11
|
import "./chunk-LTDQISD7.js";
|
|
12
12
|
import {
|
|
13
|
+
source_default,
|
|
13
14
|
withErrorHandler
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import {
|
|
16
|
-
source_default
|
|
17
|
-
} from "./chunk-JUTUEPIR.js";
|
|
15
|
+
} from "./chunk-CYF7PHDS.js";
|
|
18
16
|
import "./chunk-LRHXR7JT.js";
|
|
19
17
|
import {
|
|
20
18
|
Command
|
|
@@ -335,4 +333,4 @@ Examples:
|
|
|
335
333
|
export {
|
|
336
334
|
zeroTelegramCommand
|
|
337
335
|
};
|
|
338
|
-
//# sourceMappingURL=telegram-
|
|
336
|
+
//# sourceMappingURL=telegram-DRWWXQNJ.js.map
|