@dayofweek/dcli 1.5.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/dist/client.d.ts CHANGED
@@ -108,23 +108,27 @@ export declare class DayOfWeekClient {
108
108
  type?: string;
109
109
  parent?: string;
110
110
  limit?: number;
111
+ org?: string;
111
112
  }): Promise<any[]>;
112
- getEntity(entityId: string): Promise<any>;
113
+ getEntity(entityId: string, org?: string): Promise<any>;
113
114
  listProduce(opts?: {
114
115
  entity?: string;
115
116
  limit?: number;
117
+ org?: string;
116
118
  }): Promise<any[]>;
117
119
  listContacts(opts?: {
118
120
  entity?: string;
119
121
  limit?: number;
122
+ org?: string;
120
123
  }): Promise<any[]>;
121
- listEntityTypes(): Promise<any[]>;
124
+ listEntityTypes(org?: string): Promise<any[]>;
122
125
  searchCatalog(opts?: {
123
126
  search?: string;
124
127
  parent?: string;
125
128
  type?: string;
126
129
  includeCategories?: boolean;
127
130
  limit?: number;
131
+ org?: string;
128
132
  }): Promise<any[]>;
129
133
  listProposals(opts?: {
130
134
  status?: string;
@@ -159,6 +163,49 @@ export declare class DayOfWeekClient {
159
163
  truncated: boolean;
160
164
  total: number;
161
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>;
162
209
  /**
163
210
  * List the knowledge documents attached to an entity. `full` returns each
164
211
  * document's whole content instead of an excerpt, which is what you want when
@@ -217,6 +264,60 @@ export declare class DayOfWeekClient {
217
264
  sourceDescription?: string;
218
265
  org?: string;
219
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>;
220
321
  getSkillBundle(name?: string): Promise<{
221
322
  name: string;
222
323
  version: string;
package/dist/client.js CHANGED
@@ -189,6 +189,8 @@ export class DayOfWeekClient {
189
189
  return this.get(`/brain/audit?${query}`);
190
190
  }
191
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.
192
194
  async listEntities(opts) {
193
195
  const params = new URLSearchParams();
194
196
  if (opts?.type)
@@ -197,11 +199,14 @@ export class DayOfWeekClient {
197
199
  params.set("parent", opts.parent);
198
200
  if (opts?.limit)
199
201
  params.set("limit", String(opts.limit));
202
+ if (opts?.org)
203
+ params.set("org", opts.org);
200
204
  const qs = params.toString();
201
205
  return this.get(`/entities${qs ? `?${qs}` : ""}`);
202
206
  }
203
- async getEntity(entityId) {
204
- return this.get(`/entities/${entityId}`);
207
+ async getEntity(entityId, org) {
208
+ const qs = org ? `?org=${encodeURIComponent(org)}` : "";
209
+ return this.get(`/entities/${entityId}${qs}`);
205
210
  }
206
211
  async listProduce(opts) {
207
212
  const params = new URLSearchParams();
@@ -209,6 +214,8 @@ export class DayOfWeekClient {
209
214
  params.set("entity", opts.entity);
210
215
  if (opts?.limit)
211
216
  params.set("limit", String(opts.limit));
217
+ if (opts?.org)
218
+ params.set("org", opts.org);
212
219
  const qs = params.toString();
213
220
  return this.get(`/produce${qs ? `?${qs}` : ""}`);
214
221
  }
@@ -218,11 +225,14 @@ export class DayOfWeekClient {
218
225
  params.set("entity", opts.entity);
219
226
  if (opts?.limit)
220
227
  params.set("limit", String(opts.limit));
228
+ if (opts?.org)
229
+ params.set("org", opts.org);
221
230
  const qs = params.toString();
222
231
  return this.get(`/contacts${qs ? `?${qs}` : ""}`);
223
232
  }
224
- async listEntityTypes() {
225
- return this.get("/entity-types");
233
+ async listEntityTypes(org) {
234
+ const qs = org ? `?org=${encodeURIComponent(org)}` : "";
235
+ return this.get(`/entity-types${qs}`);
226
236
  }
227
237
  async searchCatalog(opts) {
228
238
  const params = new URLSearchParams();
@@ -236,6 +246,8 @@ export class DayOfWeekClient {
236
246
  params.set("includeCategories", "true");
237
247
  if (opts?.limit)
238
248
  params.set("limit", String(opts.limit));
249
+ if (opts?.org)
250
+ params.set("org", opts.org);
239
251
  const qs = params.toString();
240
252
  return this.get(`/catalog${qs ? `?${qs}` : ""}`);
241
253
  }
@@ -288,6 +300,52 @@ export class DayOfWeekClient {
288
300
  const qs = params.toString();
289
301
  return this.get(`/admin/proposals${qs ? `?${qs}` : ""}`);
290
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
+ }
291
349
  // ── Knowledge ─────────────────────────────────────────────────────────────
292
350
  /**
293
351
  * List the knowledge documents attached to an entity. `full` returns each
@@ -370,6 +428,83 @@ export class DayOfWeekClient {
370
428
  sourceDescription: input.sourceDescription,
371
429
  });
372
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
+ }
373
508
  // ── Skill ─────────────────────────────────────────────────────────────────
374
509
  async getSkillBundle(name) {
375
510
  return this.get(`/skill${name ? `?name=${encodeURIComponent(name)}` : ""}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dayofweek/dcli",
3
- "version": "1.5.0",
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",