@dayofweek/dcli 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -1
- package/dist/bin/dcli.js +537 -6
- package/dist/bundle/dcli.cjs +5991 -0
- package/dist/client.d.ts +167 -2
- package/dist/client.js +233 -4
- package/package.json +5 -3
package/dist/client.d.ts
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
* HTTP client for the Day of Week platform REST API.
|
|
3
3
|
* All calls go through the proxy at field.dayofweek.com/app/api/dcli.
|
|
4
4
|
*/
|
|
5
|
+
/**
|
|
6
|
+
* Node's Buffer is a Uint8Array view over a possibly-larger, possibly-shared
|
|
7
|
+
* backing store, which is not assignable to BodyInit. Copy out the exact bytes.
|
|
8
|
+
*/
|
|
9
|
+
export declare function toArrayBuffer(view: Uint8Array): ArrayBuffer;
|
|
5
10
|
export declare class ApiError extends Error {
|
|
6
11
|
status: number;
|
|
7
12
|
code?: string | undefined;
|
|
@@ -103,23 +108,27 @@ export declare class DayOfWeekClient {
|
|
|
103
108
|
type?: string;
|
|
104
109
|
parent?: string;
|
|
105
110
|
limit?: number;
|
|
111
|
+
org?: string;
|
|
106
112
|
}): Promise<any[]>;
|
|
107
|
-
getEntity(entityId: string): Promise<any>;
|
|
113
|
+
getEntity(entityId: string, org?: string): Promise<any>;
|
|
108
114
|
listProduce(opts?: {
|
|
109
115
|
entity?: string;
|
|
110
116
|
limit?: number;
|
|
117
|
+
org?: string;
|
|
111
118
|
}): Promise<any[]>;
|
|
112
119
|
listContacts(opts?: {
|
|
113
120
|
entity?: string;
|
|
114
121
|
limit?: number;
|
|
122
|
+
org?: string;
|
|
115
123
|
}): Promise<any[]>;
|
|
116
|
-
listEntityTypes(): Promise<any[]>;
|
|
124
|
+
listEntityTypes(org?: string): Promise<any[]>;
|
|
117
125
|
searchCatalog(opts?: {
|
|
118
126
|
search?: string;
|
|
119
127
|
parent?: string;
|
|
120
128
|
type?: string;
|
|
121
129
|
includeCategories?: boolean;
|
|
122
130
|
limit?: number;
|
|
131
|
+
org?: string;
|
|
123
132
|
}): Promise<any[]>;
|
|
124
133
|
listProposals(opts?: {
|
|
125
134
|
status?: string;
|
|
@@ -154,6 +163,161 @@ export declare class DayOfWeekClient {
|
|
|
154
163
|
truncated: boolean;
|
|
155
164
|
total: number;
|
|
156
165
|
}>;
|
|
166
|
+
/**
|
|
167
|
+
* Direct produce entry — creates real Creator rows, not proposals.
|
|
168
|
+
*
|
|
169
|
+
* With `dryRun` the server runs the whole import and rolls it back, so the
|
|
170
|
+
* operator approves the server's verdict instead of a reconstruction of it.
|
|
171
|
+
*/
|
|
172
|
+
importProduce(input: {
|
|
173
|
+
entityId: string;
|
|
174
|
+
items: unknown[];
|
|
175
|
+
dryRun?: boolean;
|
|
176
|
+
skipExistingNames?: boolean;
|
|
177
|
+
org?: string;
|
|
178
|
+
}): Promise<any>;
|
|
179
|
+
/** Recipe ingredients still standing in for something vaguer. */
|
|
180
|
+
listImpreciseIngredients(entityId: string, org?: string): Promise<any>;
|
|
181
|
+
/** Point an imprecise ingredient at what it actually is. */
|
|
182
|
+
refineIngredient(input: {
|
|
183
|
+
processInputId: string;
|
|
184
|
+
catalogConceptId?: string;
|
|
185
|
+
materialId?: string;
|
|
186
|
+
role?: string;
|
|
187
|
+
qty?: number;
|
|
188
|
+
unitCode?: string;
|
|
189
|
+
stillImprecise?: boolean;
|
|
190
|
+
org?: string;
|
|
191
|
+
}): Promise<any>;
|
|
192
|
+
/**
|
|
193
|
+
* Grow the shared produce catalog. Admin only — every customer sees these
|
|
194
|
+
* concepts, so adding one is a platform decision, not a per-import shortcut.
|
|
195
|
+
*/
|
|
196
|
+
createCatalogConcepts(input: {
|
|
197
|
+
concepts: unknown[];
|
|
198
|
+
org?: string;
|
|
199
|
+
}): Promise<any>;
|
|
200
|
+
/** Area sources, metadata only, newest first — the freshness evidence. */
|
|
201
|
+
listBrainSources(areaId: string): Promise<any>;
|
|
202
|
+
/** Entities with an active customer role and no investor/partner/producer role. */
|
|
203
|
+
adminCustomersOnly(): Promise<any>;
|
|
204
|
+
/** Tips mailed to press@mail.dayofweek.com, read by the press-scan skill. */
|
|
205
|
+
adminPressInbox(opts?: {
|
|
206
|
+
since?: string;
|
|
207
|
+
limit?: number;
|
|
208
|
+
}): Promise<any>;
|
|
209
|
+
/**
|
|
210
|
+
* List the knowledge documents attached to an entity. `full` returns each
|
|
211
|
+
* document's whole content instead of an excerpt, which is what you want when
|
|
212
|
+
* mirroring an entity's sources into an external knowledge base.
|
|
213
|
+
*/
|
|
214
|
+
listKnowledge(opts: {
|
|
215
|
+
entity: string;
|
|
216
|
+
full?: boolean;
|
|
217
|
+
org?: string;
|
|
218
|
+
}): Promise<any[]>;
|
|
219
|
+
getKnowledge(documentId: string, org?: string): Promise<any>;
|
|
220
|
+
/** Semantic search across knowledge documents. */
|
|
221
|
+
searchKnowledge(opts: {
|
|
222
|
+
query: string;
|
|
223
|
+
entity?: string;
|
|
224
|
+
types?: string[];
|
|
225
|
+
limit?: number;
|
|
226
|
+
allOrgs?: boolean;
|
|
227
|
+
org?: string;
|
|
228
|
+
}): Promise<any>;
|
|
229
|
+
/**
|
|
230
|
+
* Add a markdown knowledge note.
|
|
231
|
+
*
|
|
232
|
+
* Without `direct` this submits a proposal for human review — the default,
|
|
233
|
+
* and the only option non-admin tokens have. With `direct: true` an admin
|
|
234
|
+
* token writes the document immediately, skipping review. Ask the operator
|
|
235
|
+
* before doing that; see references/admin.md in the served skill.
|
|
236
|
+
*/
|
|
237
|
+
addKnowledge(input: {
|
|
238
|
+
entityId: string;
|
|
239
|
+
title: string;
|
|
240
|
+
content: string;
|
|
241
|
+
sourceType?: string;
|
|
242
|
+
sourceUrl?: string;
|
|
243
|
+
sourceDescription?: string;
|
|
244
|
+
confidence?: number;
|
|
245
|
+
sourceAgent?: string;
|
|
246
|
+
direct?: boolean;
|
|
247
|
+
org?: string;
|
|
248
|
+
}): Promise<any>;
|
|
249
|
+
/**
|
|
250
|
+
* Attach a binary source (PDF, DOCX, XLSX, …) to an entity. Admin only.
|
|
251
|
+
*
|
|
252
|
+
* Three hops: ask for an upload URL, send the bytes straight to Convex
|
|
253
|
+
* storage, then register the resulting storageId. The bytes never pass
|
|
254
|
+
* through function arguments, so file size isn't bounded by an arg limit.
|
|
255
|
+
*/
|
|
256
|
+
attachKnowledgeFile(input: {
|
|
257
|
+
entityId: string;
|
|
258
|
+
/** Raw file bytes. Buffer callers: pass `toArrayBuffer(buf)` below. */
|
|
259
|
+
data: ArrayBuffer;
|
|
260
|
+
fileName: string;
|
|
261
|
+
mimeType: string;
|
|
262
|
+
sourceType?: string;
|
|
263
|
+
sourceUrl?: string;
|
|
264
|
+
sourceDescription?: string;
|
|
265
|
+
org?: string;
|
|
266
|
+
}): Promise<any>;
|
|
267
|
+
listDatasets(org?: string): Promise<{
|
|
268
|
+
datasets: Array<{
|
|
269
|
+
name: string;
|
|
270
|
+
description: string;
|
|
271
|
+
params: string[];
|
|
272
|
+
}>;
|
|
273
|
+
}>;
|
|
274
|
+
readDataset(name: string, opts?: {
|
|
275
|
+
limit?: number;
|
|
276
|
+
org?: string;
|
|
277
|
+
}): Promise<any>;
|
|
278
|
+
listFeedback(opts?: {
|
|
279
|
+
status?: string;
|
|
280
|
+
priority?: string;
|
|
281
|
+
category?: string;
|
|
282
|
+
limit?: number;
|
|
283
|
+
}): Promise<{
|
|
284
|
+
items: any[];
|
|
285
|
+
}>;
|
|
286
|
+
getFeedbackItem(itemId: string): Promise<any>;
|
|
287
|
+
/** Top-N from the heuristic prioritizer — "what should I work on next?". */
|
|
288
|
+
feedbackRecommendations(limit?: number): Promise<{
|
|
289
|
+
recommendations: any[];
|
|
290
|
+
}>;
|
|
291
|
+
claimFeedbackItem(itemId: string): Promise<any>;
|
|
292
|
+
commentOnFeedbackItem(itemId: string, body: string): Promise<any>;
|
|
293
|
+
updateFeedbackItem(itemId: string, updates: {
|
|
294
|
+
status?: string;
|
|
295
|
+
priority?: string;
|
|
296
|
+
rejectedReason?: string;
|
|
297
|
+
}): Promise<any>;
|
|
298
|
+
listEmailThreads(opts?: {
|
|
299
|
+
status?: string;
|
|
300
|
+
since?: string;
|
|
301
|
+
customer?: string;
|
|
302
|
+
limit?: number;
|
|
303
|
+
org?: string;
|
|
304
|
+
}): Promise<any>;
|
|
305
|
+
getEmailThread(threadKey: string): Promise<any>;
|
|
306
|
+
replyToEmailThread(threadKey: string, input: {
|
|
307
|
+
message: string;
|
|
308
|
+
subject?: string;
|
|
309
|
+
to?: string;
|
|
310
|
+
cc?: string[];
|
|
311
|
+
quote?: boolean;
|
|
312
|
+
}): Promise<any>;
|
|
313
|
+
composeEmail(input: {
|
|
314
|
+
entityId?: string;
|
|
315
|
+
inbox?: string;
|
|
316
|
+
to: string;
|
|
317
|
+
cc?: string[];
|
|
318
|
+
subject: string;
|
|
319
|
+
message: string;
|
|
320
|
+
}): Promise<any>;
|
|
157
321
|
getSkillBundle(name?: string): Promise<{
|
|
158
322
|
name: string;
|
|
159
323
|
version: string;
|
|
@@ -172,6 +336,7 @@ export declare class DayOfWeekClient {
|
|
|
172
336
|
getSchema(): Promise<any>;
|
|
173
337
|
private get;
|
|
174
338
|
private post;
|
|
339
|
+
private put;
|
|
175
340
|
private patch;
|
|
176
341
|
private delete;
|
|
177
342
|
private request;
|
package/dist/client.js
CHANGED
|
@@ -8,6 +8,15 @@ import { basename, dirname, join } from "node:path";
|
|
|
8
8
|
import { Readable, Transform } from "node:stream";
|
|
9
9
|
import { pipeline } from "node:stream/promises";
|
|
10
10
|
const DEFAULT_BASE_URL = "https://field.dayofweek.com/app/api/dcli";
|
|
11
|
+
/**
|
|
12
|
+
* Node's Buffer is a Uint8Array view over a possibly-larger, possibly-shared
|
|
13
|
+
* backing store, which is not assignable to BodyInit. Copy out the exact bytes.
|
|
14
|
+
*/
|
|
15
|
+
export function toArrayBuffer(view) {
|
|
16
|
+
const out = new ArrayBuffer(view.byteLength);
|
|
17
|
+
new Uint8Array(out).set(view);
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
11
20
|
export class ApiError extends Error {
|
|
12
21
|
status;
|
|
13
22
|
code;
|
|
@@ -180,6 +189,8 @@ export class DayOfWeekClient {
|
|
|
180
189
|
return this.get(`/brain/audit?${query}`);
|
|
181
190
|
}
|
|
182
191
|
// ── Read ──────────────────────────────────────────────────────────────────
|
|
192
|
+
// Every read endpoint accepts ?org=<slug|id> for admin tokens. Exposing it as
|
|
193
|
+
// --org is what keeps admins from dropping to curl for cross-org reads.
|
|
183
194
|
async listEntities(opts) {
|
|
184
195
|
const params = new URLSearchParams();
|
|
185
196
|
if (opts?.type)
|
|
@@ -188,11 +199,14 @@ export class DayOfWeekClient {
|
|
|
188
199
|
params.set("parent", opts.parent);
|
|
189
200
|
if (opts?.limit)
|
|
190
201
|
params.set("limit", String(opts.limit));
|
|
202
|
+
if (opts?.org)
|
|
203
|
+
params.set("org", opts.org);
|
|
191
204
|
const qs = params.toString();
|
|
192
205
|
return this.get(`/entities${qs ? `?${qs}` : ""}`);
|
|
193
206
|
}
|
|
194
|
-
async getEntity(entityId) {
|
|
195
|
-
|
|
207
|
+
async getEntity(entityId, org) {
|
|
208
|
+
const qs = org ? `?org=${encodeURIComponent(org)}` : "";
|
|
209
|
+
return this.get(`/entities/${entityId}${qs}`);
|
|
196
210
|
}
|
|
197
211
|
async listProduce(opts) {
|
|
198
212
|
const params = new URLSearchParams();
|
|
@@ -200,6 +214,8 @@ export class DayOfWeekClient {
|
|
|
200
214
|
params.set("entity", opts.entity);
|
|
201
215
|
if (opts?.limit)
|
|
202
216
|
params.set("limit", String(opts.limit));
|
|
217
|
+
if (opts?.org)
|
|
218
|
+
params.set("org", opts.org);
|
|
203
219
|
const qs = params.toString();
|
|
204
220
|
return this.get(`/produce${qs ? `?${qs}` : ""}`);
|
|
205
221
|
}
|
|
@@ -209,11 +225,14 @@ export class DayOfWeekClient {
|
|
|
209
225
|
params.set("entity", opts.entity);
|
|
210
226
|
if (opts?.limit)
|
|
211
227
|
params.set("limit", String(opts.limit));
|
|
228
|
+
if (opts?.org)
|
|
229
|
+
params.set("org", opts.org);
|
|
212
230
|
const qs = params.toString();
|
|
213
231
|
return this.get(`/contacts${qs ? `?${qs}` : ""}`);
|
|
214
232
|
}
|
|
215
|
-
async listEntityTypes() {
|
|
216
|
-
|
|
233
|
+
async listEntityTypes(org) {
|
|
234
|
+
const qs = org ? `?org=${encodeURIComponent(org)}` : "";
|
|
235
|
+
return this.get(`/entity-types${qs}`);
|
|
217
236
|
}
|
|
218
237
|
async searchCatalog(opts) {
|
|
219
238
|
const params = new URLSearchParams();
|
|
@@ -227,6 +246,8 @@ export class DayOfWeekClient {
|
|
|
227
246
|
params.set("includeCategories", "true");
|
|
228
247
|
if (opts?.limit)
|
|
229
248
|
params.set("limit", String(opts.limit));
|
|
249
|
+
if (opts?.org)
|
|
250
|
+
params.set("org", opts.org);
|
|
230
251
|
const qs = params.toString();
|
|
231
252
|
return this.get(`/catalog${qs ? `?${qs}` : ""}`);
|
|
232
253
|
}
|
|
@@ -279,6 +300,211 @@ export class DayOfWeekClient {
|
|
|
279
300
|
const qs = params.toString();
|
|
280
301
|
return this.get(`/admin/proposals${qs ? `?${qs}` : ""}`);
|
|
281
302
|
}
|
|
303
|
+
// ── Produce import (admin) ────────────────────────────────────────────────
|
|
304
|
+
/**
|
|
305
|
+
* Direct produce entry — creates real Creator rows, not proposals.
|
|
306
|
+
*
|
|
307
|
+
* With `dryRun` the server runs the whole import and rolls it back, so the
|
|
308
|
+
* operator approves the server's verdict instead of a reconstruction of it.
|
|
309
|
+
*/
|
|
310
|
+
async importProduce(input) {
|
|
311
|
+
return this.post("/produce/import", input);
|
|
312
|
+
}
|
|
313
|
+
/** Recipe ingredients still standing in for something vaguer. */
|
|
314
|
+
async listImpreciseIngredients(entityId, org) {
|
|
315
|
+
const params = new URLSearchParams({ entity: entityId });
|
|
316
|
+
if (org)
|
|
317
|
+
params.set("org", org);
|
|
318
|
+
return this.get(`/produce/ingredients?${params.toString()}`);
|
|
319
|
+
}
|
|
320
|
+
/** Point an imprecise ingredient at what it actually is. */
|
|
321
|
+
async refineIngredient(input) {
|
|
322
|
+
return this.patch("/produce/ingredients", input);
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Grow the shared produce catalog. Admin only — every customer sees these
|
|
326
|
+
* concepts, so adding one is a platform decision, not a per-import shortcut.
|
|
327
|
+
*/
|
|
328
|
+
async createCatalogConcepts(input) {
|
|
329
|
+
return this.post("/catalog/concepts", input);
|
|
330
|
+
}
|
|
331
|
+
/** Area sources, metadata only, newest first — the freshness evidence. */
|
|
332
|
+
async listBrainSources(areaId) {
|
|
333
|
+
return this.get(`/brain/sources?area=${encodeURIComponent(areaId)}`);
|
|
334
|
+
}
|
|
335
|
+
/** Entities with an active customer role and no investor/partner/producer role. */
|
|
336
|
+
async adminCustomersOnly() {
|
|
337
|
+
return this.get("/admin/customers-only");
|
|
338
|
+
}
|
|
339
|
+
/** Tips mailed to press@mail.dayofweek.com, read by the press-scan skill. */
|
|
340
|
+
async adminPressInbox(opts) {
|
|
341
|
+
const params = new URLSearchParams();
|
|
342
|
+
if (opts?.since)
|
|
343
|
+
params.set("since", opts.since);
|
|
344
|
+
if (opts?.limit)
|
|
345
|
+
params.set("limit", String(opts.limit));
|
|
346
|
+
const qs = params.toString();
|
|
347
|
+
return this.get(`/press-inbox${qs ? `?${qs}` : ""}`);
|
|
348
|
+
}
|
|
349
|
+
// ── Knowledge ─────────────────────────────────────────────────────────────
|
|
350
|
+
/**
|
|
351
|
+
* List the knowledge documents attached to an entity. `full` returns each
|
|
352
|
+
* document's whole content instead of an excerpt, which is what you want when
|
|
353
|
+
* mirroring an entity's sources into an external knowledge base.
|
|
354
|
+
*/
|
|
355
|
+
async listKnowledge(opts) {
|
|
356
|
+
const params = new URLSearchParams({ entity: opts.entity });
|
|
357
|
+
if (opts.full)
|
|
358
|
+
params.set("full", "1");
|
|
359
|
+
if (opts.org)
|
|
360
|
+
params.set("org", opts.org);
|
|
361
|
+
return this.get(`/knowledge?${params.toString()}`);
|
|
362
|
+
}
|
|
363
|
+
async getKnowledge(documentId, org) {
|
|
364
|
+
const params = new URLSearchParams({ document: documentId });
|
|
365
|
+
if (org)
|
|
366
|
+
params.set("org", org);
|
|
367
|
+
return this.get(`/knowledge?${params.toString()}`);
|
|
368
|
+
}
|
|
369
|
+
/** Semantic search across knowledge documents. */
|
|
370
|
+
async searchKnowledge(opts) {
|
|
371
|
+
const params = new URLSearchParams({ q: opts.query });
|
|
372
|
+
if (opts.entity)
|
|
373
|
+
params.set("entity", opts.entity);
|
|
374
|
+
if (opts.types?.length)
|
|
375
|
+
params.set("types", opts.types.join(","));
|
|
376
|
+
if (opts.limit)
|
|
377
|
+
params.set("limit", String(opts.limit));
|
|
378
|
+
if (opts.allOrgs)
|
|
379
|
+
params.set("allOrgs", "1");
|
|
380
|
+
if (opts.org)
|
|
381
|
+
params.set("org", opts.org);
|
|
382
|
+
return this.get(`/knowledge?${params.toString()}`);
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Add a markdown knowledge note.
|
|
386
|
+
*
|
|
387
|
+
* Without `direct` this submits a proposal for human review — the default,
|
|
388
|
+
* and the only option non-admin tokens have. With `direct: true` an admin
|
|
389
|
+
* token writes the document immediately, skipping review. Ask the operator
|
|
390
|
+
* before doing that; see references/admin.md in the served skill.
|
|
391
|
+
*/
|
|
392
|
+
async addKnowledge(input) {
|
|
393
|
+
return this.post("/knowledge", input);
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Attach a binary source (PDF, DOCX, XLSX, …) to an entity. Admin only.
|
|
397
|
+
*
|
|
398
|
+
* Three hops: ask for an upload URL, send the bytes straight to Convex
|
|
399
|
+
* storage, then register the resulting storageId. The bytes never pass
|
|
400
|
+
* through function arguments, so file size isn't bounded by an arg limit.
|
|
401
|
+
*/
|
|
402
|
+
async attachKnowledgeFile(input) {
|
|
403
|
+
const { uploadUrl } = await this.post("/knowledge/file", {
|
|
404
|
+
entityId: input.entityId,
|
|
405
|
+
org: input.org,
|
|
406
|
+
});
|
|
407
|
+
const byteSize = input.data.byteLength;
|
|
408
|
+
const uploadRes = await fetch(uploadUrl, {
|
|
409
|
+
method: "POST",
|
|
410
|
+
headers: { "Content-Type": input.mimeType },
|
|
411
|
+
body: input.data,
|
|
412
|
+
});
|
|
413
|
+
if (!uploadRes.ok) {
|
|
414
|
+
throw new ApiError(uploadRes.status, `Upload to storage failed: ${uploadRes.status} ${uploadRes.statusText}`);
|
|
415
|
+
}
|
|
416
|
+
const uploaded = (await uploadRes.json());
|
|
417
|
+
if (!uploaded.storageId)
|
|
418
|
+
throw new Error("Storage upload returned no storageId");
|
|
419
|
+
return this.put("/knowledge/file", {
|
|
420
|
+
entityId: input.entityId,
|
|
421
|
+
org: input.org,
|
|
422
|
+
storageId: uploaded.storageId,
|
|
423
|
+
fileName: input.fileName,
|
|
424
|
+
mimeType: input.mimeType,
|
|
425
|
+
byteSize,
|
|
426
|
+
sourceType: input.sourceType,
|
|
427
|
+
sourceUrl: input.sourceUrl,
|
|
428
|
+
sourceDescription: input.sourceDescription,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
// ── Datasets ──────────────────────────────────────────────────────────────
|
|
432
|
+
// The server owns the catalog: which datasets exist, what they are called,
|
|
433
|
+
// and who may read them. This client is deliberately name-blind — discovery
|
|
434
|
+
// happens at runtime so the open-source CLI reveals nothing about the
|
|
435
|
+
// platform's product surfaces.
|
|
436
|
+
async listDatasets(org) {
|
|
437
|
+
const qs = org ? `?org=${encodeURIComponent(org)}` : "";
|
|
438
|
+
return this.get(`/datasets${qs}`);
|
|
439
|
+
}
|
|
440
|
+
async readDataset(name, opts) {
|
|
441
|
+
const params = new URLSearchParams();
|
|
442
|
+
if (opts?.limit)
|
|
443
|
+
params.set("limit", String(opts.limit));
|
|
444
|
+
if (opts?.org)
|
|
445
|
+
params.set("org", opts.org);
|
|
446
|
+
const qs = params.toString();
|
|
447
|
+
return this.get(`/datasets/${encodeURIComponent(name)}${qs ? `?${qs}` : ""}`);
|
|
448
|
+
}
|
|
449
|
+
// ── Feedback backlog ──────────────────────────────────────────────────────
|
|
450
|
+
// Token scopes apply: read:feedback for the GETs, write:feedback to comment,
|
|
451
|
+
// admin:feedback for claim/status/priority. backOffice users have them all.
|
|
452
|
+
async listFeedback(opts) {
|
|
453
|
+
const params = new URLSearchParams();
|
|
454
|
+
if (opts?.status)
|
|
455
|
+
params.set("status", opts.status);
|
|
456
|
+
if (opts?.priority)
|
|
457
|
+
params.set("priority", opts.priority);
|
|
458
|
+
if (opts?.category)
|
|
459
|
+
params.set("category", opts.category);
|
|
460
|
+
if (opts?.limit)
|
|
461
|
+
params.set("limit", String(opts.limit));
|
|
462
|
+
const qs = params.toString();
|
|
463
|
+
return this.get(`/feedback${qs ? `?${qs}` : ""}`);
|
|
464
|
+
}
|
|
465
|
+
async getFeedbackItem(itemId) {
|
|
466
|
+
return this.get(`/feedback/${encodeURIComponent(itemId)}`);
|
|
467
|
+
}
|
|
468
|
+
/** Top-N from the heuristic prioritizer — "what should I work on next?". */
|
|
469
|
+
async feedbackRecommendations(limit) {
|
|
470
|
+
const qs = limit ? `?limit=${limit}` : "";
|
|
471
|
+
return this.get(`/feedback/ai-recommendations${qs}`);
|
|
472
|
+
}
|
|
473
|
+
async claimFeedbackItem(itemId) {
|
|
474
|
+
return this.post(`/feedback/${encodeURIComponent(itemId)}/claim`, {});
|
|
475
|
+
}
|
|
476
|
+
async commentOnFeedbackItem(itemId, body) {
|
|
477
|
+
return this.post(`/feedback/${encodeURIComponent(itemId)}/comments`, { body });
|
|
478
|
+
}
|
|
479
|
+
async updateFeedbackItem(itemId, updates) {
|
|
480
|
+
return this.patch(`/feedback/${encodeURIComponent(itemId)}`, updates);
|
|
481
|
+
}
|
|
482
|
+
// ── Customer emails (admin only) ──────────────────────────────────────────
|
|
483
|
+
// Sending is gated on explicit human approval by the skill, not by the API.
|
|
484
|
+
async listEmailThreads(opts) {
|
|
485
|
+
const params = new URLSearchParams();
|
|
486
|
+
if (opts?.status)
|
|
487
|
+
params.set("status", opts.status);
|
|
488
|
+
if (opts?.since)
|
|
489
|
+
params.set("since", opts.since);
|
|
490
|
+
if (opts?.customer)
|
|
491
|
+
params.set("customer", opts.customer);
|
|
492
|
+
if (opts?.limit)
|
|
493
|
+
params.set("limit", String(opts.limit));
|
|
494
|
+
if (opts?.org)
|
|
495
|
+
params.set("org", opts.org);
|
|
496
|
+
const qs = params.toString();
|
|
497
|
+
return this.get(`/emails${qs ? `?${qs}` : ""}`);
|
|
498
|
+
}
|
|
499
|
+
async getEmailThread(threadKey) {
|
|
500
|
+
return this.get(`/emails/${encodeURIComponent(threadKey)}`);
|
|
501
|
+
}
|
|
502
|
+
async replyToEmailThread(threadKey, input) {
|
|
503
|
+
return this.post(`/emails/${encodeURIComponent(threadKey)}/reply`, input);
|
|
504
|
+
}
|
|
505
|
+
async composeEmail(input) {
|
|
506
|
+
return this.post("/emails/compose", input);
|
|
507
|
+
}
|
|
282
508
|
// ── Skill ─────────────────────────────────────────────────────────────────
|
|
283
509
|
async getSkillBundle(name) {
|
|
284
510
|
return this.get(`/skill${name ? `?name=${encodeURIComponent(name)}` : ""}`);
|
|
@@ -297,6 +523,9 @@ export class DayOfWeekClient {
|
|
|
297
523
|
async post(path, body) {
|
|
298
524
|
return this.request(path, { method: "POST", body: JSON.stringify(body) });
|
|
299
525
|
}
|
|
526
|
+
async put(path, body) {
|
|
527
|
+
return this.request(path, { method: "PUT", body: JSON.stringify(body) });
|
|
528
|
+
}
|
|
300
529
|
async patch(path, body) {
|
|
301
530
|
return this.request(path, { method: "PATCH", body: JSON.stringify(body) });
|
|
302
531
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dayofweek/dcli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "CLI for the Day of Week AgTech platform — read data and submit proposals for review",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -8,13 +8,15 @@
|
|
|
8
8
|
"dcli": "dist/bin/dcli.js"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
|
-
"dist/"
|
|
11
|
+
"dist/",
|
|
12
|
+
"!dist/standalone"
|
|
12
13
|
],
|
|
13
14
|
"engines": {
|
|
14
15
|
"node": ">=18"
|
|
15
16
|
},
|
|
16
17
|
"scripts": {
|
|
17
|
-
"build": "tsc",
|
|
18
|
+
"build": "tsc && node scripts/build-bundle.mjs",
|
|
19
|
+
"build:bundle": "node scripts/build-bundle.mjs",
|
|
18
20
|
"dev": "tsx src/bin/dcli.ts",
|
|
19
21
|
"test": "vitest run",
|
|
20
22
|
"test:watch": "vitest",
|