@robbeverhelst/do 1.365.0 → 1.367.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.
Files changed (2) hide show
  1. package/dist/do.js +458 -29
  2. package/package.json +1 -1
package/dist/do.js CHANGED
@@ -14420,7 +14420,7 @@ var configError = (message) => new CliError("config", message, EXIT.CONFIG);
14420
14420
 
14421
14421
  // src/meta.ts
14422
14422
  var CLI_NAME = "do";
14423
- var VERSION = "1.365.0";
14423
+ var VERSION = "1.367.0";
14424
14424
  var API_PREFIX = "/api/v1";
14425
14425
  var DEFAULT_API_URL = "http://localhost:3001";
14426
14426
 
@@ -18024,6 +18024,7 @@ var habits = pgTable("habits", {
18024
18024
  sourceMetric: text("source_metric"),
18025
18025
  aliases: text("aliases").array().notNull().default(sql`'{}'::text[]`),
18026
18026
  timeOfDay: text("time_of_day"),
18027
+ dayTimes: jsonb("day_times").$type(),
18027
18028
  pausedFrom: date5("paused_from", { mode: "string" }),
18028
18029
  pausedUntil: date5("paused_until", { mode: "string" }),
18029
18030
  remind: boolean4("remind").notNull().default(false),
@@ -18130,7 +18131,8 @@ var routines = pgTable("routines", {
18130
18131
  restingUntil: date5("resting_until", { mode: "string" }),
18131
18132
  icon: text("icon"),
18132
18133
  keptNotice: text("kept_notice"),
18133
- dayTimes: jsonb("day_times").$type().notNull().default({})
18134
+ dayTimes: jsonb("day_times").$type().notNull().default({}),
18135
+ durationMinutes: integer2("duration_minutes")
18134
18136
  }, (t) => [
18135
18137
  index("routines_tenant_idx").on(t.tenantId),
18136
18138
  index("routines_tenant_area_idx").on(t.tenantId, t.areaId)
@@ -19158,9 +19160,11 @@ var saveAgentConnectionInputSchema = object({
19158
19160
  message: "a connection without an endpoint names its agent",
19159
19161
  path: ["agentId"]
19160
19162
  });
19163
+ var ECHO_PAGE_LABEL_MAX = 120;
19161
19164
  var agentPageContextSchema = object({
19162
19165
  route: string2().trim().min(1).max(500).startsWith("/"),
19163
19166
  nodeId: string2().trim().min(1).max(64).nullable(),
19167
+ page: string2().trim().min(1).max(ECHO_PAGE_LABEL_MAX).optional(),
19164
19168
  focusArea: object({
19165
19169
  id: string2().trim().min(1).max(64),
19166
19170
  title: string2().trim().min(1).max(200)
@@ -19516,6 +19520,177 @@ var linkGoogleInputSchema = object({
19516
19520
  state: string2().min(1)
19517
19521
  });
19518
19522
 
19523
+ // ../../packages/schema/src/contracts/post-cards.ts
19524
+ var line2 = string2().trim().min(1).max(200);
19525
+ var words = string2().trim().max(2000);
19526
+ var href = string2().trim().min(1).max(2000);
19527
+ var postCardWhoSchema = object({
19528
+ name: line2,
19529
+ av: union([
19530
+ object({
19531
+ kind: literal("initials"),
19532
+ text: string2().trim().min(1).max(3),
19533
+ tone: _enum2(["you", "plum", "sky", "sea", "sun", "cc", "cx", "clay", "mist"])
19534
+ }),
19535
+ object({ kind: _enum2(["echo", "job", "system"]) })
19536
+ ])
19537
+ });
19538
+ var postCardStepSchema = object({
19539
+ label: line2,
19540
+ state: _enum2(["done", "running", "failed", "waiting", "queued"]),
19541
+ at: string2().trim().max(20).optional(),
19542
+ detail: words.optional()
19543
+ });
19544
+ var postCardTextSchema = object({ markdown: string2().max(8000) });
19545
+ var postCardBriefSchema = object({
19546
+ title: line2,
19547
+ sub: line2.optional(),
19548
+ read: line2.optional(),
19549
+ sections: array(object({
19550
+ title: line2,
19551
+ n: union([string2().max(20), number2()]).optional(),
19552
+ body: string2().max(4000)
19553
+ })).min(1).max(12),
19554
+ open: array(number2().int().nonnegative()).max(12).optional()
19555
+ });
19556
+ var postCardRunSchema = object({
19557
+ kind: _enum2(["kanban", "job", "session"]).optional(),
19558
+ title: line2,
19559
+ agent: postCardWhoSchema,
19560
+ machine: line2,
19561
+ account: line2.optional(),
19562
+ since: line2.optional(),
19563
+ state: _enum2(["queued", "running", "paused", "waiting", "done", "failed", "stopped"]),
19564
+ stateText: line2.optional(),
19565
+ now: words.optional(),
19566
+ progress: number2().min(0).max(1).optional(),
19567
+ progressText: line2.optional(),
19568
+ steps: array(postCardStepSchema).max(30).optional(),
19569
+ outputs: array(object({ icon: string2().max(24), label: line2, href })).max(12).optional()
19570
+ });
19571
+ var postCardDeploySchema = object({
19572
+ title: line2,
19573
+ sub: line2.optional(),
19574
+ state: _enum2(["running", "live", "failed", "queued"]),
19575
+ steps: array(postCardStepSchema).max(30),
19576
+ siteHref: href.optional(),
19577
+ logsHref: href.optional()
19578
+ });
19579
+ var postCardAskSchema = object({
19580
+ kind: _enum2(["approval", "question", "review"]),
19581
+ state: _enum2(["open", "answered", "expired", "snoozed", "delegated"]).default("open"),
19582
+ from: postCardWhoSchema,
19583
+ title: line2,
19584
+ detail: words.optional(),
19585
+ code: string2().max(4000).optional(),
19586
+ why: words.optional(),
19587
+ risk: literal("high").optional(),
19588
+ expires: object({
19589
+ at: exports_iso.datetime({ offset: true }),
19590
+ windowS: number2().int().positive().max(7 * 24 * 3600).optional(),
19591
+ note: words.optional()
19592
+ }).optional(),
19593
+ yes: line2.optional(),
19594
+ no: line2.optional(),
19595
+ options: array(object({ label: line2, sub: line2.optional() })).max(12).optional(),
19596
+ multi: boolean2().optional(),
19597
+ submit: line2.optional(),
19598
+ acts: array(object({ label: line2, primary: boolean2().optional(), href: href.optional() })).max(6).optional(),
19599
+ done: object({
19600
+ answer: line2.optional(),
19601
+ answeredAt: line2.optional(),
19602
+ expiredAt: line2.optional(),
19603
+ expiredWhat: words.optional(),
19604
+ until: line2.optional(),
19605
+ delegatedWhat: words.optional()
19606
+ }).optional()
19607
+ });
19608
+ var postCardPrSchema = object({
19609
+ title: line2,
19610
+ repo: line2,
19611
+ num: union([string2().trim().min(1).max(20), number2().int().positive()]),
19612
+ branch: line2.optional(),
19613
+ state: _enum2(["checks", "ready", "red", "merged", "draft", "closed"]),
19614
+ add: string2().max(20),
19615
+ del: string2().max(20),
19616
+ files: string2().max(20),
19617
+ by: postCardWhoSchema.optional(),
19618
+ checks: array(object({
19619
+ name: line2,
19620
+ state: string2().trim().min(1).max(20),
19621
+ note: string2().max(40).optional()
19622
+ })).max(40).optional(),
19623
+ mergedAt: line2.optional(),
19624
+ mergedBy: line2.optional(),
19625
+ href: href.optional()
19626
+ });
19627
+ var postCardDigestSchema = object({
19628
+ title: line2,
19629
+ sub: line2,
19630
+ items: array(object({
19631
+ id: string2().trim().min(1).max(64).optional(),
19632
+ at: string2().trim().max(20),
19633
+ text: line2
19634
+ })).min(1).max(50)
19635
+ });
19636
+ var postCardChipsSchema = object({
19637
+ items: array(object({
19638
+ id: string2().trim().min(1).max(64).optional(),
19639
+ kind: _enum2(["task", "habit", "event"]).optional(),
19640
+ title: line2,
19641
+ meta: line2.optional(),
19642
+ done: boolean2().optional(),
19643
+ href: href.optional()
19644
+ })).min(1).max(20)
19645
+ });
19646
+ var tableBody = object({
19647
+ label: line2.optional(),
19648
+ cols: array(string2().trim().max(60)).min(1).max(12),
19649
+ rows: array(array(string2().max(500)).min(1).max(12)).max(100),
19650
+ num: array(number2().int().nonnegative()).max(12).optional()
19651
+ }).refine((t) => t.rows.every((r) => r.length <= t.cols.length), {
19652
+ message: "a row has at most as many cells as there are columns"
19653
+ }).refine((t) => new Set(t.rows.map((r) => r[0])).size === t.rows.length, {
19654
+ message: "each row's head is its own"
19655
+ });
19656
+ var bars = array(object({
19657
+ label: line2,
19658
+ value: number2(),
19659
+ tone: _enum2(["warn", "err"]).optional(),
19660
+ text: string2().max(20).optional()
19661
+ })).min(1).max(30);
19662
+ var postCardTableSchema = object({ title: line2.optional(), sub: line2.optional() }).and(tableBody);
19663
+ var postCardChartSchema = object({
19664
+ title: line2,
19665
+ sub: line2.optional(),
19666
+ label: line2,
19667
+ bars
19668
+ });
19669
+ var postCardReportSchema = object({
19670
+ title: line2,
19671
+ sub: line2.optional(),
19672
+ state: string2().trim().min(1).max(20).optional(),
19673
+ stateText: line2.optional(),
19674
+ lead: string2().max(4000),
19675
+ stats: array(tuple([string2().trim().max(20), line2])).max(8).optional(),
19676
+ chart: object({ label: line2, bars }).optional(),
19677
+ table: tableBody.optional(),
19678
+ href: href.optional()
19679
+ });
19680
+ var POST_CARD_DATA = {
19681
+ text: postCardTextSchema,
19682
+ brief: postCardBriefSchema,
19683
+ run: postCardRunSchema,
19684
+ deploy: postCardDeploySchema,
19685
+ ask: postCardAskSchema,
19686
+ pr: postCardPrSchema,
19687
+ digest: postCardDigestSchema,
19688
+ chips: postCardChipsSchema,
19689
+ table: postCardTableSchema,
19690
+ chart: postCardChartSchema,
19691
+ report: postCardReportSchema
19692
+ };
19693
+
19519
19694
  // ../../packages/schema/src/contracts/agent-gateway.ts
19520
19695
  var AGENT_GATEWAY_VERSION = 1;
19521
19696
  var AGENT_GATEWAY_MAX_FRAME_BYTES = 1024 * 1024;
@@ -19540,6 +19715,66 @@ var briefRowSchema = object({
19540
19715
  verb: briefVerbSchema.optional()
19541
19716
  }).strict();
19542
19717
  var BRIEF_ROWS_MAX = 8;
19718
+ var postCardTypeSchema = _enum2([
19719
+ "text",
19720
+ "brief",
19721
+ "report",
19722
+ "table",
19723
+ "chart",
19724
+ "pr",
19725
+ "deploy",
19726
+ "run",
19727
+ "compare",
19728
+ "gallery",
19729
+ "design",
19730
+ "chip",
19731
+ "chips",
19732
+ "invoice",
19733
+ "mail",
19734
+ "link",
19735
+ "file",
19736
+ "voice",
19737
+ "code",
19738
+ "ask",
19739
+ "digest",
19740
+ "handoff",
19741
+ "decision",
19742
+ "answer"
19743
+ ]);
19744
+ var postDigestKeySchema = string2().trim().min(1).max(40);
19745
+ var POST_CARD_DATA_MAX = 16000;
19746
+ var withinLimit = (d) => JSON.stringify(d ?? {}).length <= POST_CARD_DATA_MAX;
19747
+ var LIMIT = `a card's data is at most ${POST_CARD_DATA_MAX} characters as JSON`;
19748
+ var pinned = (type) => object({ type: literal(type), data: POST_CARD_DATA[type] });
19749
+ var postCardSchema = discriminatedUnion("type", [
19750
+ pinned("text"),
19751
+ pinned("brief"),
19752
+ pinned("run"),
19753
+ pinned("deploy"),
19754
+ pinned("ask"),
19755
+ pinned("pr"),
19756
+ pinned("digest"),
19757
+ pinned("chips"),
19758
+ pinned("table"),
19759
+ pinned("chart"),
19760
+ pinned("report"),
19761
+ object({
19762
+ type: postCardTypeSchema.exclude([
19763
+ "text",
19764
+ "brief",
19765
+ "run",
19766
+ "deploy",
19767
+ "ask",
19768
+ "pr",
19769
+ "digest",
19770
+ "chips",
19771
+ "table",
19772
+ "chart",
19773
+ "report"
19774
+ ]),
19775
+ data: record(string2(), unknown()).default({})
19776
+ })
19777
+ ]).refine((card) => withinLimit(card.data), { message: LIMIT, path: ["data"] });
19543
19778
  var briefSchema = object({
19544
19779
  label: string2().trim().min(1).max(40),
19545
19780
  title: string2().trim().min(1).max(200),
@@ -19652,6 +19887,8 @@ var agentPostInputSchema = object({
19652
19887
  run: postRunSchema.optional(),
19653
19888
  recovered: boolean2().optional(),
19654
19889
  brief: briefSchema.optional(),
19890
+ card: postCardSchema.optional(),
19891
+ digestKey: postDigestKeySchema.optional(),
19655
19892
  receipt: postReceiptInputSchema.optional()
19656
19893
  });
19657
19894
  var agentPostEditSchema = object({
@@ -19660,9 +19897,10 @@ var agentPostEditSchema = object({
19660
19897
  final: boolean2().optional(),
19661
19898
  level: postLevelSchema.optional(),
19662
19899
  run: postRunSchema.optional(),
19663
- brief: briefSchema.optional()
19900
+ brief: briefSchema.optional(),
19901
+ card: postCardSchema.optional()
19664
19902
  }).refine((e) => Object.values(e).some((v) => v !== undefined), {
19665
- message: "send text, title, final, level, run or brief"
19903
+ message: "send text, title, final, level, run, brief or card"
19666
19904
  });
19667
19905
  var agentPostResultSchema = object({ postId: ulidSchema, created: boolean2() });
19668
19906
  var promptOptionSchema = object({
@@ -21364,6 +21602,7 @@ var occurrenceSchema = createSelectSchema(occurrences, {
21364
21602
  completedAt: exports_coerce.date().nullable()
21365
21603
  });
21366
21604
  var byDayCodeSchema = _enum2(["MO", "TU", "WE", "TH", "FR", "SA", "SU"]);
21605
+ var weekdayTimesSchema = partialRecord(byDayCodeSchema, string2().regex(/^([01]\d|2[0-3]):[0-5]\d$/));
21367
21606
  var byDayOrdinalSchema = _enum2(["1", "2", "3", "4", "-1"]);
21368
21607
  var byDaySchema = union([
21369
21608
  byDayCodeSchema,
@@ -21428,6 +21667,7 @@ var habitSchema = createSelectSchema(habits, {
21428
21667
  sourceMetric: string2().nullable().default(null),
21429
21668
  aliases: array(string2()).default([]),
21430
21669
  timeOfDay: string2().nullable().default(null),
21670
+ dayTimes: weekdayTimesSchema.nullish(),
21431
21671
  pausedFrom: exports_iso.date().nullable().default(null),
21432
21672
  pausedUntil: exports_iso.date().nullable().default(null),
21433
21673
  remind: boolean2().default(false),
@@ -21501,6 +21741,7 @@ var createHabitInputSchema = createInsertSchema(habits, {
21501
21741
  areaId: ulidSchema.nullish(),
21502
21742
  aliases: habitAliasesSchema.optional(),
21503
21743
  timeOfDay: habitTimeOfDaySchema.nullish(),
21744
+ dayTimes: weekdayTimesSchema.nullish(),
21504
21745
  remind: boolean2().optional(),
21505
21746
  durationMinutes: habitDurationMinutesSchema.nullish(),
21506
21747
  activeMonths: habitActiveMonthsSchema.optional()
@@ -21519,6 +21760,7 @@ var updateHabitInputSchema = createUpdateSchema(habits, {
21519
21760
  areaId: ulidSchema.nullish(),
21520
21761
  aliases: habitAliasesSchema.optional(),
21521
21762
  timeOfDay: habitTimeOfDaySchema.nullish(),
21763
+ dayTimes: weekdayTimesSchema.nullish(),
21522
21764
  remind: boolean2().optional(),
21523
21765
  durationMinutes: habitDurationMinutesSchema.nullish(),
21524
21766
  activeMonths: habitActiveMonthsSchema.optional()
@@ -21641,7 +21883,8 @@ var habitDueDateSchema = object({
21641
21883
  scheduleLabel: string2().min(1),
21642
21884
  daily: boolean2(),
21643
21885
  streakLabel: string2().min(1),
21644
- done: boolean2().default(false)
21886
+ done: boolean2().default(false),
21887
+ entryId: string2().nullable().default(null)
21645
21888
  });
21646
21889
  var habitEntriesQuerySchema = object({
21647
21890
  before: exports_coerce.date().optional(),
@@ -22655,7 +22898,7 @@ var projectDetailSchema = projectViewSchema.extend({
22655
22898
  var attachTaskInputSchema = object({ taskId: ulidSchema });
22656
22899
 
22657
22900
  // ../../packages/schema/src/contracts/routines.ts
22658
- var routineDayTimesSchema = partialRecord(_enum2(["MO", "TU", "WE", "TH", "FR", "SA", "SU"]), string2().regex(/^([01]\d|2[0-3]):[0-5]\d$/));
22901
+ var routineDayTimesSchema = weekdayTimesSchema;
22659
22902
  var routineSchema = createSelectSchema(routines);
22660
22903
  var routineStepSchema = createSelectSchema(routineSteps, {
22661
22904
  createdAt: exports_coerce.date(),
@@ -22745,8 +22988,10 @@ var routineStepInputSchema = object({
22745
22988
  }
22746
22989
  }
22747
22990
  });
22991
+ var routineDurationSchema = number2().int().min(1).max(1440);
22748
22992
  var createRoutineInputSchema = createInsertSchema(routines, {
22749
22993
  id: ulidSchema,
22994
+ durationMinutes: routineDurationSchema.nullish(),
22750
22995
  areaId: ulidSchema.nullish()
22751
22996
  }).omit({ tenantId: true, recurrenceRuleId: true }).extend({
22752
22997
  title: string2().min(1),
@@ -22765,7 +23010,8 @@ var createRoutineInputSchema = createInsertSchema(routines, {
22765
23010
  }
22766
23011
  });
22767
23012
  var updateRoutineInputSchema = createUpdateSchema(routines, {
22768
- areaId: ulidSchema.nullish()
23013
+ areaId: ulidSchema.nullish(),
23014
+ durationMinutes: routineDurationSchema.nullish()
22769
23015
  }).omit({ id: true, tenantId: true, recurrenceRuleId: true }).extend({
22770
23016
  title: string2().min(1).optional(),
22771
23017
  parentId: ulidSchema.nullish(),
@@ -22777,6 +23023,7 @@ var routineViewSchema = routineSchema.extend({
22777
23023
  icon: string2().nullable().default(null),
22778
23024
  keptNotice: string2().nullable().default(null),
22779
23025
  dayTimes: routineDayTimesSchema.default({}),
23026
+ durationMinutes: number2().int().nullish(),
22780
23027
  title: string2(),
22781
23028
  parentId: ulidSchema.nullable(),
22782
23029
  createdAt: exports_coerce.date(),
@@ -24151,6 +24398,7 @@ var timeBlocks = pgTable("time_blocks", {
24151
24398
  taskId: text("task_id").references(() => tasks.id, { onDelete: "set null" }),
24152
24399
  kind: text("kind", { enum: TIME_BLOCK_KINDS }).notNull().default("focus"),
24153
24400
  lifeKind: text("life_kind", { enum: LIFE_BLOCK_KINDS }),
24401
+ label: text("label"),
24154
24402
  plannedStartAt: timestamp("planned_start_at", { withTimezone: true }),
24155
24403
  plannedEndAt: timestamp("planned_end_at", { withTimezone: true }),
24156
24404
  recurrenceRuleId: text("recurrence_rule_id").references(() => recurrenceRules.id),
@@ -24221,6 +24469,7 @@ var blockEvidence = pgTable("block_evidence", {
24221
24469
  // ../../packages/schema/src/contracts/time-blocks.ts
24222
24470
  var TIME_BLOCK_MAX_MINUTES = 24 * 60;
24223
24471
  var timeBlockSchema = createSelectSchema(timeBlocks, {
24472
+ label: string2().nullish(),
24224
24473
  startAt: exports_coerce.date(),
24225
24474
  endAt: exports_coerce.date(),
24226
24475
  plannedStartAt: exports_coerce.date().nullable(),
@@ -24239,12 +24488,14 @@ var lifeBlockKindSchema = _enum2(LIFE_BLOCK_KINDS);
24239
24488
  var lifeBlockShareSchema = _enum2(["details", "busy"]);
24240
24489
  var lifeBlockSharingSchema = partialRecord(lifeBlockKindSchema, lifeBlockShareSchema);
24241
24490
  var SPAN_MESSAGE = `endAt must be after startAt and at most ${TIME_BLOCK_MAX_MINUTES / 60} hours later`;
24491
+ var blockLabelSchema = string2().trim().min(1).max(200);
24242
24492
  var createTimeBlockInputSchema = object({
24243
24493
  id: ulidSchema,
24244
24494
  title: string2().trim().min(1).max(500).optional(),
24245
24495
  taskId: ulidSchema.nullish(),
24246
24496
  lifeKind: lifeBlockKindSchema.optional(),
24247
24497
  routineId: ulidSchema.nullish(),
24498
+ label: blockLabelSchema.nullish(),
24248
24499
  recorded: boolean2().optional(),
24249
24500
  startAt: exports_coerce.date(),
24250
24501
  endAt: exports_coerce.date()
@@ -24266,6 +24517,7 @@ var updateTimeBlockInputSchema = object({
24266
24517
  taskId: ulidSchema.nullish(),
24267
24518
  lifeKind: lifeBlockKindSchema.optional(),
24268
24519
  routineId: ulidSchema.nullish(),
24520
+ label: blockLabelSchema.nullish(),
24269
24521
  startAt: exports_coerce.date().optional(),
24270
24522
  endAt: exports_coerce.date().optional()
24271
24523
  }).strict().refine(validSpan, { message: SPAN_MESSAGE, path: ["endAt"] });
@@ -24285,6 +24537,7 @@ var timeBlockViewSchema = timeBlockSchema.omit({
24285
24537
  recordAskedAt: true
24286
24538
  }).extend({
24287
24539
  title: string2(),
24540
+ label: string2().nullish(),
24288
24541
  task: timeBlockTaskSchema.nullable(),
24289
24542
  status: _enum2(TIME_BLOCK_STATUSES).optional(),
24290
24543
  recordState: _enum2(RECORD_STATES).optional(),
@@ -27253,6 +27506,11 @@ var answerEchoPromptInputSchema = object({
27253
27506
  text: string2().trim().min(1).max(2000).optional(),
27254
27507
  device: echoDeviceSchema.optional()
27255
27508
  }).strict();
27509
+ var echoPostContextSchema = object({
27510
+ route: string2(),
27511
+ nodeId: string2().nullable(),
27512
+ page: string2().optional()
27513
+ });
27256
27514
  var echoPostSchema = object({
27257
27515
  id: string2(),
27258
27516
  threadId: string2(),
@@ -27274,15 +27532,44 @@ var echoPostSchema = object({
27274
27532
  receipt: postReceiptSchema.nullable().default(null),
27275
27533
  createdAt: exports_coerce.date(),
27276
27534
  updatedAt: exports_coerce.date(),
27277
- brief: briefSchema.nullable().default(null)
27535
+ brief: briefSchema.nullable().default(null),
27536
+ card: postCardSchema.nullable().default(null),
27537
+ digestKey: string2().nullable().default(null),
27538
+ context: echoPostContextSchema.nullable().default(null)
27278
27539
  });
27279
27540
  var threadPushSchema = _enum2(["needs_you", "all", "off"]);
27541
+ var threadKindSchema = _enum2([
27542
+ "personal",
27543
+ "work",
27544
+ "system",
27545
+ "client",
27546
+ "object",
27547
+ "shared"
27548
+ ]);
27549
+ var threadTopicKindSchema = threadKindSchema.extract([
27550
+ "personal",
27551
+ "work",
27552
+ "system",
27553
+ "client"
27554
+ ]);
27555
+ var threadAnchorTypeSchema = _enum2(["task", "project", "habit", "note"]);
27556
+ var threadAnchorSchema = object({ type: threadAnchorTypeSchema, id: string2() });
27557
+ var threadNotifyLevelSchema = _enum2(["now", "today", "digest", "off"]);
27558
+ var threadMemoryScopeSchema = _enum2(["personal", "work", "none", "isolated", "inherit"]);
27559
+ var threadIconSchema = string2().regex(/^[a-z][a-z0-9-]{0,23}$/, "an icon is a lowercase icon name");
27560
+ var ECHO_THREAD_DESCRIPTION_MAX = 200;
27561
+ var threadDescriptionSchema = string2().trim().max(ECHO_THREAD_DESCRIPTION_MAX);
27280
27562
  var echoBriefCardSchema = echoPostSchema.extend({
27281
27563
  brief: briefSchema,
27282
27564
  threadTitle: string2().nullable(),
27283
27565
  threadSlug: string2().nullable()
27284
27566
  });
27285
27567
  var echoBriefsQuerySchema = object({ since: exports_coerce.date() });
27568
+ var echoNeedSchema = echoPostSchema.extend({
27569
+ threadTitle: string2().nullable(),
27570
+ threadSlug: string2().nullable()
27571
+ });
27572
+ var echoNeedsSchema = object({ needs: array(echoNeedSchema) });
27286
27573
  var echoBriefsSchema = object({ briefs: array(echoBriefCardSchema) });
27287
27574
  var echoRunSchema = echoPostSchema.extend({
27288
27575
  threadTitle: string2().nullable()
@@ -27297,6 +27584,17 @@ var echoThreadSummarySchema = object({
27297
27584
  home: boolean2().default(false),
27298
27585
  areaIds: array(string2()).default([]),
27299
27586
  peopleCapture: boolean2().default(true),
27587
+ kind: threadKindSchema.default("personal"),
27588
+ anchor: threadAnchorSchema.nullable().default(null),
27589
+ parentId: string2().nullable().default(null),
27590
+ icon: string2().default("lock"),
27591
+ description: string2().nullable().default(null),
27592
+ memoryScope: threadMemoryScopeSchema.default("personal"),
27593
+ notifyLevel: threadNotifyLevelSchema.default("now"),
27594
+ lastMessageAt: exports_coerce.date().nullable().default(null),
27595
+ lastLine: string2().nullable().default(null),
27596
+ needsYou: number2().int().nonnegative().default(0),
27597
+ unseen: number2().int().nonnegative().default(0),
27300
27598
  turnCount: number2().int(),
27301
27599
  postCount: number2().int().default(0),
27302
27600
  createdAt: exports_coerce.date(),
@@ -27333,17 +27631,30 @@ var threadAreaIdsSchema = array(string2().min(1)).max(ECHO_THREAD_AREAS_MAX);
27333
27631
  var createStandingThreadInputSchema = object({
27334
27632
  title: threadTitleSchema,
27335
27633
  slug: threadSlugSchema.optional(),
27336
- areaIds: threadAreaIdsSchema.default([])
27634
+ areaIds: threadAreaIdsSchema.default([]),
27635
+ kind: threadTopicKindSchema.optional(),
27636
+ icon: threadIconSchema.optional(),
27637
+ description: threadDescriptionSchema.optional(),
27638
+ memoryScope: threadMemoryScopeSchema.exclude(["inherit"]).optional()
27337
27639
  }).strict();
27338
27640
  var updateEchoThreadInputSchema = object({
27339
27641
  push: threadPushSchema.optional(),
27340
27642
  title: threadTitleSchema.optional(),
27341
27643
  areaIds: threadAreaIdsSchema.optional(),
27342
27644
  archived: boolean2().optional(),
27343
- peopleCapture: boolean2().optional()
27645
+ peopleCapture: boolean2().optional(),
27646
+ kind: threadTopicKindSchema.optional(),
27647
+ icon: threadIconSchema.optional(),
27648
+ description: threadDescriptionSchema.optional(),
27649
+ memoryScope: threadMemoryScopeSchema.optional()
27344
27650
  }).strict().refine((e) => Object.values(e).some((v) => v !== undefined), {
27345
- message: "send push, title, areaIds, archived or peopleCapture"
27651
+ message: "send push, title, areaIds, archived, peopleCapture, kind, icon, description or memoryScope"
27346
27652
  });
27653
+ var createEchoThreadInputSchema = object({
27654
+ title: threadTitleSchema.optional(),
27655
+ anchor: threadAnchorSchema.optional(),
27656
+ parentId: string2().trim().min(1).max(64).optional()
27657
+ }).strict();
27347
27658
 
27348
27659
  // ../../packages/schema/src/operations/echo-threads.ts
27349
27660
  var NO_USER = "The key has no user identity (threads are per member).";
@@ -27354,7 +27665,7 @@ var echoThreadOperations = defineOperations({
27354
27665
  scopes: ["agents:read"],
27355
27666
  tag: "Agents",
27356
27667
  summary: "List agent threads",
27357
- description: "The member's most recent agent threads, newest first: `id`, `title` (the first question), `turnCount`, `createdAt`, `updatedAt`.",
27668
+ description: "The member's most recent agent threads, newest first: `id`, `title` (the first question), `turnCount`, `createdAt`, `updatedAt`. Each also says what it is for (`kind`: `personal`, `work`, `system`, `client`, `object` or `shared`), the do object it hangs on (`anchor`: `{ type, id }`, null for a topic) and the thread it started from (`parentId`), its `icon`, `description` and `memoryScope` (`personal`, `work`, `none`, `isolated`, `inherit`), the most its posts may push in do v2 (`notifyLevel`: `now`, `today`, `digest` or `off`), when its last message was written (`lastMessageAt`) with that message as one plain line (`lastLine`), and how many of the agent's posts there are unseen (`needsYou` for Needs you, `unseen` for any that isn't silent).",
27358
27669
  query: [
27359
27670
  {
27360
27671
  name: "limit",
@@ -27375,7 +27686,9 @@ var echoThreadOperations = defineOperations({
27375
27686
  scopes: ["agents:write"],
27376
27687
  tag: "Agents",
27377
27688
  summary: "Start a new agent thread",
27378
- description: "New conversation: a fresh thread that becomes the member's current one. When the current thread has nothing in it yet, that one is returned instead.",
27689
+ description: "New conversation: a fresh thread that becomes the member's current one. When the current thread has nothing in it yet, that one is returned instead. With a body, a new thread (do v2): loose with a `title`, or on a thing of the Space (`anchor`: `{ type: task|project|habit|note, id }`, a 404 when there is no such live thing; titled after it unless a `title` is given), started from one of the member's threads (`parentId`, else a 404). A thing has one thread per member: asking again returns it.",
27690
+ body: createEchoThreadInputSchema,
27691
+ bodyOptional: true,
27379
27692
  status: 201,
27380
27693
  response: { description: "The new current thread." },
27381
27694
  errors: { 403: NO_USER }
@@ -27428,7 +27741,7 @@ var echoThreadOperations = defineOperations({
27428
27741
  scopes: ["agents:write"],
27429
27742
  tag: "Agents",
27430
27743
  summary: "Change an agent thread",
27431
- description: "What the agent's posts in this thread may push to the member's devices (do-4): `all` (Needs you, and Told quietly), `needs_you` (only what waits on the member) or `off`. For later and Silent posts never push. Returns the thread as the list shows it. Another member's thread is a 404. Rename a thread (`title`), change the Areas a standing thread links (`areaIds`), or archive it (`archived: true`; `false` brings it back). An archived thread leaves the list and its slug no longer reaches it. The home thread (named after the Space's agent) can't be archived.",
27744
+ description: "What the agent's posts in this thread may push to the member's devices (do-4): `all` (Needs you, and Told quietly), `needs_you` (only what waits on the member) or `off`. For later and Silent posts never push. Returns the thread as the list shows it. Another member's thread is a 404. Rename a thread (`title`), change the Areas a standing thread links (`areaIds`), or archive it (`archived: true`; `false` brings it back). An archived thread leaves the list and its slug no longer reaches it. The home thread (named after the Space's agent) can't be archived. Say what a topic is for (`kind`: `personal`, `work`, `system` or `client`); a thread on a thing keeps `object`, a 400. Set its `icon`, its one-line `description` (`\"\"` clears it) and which memory the agent answers with (`memoryScope`: `personal`, `work`, `none`, `isolated` or `inherit`).",
27432
27745
  body: updateEchoThreadInputSchema,
27433
27746
  status: 200,
27434
27747
  response: { description: "The thread as the list shows it, with its `push`." },
@@ -27440,7 +27753,7 @@ var echoThreadOperations = defineOperations({
27440
27753
  scopes: ["agents:write"],
27441
27754
  tag: "Agents",
27442
27755
  summary: "Add a standing thread",
27443
- description: "A standing thread of the member's own (Build, Business), pinned under the agent's home thread. `slug` is what the agent and scripts address it by (`do echo post --thread build`); it defaults to one made from the title. A slug another live thread has is a 409; an archived thread's brings that thread back.",
27756
+ description: "A standing thread of the member's own (Build, Business), pinned under the agent's home thread. `slug` is what the agent and scripts address it by (`do echo post --thread build`); it defaults to one made from the title. `kind` says what it is for (`personal`, `work`, `system` or `client`; `work` when not given), with an `icon` (a v2 icon name), a one-line `description` and its `memoryScope` (`personal`, `work`, `none` or `isolated`). A slug another live thread has is a 409; an archived thread's brings that thread back.",
27444
27757
  body: createStandingThreadInputSchema,
27445
27758
  status: 201,
27446
27759
  response: { description: "The standing thread." },
@@ -43715,13 +44028,15 @@ async function agentPost({
43715
44028
  }
43716
44029
  const text = await postText(io, args);
43717
44030
  const brief = flagString(flags, "brief") === undefined ? undefined : readDataFlag(flags, "brief");
44031
+ const card = flagString(flags, "card") === undefined ? undefined : readDataFlag(flags, "card");
43718
44032
  const edit = flagString(flags, "edit");
43719
44033
  if (edit !== undefined) {
43720
44034
  const body = parseInput(agentPostEditSchema, {
43721
44035
  text,
43722
44036
  ...flagBool(flags, "draft") ? { final: false } : {},
43723
44037
  level: flagString(flags, "level"),
43724
- brief
44038
+ brief,
44039
+ card
43725
44040
  });
43726
44041
  return {
43727
44042
  data: await client.patch(pathOf(agentPostOperations.edit, { postId: edit }), body),
@@ -43734,10 +44049,12 @@ async function agentPost({
43734
44049
  externalId: flagString(flags, "external-id") ?? `cli:${ulid3()}`,
43735
44050
  thread: ULID.test(thread) ? { id: thread.toUpperCase() } : { slug: thread, ...member ? { memberId: member } : {} },
43736
44051
  text,
43737
- kind: flagString(flags, "kind") ?? (brief ? "brief" : undefined),
44052
+ kind: flagString(flags, "kind") ?? (brief ? "brief" : card ? "card" : undefined),
43738
44053
  level: flagString(flags, "level"),
43739
44054
  final: !flagBool(flags, "draft"),
43740
- brief
44055
+ brief,
44056
+ card,
44057
+ digestKey: flagString(flags, "digest-key")
43741
44058
  });
43742
44059
  return { data: await client.post(pathOf(agentPostOperations.post), body), render: renderRecord };
43743
44060
  }
@@ -44445,6 +44762,16 @@ var commands = [
44445
44762
  type: "string",
44446
44763
  description: `A brief's sections as JSON: {"label":"HQ brief","title":"\u2026","rows":[{"text":"\u2026","meta":"\u2026","icon":"tasks","verb":{"label":"Start","href":"/tasks"}}]} (a verb has href or say). Makes the post a brief; shows as a card on Now until the day ends.`
44447
44764
  },
44765
+ {
44766
+ name: "card",
44767
+ type: "string",
44768
+ description: `A typed card as JSON: {"type":"pr","data":{\u2026}} (do v2's Echo draws it by type, else the text). Makes the post a card; the same --external-id changes it in place.`
44769
+ },
44770
+ {
44771
+ name: "digest-key",
44772
+ type: "string",
44773
+ description: "A quiet post's noun (`heartbeat`): with --level for_later, do v2 folds such posts into one digest line."
44774
+ },
44448
44775
  { name: "edit", type: "string", description: "Edit this post (its id) instead: its text." },
44449
44776
  { name: "delete", type: "string", description: "Take this post (its id) back." }
44450
44777
  ],
@@ -47680,11 +48007,16 @@ async function echoThreadAdd({ args, flags, requireClient }) {
47680
48007
  throw usageError("missing required argument: <title>");
47681
48008
  const slug = flagString(flags, "slug");
47682
48009
  const areas = flagString(flags, "areas");
48010
+ const kind = flagString(flags, "kind");
48011
+ if (kind !== undefined)
48012
+ topicKind(kind);
47683
48013
  return {
47684
48014
  data: await requireClient().post(pathOf(echoThreadOperations.addStanding), {
47685
48015
  title,
47686
48016
  ...slug ? { slug } : {},
47687
- ...areas === undefined ? {} : { areaIds: splitList(areas) }
48017
+ ...areas === undefined ? {} : { areaIds: splitList(areas) },
48018
+ ...kind ? { kind } : {},
48019
+ ...aboutOf(flags)
47688
48020
  }),
47689
48021
  render: renderEchoThread
47690
48022
  };
@@ -47700,6 +48032,44 @@ async function echoThreadId(client, ref) {
47700
48032
  throw usageError(`no thread \`${ref}\` (see \`do echo threads list\`)`);
47701
48033
  return found.id;
47702
48034
  }
48035
+ var TOPIC_KINDS = ["personal", "work", "system", "client"];
48036
+ function topicKind(value) {
48037
+ if (!TOPIC_KINDS.includes(value)) {
48038
+ throw usageError(`kind is one of ${TOPIC_KINDS.join(", ")}`);
48039
+ }
48040
+ return value;
48041
+ }
48042
+ function anchorOf(value) {
48043
+ const [type, id] = value.split(":");
48044
+ if (!type || !id || !["task", "project", "habit", "note"].includes(type)) {
48045
+ throw usageError("--on is type:id, the type one of task, project, habit, note");
48046
+ }
48047
+ return { type, id };
48048
+ }
48049
+ var KIND_FLAG = {
48050
+ name: "kind",
48051
+ type: "string",
48052
+ description: "What it is for: personal, work (default), system or client."
48053
+ };
48054
+ var ABOUT_FLAGS = [
48055
+ { name: "icon", type: "string", description: "Its icon in the list (`wrench`)." },
48056
+ { name: "about", type: "string", description: "One line on what it is for." },
48057
+ {
48058
+ name: "memory",
48059
+ type: "string",
48060
+ description: "Which memory the agent answers with: personal, work, none or isolated."
48061
+ }
48062
+ ];
48063
+ function aboutOf(flags) {
48064
+ const icon = flagString(flags, "icon");
48065
+ const description = flagString(flags, "about");
48066
+ const memoryScope = flagString(flags, "memory");
48067
+ return {
48068
+ ...icon ? { icon } : {},
48069
+ ...description === undefined ? {} : { description },
48070
+ ...memoryScope ? { memoryScope } : {}
48071
+ };
48072
+ }
47703
48073
  function splitList(value) {
47704
48074
  return value.split(",").map((v) => v.trim()).filter((v) => v.length > 0);
47705
48075
  }
@@ -47743,6 +48113,16 @@ var commands16 = [
47743
48113
  type: "string",
47744
48114
  description: `A brief's sections as JSON: {"label":"HQ brief","title":"\u2026","rows":[{"text":"\u2026","meta":"\u2026","icon":"tasks","verb":{"label":"Start","href":"/tasks"}}]} (a verb has href or say). Makes the post a brief; shows as a card on Now until the day ends.`
47745
48115
  },
48116
+ {
48117
+ name: "card",
48118
+ type: "string",
48119
+ description: `A typed card as JSON: {"type":"pr","data":{\u2026}} (do v2's Echo draws it by type, else the text). Makes the post a card; the same --external-id changes it in place.`
48120
+ },
48121
+ {
48122
+ name: "digest-key",
48123
+ type: "string",
48124
+ description: "A quiet post's noun (`heartbeat`): with --level for_later, do v2 folds such posts into one digest line."
48125
+ },
47746
48126
  { name: "edit", type: "string", description: "Edit this post (its id) instead: its text." },
47747
48127
  { name: "delete", type: "string", description: "Take this post (its id) back." }
47748
48128
  ],
@@ -47801,15 +48181,37 @@ var commands16 = [
47801
48181
  path: ["echo", "threads", "new"],
47802
48182
  summary: "Start a new agent conversation (it becomes the current thread).",
47803
48183
  args: [],
47804
- flags: [],
48184
+ flags: [
48185
+ { name: "title", type: "string", description: "Its name: a loose thread (do v2)." },
48186
+ {
48187
+ name: "on",
48188
+ type: "string",
48189
+ description: "A thing it hangs on, as type:id (task:01J\u2026, project, habit or note)."
48190
+ },
48191
+ {
48192
+ name: "from",
48193
+ type: "string",
48194
+ description: "The thread it starts from (id or slug): a thread on a thing takes its memory."
48195
+ }
48196
+ ],
47805
48197
  scopes: [...echoThreadOperations.create.scopes],
47806
48198
  returns: "EchoThread",
47807
- notes: "When the current thread is still empty, that one is returned instead."
48199
+ notes: "Without flags: when the current thread is still empty, that one is returned instead. A thing has one thread per member: --on again returns it."
47808
48200
  },
47809
- run: async ({ requireClient }) => ({
47810
- data: await requireClient().post(pathOf(echoThreadOperations.create), {}),
47811
- render: renderEchoThread
47812
- })
48201
+ run: async ({ flags, requireClient }) => {
48202
+ const client = requireClient();
48203
+ const title = flagString(flags, "title");
48204
+ const on = flagString(flags, "on");
48205
+ const from = flagString(flags, "from");
48206
+ return {
48207
+ data: await client.post(pathOf(echoThreadOperations.create), {
48208
+ ...title ? { title } : {},
48209
+ ...on === undefined ? {} : { anchor: anchorOf(on) },
48210
+ ...from ? { parentId: await echoThreadId(client, from) } : {}
48211
+ }),
48212
+ render: renderEchoThread
48213
+ };
48214
+ }
47813
48215
  },
47814
48216
  {
47815
48217
  spec: {
@@ -47899,7 +48301,9 @@ var commands16 = [
47899
48301
  type: "string",
47900
48302
  description: "What the agent and scripts address it by (default: from the title)."
47901
48303
  },
47902
- { name: "areas", type: "string", description: "Area ids it covers, comma-separated." }
48304
+ { name: "areas", type: "string", description: "Area ids it covers, comma-separated." },
48305
+ KIND_FLAG,
48306
+ ...ABOUT_FLAGS
47903
48307
  ],
47904
48308
  scopes: [...echoThreadOperations.addStanding.scopes],
47905
48309
  returns: "EchoThread",
@@ -47918,7 +48322,9 @@ var commands16 = [
47918
48322
  type: "string",
47919
48323
  description: "What the agent and scripts address it by (default: from the title)."
47920
48324
  },
47921
- { name: "areas", type: "string", description: "Area ids it covers, comma-separated." }
48325
+ { name: "areas", type: "string", description: "Area ids it covers, comma-separated." },
48326
+ KIND_FLAG,
48327
+ ...ABOUT_FLAGS
47922
48328
  ],
47923
48329
  scopes: [...echoThreadOperations.addStanding.scopes],
47924
48330
  returns: "EchoThread"
@@ -47949,6 +48355,29 @@ var commands16 = [
47949
48355
  };
47950
48356
  }
47951
48357
  },
48358
+ {
48359
+ spec: {
48360
+ path: ["echo", "threads", "kind"],
48361
+ summary: "Say what one of your agent topics is for: personal, work, system or client.",
48362
+ args: [
48363
+ { name: "thread", required: true, description: "Its id, or a standing thread's slug." },
48364
+ { name: "kind", required: true, description: "personal, work, system or client." }
48365
+ ],
48366
+ flags: [],
48367
+ scopes: [...echoThreadOperations.update.scopes],
48368
+ returns: "EchoThreadSummary",
48369
+ notes: "A thread on a thing (a task, a project) keeps its kind, `object`: a 400."
48370
+ },
48371
+ run: async ({ args, requireClient }) => {
48372
+ const client = requireClient();
48373
+ const id = await echoThreadId(client, requireArg(args, 0, "thread"));
48374
+ const kind = topicKind(requireArg(args, 1, "kind"));
48375
+ return {
48376
+ data: await client.patch(pathOf(echoThreadOperations.update, { id }), { kind }),
48377
+ render: renderRecord
48378
+ };
48379
+ }
48380
+ },
47952
48381
  {
47953
48382
  spec: {
47954
48383
  path: ["echo", "threads", "link"],
@@ -51698,7 +52127,7 @@ function renderLogged(data, mode) {
51698
52127
  return rows.map((e) => `${e.at} ${e.what} ${paint(mode, "dim", e.where)}`).join(`
51699
52128
  `);
51700
52129
  }
51701
- var KIND_FLAG = {
52130
+ var KIND_FLAG2 = {
51702
52131
  name: "kind",
51703
52132
  type: "string",
51704
52133
  description: "The kind of an unknown word (pages, eggs, health, note, or a word taught before); remembered for the Space."
@@ -51711,7 +52140,7 @@ var commands28 = [
51711
52140
  args: [{ name: "line", required: true, description: 'The line, e.g. "pages 34".' }],
51712
52141
  flags: [
51713
52142
  { name: "dry-run", type: "boolean", description: "Preview only; write nothing." },
51714
- KIND_FLAG,
52143
+ KIND_FLAG2,
51715
52144
  {
51716
52145
  name: "destination",
51717
52146
  type: "string",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robbeverhelst/do",
3
- "version": "1.365.0",
3
+ "version": "1.367.0",
4
4
  "private": false,
5
5
  "description": "do — the agent-drivable CLI over the public /api/v1 surface",
6
6
  "homepage": "https://github.com/robbeverhelst/do/tree/main/apps/cli",