@dench.com/cli 3.6.6-staging.386 → 3.7.0-staging.387
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-config.ts +17 -3
- package/app-sdk.d.ts +248 -10
- package/crm.ts +92 -24
- package/dench.ts +128 -19
- package/email-inbox.ts +169 -0
- package/email.ts +103 -21
- package/lib/api-schemas.ts +156 -14
- package/lib/app-sdk-catalog.generated.ts +9 -3
- package/lib/bundled-references.ts +17 -0
- package/lib/cli-args.ts +30 -3
- package/lib/command-args.ts +237 -0
- package/lib/command-help.ts +78 -0
- package/lib/command-registry.ts +75 -3
- package/lib/native-email-wait.ts +75 -0
- package/lib/public-error.ts +82 -0
- package/lib/references.generated.json +66 -0
- package/package.json +3 -1
- package/reference.ts +47 -0
package/lib/api-schemas.ts
CHANGED
|
@@ -57,6 +57,48 @@ const nativeEmailCreate = z.object({
|
|
|
57
57
|
requestId: z.string(),
|
|
58
58
|
...nativeEmailContent,
|
|
59
59
|
});
|
|
60
|
+
const inboxHeader = z.object({
|
|
61
|
+
messageHandle: z.string(),
|
|
62
|
+
threadHandle: z.string(),
|
|
63
|
+
mailboxId: z.string(),
|
|
64
|
+
from: nativeEmailRecipient,
|
|
65
|
+
to: z.array(nativeEmailRecipient),
|
|
66
|
+
subject: z.string(),
|
|
67
|
+
at: z.number(),
|
|
68
|
+
dateSource: z.enum(["sentAt", "createdAt"]),
|
|
69
|
+
direction: z.enum(["inbound", "outbound"]),
|
|
70
|
+
status: z.string(),
|
|
71
|
+
hasAttachments: z.boolean(),
|
|
72
|
+
headersTruncated: z.boolean(),
|
|
73
|
+
});
|
|
74
|
+
const inboxCoverage = z.object({
|
|
75
|
+
source: z.literal("synced"),
|
|
76
|
+
scope: z.literal("mailbox_linked_messages"),
|
|
77
|
+
mailboxId: z.string(),
|
|
78
|
+
mailboxEmail: z.string(),
|
|
79
|
+
mailboxStatus: z.string(),
|
|
80
|
+
ingestionMode: z.string(),
|
|
81
|
+
phase: z.string(),
|
|
82
|
+
syncStatus: z.string().nullable(),
|
|
83
|
+
lastPolledAt: z.number().nullable(),
|
|
84
|
+
lastBackfillCompletedAt: z.number().nullable(),
|
|
85
|
+
oldestSeenAt: z.number().nullable(),
|
|
86
|
+
backfillStatus: z.string().nullable(),
|
|
87
|
+
backfillCapped: z.boolean(),
|
|
88
|
+
providerComplete: z.literal(false),
|
|
89
|
+
privacyLimited: z.boolean(),
|
|
90
|
+
});
|
|
91
|
+
const inboxPaging = {
|
|
92
|
+
limit: z.coerce.number().int().min(1).max(50).optional(),
|
|
93
|
+
cursor: z.string().optional(),
|
|
94
|
+
};
|
|
95
|
+
const inboxPage = z.object({
|
|
96
|
+
page: z.array(inboxHeader),
|
|
97
|
+
continueCursor: z.string().nullable(),
|
|
98
|
+
isDone: z.boolean(),
|
|
99
|
+
coverage: inboxCoverage,
|
|
100
|
+
order: z.literal("sentAt_desc_then_undated"),
|
|
101
|
+
});
|
|
60
102
|
const nativeEmailReceipt = z
|
|
61
103
|
.object({
|
|
62
104
|
ok: z.boolean(),
|
|
@@ -2118,7 +2160,7 @@ const composioToolRun = z.object({
|
|
|
2118
2160
|
tool_slug: z
|
|
2119
2161
|
.string()
|
|
2120
2162
|
.optional()
|
|
2121
|
-
.describe("Tool slug, e.g.
|
|
2163
|
+
.describe("Tool slug, e.g. SLACK_LIST_CHANNELS."),
|
|
2122
2164
|
arguments: z
|
|
2123
2165
|
.record(z.string(), z.unknown())
|
|
2124
2166
|
.optional()
|
|
@@ -3392,8 +3434,34 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
|
|
|
3392
3434
|
)
|
|
3393
3435
|
.optional(),
|
|
3394
3436
|
}),
|
|
3437
|
+
"email.inbox.search": z.object({
|
|
3438
|
+
...inboxPaging,
|
|
3439
|
+
mailbox: z.string().optional(),
|
|
3440
|
+
from: z.string().min(1).max(500).optional(),
|
|
3441
|
+
to: z.string().min(1).max(500).optional(),
|
|
3442
|
+
subject: z.string().min(1).max(500).optional(),
|
|
3443
|
+
after: z.coerce
|
|
3444
|
+
.number()
|
|
3445
|
+
.optional()
|
|
3446
|
+
.describe(
|
|
3447
|
+
"Inclusive Unix milliseconds; missing sentAt falls back to createdAt.",
|
|
3448
|
+
),
|
|
3449
|
+
before: z.coerce
|
|
3450
|
+
.number()
|
|
3451
|
+
.optional()
|
|
3452
|
+
.describe("Exclusive Unix milliseconds."),
|
|
3453
|
+
direction: z.enum(["inbound", "outbound"]).optional(),
|
|
3454
|
+
}),
|
|
3455
|
+
"email.inbox.thread": z.object({ ...inboxPaging, threadHandle: z.string() }),
|
|
3456
|
+
"email.inbox.message": z.object({
|
|
3457
|
+
messageHandle: z.string(),
|
|
3458
|
+
format: z.enum(["text", "html"]).optional(),
|
|
3459
|
+
maxBytes: z.coerce.number().int().min(1).max(100000).optional(),
|
|
3460
|
+
}),
|
|
3395
3461
|
"email.drafts.create": nativeEmailCreate,
|
|
3396
|
-
"email.native.send": nativeEmailCreate
|
|
3462
|
+
"email.native.send": nativeEmailCreate.extend({
|
|
3463
|
+
to: z.array(nativeEmailRecipient).min(1),
|
|
3464
|
+
}),
|
|
3397
3465
|
"email.drafts.get": z.object({ draftId: z.string() }),
|
|
3398
3466
|
"email.drafts.senders": z.object({ organizationId: z.string().optional() }),
|
|
3399
3467
|
"email.drafts.update": z.object({
|
|
@@ -3536,6 +3604,7 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
|
|
|
3536
3604
|
|
|
3537
3605
|
// CRM objects
|
|
3538
3606
|
"crm.objects.list": noInput,
|
|
3607
|
+
"crm.objects.listCompact": noInput,
|
|
3539
3608
|
"crm.objects.get": z.object({ name: z.string() }),
|
|
3540
3609
|
"crm.objects.create": z.object({
|
|
3541
3610
|
name: z.string().describe("Object name (lowercased, singular)."),
|
|
@@ -3631,6 +3700,7 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
|
|
|
3631
3700
|
|
|
3632
3701
|
// CRM fields
|
|
3633
3702
|
"crm.fields.list": z.object({ objectName: z.string() }),
|
|
3703
|
+
"crm.fields.listCompact": z.object({ objectName: z.string() }),
|
|
3634
3704
|
"crm.fields.create": z.object({
|
|
3635
3705
|
objectName: z.string(),
|
|
3636
3706
|
name: z.string(),
|
|
@@ -4163,6 +4233,18 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
|
|
|
4163
4233
|
"Number field to total per bucket (e.g. Amount grouped by Stage). Exact at any table size.",
|
|
4164
4234
|
),
|
|
4165
4235
|
}),
|
|
4236
|
+
"crm.search.page": z.object({
|
|
4237
|
+
text: z.string().describe("Full-text query over readable entries."),
|
|
4238
|
+
objectName: z.string().optional(),
|
|
4239
|
+
select: z.array(z.string().min(1)).min(1).max(30).optional(),
|
|
4240
|
+
limit: z.coerce.number().int().min(1).max(100).optional(),
|
|
4241
|
+
cursor: z
|
|
4242
|
+
.string()
|
|
4243
|
+
.optional()
|
|
4244
|
+
.describe(
|
|
4245
|
+
"Use the preceding continueCursor, with the same query and projection.",
|
|
4246
|
+
),
|
|
4247
|
+
}),
|
|
4166
4248
|
"crm.search": z.object({
|
|
4167
4249
|
text: z.string().describe("Full-text query."),
|
|
4168
4250
|
objectName: z.string().optional().describe("Omit to search org-wide."),
|
|
@@ -5157,6 +5239,24 @@ export const responseSchemas: Record<string, ZodTypeAny> = {
|
|
|
5157
5239
|
|
|
5158
5240
|
// Workspace orientation
|
|
5159
5241
|
"workspace.context.sections": z.object({}).passthrough(),
|
|
5242
|
+
"email.inbox.search": inboxPage,
|
|
5243
|
+
"email.inbox.thread": inboxPage,
|
|
5244
|
+
"email.inbox.message": z.object({
|
|
5245
|
+
header: inboxHeader,
|
|
5246
|
+
coverage: inboxCoverage,
|
|
5247
|
+
body: z.object({
|
|
5248
|
+
format: z.enum(["text", "html"]),
|
|
5249
|
+
content: z.string(),
|
|
5250
|
+
truncated: z.boolean(),
|
|
5251
|
+
totalBytes: z.number(),
|
|
5252
|
+
}),
|
|
5253
|
+
recipients: z.object({
|
|
5254
|
+
to: z.array(nativeEmailRecipient),
|
|
5255
|
+
cc: z.array(nativeEmailRecipient),
|
|
5256
|
+
bcc: z.array(nativeEmailRecipient),
|
|
5257
|
+
truncated: z.boolean(),
|
|
5258
|
+
}),
|
|
5259
|
+
}),
|
|
5160
5260
|
"email.drafts.create": nativeEmailReceipt,
|
|
5161
5261
|
"email.drafts.get": nativeEmailReceipt,
|
|
5162
5262
|
"email.drafts.update": nativeEmailReceipt,
|
|
@@ -5283,6 +5383,18 @@ export const responseSchemas: Record<string, ZodTypeAny> = {
|
|
|
5283
5383
|
|
|
5284
5384
|
// CRM objects
|
|
5285
5385
|
"crm.objects.list": z.array(crmObjectDoc),
|
|
5386
|
+
"crm.objects.listCompact": z.array(
|
|
5387
|
+
z.object({
|
|
5388
|
+
_id: z.string(),
|
|
5389
|
+
name: z.string(),
|
|
5390
|
+
displayName: z.string(),
|
|
5391
|
+
description: z.string().optional(),
|
|
5392
|
+
entryCount: z.number().nullable(),
|
|
5393
|
+
countScope: z.enum(["workspace", "private_unknown"]),
|
|
5394
|
+
visibility: z.enum(["workspace", "owner_only", "owner_plus_members"]),
|
|
5395
|
+
archived: z.boolean(),
|
|
5396
|
+
}),
|
|
5397
|
+
),
|
|
5286
5398
|
"crm.objects.get": crmObjectDoc.nullable(),
|
|
5287
5399
|
"crm.objects.create": z.object({ id: z.string() }),
|
|
5288
5400
|
"crm.objects.update": okResponse,
|
|
@@ -5337,6 +5449,20 @@ export const responseSchemas: Record<string, ZodTypeAny> = {
|
|
|
5337
5449
|
|
|
5338
5450
|
// CRM fields
|
|
5339
5451
|
"crm.fields.list": z.array(crmFieldDoc),
|
|
5452
|
+
"crm.fields.listCompact": z.array(
|
|
5453
|
+
z.object({
|
|
5454
|
+
_id: z.string(),
|
|
5455
|
+
name: z.string(),
|
|
5456
|
+
type: z.string(),
|
|
5457
|
+
required: z.boolean(),
|
|
5458
|
+
readOnly: z.boolean(),
|
|
5459
|
+
defaultValue: z.string().optional(),
|
|
5460
|
+
enumValues: z.array(z.string()).optional(),
|
|
5461
|
+
enumMultiple: z.boolean(),
|
|
5462
|
+
relatedObjectId: z.string().optional(),
|
|
5463
|
+
relationshipType: z.string().optional(),
|
|
5464
|
+
}),
|
|
5465
|
+
),
|
|
5340
5466
|
"crm.fields.create": z.object({ id: z.string() }),
|
|
5341
5467
|
"crm.fields.update": okResponse,
|
|
5342
5468
|
"crm.fields.delete": okResponse,
|
|
@@ -5493,6 +5619,16 @@ export const responseSchemas: Record<string, ZodTypeAny> = {
|
|
|
5493
5619
|
sumNumber: z.number().optional(),
|
|
5494
5620
|
}),
|
|
5495
5621
|
),
|
|
5622
|
+
"crm.search.page": z.object({
|
|
5623
|
+
page: z.array(
|
|
5624
|
+
z.object({ _id: z.string(), objectId: z.string(), data: fieldsMap }),
|
|
5625
|
+
),
|
|
5626
|
+
isDone: z.boolean(),
|
|
5627
|
+
continueCursor: z.string().nullable(),
|
|
5628
|
+
returnedCount: z.number(),
|
|
5629
|
+
selectedFields: z.array(z.string()).nullable(),
|
|
5630
|
+
completeness: z.literal("page"),
|
|
5631
|
+
}),
|
|
5496
5632
|
"crm.search": z.array(
|
|
5497
5633
|
z
|
|
5498
5634
|
.object({
|
|
@@ -6217,6 +6353,12 @@ export const convexExtras: Record<string, ConvexExtras> = {
|
|
|
6217
6353
|
// ---------------------------------------------------------------------------
|
|
6218
6354
|
|
|
6219
6355
|
export const requestExamples: Record<string, unknown> = {
|
|
6356
|
+
"email.native.send": {
|
|
6357
|
+
requestId: "send-intro-001",
|
|
6358
|
+
to: [{ email: "ada@example.com", name: "Ada" }],
|
|
6359
|
+
subject: "Introduction",
|
|
6360
|
+
textBody: "Hello Ada",
|
|
6361
|
+
},
|
|
6220
6362
|
"campaigns.accounts.linkedin": {},
|
|
6221
6363
|
"campaigns.create": {
|
|
6222
6364
|
name: "Founder outreach",
|
|
@@ -6470,11 +6612,11 @@ export const requestExamples: Record<string, unknown> = {
|
|
|
6470
6612
|
input_images_base64: ["iVBORw0KGgoAAAANSUhEUg..."],
|
|
6471
6613
|
},
|
|
6472
6614
|
"tool.search": {
|
|
6473
|
-
queries: [{ use_case: "
|
|
6615
|
+
queries: [{ use_case: "list Slack channels" }],
|
|
6474
6616
|
},
|
|
6475
6617
|
"tool.run": {
|
|
6476
|
-
tool_slug: "
|
|
6477
|
-
arguments: {
|
|
6618
|
+
tool_slug: "SLACK_LIST_CHANNELS",
|
|
6619
|
+
arguments: { limit: 10 },
|
|
6478
6620
|
},
|
|
6479
6621
|
"crm.people.search": {
|
|
6480
6622
|
titles: ["Head of Sales"],
|
|
@@ -8019,18 +8161,18 @@ export const responseExamples: Record<string, unknown> = {
|
|
|
8019
8161
|
error: null,
|
|
8020
8162
|
results: [
|
|
8021
8163
|
{
|
|
8022
|
-
use_case: "
|
|
8023
|
-
primary_tool_slugs: ["
|
|
8024
|
-
toolkits: ["
|
|
8164
|
+
use_case: "list Slack channels",
|
|
8165
|
+
primary_tool_slugs: ["SLACK_LIST_CHANNELS"],
|
|
8166
|
+
toolkits: ["slack"],
|
|
8025
8167
|
},
|
|
8026
8168
|
],
|
|
8027
8169
|
toolkit_connection_statuses: [
|
|
8028
|
-
{ toolkit: "
|
|
8170
|
+
{ toolkit: "slack", has_active_connection: true },
|
|
8029
8171
|
],
|
|
8030
8172
|
tool_schemas: {
|
|
8031
|
-
|
|
8032
|
-
toolkit: "
|
|
8033
|
-
tool_slug: "
|
|
8173
|
+
SLACK_LIST_CHANNELS: {
|
|
8174
|
+
toolkit: "slack",
|
|
8175
|
+
tool_slug: "SLACK_LIST_CHANNELS",
|
|
8034
8176
|
execution_ref: "eyJzZXNzaW9uIjoi...",
|
|
8035
8177
|
execution_ref_version: 1,
|
|
8036
8178
|
},
|
|
@@ -8039,11 +8181,11 @@ export const responseExamples: Record<string, unknown> = {
|
|
|
8039
8181
|
execution_ref_version: 1,
|
|
8040
8182
|
},
|
|
8041
8183
|
"tool.run": {
|
|
8042
|
-
data: {
|
|
8184
|
+
data: { channels: [{ id: "C_EXAMPLE", name: "general" }] },
|
|
8043
8185
|
error: null,
|
|
8044
8186
|
log_id: "log_exec_01",
|
|
8045
8187
|
execution_mode: "gateway_tool_router",
|
|
8046
|
-
tool_slug: "
|
|
8188
|
+
tool_slug: "SLACK_LIST_CHANNELS",
|
|
8047
8189
|
tool_router_session_id: "trs_abc123",
|
|
8048
8190
|
},
|
|
8049
8191
|
"tool.disconnect": { id: "ca_github01", deleted: true },
|
|
@@ -141,6 +141,7 @@ export const APP_SDK_OPERATIONS: readonly AppSdkOperationInfo[] = [
|
|
|
141
141
|
{"id":"chat.send","group":"chat","summary":"Send a message to an existing chat thread.","cli":"dench chat send","method":"POST","path":"/chat/threads/{threadId}/messages","permission":"ai:chat","pathParams":["threadId"]},
|
|
142
142
|
{"id":"chat.follow","group":"chat","summary":"Follow a live chat response stream.","cli":"dench chat follow","method":"GET","path":"/chat/threads/{threadId}/stream","permission":"ai:chat","pathParams":["threadId"]},
|
|
143
143
|
{"id":"crm.objects.list","group":"crm","summary":"List CRM objects.","cli":"dench crm objects list","method":"GET","path":"/crm/objects","permission":"crm:read","pathParams":[]},
|
|
144
|
+
{"id":"crm.objects.listCompact","group":"crm","summary":"List names, display labels, visibility and workspace counts without internal state.","cli":"dench crm objects list --compact","method":"GET","path":"/crm/catalog/objects","permission":"crm:read","pathParams":[]},
|
|
144
145
|
{"id":"crm.objects.get","group":"crm","summary":"Get a CRM object.","cli":"dench crm objects get","method":"GET","path":"/crm/objects/{name}","permission":"crm:read","pathParams":["name"]},
|
|
145
146
|
{"id":"crm.objects.create","group":"crm","summary":"Create a CRM object.","cli":"dench crm objects create","method":"POST","path":"/crm/objects","permission":"crm:write","pathParams":[]},
|
|
146
147
|
{"id":"crm.objects.update","group":"crm","summary":"Update a CRM object.","cli":"dench crm objects update","method":"PATCH","path":"/crm/objects/{name}","permission":"crm:write","pathParams":["name"]},
|
|
@@ -165,6 +166,7 @@ export const APP_SDK_OPERATIONS: readonly AppSdkOperationInfo[] = [
|
|
|
165
166
|
{"id":"crm.sidebar.groups.move-item","group":"crm","summary":"Move a sidebar row into a group (groupId set) or back to the top level (groupId null). Open to any member.","cli":"dench crm sidebar group add","method":"POST","path":"/crm/sidebar/groups/move","permission":"crm:write","pathParams":[]},
|
|
166
167
|
{"id":"crm.sidebar.pins.set","group":"crm","summary":"Pin (pinned true) or unpin a Library row — or a whole group — on the home-level Pinned shortcut strip (the \"tab on the left\"). Does not move the row inside Library. Workspace-shared; open to any member.","cli":"dench crm sidebar pin","method":"POST","path":"/crm/sidebar/pins","permission":"crm:write","pathParams":[]},
|
|
167
168
|
{"id":"crm.fields.list","group":"crm","summary":"List fields for a CRM object, including read-only calculation metadata.","cli":"dench crm fields list","method":"GET","path":"/crm/objects/{objectName}/fields","permission":"crm:read","pathParams":["objectName"]},
|
|
169
|
+
{"id":"crm.fields.listCompact","group":"crm","summary":"List field names, types and effective constraints without indexing or enrichment internals.","cli":"dench crm fields list --compact","method":"GET","path":"/crm/catalog/objects/{objectName}/fields","permission":"crm:read","pathParams":["objectName"]},
|
|
168
170
|
{"id":"crm.fields.create","group":"crm","summary":"Create a CRM field or read-only campaign activity boolean column.","cli":"dench crm fields create","method":"POST","path":"/crm/objects/{objectName}/fields","permission":"crm:write","pathParams":["objectName"]},
|
|
169
171
|
{"id":"crm.fields.update","group":"crm","summary":"Update a CRM field or change/explicitly clear an existing campaign calculation.","cli":"dench crm fields update","method":"PATCH","path":"/crm/objects/{objectName}/fields/{fieldName}","permission":"crm:write","pathParams":["objectName","fieldName"]},
|
|
170
172
|
{"id":"crm.fields.delete","group":"crm","summary":"Delete a CRM field.","cli":"dench crm fields delete","method":"DELETE","path":"/crm/objects/{objectName}/fields/{fieldName}","permission":"crm:write","pathParams":["objectName","fieldName"]},
|
|
@@ -237,6 +239,7 @@ export const APP_SDK_OPERATIONS: readonly AppSdkOperationInfo[] = [
|
|
|
237
239
|
{"id":"crm.sql","group":"crm","summary":"Run CRM SQL-compatible query.","cli":"dench crm sql","method":"POST","path":"/crm/sql","permission":"crm:read","pathParams":[]},
|
|
238
240
|
{"id":"crm.aggregate","group":"crm","summary":"Aggregate CRM entries.","cli":"dench crm aggregate","method":"POST","path":"/crm/aggregate","permission":"crm:read","pathParams":[]},
|
|
239
241
|
{"id":"crm.search","group":"crm","summary":"Search CRM entries.","cli":"dench crm search","method":"GET","path":"/crm/search","permission":"crm:read","pathParams":[]},
|
|
242
|
+
{"id":"crm.search.page","group":"crm","summary":"Search bounded pages of readable CRM entries, optionally projecting cells. Always follow continueCursor until isDone.","cli":"dench crm search --page","method":"GET","path":"/crm/search/page","permission":"crm:read","pathParams":[]},
|
|
240
243
|
{"id":"crm.statuses.list","group":"crm","summary":"List CRM statuses.","cli":"dench crm statuses list","method":"GET","path":"/crm/objects/{objectName}/statuses","permission":"crm:read","pathParams":["objectName"]},
|
|
241
244
|
{"id":"crm.statuses.set","group":"crm","summary":"Set CRM statuses.","cli":"dench crm statuses set","method":"PUT","path":"/crm/objects/{objectName}/statuses","permission":"crm:write","pathParams":["objectName"]},
|
|
242
245
|
{"id":"crm.batch","group":"crm","summary":"Apply a CRM batch.","cli":"dench crm batch","method":"POST","path":"/crm/batch","permission":"crm:write","pathParams":[]},
|
|
@@ -315,6 +318,9 @@ export const APP_SDK_OPERATIONS: readonly AppSdkOperationInfo[] = [
|
|
|
315
318
|
{"id":"email.identity.disable","group":"email","summary":"Soft-disable a sender (or every sender on a domain) for the workspace; sends are blocked until restored.","cli":"dench email identity disable","method":"POST","path":"/email/sending-identities/{identity}/disable","permission":"email:write","pathParams":["identity"]},
|
|
316
319
|
{"id":"email.identity.restore","group":"email","summary":"Restore a previously disabled sender for the workspace.","cli":"dench email identity restore","method":"POST","path":"/email/sending-identities/{identity}/restore","permission":"email:write","pathParams":["identity"]},
|
|
317
320
|
{"id":"email.identity.delete","group":"email","summary":"Permanently delete a sender (or every sender on a domain) from the workspace; re-adding it requires verification from scratch.","cli":"dench email identity delete","method":"DELETE","path":"/email/sending-identities/{identity}","permission":"email:write","pathParams":["identity"]},
|
|
321
|
+
{"id":"email.inbox.search","group":"email","summary":"Search authorized synced mailbox headers with bounded cursor pagination. isDone covers stored records, not provider completeness.","cli":"dench email inbox search","method":"GET","path":"/email/inbox/search","permission":"email:read","pathParams":[]},
|
|
322
|
+
{"id":"email.inbox.thread","group":"email","summary":"Read a bounded page of synced headers using an exact thread handle from inbox search; bodies remain on demand.","cli":"dench email inbox thread","method":"GET","path":"/email/inbox/threads/{threadHandle}","permission":"email:read","pathParams":["threadHandle"]},
|
|
323
|
+
{"id":"email.inbox.message","group":"email","summary":"Read a bounded stored body using an exact message handle from inbox search; rechecks mailbox and record privacy.","cli":"dench email inbox message","method":"GET","path":"/email/inbox/messages/{messageHandle}","permission":"email:read","pathParams":["messageHandle"]},
|
|
318
324
|
{"id":"email.drafts.create","group":"email","summary":"Create an editable Dench email draft and synchronize its selected native mailbox asynchronously. Use a stable requestId for retries.","cli":"dench email draft create","method":"POST","path":"/email/drafts","permission":"email:write","pathParams":[]},
|
|
319
325
|
{"id":"email.drafts.get","group":"email","summary":"Read an email draft, eligible senders and provider sync status.","cli":"dench email draft show","method":"GET","path":"/email/drafts/{draftId}","permission":"email:read","pathParams":["draftId"]},
|
|
320
326
|
{"id":"email.drafts.senders","group":"email","summary":"List native mailboxes this caller may use.","cli":"dench email draft senders","method":"GET","path":"/email/drafts/senders","permission":"email:read","pathParams":[]},
|
|
@@ -322,8 +328,8 @@ export const APP_SDK_OPERATIONS: readonly AppSdkOperationInfo[] = [
|
|
|
322
328
|
{"id":"email.drafts.send","group":"email","summary":"Send the current Dench draft revision through its native mailbox. Repeated requests share a durable receipt.","cli":"dench email draft send","method":"POST","path":"/email/drafts/{draftId}/send","permission":"email:write","pathParams":["draftId"]},
|
|
323
329
|
{"id":"email.drafts.upload","group":"email","summary":"Upload attachment bytes authorized against this draft before adding its storage reference.","cli":"dench email draft attach","method":"POST","path":"/email/drafts/{draftId}/attachments","permission":"email:write","pathParams":["draftId"]},
|
|
324
330
|
{"id":"email.drafts.signature","group":"email","summary":"Load the selected mailbox signature for explicit visible insertion.","cli":"dench email draft signature","method":"GET","path":"/email/drafts/{draftId}/signature","permission":"email:read","pathParams":["draftId"]},
|
|
325
|
-
{"id":"email.native.send","group":"email","summary":"Send through a native Gmail or Outlook mailbox with a durable request receipt. Only use for an explicit send request.","cli":"dench email send --mailbox","method":"POST","path":"/email/native/send","permission":"email:write","pathParams":[]},
|
|
326
|
-
{"id":"email.send","group":"email","summary":"Send one raw email (no campaign): to/cc/bcc, custom from-name and reply-to, optional reply threading via replyToMessageId.","cli":"dench email send","method":"POST","path":"/email/send","permission":"email:write","pathParams":[]},
|
|
331
|
+
{"id":"email.native.send","group":"email","summary":"Send through a native Gmail or Outlook mailbox with a durable request receipt. Only use for an explicit send request.","cli":"dench email send [--mailbox <id/email>]","method":"POST","path":"/email/native/send","permission":"email:write","pathParams":[]},
|
|
332
|
+
{"id":"email.send","group":"email","summary":"Send one raw email (no campaign): to/cc/bcc, custom from-name and reply-to, optional reply threading via replyToMessageId.","cli":"dench email send --from <verified-email>","method":"POST","path":"/email/send","permission":"email:write","pathParams":[]},
|
|
327
333
|
{"id":"email.message.get","group":"email","summary":"Read a raw email message's status and open/click counters.","cli":"dench email message status","method":"GET","path":"/email/messages/{messageId}","permission":"email:read","pathParams":["messageId"]},
|
|
328
334
|
{"id":"email.message.list","group":"email","summary":"List recent raw email messages for the workspace.","cli":"dench email message list","method":"GET","path":"/email/messages","permission":"email:read","pathParams":[]},
|
|
329
335
|
{"id":"email.template.create","group":"email","summary":"Create a managed email campaign template.","cli":"dench email template create","method":"POST","path":"/email/templates","permission":"email:write","pathParams":[]},
|
|
@@ -459,7 +465,7 @@ export const APP_SDK_OPERATIONS: readonly AppSdkOperationInfo[] = [
|
|
|
459
465
|
{"id":"agentConfig.user.show","group":"agent-config","summary":"Read USER.md.","cli":"dench user show","method":"GET","path":"/agent-config/user","permission":"agent-config:read","pathParams":[]},
|
|
460
466
|
{"id":"agentConfig.user.edit","group":"agent-config","summary":"Update USER.md.","cli":"dench user edit","method":"PUT","path":"/agent-config/user","permission":"agent-config:write","pathParams":[]},
|
|
461
467
|
{"id":"agentConfig.tools.show","group":"agent-config","summary":"Read tool notes.","cli":"dench tools show","method":"GET","path":"/agent-config/tools","permission":"agent-config:read","pathParams":[]},
|
|
462
|
-
{"id":"agentConfig.tools.edit","group":"agent-config","summary":"Update tool notes.","cli":"dench tools
|
|
468
|
+
{"id":"agentConfig.tools.edit","group":"agent-config","summary":"Update tool notes.","cli":"dench tools edit","method":"PUT","path":"/agent-config/tools","permission":"agent-config:write","pathParams":[]},
|
|
463
469
|
{"id":"agentConfig.mem.show","group":"agent-config","summary":"Read aggregate memory.","cli":"dench mem show","method":"GET","path":"/agent-config/mem","permission":"agent-config:read","pathParams":[]},
|
|
464
470
|
{"id":"agentConfig.mem.edit","group":"agent-config","summary":"Update aggregate memory.","cli":"dench mem set","method":"PUT","path":"/agent-config/mem","permission":"agent-config:write","pathParams":[]},
|
|
465
471
|
{"id":"agentConfig.bootstrap.show","group":"agent-config","summary":"Read bootstrap state.","cli":"dench bootstrap status","method":"GET","path":"/agent-config/bootstrap","permission":"agent-config:read","pathParams":[]},
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import bundle from "./references.generated.json";
|
|
2
|
+
|
|
3
|
+
export const referenceRevision = bundle.revision;
|
|
4
|
+
const files: Record<string, { sha256: string; content: string }> = bundle.files;
|
|
5
|
+
export function getBundledReference(path: string): string | undefined {
|
|
6
|
+
return Object.hasOwn(files, path) ? files[path].content : undefined;
|
|
7
|
+
}
|
|
8
|
+
export function bundledReferenceIndex() {
|
|
9
|
+
return {
|
|
10
|
+
revision: referenceRevision,
|
|
11
|
+
references: Object.entries(files).map(([path, file]) => ({
|
|
12
|
+
path,
|
|
13
|
+
sha256: file.sha256,
|
|
14
|
+
bytes: new TextEncoder().encode(file.content).byteLength,
|
|
15
|
+
})),
|
|
16
|
+
};
|
|
17
|
+
}
|
package/lib/cli-args.ts
CHANGED
|
@@ -27,7 +27,15 @@
|
|
|
27
27
|
* the caller adapts.
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
|
-
export class CliArgError extends Error {
|
|
30
|
+
export class CliArgError extends Error {
|
|
31
|
+
readonly code = "invalid_arguments";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Help is a local operation, even after otherwise valid mutation arguments. */
|
|
35
|
+
export function isHelpRequest(args: readonly string[]): boolean {
|
|
36
|
+
if (args.includes("--help") || args.includes("-h")) return true;
|
|
37
|
+
return args[0] === "help" || args[1] === "help";
|
|
38
|
+
}
|
|
31
39
|
|
|
32
40
|
export function shift(args: string[], expected: string): string {
|
|
33
41
|
const value = args.shift();
|
|
@@ -35,10 +43,28 @@ export function shift(args: string[], expected: string): string {
|
|
|
35
43
|
return value;
|
|
36
44
|
}
|
|
37
45
|
|
|
46
|
+
/** A standalone short option cannot supply another flag's value. Descending
|
|
47
|
+
* --sort uses -Field (including single-letter fields); negative numbers remain
|
|
48
|
+
* ordinary values. Longer dash-prefixed text remains supported. */
|
|
49
|
+
export function missingFlagValue(
|
|
50
|
+
value: string | undefined,
|
|
51
|
+
name: string,
|
|
52
|
+
): boolean {
|
|
53
|
+
return (
|
|
54
|
+
value === undefined ||
|
|
55
|
+
value.startsWith("--") ||
|
|
56
|
+
value === "-h" ||
|
|
57
|
+
(name !== "--sort" && /^-[a-zA-Z]$/.test(value))
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
38
61
|
export function getFlag(args: string[], name: string): string | undefined {
|
|
39
62
|
const idx = args.indexOf(name);
|
|
40
63
|
if (idx === -1) return undefined;
|
|
41
64
|
const value = args[idx + 1];
|
|
65
|
+
if (missingFlagValue(value, name)) {
|
|
66
|
+
throw new CliArgError(`${name} needs a value`);
|
|
67
|
+
}
|
|
42
68
|
args.splice(idx, 2);
|
|
43
69
|
return value;
|
|
44
70
|
}
|
|
@@ -141,9 +167,10 @@ export function assertNoUnknownFlags(
|
|
|
141
167
|
// some shells to terminate option parsing) is allowed.
|
|
142
168
|
for (const token of args) {
|
|
143
169
|
if (token === "--") continue;
|
|
144
|
-
if (
|
|
170
|
+
if (/^--?[^\d.]/.test(token)) {
|
|
171
|
+
const path = command.replace(/^dench\s+/, "");
|
|
145
172
|
throw new CliArgError(
|
|
146
|
-
`Unknown flag for ${
|
|
173
|
+
`Unknown flag for ${path}: ${token}. Run \`dench ${path} --help\` for usage.`,
|
|
147
174
|
);
|
|
148
175
|
}
|
|
149
176
|
}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { CliArgError, missingFlagValue } from "./cli-args";
|
|
2
|
+
|
|
3
|
+
type PositionalArity = readonly [min: number, max: number | null];
|
|
4
|
+
|
|
5
|
+
type CommandArguments = {
|
|
6
|
+
command: string;
|
|
7
|
+
values: string[];
|
|
8
|
+
switches: string[];
|
|
9
|
+
positionals: PositionalArity;
|
|
10
|
+
flagPositionals: Record<string, PositionalArity>;
|
|
11
|
+
};
|
|
12
|
+
const spec = (
|
|
13
|
+
command: string,
|
|
14
|
+
positionals: PositionalArity,
|
|
15
|
+
values = "",
|
|
16
|
+
switches = "",
|
|
17
|
+
flagPositionals: Record<string, PositionalArity> = {},
|
|
18
|
+
): CommandArguments => ({
|
|
19
|
+
command,
|
|
20
|
+
positionals,
|
|
21
|
+
flagPositionals,
|
|
22
|
+
values: values.split(" ").filter(Boolean),
|
|
23
|
+
switches: switches.split(" ").filter(Boolean),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const browserSpec = (
|
|
27
|
+
verb: string,
|
|
28
|
+
positionals: PositionalArity,
|
|
29
|
+
flagPositionals: Record<string, PositionalArity> = {},
|
|
30
|
+
): CommandArguments =>
|
|
31
|
+
spec(
|
|
32
|
+
`browser ${verb}`,
|
|
33
|
+
positionals,
|
|
34
|
+
"--thread --selector --text --label --value --key --target-id --targetId --pixels --timeout-ms --timeoutMs --x --y --output --url --script",
|
|
35
|
+
"--full-page",
|
|
36
|
+
flagPositionals,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
/** CLI spellings for dispatchers that do not reject leftovers themselves.
|
|
40
|
+
* Positional ranges follow the actual handlers; null deliberately allows free text
|
|
41
|
+
* or multiple IDs. Flag alternatives cover positional inputs replaced by flags.
|
|
42
|
+
* Shared by pre-dispatch validation and help; API property names are not flags. */
|
|
43
|
+
export const COMMAND_ARGUMENTS = [
|
|
44
|
+
spec(
|
|
45
|
+
"signin",
|
|
46
|
+
[0, 0],
|
|
47
|
+
"--kind --name --email --org-name --org --timeout-ms --otp-code",
|
|
48
|
+
"--new-workspace --no-open",
|
|
49
|
+
),
|
|
50
|
+
spec("logout", [0, 1], "", "--all"),
|
|
51
|
+
spec("use", [1, 1]),
|
|
52
|
+
spec("backend set", [1, 1]),
|
|
53
|
+
spec("backend clear", [0, 0]),
|
|
54
|
+
...["install", "uninstall", "refresh"].map((verb) =>
|
|
55
|
+
spec(
|
|
56
|
+
`ads ${verb}`,
|
|
57
|
+
[0, 0],
|
|
58
|
+
"--target",
|
|
59
|
+
"--no-open --apply --color --no-color",
|
|
60
|
+
),
|
|
61
|
+
),
|
|
62
|
+
spec(
|
|
63
|
+
"ads payout setup",
|
|
64
|
+
[0, 0],
|
|
65
|
+
"--target",
|
|
66
|
+
"--no-open --apply --color --no-color",
|
|
67
|
+
),
|
|
68
|
+
spec(
|
|
69
|
+
"ads payout onboard",
|
|
70
|
+
[0, 0],
|
|
71
|
+
"--target",
|
|
72
|
+
"--no-open --apply --color --no-color",
|
|
73
|
+
),
|
|
74
|
+
spec(
|
|
75
|
+
"ads withdraw",
|
|
76
|
+
[0, 0],
|
|
77
|
+
"--amount --idempotency-key --target",
|
|
78
|
+
"--no-open --apply --color --no-color",
|
|
79
|
+
),
|
|
80
|
+
spec(
|
|
81
|
+
"chat new",
|
|
82
|
+
[1, null],
|
|
83
|
+
"--model --file-context --visibility --title",
|
|
84
|
+
"--yolo --follow",
|
|
85
|
+
),
|
|
86
|
+
spec("chat send", [2, null], "--model", "--yolo --follow"),
|
|
87
|
+
spec("chat rename", [2, null], "", "--from-stdin", {
|
|
88
|
+
"--from-stdin": [0, 0],
|
|
89
|
+
}),
|
|
90
|
+
spec("chat delete", [1, null], "--ids", "--yes -y --include-automated", {
|
|
91
|
+
"--ids": [0, null],
|
|
92
|
+
}),
|
|
93
|
+
spec("apps create", [1, 1], "--name --icon --description", "", {
|
|
94
|
+
"--name": [0, 1],
|
|
95
|
+
}),
|
|
96
|
+
spec(
|
|
97
|
+
"apps publish",
|
|
98
|
+
[1, 1],
|
|
99
|
+
"--slug --name --description --icon --visibility --version",
|
|
100
|
+
),
|
|
101
|
+
...["install", "uninstall", "enable", "disable", "pin", "unpin"].map((verb) =>
|
|
102
|
+
spec(`apps ${verb}`, [1, 1]),
|
|
103
|
+
),
|
|
104
|
+
spec("apps webhooks register", [2, 2], "", "--rotate"),
|
|
105
|
+
spec("apps webhooks delete", [2, 2]),
|
|
106
|
+
spec("apps validate", [1, 1]),
|
|
107
|
+
spec(
|
|
108
|
+
"members me",
|
|
109
|
+
[0, 0],
|
|
110
|
+
"--name --tagline --timezone --image-url --avatar",
|
|
111
|
+
"--clear-avatar --auto-timezone",
|
|
112
|
+
),
|
|
113
|
+
spec(
|
|
114
|
+
"cron create",
|
|
115
|
+
[1, 1],
|
|
116
|
+
"--prompt --description --overlap --target --type --at --cron --tz --every --every-ms --connection --event --toolkit --trigger-config --object --where --where-logic",
|
|
117
|
+
"--disabled --delete-after-run --no-secret --signed",
|
|
118
|
+
),
|
|
119
|
+
spec(
|
|
120
|
+
"cron update",
|
|
121
|
+
[1, 1],
|
|
122
|
+
"--name --prompt --description --overlap --enabled --at --cron --tz --every --every-ms",
|
|
123
|
+
),
|
|
124
|
+
spec("cron run", [1, 1], "", "--wait"),
|
|
125
|
+
spec("cron secret", [1, 1], "", "--off"),
|
|
126
|
+
...["delete", "enable", "disable"].map((verb) =>
|
|
127
|
+
spec(`cron ${verb}`, [1, 1]),
|
|
128
|
+
),
|
|
129
|
+
spec("files rm", [1, 1], "", "--recursive -r"),
|
|
130
|
+
spec("files mv", [2, 2]),
|
|
131
|
+
spec("files write", [1, 1]),
|
|
132
|
+
spec("stage", [1, 2], "", "--clean"),
|
|
133
|
+
...["identity", "organisation", "user", "tools", "mem"].flatMap((group) =>
|
|
134
|
+
["edit", "set"].map((verb) =>
|
|
135
|
+
spec(`${group} ${verb}`, [0, 0], "--content", "--stdin"),
|
|
136
|
+
),
|
|
137
|
+
),
|
|
138
|
+
spec("mem append", [1, null]),
|
|
139
|
+
spec("model default", [0, 1]),
|
|
140
|
+
spec("model thread", [2, 2]),
|
|
141
|
+
spec("bootstrap complete", [0, 0]),
|
|
142
|
+
spec("bootstrap reopen", [0, 0]),
|
|
143
|
+
spec("bootstrap template", [0, 0], "--content", "--stdin"),
|
|
144
|
+
spec(
|
|
145
|
+
"memory save",
|
|
146
|
+
[2, null],
|
|
147
|
+
"--kind --tags --sensitivity --scope --visibility",
|
|
148
|
+
),
|
|
149
|
+
spec("project create", [1, 1], "--repo --root"),
|
|
150
|
+
spec("approval request", [1, 1], "--reason --risk --agent"),
|
|
151
|
+
spec("approval approve", [1, 1], "--evidence"),
|
|
152
|
+
spec("approval reject", [1, 1], "--evidence"),
|
|
153
|
+
spec("billing topup", [1, 1], "--amount", "--no-open", {
|
|
154
|
+
"--amount": [0, 0],
|
|
155
|
+
}),
|
|
156
|
+
spec("upgrade", [0, 0], "--tier --cycle --billing-cycle", "--no-open"),
|
|
157
|
+
spec("tool run", [1, 1], "--args --account --approval"),
|
|
158
|
+
spec("tool connect", [1, 1], "--callback-url"),
|
|
159
|
+
spec("tool disconnect", [1, 1]),
|
|
160
|
+
spec(
|
|
161
|
+
"browser session create",
|
|
162
|
+
[0, 0],
|
|
163
|
+
"--context-id --contextId --width --height",
|
|
164
|
+
),
|
|
165
|
+
spec("browser session stop", [1, 1]),
|
|
166
|
+
// Value flags replace the joined positional input. The clickAt handler
|
|
167
|
+
// instead lets its first/second positionals override --x/--y individually.
|
|
168
|
+
browserSpec("open", [0, null], { "--url": [0, 0] }),
|
|
169
|
+
browserSpec("state", [0, 0]),
|
|
170
|
+
browserSpec("inspect", [0, 0]),
|
|
171
|
+
browserSpec("navigate", [0, null], { "--url": [0, 0] }),
|
|
172
|
+
browserSpec("click", [0, 0]),
|
|
173
|
+
browserSpec("clickAt", [0, 2]),
|
|
174
|
+
browserSpec("click-at", [0, 2]),
|
|
175
|
+
browserSpec("fill", [0, 0]),
|
|
176
|
+
browserSpec("type", [0, null], { "--value": [0, 0] }),
|
|
177
|
+
browserSpec("key", [0, null], { "--key": [0, 0] }),
|
|
178
|
+
browserSpec("scroll", [0, 1]),
|
|
179
|
+
browserSpec("wait", [0, 0]),
|
|
180
|
+
browserSpec("evaluate", [0, null], { "--script": [0, 0] }),
|
|
181
|
+
browserSpec("tabs", [0, 0]),
|
|
182
|
+
browserSpec("newTab", [0, null], { "--url": [0, 0] }),
|
|
183
|
+
browserSpec("new-tab", [0, null], { "--url": [0, 0] }),
|
|
184
|
+
...["activateTab", "activate-tab", "closeTab", "close-tab"].map((verb) =>
|
|
185
|
+
browserSpec(verb, [0, 1], { "--target-id": [0, 0], "--targetId": [0, 0] }),
|
|
186
|
+
),
|
|
187
|
+
browserSpec("screenshot", [0, 0]),
|
|
188
|
+
browserSpec("stop", [0, 0]),
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
export function assertDeclaredCommandFlags(argv: readonly string[]): void {
|
|
192
|
+
const args = argv.filter((arg) => arg !== "--json");
|
|
193
|
+
if (["routine", "routines"].includes(args[0])) args[0] = "cron";
|
|
194
|
+
if (["ad", "adline"].includes(args[0])) args[0] = "ads";
|
|
195
|
+
if (args[0] === "agent" && ["new", "send"].includes(args[1]))
|
|
196
|
+
args[0] = "chat";
|
|
197
|
+
if (args[0] === "crm" && args[1] === "members") args.shift();
|
|
198
|
+
const contract = COMMAND_ARGUMENTS.find(({ command }) =>
|
|
199
|
+
command.split(" ").every((part, index) => args[index] === part),
|
|
200
|
+
);
|
|
201
|
+
if (!contract) return; // Domain parsers keep their own consumed-argument validation.
|
|
202
|
+
const positionals: string[] = [];
|
|
203
|
+
const flags = new Set<string>();
|
|
204
|
+
for (let i = contract.command.split(" ").length; i < args.length; i++) {
|
|
205
|
+
const arg = args[i];
|
|
206
|
+
if (!/^--?[^\d.]/.test(arg)) {
|
|
207
|
+
positionals.push(arg);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
flags.add(arg);
|
|
211
|
+
if (contract.switches.includes(arg)) continue;
|
|
212
|
+
if (contract.values.includes(arg)) {
|
|
213
|
+
const value = args[++i];
|
|
214
|
+
if (missingFlagValue(value, arg))
|
|
215
|
+
throw new CliArgError(`Missing value for ${arg}`);
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
throw new CliArgError(
|
|
219
|
+
`Unknown flag for ${contract.command}: ${arg}. Run \`dench ${contract.command} --help\` for usage.`,
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
const [min, max] =
|
|
223
|
+
Object.entries(contract.flagPositionals).find(([flag]) =>
|
|
224
|
+
flags.has(flag),
|
|
225
|
+
)?.[1] ?? contract.positionals;
|
|
226
|
+
if (positionals.length < min || (max !== null && positionals.length > max)) {
|
|
227
|
+
const expected =
|
|
228
|
+
max === null
|
|
229
|
+
? `at least ${min}`
|
|
230
|
+
: min === max
|
|
231
|
+
? String(min)
|
|
232
|
+
: `${min}–${max}`;
|
|
233
|
+
throw new CliArgError(
|
|
234
|
+
`${positionals.length < min ? "Missing" : "Unexpected"} positional argument for ${contract.command}: expected ${expected}, received ${positionals.length}. Run \`dench ${contract.command} --help\` for usage.`,
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
}
|