@robbeverhelst/do 1.160.0 → 1.162.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/do.js +1117 -69
- package/package.json +1 -1
package/dist/do.js
CHANGED
|
@@ -3514,6 +3514,8 @@ var tenants = pgTable("tenants", {
|
|
|
3514
3514
|
name: text("name").notNull(),
|
|
3515
3515
|
backdrop: text("backdrop"),
|
|
3516
3516
|
gaardHouseUrl: text("gaard_house_url"),
|
|
3517
|
+
awayFrom: date("away_from", { mode: "string" }),
|
|
3518
|
+
awayUntil: date("away_until", { mode: "string" }),
|
|
3517
3519
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
3518
3520
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
3519
3521
|
deletedAt: timestamp("deleted_at", { withTimezone: true })
|
|
@@ -3572,6 +3574,7 @@ var agents = pgTable("agents", {
|
|
|
3572
3574
|
tenantId: text("tenant_id").notNull().references(() => tenants.id),
|
|
3573
3575
|
name: text("name").notNull(),
|
|
3574
3576
|
revokedAt: timestamp("revoked_at", { withTimezone: true }),
|
|
3577
|
+
trustedDesks: text("trusted_desks").array().notNull().default([]),
|
|
3575
3578
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
3576
3579
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
3577
3580
|
}, (t) => [
|
|
@@ -3597,8 +3600,13 @@ var areas = pgTable("areas", {
|
|
|
3597
3600
|
color: areaColor("color").notNull().default("teal"),
|
|
3598
3601
|
icon: text("icon"),
|
|
3599
3602
|
reviewCadence: reviewCadence("review_cadence"),
|
|
3600
|
-
archivedAt: timestamp("archived_at", { withTimezone: true })
|
|
3601
|
-
|
|
3603
|
+
archivedAt: timestamp("archived_at", { withTimezone: true }),
|
|
3604
|
+
purpose: text("purpose"),
|
|
3605
|
+
standards: jsonb("standards").$type().notNull().default(sql`'[]'::jsonb`)
|
|
3606
|
+
}, (t) => [
|
|
3607
|
+
index("areas_tenant_idx").on(t.tenantId),
|
|
3608
|
+
check("areas_standards_chk", sql`jsonb_typeof(${t.standards}) = 'array' AND jsonb_array_length(${t.standards}) <= 5`)
|
|
3609
|
+
]);
|
|
3602
3610
|
|
|
3603
3611
|
// ../../packages/schema/src/db/core.ts
|
|
3604
3612
|
var routineKind = pgEnum("routine_kind", ["sequence", "time_blocked", "checklist"]);
|
|
@@ -3746,7 +3754,13 @@ var habitMeasurementType = pgEnum("habit_measurement_type", [
|
|
|
3746
3754
|
"negative"
|
|
3747
3755
|
]);
|
|
3748
3756
|
var habitPeriod = pgEnum("habit_period", ["day", "week", "month"]);
|
|
3749
|
-
var habitEntrySource = pgEnum("habit_entry_source", [
|
|
3757
|
+
var habitEntrySource = pgEnum("habit_entry_source", [
|
|
3758
|
+
"manual",
|
|
3759
|
+
"routine",
|
|
3760
|
+
"ingest",
|
|
3761
|
+
"agent"
|
|
3762
|
+
]);
|
|
3763
|
+
var habitEntryKind = pgEnum("habit_entry_kind", ["check_in", "skip"]);
|
|
3750
3764
|
var habitSource = pgEnum("habit_source", ["manual", "google_fit", "strava", "github"]);
|
|
3751
3765
|
var recurrenceMode = pgEnum("recurrence_mode", ["rigid", "flexible"]);
|
|
3752
3766
|
var recurrenceFreq = pgEnum("recurrence_freq", ["daily", "weekly", "monthly", "yearly"]);
|
|
@@ -3788,7 +3802,12 @@ var tasks = pgTable("tasks", {
|
|
|
3788
3802
|
completedByUserId: text("completed_by_user_id"),
|
|
3789
3803
|
completedByAgentId: text("completed_by_agent_id"),
|
|
3790
3804
|
placeId: text("place_id").references(() => places.id, { onDelete: "set null" }),
|
|
3791
|
-
filingSuggestion: jsonb("filing_suggestion").$type()
|
|
3805
|
+
filingSuggestion: jsonb("filing_suggestion").$type(),
|
|
3806
|
+
proposedAt: timestamp("proposed_at", { withTimezone: true }),
|
|
3807
|
+
proposedDesk: text("proposed_desk"),
|
|
3808
|
+
notNowUntil: timestamp("not_now_until", { withTimezone: true }),
|
|
3809
|
+
readyAt: timestamp("ready_at", { withTimezone: true }),
|
|
3810
|
+
readyNote: text("ready_note")
|
|
3792
3811
|
}, (t) => [
|
|
3793
3812
|
index("tasks_tenant_project_idx").on(t.tenantId, t.projectId),
|
|
3794
3813
|
index("tasks_tenant_place_idx").on(t.tenantId, t.placeId),
|
|
@@ -3803,6 +3822,8 @@ var tasks = pgTable("tasks", {
|
|
|
3803
3822
|
index("tasks_tenant_scheduled_idx").on(t.tenantId, t.scheduledAt),
|
|
3804
3823
|
index("tasks_tenant_due_idx").on(t.tenantId, t.dueAt),
|
|
3805
3824
|
index("tasks_tenant_completed_idx").on(t.tenantId, t.completedAt),
|
|
3825
|
+
index("tasks_tenant_proposed_idx").on(t.tenantId, t.proposedAt).where(sql`${t.proposedAt} IS NOT NULL`),
|
|
3826
|
+
index("tasks_tenant_ready_idx").on(t.tenantId, t.readyAt).where(sql`${t.readyAt} IS NOT NULL`),
|
|
3806
3827
|
check("tasks_area_xor_project_chk", sql`${t.projectId} IS NULL OR ${t.areaId} IS NULL`)
|
|
3807
3828
|
]);
|
|
3808
3829
|
var habits = pgTable("habits", {
|
|
@@ -3816,10 +3837,17 @@ var habits = pgTable("habits", {
|
|
|
3816
3837
|
recurrenceRuleId: text("recurrence_rule_id").references(() => recurrenceRules.id),
|
|
3817
3838
|
areaId: text("area_id").references(() => areas.id),
|
|
3818
3839
|
source: habitSource("source").notNull().default("manual"),
|
|
3819
|
-
sourceMetric: text("source_metric")
|
|
3840
|
+
sourceMetric: text("source_metric"),
|
|
3841
|
+
aliases: text("aliases").array().notNull().default(sql`'{}'::text[]`),
|
|
3842
|
+
timeOfDay: text("time_of_day"),
|
|
3843
|
+
pausedFrom: date("paused_from", { mode: "string" }),
|
|
3844
|
+
pausedUntil: date("paused_until", { mode: "string" }),
|
|
3845
|
+
remind: boolean("remind").notNull().default(false),
|
|
3846
|
+
retiredAt: timestamp("retired_at", { withTimezone: true })
|
|
3820
3847
|
}, (t) => [
|
|
3821
3848
|
index("habits_tenant_idx").on(t.tenantId),
|
|
3822
|
-
index("habits_tenant_area_idx").on(t.tenantId, t.areaId)
|
|
3849
|
+
index("habits_tenant_area_idx").on(t.tenantId, t.areaId),
|
|
3850
|
+
check("habits_time_of_day_chk", sql`${t.timeOfDay} IS NULL OR ${t.timeOfDay} IN ('morning', 'midday', 'evening') OR ${t.timeOfDay} ~ '^([01][0-9]|2[0-3]):[0-5][0-9]$'`)
|
|
3823
3851
|
]);
|
|
3824
3852
|
var habitEntries = pgTable("habit_entries", {
|
|
3825
3853
|
id: text("id").primaryKey(),
|
|
@@ -3827,9 +3855,12 @@ var habitEntries = pgTable("habit_entries", {
|
|
|
3827
3855
|
habitId: text("habit_id").notNull().references(() => habits.id),
|
|
3828
3856
|
value: doublePrecision("value").notNull().default(1),
|
|
3829
3857
|
source: habitEntrySource("source").notNull().default("manual"),
|
|
3858
|
+
kind: habitEntryKind("kind").notNull().default("check_in"),
|
|
3830
3859
|
occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull(),
|
|
3831
3860
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
3832
|
-
externalId: text("external_id")
|
|
3861
|
+
externalId: text("external_id"),
|
|
3862
|
+
agentId: text("agent_id"),
|
|
3863
|
+
note: text("note")
|
|
3833
3864
|
}, (t) => [
|
|
3834
3865
|
index("habit_entries_habit_occurred_idx").on(t.habitId, t.occurredAt),
|
|
3835
3866
|
uniqueIndex("habit_entries_habit_external_uniq").on(t.habitId, t.externalId).where(sql`${t.externalId} IS NOT NULL`)
|
|
@@ -3874,7 +3905,8 @@ var notificationType = pgEnum("notification_type", [
|
|
|
3874
3905
|
"automation",
|
|
3875
3906
|
"streak_at_risk",
|
|
3876
3907
|
"reflection_nudge",
|
|
3877
|
-
"shutdown_nudge"
|
|
3908
|
+
"shutdown_nudge",
|
|
3909
|
+
"habit_reminder"
|
|
3878
3910
|
]);
|
|
3879
3911
|
var notifications = pgTable("notifications", {
|
|
3880
3912
|
id: text("id").primaryKey(),
|
|
@@ -18036,7 +18068,7 @@ var spaceSchema = createSelectSchema(tenants, {
|
|
|
18036
18068
|
createdAt: exports_coerce.date(),
|
|
18037
18069
|
updatedAt: exports_coerce.date(),
|
|
18038
18070
|
deletedAt: exports_coerce.date().nullable()
|
|
18039
|
-
}).omit({ gaardHouseUrl: true });
|
|
18071
|
+
}).omit({ gaardHouseUrl: true, awayFrom: true, awayUntil: true });
|
|
18040
18072
|
var backdropIdSchema = string2().trim().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "a backdrop id is lowercase words joined by dashes").max(40);
|
|
18041
18073
|
var updateSpaceInputSchema = object({
|
|
18042
18074
|
name: string2().trim().min(1).max(120).optional(),
|
|
@@ -18128,6 +18160,7 @@ var routineRunStepStatusSchema = _enum2(routineRunStepStatus.enumValues);
|
|
|
18128
18160
|
var habitMeasurementTypeSchema = _enum2(habitMeasurementType.enumValues);
|
|
18129
18161
|
var habitPeriodSchema = _enum2(habitPeriod.enumValues);
|
|
18130
18162
|
var habitEntrySourceSchema = _enum2(habitEntrySource.enumValues);
|
|
18163
|
+
var habitEntryKindSchema = _enum2(habitEntryKind.enumValues);
|
|
18131
18164
|
var recurrenceModeSchema = _enum2(recurrenceMode.enumValues);
|
|
18132
18165
|
var recurrenceFreqSchema = _enum2(recurrenceFreq.enumValues);
|
|
18133
18166
|
var recurrenceUnitSchema = _enum2(recurrenceUnit.enumValues);
|
|
@@ -18153,13 +18186,20 @@ var reflectionKindSchema = _enum2(reflectionKind.enumValues);
|
|
|
18153
18186
|
|
|
18154
18187
|
// ../../packages/schema/src/contracts/agents.ts
|
|
18155
18188
|
var agentSchema = createSelectSchema(agents, {
|
|
18189
|
+
trustedDesks: array(string2()).default([]),
|
|
18156
18190
|
revokedAt: exports_coerce.date().nullable(),
|
|
18157
18191
|
createdAt: exports_coerce.date(),
|
|
18158
18192
|
updatedAt: exports_coerce.date()
|
|
18159
18193
|
});
|
|
18160
18194
|
var agentNameSchema = string2().trim().min(1).max(60);
|
|
18161
18195
|
var createAgentInputSchema = object({ name: agentNameSchema }).strict();
|
|
18162
|
-
var
|
|
18196
|
+
var deskSchema = string2().trim().toLowerCase().regex(/^[a-z0-9][a-z0-9_-]{0,39}$/, "a desk is a lower-case slug like `finance`");
|
|
18197
|
+
var updateAgentInputSchema = object({
|
|
18198
|
+
name: agentNameSchema.optional(),
|
|
18199
|
+
trustedDesks: array(deskSchema).max(40).transform((desks) => [...new Set(desks)]).optional()
|
|
18200
|
+
}).strict().refine((v) => v.name !== undefined || v.trustedDesks !== undefined, {
|
|
18201
|
+
message: "send a name or trustedDesks"
|
|
18202
|
+
});
|
|
18163
18203
|
var actorKindSchema = _enum2(["member", "agent"]);
|
|
18164
18204
|
var actorRefSchema = object({
|
|
18165
18205
|
kind: actorKindSchema,
|
|
@@ -18322,9 +18362,13 @@ var taskSchema = createSelectSchema(tasks, {
|
|
|
18322
18362
|
startAt: exports_coerce.date().nullable(),
|
|
18323
18363
|
dueAt: exports_coerce.date().nullable(),
|
|
18324
18364
|
completedAt: exports_coerce.date().nullable().default(null),
|
|
18325
|
-
placeId: string2().nullable().default(null)
|
|
18365
|
+
placeId: string2().nullable().default(null),
|
|
18366
|
+
proposedAt: exports_coerce.date().nullable().default(null),
|
|
18367
|
+
proposedDesk: string2().nullable().default(null),
|
|
18368
|
+
notNowUntil: exports_coerce.date().nullable().default(null),
|
|
18369
|
+
readyAt: exports_coerce.date().nullable().default(null),
|
|
18370
|
+
readyNote: string2().nullable().default(null)
|
|
18326
18371
|
});
|
|
18327
|
-
var deskSchema = string2().trim().toLowerCase().regex(/^[a-z0-9][a-z0-9_-]{0,39}$/, "a desk is a lower-case slug like `finance`");
|
|
18328
18372
|
var PARTY_RE = /^(?:(me)|(member|agent):([^/]+?))(?:\/(.+))?$/;
|
|
18329
18373
|
function partySchema(allowDesk) {
|
|
18330
18374
|
return string2().trim().min(1).max(200).transform((raw, ctx) => {
|
|
@@ -18419,7 +18463,12 @@ var createTaskInputSchema = createInsertSchema(tasks, {
|
|
|
18419
18463
|
waitingSince: true,
|
|
18420
18464
|
completedByUserId: true,
|
|
18421
18465
|
completedByAgentId: true,
|
|
18422
|
-
filingSuggestion: true
|
|
18466
|
+
filingSuggestion: true,
|
|
18467
|
+
proposedAt: true,
|
|
18468
|
+
proposedDesk: true,
|
|
18469
|
+
notNowUntil: true,
|
|
18470
|
+
readyAt: true,
|
|
18471
|
+
readyNote: true
|
|
18423
18472
|
}).extend({
|
|
18424
18473
|
title: string2().min(1),
|
|
18425
18474
|
parentId: ulidSchema.nullish(),
|
|
@@ -18429,8 +18478,12 @@ var createTaskInputSchema = createInsertSchema(tasks, {
|
|
|
18429
18478
|
owner: taskOwnerInputSchema.nullish(),
|
|
18430
18479
|
waitingOn: taskWaitingOnInputSchema.nullish(),
|
|
18431
18480
|
source: taskSourceSchema.nullish(),
|
|
18432
|
-
nextStep: taskNextStepSchema.nullish()
|
|
18481
|
+
nextStep: taskNextStepSchema.nullish(),
|
|
18482
|
+
proposed: boolean3().optional(),
|
|
18483
|
+
fromDesk: deskSchema.nullish()
|
|
18433
18484
|
});
|
|
18485
|
+
var taskReadyNoteSchema = string2().trim().min(1).max(500);
|
|
18486
|
+
var markTaskReadyInputSchema = object({ note: taskReadyNoteSchema.nullish() }).strict();
|
|
18434
18487
|
var updateTaskInputSchema = createUpdateSchema(tasks, {
|
|
18435
18488
|
completedAt: completedAtInputSchema,
|
|
18436
18489
|
scheduledAt: exports_coerce.date().nullish(),
|
|
@@ -18453,7 +18506,10 @@ var updateTaskInputSchema = createUpdateSchema(tasks, {
|
|
|
18453
18506
|
waitingSince: true,
|
|
18454
18507
|
completedByUserId: true,
|
|
18455
18508
|
completedByAgentId: true,
|
|
18456
|
-
filingSuggestion: true
|
|
18509
|
+
filingSuggestion: true,
|
|
18510
|
+
proposedAt: true,
|
|
18511
|
+
proposedDesk: true,
|
|
18512
|
+
readyAt: true
|
|
18457
18513
|
}).extend({
|
|
18458
18514
|
title: string2().min(1).optional(),
|
|
18459
18515
|
parentId: ulidSchema.nullish(),
|
|
@@ -18462,7 +18518,11 @@ var updateTaskInputSchema = createUpdateSchema(tasks, {
|
|
|
18462
18518
|
owner: taskOwnerInputSchema.nullish(),
|
|
18463
18519
|
waitingOn: taskWaitingOnInputSchema.nullish(),
|
|
18464
18520
|
source: taskSourceSchema.nullish(),
|
|
18465
|
-
nextStep: taskNextStepSchema.nullish()
|
|
18521
|
+
nextStep: taskNextStepSchema.nullish(),
|
|
18522
|
+
proposed: boolean3().optional(),
|
|
18523
|
+
notNowUntil: exports_coerce.date().nullish(),
|
|
18524
|
+
ready: boolean3().optional(),
|
|
18525
|
+
readyNote: taskReadyNoteSchema.nullish()
|
|
18466
18526
|
}).strict();
|
|
18467
18527
|
var taskListFilterSchema = _enum2(["all", "unsorted", "starred"]);
|
|
18468
18528
|
|
|
@@ -18606,13 +18666,31 @@ var habitSourceSchema = _enum2(["manual", "google_fit", "strava", "github"]);
|
|
|
18606
18666
|
// ../../packages/schema/src/contracts/habits.ts
|
|
18607
18667
|
var habitSchema = createSelectSchema(habits, {
|
|
18608
18668
|
source: habitSourceSchema.default("manual"),
|
|
18609
|
-
sourceMetric: string2().nullable().default(null)
|
|
18669
|
+
sourceMetric: string2().nullable().default(null),
|
|
18670
|
+
aliases: array(string2()).default([]),
|
|
18671
|
+
timeOfDay: string2().nullable().default(null),
|
|
18672
|
+
pausedFrom: exports_iso.date().nullable().default(null),
|
|
18673
|
+
pausedUntil: exports_iso.date().nullable().default(null),
|
|
18674
|
+
remind: boolean3().default(false),
|
|
18675
|
+
retiredAt: exports_coerce.date().nullable().default(null)
|
|
18610
18676
|
});
|
|
18611
18677
|
var habitEntrySchema = createSelectSchema(habitEntries, {
|
|
18612
18678
|
occurredAt: exports_coerce.date(),
|
|
18613
18679
|
createdAt: exports_coerce.date(),
|
|
18614
|
-
externalId: string2().nullish()
|
|
18680
|
+
externalId: string2().nullish(),
|
|
18681
|
+
kind: habitEntryKindSchema.default("check_in"),
|
|
18682
|
+
agentId: string2().nullish(),
|
|
18683
|
+
note: string2().nullish()
|
|
18684
|
+
}).extend({
|
|
18685
|
+
by: string2().nullish()
|
|
18615
18686
|
});
|
|
18687
|
+
var HABIT_PARTS_OF_DAY = ["morning", "midday", "evening"];
|
|
18688
|
+
var habitTimeOfDaySchema = union([
|
|
18689
|
+
_enum2(HABIT_PARTS_OF_DAY),
|
|
18690
|
+
string2().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "Use a 24-hour time, like 07:30")
|
|
18691
|
+
]);
|
|
18692
|
+
var habitAliasSchema = string2().trim().min(1).max(60);
|
|
18693
|
+
var habitAliasesSchema = array(habitAliasSchema).max(12).transform((aliases) => aliases.filter((a, i) => aliases.findIndex((b) => b.toLowerCase() === a.toLowerCase()) === i));
|
|
18616
18694
|
var createHabitInputSchema = createInsertSchema(habits, {
|
|
18617
18695
|
id: ulidSchema,
|
|
18618
18696
|
source: habitSourceSchema.optional(),
|
|
@@ -18622,8 +18700,11 @@ var createHabitInputSchema = createInsertSchema(habits, {
|
|
|
18622
18700
|
targetUnit: string2().min(1).nullish(),
|
|
18623
18701
|
period: habitPeriodSchema.default("day"),
|
|
18624
18702
|
frequencyCount: number2().int().positive().default(1),
|
|
18625
|
-
areaId: ulidSchema.nullish()
|
|
18626
|
-
|
|
18703
|
+
areaId: ulidSchema.nullish(),
|
|
18704
|
+
aliases: habitAliasesSchema.optional(),
|
|
18705
|
+
timeOfDay: habitTimeOfDaySchema.nullish(),
|
|
18706
|
+
remind: boolean3().optional()
|
|
18707
|
+
}).omit({ tenantId: true, recurrenceRuleId: true, retiredAt: true }).extend({
|
|
18627
18708
|
title: string2().min(1),
|
|
18628
18709
|
displayKind: string2().min(1).nullish()
|
|
18629
18710
|
});
|
|
@@ -18634,14 +18715,29 @@ var updateHabitInputSchema = createUpdateSchema(habits, {
|
|
|
18634
18715
|
targetUnit: string2().min(1).nullish(),
|
|
18635
18716
|
period: habitPeriodSchema.optional(),
|
|
18636
18717
|
frequencyCount: number2().int().positive().optional(),
|
|
18637
|
-
areaId: ulidSchema.nullish()
|
|
18638
|
-
|
|
18718
|
+
areaId: ulidSchema.nullish(),
|
|
18719
|
+
aliases: habitAliasesSchema.optional(),
|
|
18720
|
+
timeOfDay: habitTimeOfDaySchema.nullish(),
|
|
18721
|
+
remind: boolean3().optional()
|
|
18722
|
+
}).omit({
|
|
18723
|
+
id: true,
|
|
18724
|
+
tenantId: true,
|
|
18725
|
+
measurementType: true,
|
|
18726
|
+
recurrenceRuleId: true,
|
|
18727
|
+
pausedFrom: true,
|
|
18728
|
+
pausedUntil: true,
|
|
18729
|
+
retiredAt: true
|
|
18730
|
+
}).extend({ title: string2().min(1).optional() });
|
|
18731
|
+
var HABIT_ENTRY_NOTE_MAX = 280;
|
|
18732
|
+
var habitEntryNoteSchema = string2().trim().max(HABIT_ENTRY_NOTE_MAX).transform((note) => note === "" ? null : note);
|
|
18639
18733
|
var createHabitEntryInputSchema = createInsertSchema(habitEntries, {
|
|
18640
18734
|
id: ulidSchema,
|
|
18641
18735
|
value: number2().nonnegative().default(1),
|
|
18642
18736
|
source: habitEntrySourceSchema.default("manual"),
|
|
18643
|
-
occurredAt: exports_coerce.date().optional()
|
|
18644
|
-
|
|
18737
|
+
occurredAt: exports_coerce.date().optional(),
|
|
18738
|
+
note: habitEntryNoteSchema.nullish()
|
|
18739
|
+
}).omit({ tenantId: true, habitId: true, createdAt: true, agentId: true, kind: true });
|
|
18740
|
+
var updateHabitEntryInputSchema = object({ note: habitEntryNoteSchema.nullable() }).strict();
|
|
18645
18741
|
var habitStreakStateSchema = _enum2(["active", "recovering", "broken"]);
|
|
18646
18742
|
var habitStreakSchema = object({
|
|
18647
18743
|
current: number2().int().nonnegative(),
|
|
@@ -18652,7 +18748,8 @@ var habitStreakSchema = object({
|
|
|
18652
18748
|
completionRate: number2().min(0).max(1),
|
|
18653
18749
|
state: habitStreakStateSchema,
|
|
18654
18750
|
graceBudget: number2().int().nonnegative(),
|
|
18655
|
-
graceRemaining: number2().int().nonnegative()
|
|
18751
|
+
graceRemaining: number2().int().nonnegative(),
|
|
18752
|
+
skippedToday: boolean3().default(false)
|
|
18656
18753
|
});
|
|
18657
18754
|
var habitRoutineRefSchema = object({
|
|
18658
18755
|
id: ulidSchema,
|
|
@@ -18661,7 +18758,19 @@ var habitRoutineRefSchema = object({
|
|
|
18661
18758
|
var habitLastCheckInSchema = object({
|
|
18662
18759
|
at: exports_coerce.date(),
|
|
18663
18760
|
value: number2(),
|
|
18664
|
-
source: habitEntrySourceSchema
|
|
18761
|
+
source: habitEntrySourceSchema,
|
|
18762
|
+
by: string2().nullish(),
|
|
18763
|
+
id: string2().optional(),
|
|
18764
|
+
note: string2().nullish()
|
|
18765
|
+
});
|
|
18766
|
+
var habitPauseSchema = object({
|
|
18767
|
+
until: exports_iso.date(),
|
|
18768
|
+
by: _enum2(["habit", "away"])
|
|
18769
|
+
});
|
|
18770
|
+
var habitTodaySchema = object({
|
|
18771
|
+
due: boolean3(),
|
|
18772
|
+
done: boolean3(),
|
|
18773
|
+
week: object({ done: number2().int().nonnegative(), target: number2().int().positive() }).optional()
|
|
18665
18774
|
});
|
|
18666
18775
|
var habitSummarySchema = habitSchema.extend({
|
|
18667
18776
|
title: string2(),
|
|
@@ -18669,12 +18778,16 @@ var habitSummarySchema = habitSchema.extend({
|
|
|
18669
18778
|
displayKind: string2().default("default"),
|
|
18670
18779
|
streak: habitStreakSchema,
|
|
18671
18780
|
inRoutines: array(habitRoutineRefSchema).default([]),
|
|
18672
|
-
lastCheckIn: habitLastCheckInSchema.nullable().default(null)
|
|
18781
|
+
lastCheckIn: habitLastCheckInSchema.nullable().default(null),
|
|
18782
|
+
pause: habitPauseSchema.nullable().default(null),
|
|
18783
|
+
today: habitTodaySchema.default({ due: true, done: false })
|
|
18673
18784
|
});
|
|
18674
18785
|
var habitHeatmapCellSchema = object({
|
|
18675
18786
|
date: string2(),
|
|
18676
18787
|
value: number2(),
|
|
18677
|
-
satisfied: boolean3()
|
|
18788
|
+
satisfied: boolean3(),
|
|
18789
|
+
rest: boolean3().default(false),
|
|
18790
|
+
notes: array(string2()).optional()
|
|
18678
18791
|
});
|
|
18679
18792
|
var habitDetailSchema = habitSummarySchema.extend({
|
|
18680
18793
|
heatmap: array(habitHeatmapCellSchema),
|
|
@@ -18686,11 +18799,69 @@ var habitEntriesQuerySchema = object({
|
|
|
18686
18799
|
before: exports_coerce.date().optional(),
|
|
18687
18800
|
limit: exports_coerce.number().int().min(1).max(200).default(50)
|
|
18688
18801
|
});
|
|
18802
|
+
var civilDateSchema = string2().regex(/^\d{4}-\d{2}-\d{2}$/, "expected YYYY-MM-DD");
|
|
18803
|
+
var habitCheckInModeSchema = _enum2(["add", "set"]);
|
|
18689
18804
|
var habitCheckInByTitleInputSchema = object({
|
|
18690
18805
|
title: string2().trim().min(1).max(300),
|
|
18691
18806
|
value: number2().nonnegative().optional(),
|
|
18692
|
-
|
|
18807
|
+
mode: habitCheckInModeSchema.default("add"),
|
|
18808
|
+
occurredAt: union([civilDateSchema, exports_coerce.date()]).optional(),
|
|
18809
|
+
note: habitEntryNoteSchema.nullish()
|
|
18810
|
+
}).strict();
|
|
18811
|
+
var habitCandidateSchema = object({
|
|
18812
|
+
id: ulidSchema,
|
|
18813
|
+
title: string2(),
|
|
18814
|
+
aliases: array(string2())
|
|
18815
|
+
});
|
|
18816
|
+
var habitCheckInAmbiguousSchema = object({
|
|
18817
|
+
error: object({
|
|
18818
|
+
code: literal("ambiguous_habit"),
|
|
18819
|
+
message: string2(),
|
|
18820
|
+
details: object({ candidates: array(habitCandidateSchema).min(2) })
|
|
18821
|
+
})
|
|
18822
|
+
});
|
|
18823
|
+
var habitAliasInputSchema = object({ alias: habitAliasSchema }).strict();
|
|
18824
|
+
var habitSkipInputSchema = object({
|
|
18825
|
+
date: exports_iso.date().optional(),
|
|
18826
|
+
note: habitEntryNoteSchema.nullish()
|
|
18693
18827
|
}).strict();
|
|
18828
|
+
var habitPauseInputSchema = object({ until: exports_iso.date() }).strict();
|
|
18829
|
+
var awayInputSchema = object({ until: exports_iso.date().nullable() }).strict();
|
|
18830
|
+
var awayStateSchema = object({
|
|
18831
|
+
until: exports_iso.date().nullable()
|
|
18832
|
+
});
|
|
18833
|
+
var habitDayPartSchema = _enum2(["morning", "midday", "evening", "anytime"]);
|
|
18834
|
+
var habitTodayStateSchema = _enum2(["done", "open", "skipped"]);
|
|
18835
|
+
var habitTodayItemSchema = object({
|
|
18836
|
+
habitId: ulidSchema,
|
|
18837
|
+
title: string2(),
|
|
18838
|
+
aliases: array(string2()).default([]),
|
|
18839
|
+
measurementType: habitMeasurementTypeSchema,
|
|
18840
|
+
unit: string2().nullable(),
|
|
18841
|
+
target: number2().nullable(),
|
|
18842
|
+
timeOfDay: string2().nullable().default(null),
|
|
18843
|
+
value: number2(),
|
|
18844
|
+
state: habitTodayStateSchema,
|
|
18845
|
+
week: object({ done: number2().int().nonnegative(), target: number2().int().positive() }).optional(),
|
|
18846
|
+
last: object({
|
|
18847
|
+
source: habitEntrySourceSchema,
|
|
18848
|
+
by: string2().optional(),
|
|
18849
|
+
at: exports_coerce.date()
|
|
18850
|
+
}).nullable().default(null)
|
|
18851
|
+
});
|
|
18852
|
+
var habitTodayRoutineSchema = object({
|
|
18853
|
+
routineId: ulidSchema,
|
|
18854
|
+
title: string2(),
|
|
18855
|
+
timeOfDay: string2().nullable(),
|
|
18856
|
+
stepsDone: number2().int().nonnegative(),
|
|
18857
|
+
stepsTotal: number2().int().nonnegative()
|
|
18858
|
+
});
|
|
18859
|
+
var habitsTodayResponseSchema = object({
|
|
18860
|
+
date: string2().regex(/^\d{4}-\d{2}-\d{2}$/),
|
|
18861
|
+
timezone: string2().min(1),
|
|
18862
|
+
groups: array(object({ part: habitDayPartSchema, habits: array(habitTodayItemSchema) })),
|
|
18863
|
+
routines: array(habitTodayRoutineSchema)
|
|
18864
|
+
});
|
|
18694
18865
|
|
|
18695
18866
|
// ../../packages/schema/src/contracts/metrics.ts
|
|
18696
18867
|
var metricKeySchema = _enum2(["weight", "sleep", "mood"]);
|
|
@@ -18880,6 +19051,26 @@ var updateRoutineRunStepInputSchema = object({
|
|
|
18880
19051
|
var updateRoutineRunInputSchema = object({
|
|
18881
19052
|
status: routineRunStatusSchema.optional()
|
|
18882
19053
|
}).strict();
|
|
19054
|
+
var routineRunsQuerySchema = object({
|
|
19055
|
+
limit: exports_coerce.number().int().min(1).max(200).optional()
|
|
19056
|
+
});
|
|
19057
|
+
var routineDoneInputSchema = object({
|
|
19058
|
+
id: ulidSchema.optional(),
|
|
19059
|
+
occurrenceDate: exports_coerce.date().nullish()
|
|
19060
|
+
}).strict();
|
|
19061
|
+
var routineDoneStepSchema = object({
|
|
19062
|
+
stepRunId: string2(),
|
|
19063
|
+
title: string2(),
|
|
19064
|
+
habitId: string2().nullable(),
|
|
19065
|
+
habitEntryId: string2().nullable()
|
|
19066
|
+
});
|
|
19067
|
+
var routineDoneResultSchema = object({
|
|
19068
|
+
run: routineRunViewSchema,
|
|
19069
|
+
taken: array(routineDoneStepSchema)
|
|
19070
|
+
});
|
|
19071
|
+
var routineRunUndoInputSchema = object({
|
|
19072
|
+
stepRunIds: array(string2().min(1)).min(1).max(100)
|
|
19073
|
+
}).strict();
|
|
18883
19074
|
|
|
18884
19075
|
// ../../packages/schema/src/contracts/projects.ts
|
|
18885
19076
|
var projectSchema = createSelectSchema(projects, {
|
|
@@ -18977,15 +19168,50 @@ var attachedNoteViewSchema = object({
|
|
|
18977
19168
|
var setAttachedNoteInputSchema = object({ body: string2().max(ATTACHED_NOTE_BODY_MAX) }).strict();
|
|
18978
19169
|
|
|
18979
19170
|
// ../../packages/schema/src/contracts/areas.ts
|
|
18980
|
-
var
|
|
19171
|
+
var areaPurposeSchema = string2().trim().max(140).transform((v) => v.length === 0 ? null : v);
|
|
19172
|
+
var areaStandardTextSchema = string2().trim().min(1).max(120);
|
|
19173
|
+
var linkedNodeIdSchema = string2().trim().min(1).max(64);
|
|
19174
|
+
var areaStandardLinkSchema = discriminatedUnion("kind", [
|
|
19175
|
+
object({ kind: literal("habit"), id: linkedNodeIdSchema }).strict(),
|
|
19176
|
+
object({ kind: literal("task"), id: linkedNodeIdSchema }).strict(),
|
|
19177
|
+
object({ kind: literal("metric"), key: metricKeySchema }).strict()
|
|
19178
|
+
]);
|
|
19179
|
+
var areaStandardSchema = object({
|
|
19180
|
+
id: string2(),
|
|
19181
|
+
text: string2(),
|
|
19182
|
+
link: areaStandardLinkSchema.nullable().default(null)
|
|
19183
|
+
});
|
|
19184
|
+
var areaStandardInputSchema = object({
|
|
19185
|
+
id: string2().min(1).max(64).optional(),
|
|
19186
|
+
text: areaStandardTextSchema,
|
|
19187
|
+
link: areaStandardLinkSchema.nullish()
|
|
19188
|
+
}).strict();
|
|
19189
|
+
var addAreaStandardInputSchema = object({ text: areaStandardTextSchema, link: areaStandardLinkSchema.nullish() }).strict();
|
|
19190
|
+
var updateAreaStandardInputSchema = object({
|
|
19191
|
+
text: areaStandardTextSchema.optional(),
|
|
19192
|
+
link: areaStandardLinkSchema.nullable().optional()
|
|
19193
|
+
}).strict();
|
|
19194
|
+
var areaStandardStateSchema = _enum2(["holding", "worth_a_look"]);
|
|
19195
|
+
var areaStandardViewSchema = areaStandardSchema.extend({
|
|
19196
|
+
state: areaStandardStateSchema.nullable(),
|
|
19197
|
+
why: string2().nullable(),
|
|
19198
|
+
heldBy: string2().nullable()
|
|
19199
|
+
});
|
|
19200
|
+
var areaSchema = createSelectSchema(areas, {
|
|
19201
|
+
purpose: string2().nullable().default(null),
|
|
19202
|
+
standards: array(areaStandardSchema).default([])
|
|
19203
|
+
});
|
|
18981
19204
|
var areaIconSchema = string2().trim().min(1).max(64);
|
|
18982
19205
|
var createAreaInputSchema = createInsertSchema(areas, {
|
|
18983
19206
|
id: ulidSchema,
|
|
18984
|
-
icon: areaIconSchema.nullish()
|
|
18985
|
-
|
|
19207
|
+
icon: areaIconSchema.nullish(),
|
|
19208
|
+
purpose: areaPurposeSchema.nullish()
|
|
19209
|
+
}).omit({ tenantId: true, archivedAt: true, standards: true }).extend({ title: string2().min(1) });
|
|
18986
19210
|
var updateAreaInputSchema = createUpdateSchema(areas, {
|
|
18987
19211
|
icon: areaIconSchema.nullish(),
|
|
18988
|
-
archivedAt: exports_coerce.date().nullish()
|
|
19212
|
+
archivedAt: exports_coerce.date().nullish(),
|
|
19213
|
+
purpose: areaPurposeSchema.nullish(),
|
|
19214
|
+
standards: array(areaStandardInputSchema).max(5).optional()
|
|
18989
19215
|
}).omit({ id: true, tenantId: true }).extend({ title: string2().min(1).optional() }).strict();
|
|
18990
19216
|
var areaViewSchema = areaSchema.extend({
|
|
18991
19217
|
title: string2(),
|
|
@@ -18996,12 +19222,14 @@ var areaViewSchema = areaSchema.extend({
|
|
|
18996
19222
|
projectCount: number2().int().min(0),
|
|
18997
19223
|
taskCount: number2().int().min(0),
|
|
18998
19224
|
habitCount: number2().int().min(0),
|
|
18999
|
-
routineCount: number2().int().min(0)
|
|
19225
|
+
routineCount: number2().int().min(0),
|
|
19226
|
+
standardsWorthALook: number2().int().min(0).default(0)
|
|
19000
19227
|
});
|
|
19001
19228
|
var areaProjectSchema = projectViewSchema.extend({
|
|
19002
19229
|
tasks: array(taskViewSchema)
|
|
19003
19230
|
});
|
|
19004
19231
|
var areaDetailSchema = areaViewSchema.extend({
|
|
19232
|
+
standards: array(areaStandardViewSchema).default([]),
|
|
19005
19233
|
projects: array(areaProjectSchema),
|
|
19006
19234
|
habits: array(habitSummarySchema),
|
|
19007
19235
|
routines: array(routineViewSchema),
|
|
@@ -19328,7 +19556,7 @@ function setModuleEnabled(enabled, key, on) {
|
|
|
19328
19556
|
var userSettingsSchema = createSelectSchema(userSettings, {
|
|
19329
19557
|
createdAt: exports_coerce.date(),
|
|
19330
19558
|
updatedAt: exports_coerce.date()
|
|
19331
|
-
});
|
|
19559
|
+
}).omit({ autoRollOverdue: true });
|
|
19332
19560
|
var updateUserSettingsInputSchema = createUpdateSchema(userSettings, {
|
|
19333
19561
|
displayName: string2().trim().max(80).nullish(),
|
|
19334
19562
|
avatarUrl: union([string2().url().max(2048), literal("")]).nullish(),
|
|
@@ -19339,9 +19567,15 @@ var updateUserSettingsInputSchema = createUpdateSchema(userSettings, {
|
|
|
19339
19567
|
accent: settingsAccentSchema.optional(),
|
|
19340
19568
|
sunCity: string2().trim().max(80).transform((city) => city === "" ? null : city).nullish(),
|
|
19341
19569
|
backdrop: backdropIdSchema.nullish(),
|
|
19342
|
-
enabledModules: array(string2().trim().min(1)).transform(normalizeEnabledModules).optional()
|
|
19343
|
-
|
|
19344
|
-
|
|
19570
|
+
enabledModules: array(string2().trim().min(1)).transform(normalizeEnabledModules).optional()
|
|
19571
|
+
}).omit({
|
|
19572
|
+
id: true,
|
|
19573
|
+
tenantId: true,
|
|
19574
|
+
userId: true,
|
|
19575
|
+
createdAt: true,
|
|
19576
|
+
updatedAt: true,
|
|
19577
|
+
autoRollOverdue: true
|
|
19578
|
+
}).strict();
|
|
19345
19579
|
|
|
19346
19580
|
// ../../packages/schema/src/contracts/shopping.ts
|
|
19347
19581
|
var shoppingRecurrenceUnitSchema = _enum2(["day", "week", "month"]);
|
|
@@ -19607,7 +19841,8 @@ var timeBlockTaskSchema = object({
|
|
|
19607
19841
|
id: ulidSchema,
|
|
19608
19842
|
title: string2(),
|
|
19609
19843
|
status: string2(),
|
|
19610
|
-
areaId: string2().nullable()
|
|
19844
|
+
areaId: string2().nullable(),
|
|
19845
|
+
projectId: string2().nullable().optional()
|
|
19611
19846
|
});
|
|
19612
19847
|
var timeBlockViewSchema = timeBlockSchema.extend({
|
|
19613
19848
|
title: string2(),
|
|
@@ -19687,7 +19922,12 @@ var agentChangeSchema = object({
|
|
|
19687
19922
|
changedAt: exports_coerce.date(),
|
|
19688
19923
|
title: string2().nullable(),
|
|
19689
19924
|
actor: actorRefSchema,
|
|
19690
|
-
fields: array(agentChangeFieldSchema).optional()
|
|
19925
|
+
fields: array(agentChangeFieldSchema).optional(),
|
|
19926
|
+
checkIn: object({
|
|
19927
|
+
value: number2(),
|
|
19928
|
+
unit: string2().nullable(),
|
|
19929
|
+
measurementType: habitMeasurementTypeSchema
|
|
19930
|
+
}).optional()
|
|
19691
19931
|
});
|
|
19692
19932
|
var agentChangesPageSchema = object({
|
|
19693
19933
|
data: array(agentChangeSchema),
|
|
@@ -20843,7 +21083,7 @@ function parseCapture2(input, now) {
|
|
|
20843
21083
|
|
|
20844
21084
|
// src/meta.ts
|
|
20845
21085
|
var CLI_NAME = "do";
|
|
20846
|
-
var VERSION = "1.
|
|
21086
|
+
var VERSION = "1.162.0";
|
|
20847
21087
|
var API_PREFIX = "/api/v1";
|
|
20848
21088
|
var DEFAULT_API_URL = "http://localhost:3001";
|
|
20849
21089
|
|
|
@@ -21066,7 +21306,7 @@ var ENTITIES = [
|
|
|
21066
21306
|
listFlags: [
|
|
21067
21307
|
{
|
|
21068
21308
|
name: "filter",
|
|
21069
|
-
description: "all (default), unsorted (the
|
|
21309
|
+
description: "all (default), unsorted (the Inbox's tasks to file: no day, Deadline, Area or Project; never a proposal) or starred",
|
|
21070
21310
|
query: "filter"
|
|
21071
21311
|
},
|
|
21072
21312
|
{ ...AREA_FLAG, description: "only tasks in this area id (a project task by its project's)" },
|
|
@@ -21087,7 +21327,17 @@ var ENTITIES = [
|
|
|
21087
21327
|
description: "waiting on: me, member:<id|email>, agent:<id|name>, any or none"
|
|
21088
21328
|
},
|
|
21089
21329
|
{ name: "completedSince", description: "finished at or after this instant (ISO or date)" },
|
|
21090
|
-
{ name: "completedBefore", description: "finished before this instant (ISO or date)" }
|
|
21330
|
+
{ name: "completedBefore", description: "finished before this instant (ISO or date)" },
|
|
21331
|
+
{
|
|
21332
|
+
name: "proposed",
|
|
21333
|
+
description: "only tasks Proposed by Echo (made by an Agent for a member, not accepted yet); --proposed=false for only the plan",
|
|
21334
|
+
boolean: true
|
|
21335
|
+
},
|
|
21336
|
+
{
|
|
21337
|
+
name: "ready",
|
|
21338
|
+
description: "only open tasks their Owner marked Ready for you; --ready=false for the rest",
|
|
21339
|
+
boolean: true
|
|
21340
|
+
}
|
|
21091
21341
|
],
|
|
21092
21342
|
write: {
|
|
21093
21343
|
scope: "tasks:write",
|
|
@@ -21104,7 +21354,14 @@ var ENTITIES = [
|
|
|
21104
21354
|
readScope: "habits:read",
|
|
21105
21355
|
returns: "HabitSummary",
|
|
21106
21356
|
canGet: true,
|
|
21107
|
-
listFlags: [
|
|
21357
|
+
listFlags: [
|
|
21358
|
+
AREA_FLAG,
|
|
21359
|
+
UPDATED_SINCE_FLAG,
|
|
21360
|
+
{
|
|
21361
|
+
name: "retired",
|
|
21362
|
+
description: "list the Grown shelf (retired habits) instead of the growing ones"
|
|
21363
|
+
}
|
|
21364
|
+
],
|
|
21108
21365
|
write: {
|
|
21109
21366
|
scope: "habits:write",
|
|
21110
21367
|
createSchema: createHabitInputSchema,
|
|
@@ -21144,7 +21401,15 @@ var ENTITIES = [
|
|
|
21144
21401
|
readScope: "areas:read",
|
|
21145
21402
|
returns: "AreaView",
|
|
21146
21403
|
canGet: true,
|
|
21147
|
-
listFlags: [
|
|
21404
|
+
listFlags: [
|
|
21405
|
+
{
|
|
21406
|
+
name: "active",
|
|
21407
|
+
description: "only live areas (not archived)",
|
|
21408
|
+
query: "archived",
|
|
21409
|
+
sends: "false"
|
|
21410
|
+
},
|
|
21411
|
+
{ name: "archived", description: "only archived areas", query: "archived", sends: "true" }
|
|
21412
|
+
],
|
|
21148
21413
|
write: {
|
|
21149
21414
|
scope: "areas:write",
|
|
21150
21415
|
createSchema: createAreaInputSchema,
|
|
@@ -21355,6 +21620,11 @@ var PAGINATION_FLAGS = [
|
|
|
21355
21620
|
description: "Opaque keyset cursor from a previous page's nextCursor."
|
|
21356
21621
|
}
|
|
21357
21622
|
];
|
|
21623
|
+
var STANDARD_LINK_FLAGS = [
|
|
21624
|
+
{ name: "habit", type: "string", description: "Held by this habit (its id)." },
|
|
21625
|
+
{ name: "task", type: "string", description: "Held by this recurring task (its id)." },
|
|
21626
|
+
{ name: "metric", type: "string", description: "Held by this Metric: weight, sleep or mood." }
|
|
21627
|
+
];
|
|
21358
21628
|
var GLOBAL_FLAGS = [
|
|
21359
21629
|
{ name: "json", type: "boolean", description: "Emit JSON (automatic when stdout is piped)." },
|
|
21360
21630
|
{ name: "quiet", type: "boolean", description: "Suppress human output (errors still report)." },
|
|
@@ -21408,12 +21678,37 @@ var COMMAND_SPECS = [
|
|
|
21408
21678
|
},
|
|
21409
21679
|
{
|
|
21410
21680
|
path: ["today"],
|
|
21411
|
-
summary: "Show today's actionable tasks (scheduled, due, overdue, in-progress).",
|
|
21681
|
+
summary: "Show today's actionable tasks (scheduled, due, overdue, in-progress), then the habits and routines due today.",
|
|
21412
21682
|
args: [],
|
|
21413
21683
|
flags: [],
|
|
21414
21684
|
scopes: ["tasks:read"],
|
|
21415
21685
|
returns: "TodaySummary",
|
|
21416
|
-
notes: "
|
|
21686
|
+
notes: "Tasks are composed client-side from GET /api/v1/tasks (the local day from your clock); habits and routines come from GET /api/v1/habits/today (your saved time zone's day) under `habits`, left out when the key lacks habits:read."
|
|
21687
|
+
},
|
|
21688
|
+
{
|
|
21689
|
+
path: ["today", "earlier"],
|
|
21690
|
+
summary: "From earlier: planned tasks of the last 14 days that weren't done, newest first, and the day Later this week lands on.",
|
|
21691
|
+
args: [],
|
|
21692
|
+
flags: [{ name: "area", type: "string", description: "Only tasks in this Area (id)." }],
|
|
21693
|
+
scopes: ["tasks:read"],
|
|
21694
|
+
returns: "FromEarlierResponse",
|
|
21695
|
+
notes: "GET /api/v1/today/from-earlier, from your local day. Nothing here is late: timed tasks, time blocks and agents' work never roll, and a plan older than 14 days just waits where it was filed. Answer with `do today answer`."
|
|
21696
|
+
},
|
|
21697
|
+
{
|
|
21698
|
+
path: ["today", "answer"],
|
|
21699
|
+
summary: "Answer From earlier for one or more tasks: today, later (this week), someday or let-go.",
|
|
21700
|
+
args: [
|
|
21701
|
+
{
|
|
21702
|
+
name: "answer",
|
|
21703
|
+
required: true,
|
|
21704
|
+
description: "today (plan it today) \xB7 later (the quiet day later this week) \xB7 someday (no date, kept in its Area or Project) \xB7 let-go (close it without doing it)."
|
|
21705
|
+
},
|
|
21706
|
+
{ name: "ids", required: true, description: "One or more task ids." }
|
|
21707
|
+
],
|
|
21708
|
+
flags: [],
|
|
21709
|
+
scopes: ["tasks:write"],
|
|
21710
|
+
returns: "RolloverResult",
|
|
21711
|
+
notes: "POST /api/v1/today/rollover. `later` reads the day from `do today earlier` first. Let go is cancelled, never done, so it stays out of Landed; undo with `do task reopen`."
|
|
21417
21712
|
},
|
|
21418
21713
|
{
|
|
21419
21714
|
path: ["now"],
|
|
@@ -21474,6 +21769,15 @@ var COMMAND_SPECS = [
|
|
|
21474
21769
|
scopes: ["tasks:read", "habits:read"],
|
|
21475
21770
|
returns: "ProgressDayDetail"
|
|
21476
21771
|
},
|
|
21772
|
+
{
|
|
21773
|
+
path: ["progress", "habits"],
|
|
21774
|
+
summary: "Habits this week: a done/skipped grid, each habit's strength word, patterns and when you check in.",
|
|
21775
|
+
args: [],
|
|
21776
|
+
flags: [],
|
|
21777
|
+
scopes: ["habits:read"],
|
|
21778
|
+
returns: "ProgressHabitsResponse",
|
|
21779
|
+
notes: "GET /api/v1/progress/habits \u2014 the week is your saved timezone's, Monday first. Strength is a word (steady, building, settling-in); patterns come from the insights worker with a confidence label."
|
|
21780
|
+
},
|
|
21477
21781
|
{
|
|
21478
21782
|
path: ["search"],
|
|
21479
21783
|
summary: "Search node titles and note bodies across the Space.",
|
|
@@ -21531,6 +21835,39 @@ var COMMAND_SPECS = [
|
|
|
21531
21835
|
returns: "Task",
|
|
21532
21836
|
notes: "POST /api/v1/tasks/{id}/cancel. Use this, not `task done`, for a dropped task."
|
|
21533
21837
|
},
|
|
21838
|
+
{
|
|
21839
|
+
path: ["tasks", "accept"],
|
|
21840
|
+
summary: "Accept a task Proposed by Echo: it joins the plan as suggested (day, Deadline, Area kept).",
|
|
21841
|
+
args: [{ name: "id", required: true, description: "Task ULID." }],
|
|
21842
|
+
flags: [],
|
|
21843
|
+
scopes: ["tasks:write"],
|
|
21844
|
+
returns: "Task",
|
|
21845
|
+
notes: "POST /api/v1/tasks/{id}/accept (#889). A no-op on a task that isn't a proposal. List proposals with `do tasks list --proposed`."
|
|
21846
|
+
},
|
|
21847
|
+
{
|
|
21848
|
+
path: ["tasks", "dismiss"],
|
|
21849
|
+
summary: "Not now on a task Proposed by Echo: it leaves the Inbox for a week, still proposed.",
|
|
21850
|
+
args: [{ name: "id", required: true, description: "Task ULID." }],
|
|
21851
|
+
flags: [],
|
|
21852
|
+
scopes: ["tasks:write"],
|
|
21853
|
+
returns: "Task",
|
|
21854
|
+
notes: "POST /api/v1/tasks/{id}/not-now (#889); 409 when the task isn't a proposal. Let go is `do task cancel`."
|
|
21855
|
+
},
|
|
21856
|
+
{
|
|
21857
|
+
path: ["tasks", "ready"],
|
|
21858
|
+
summary: "Mark a task Ready for you: its Owner finished something the member should look at (a draft, a link, a worktree).",
|
|
21859
|
+
args: [{ name: "id", required: true, description: "Task ULID." }],
|
|
21860
|
+
flags: [
|
|
21861
|
+
{
|
|
21862
|
+
name: "note",
|
|
21863
|
+
type: "string",
|
|
21864
|
+
description: `What's ready, in a line, with a link when there is one ("Draft ready: 38 hours, 3,420 euro \u2014 https://\u2026"); at most 500 characters. Absent keeps the note already there.`
|
|
21865
|
+
}
|
|
21866
|
+
],
|
|
21867
|
+
scopes: ["tasks:write"],
|
|
21868
|
+
returns: "Task",
|
|
21869
|
+
notes: "POST /api/v1/tasks/{id}/ready (#902); 409 when the task is done or let go. It reaches Now's Needs you with Review (Looks good = done, Send back = `ready: false`). List them with `do tasks list --ready`."
|
|
21870
|
+
},
|
|
21534
21871
|
{
|
|
21535
21872
|
path: ["task", "reopen"],
|
|
21536
21873
|
summary: "Reopen a done or cancelled task (status todo; clears completedAt).",
|
|
@@ -21561,22 +21898,76 @@ var COMMAND_SPECS = [
|
|
|
21561
21898
|
description: "Amount logged (binary habits use 1).",
|
|
21562
21899
|
default: "1"
|
|
21563
21900
|
},
|
|
21564
|
-
{ name: "at", type: "string", description: "When it occurred (ISO); defaults to now." }
|
|
21901
|
+
{ name: "at", type: "string", description: "When it occurred (ISO); defaults to now." },
|
|
21902
|
+
{
|
|
21903
|
+
name: "note",
|
|
21904
|
+
type: "string",
|
|
21905
|
+
description: 'A short note on the check-in ("felt heavy"), at most 280 characters.'
|
|
21906
|
+
}
|
|
21565
21907
|
],
|
|
21566
21908
|
scopes: ["habits:write"],
|
|
21567
21909
|
returns: "HabitSummary"
|
|
21568
21910
|
},
|
|
21569
21911
|
{
|
|
21570
21912
|
path: ["habit", "check-in"],
|
|
21571
|
-
summary: 'Check a habit in by its title ("did my run").',
|
|
21572
|
-
args: [
|
|
21913
|
+
summary: 'Check a habit in by its title or an alias ("wake", "did my run").',
|
|
21914
|
+
args: [
|
|
21915
|
+
{ name: "title", required: true, description: "The habit's title or one of its aliases." }
|
|
21916
|
+
],
|
|
21573
21917
|
flags: [
|
|
21574
21918
|
{ name: "value", type: "string", description: "Amount logged; defaults to 1." },
|
|
21575
|
-
{
|
|
21919
|
+
{
|
|
21920
|
+
name: "set",
|
|
21921
|
+
type: "boolean",
|
|
21922
|
+
description: "Make --value the day's total instead of adding it (amount habits)."
|
|
21923
|
+
},
|
|
21924
|
+
{
|
|
21925
|
+
name: "at",
|
|
21926
|
+
type: "string",
|
|
21927
|
+
description: "When it occurred: an ISO instant, or a day (YYYY-MM-DD, your time zone); defaults to now."
|
|
21928
|
+
},
|
|
21929
|
+
{
|
|
21930
|
+
name: "note",
|
|
21931
|
+
type: "string",
|
|
21932
|
+
description: 'A short note on the check-in ("felt heavy"), at most 280 characters.'
|
|
21933
|
+
}
|
|
21934
|
+
],
|
|
21935
|
+
scopes: ["habits:write"],
|
|
21936
|
+
returns: "HabitSummary",
|
|
21937
|
+
notes: `POST /api/v1/habits/check-in. Title or alias, case-insensitive; several matches \u2192 409 with error.details.candidates (id, title, aliases), none \u2192 404 naming close titles; a habit counted from Google Fit, Strava or GitHub \u2192 409. --set writes the difference to the day's total as its own check-in. An Agent's key records the check-in as that Agent's ("Echo, 07:12"). --note puts a short note on it ("drill done, felt heavy" \u2192 --note "felt heavy"); the reply's lastCheckIn.id is the check-in, for \`do habit note\` later.`
|
|
21938
|
+
},
|
|
21939
|
+
{
|
|
21940
|
+
path: ["habit", "alias", "add"],
|
|
21941
|
+
summary: 'Give a habit another name check-ins match ("wake" for "Wake up by 07:00").',
|
|
21942
|
+
args: [
|
|
21943
|
+
{ name: "id", required: true, description: "Habit ULID." },
|
|
21944
|
+
{ name: "alias", required: true, description: "The other name." }
|
|
21576
21945
|
],
|
|
21946
|
+
flags: [],
|
|
21577
21947
|
scopes: ["habits:write"],
|
|
21578
21948
|
returns: "HabitSummary",
|
|
21579
|
-
notes: "POST /api/v1/habits/
|
|
21949
|
+
notes: "POST /api/v1/habits/:id/aliases. One already there (ignoring case) is a no-op; at most 12."
|
|
21950
|
+
},
|
|
21951
|
+
{
|
|
21952
|
+
path: ["habit", "alias", "rm"],
|
|
21953
|
+
summary: "Drop one of a habit's aliases.",
|
|
21954
|
+
args: [
|
|
21955
|
+
{ name: "id", required: true, description: "Habit ULID." },
|
|
21956
|
+
{ name: "alias", required: true, description: "The alias to drop (ignoring case)." }
|
|
21957
|
+
],
|
|
21958
|
+
flags: [],
|
|
21959
|
+
scopes: ["habits:write"],
|
|
21960
|
+
returns: "HabitSummary",
|
|
21961
|
+
notes: "DELETE /api/v1/habits/:id/aliases/:alias. 404 when the habit doesn't have it."
|
|
21962
|
+
},
|
|
21963
|
+
{
|
|
21964
|
+
path: ["habits", "today"],
|
|
21965
|
+
summary: "What's left today: the habits due by part of day, and today's routines.",
|
|
21966
|
+
args: [],
|
|
21967
|
+
flags: [],
|
|
21968
|
+
scopes: ["habits:read"],
|
|
21969
|
+
returns: "HabitsTodayResponse",
|
|
21970
|
+
notes: "GET /api/v1/habits/today. Your saved time zone's day; already filtered by schedule. Each habit says done/open/skipped (never overdue), its value today, the week for an N-per-week habit and its last check-in (`by` names the Agent). Quit habits are left out."
|
|
21580
21971
|
},
|
|
21581
21972
|
{
|
|
21582
21973
|
path: ["habit", "check-ins"],
|
|
@@ -21589,6 +21980,149 @@ var COMMAND_SPECS = [
|
|
|
21589
21980
|
scopes: ["habits:read"],
|
|
21590
21981
|
returns: "HabitEntry"
|
|
21591
21982
|
},
|
|
21983
|
+
{
|
|
21984
|
+
path: ["habit", "note"],
|
|
21985
|
+
summary: 'Put a note on a check-in afterwards ("felt heavy"), or clear it.',
|
|
21986
|
+
args: [
|
|
21987
|
+
{ name: "id", required: true, description: "Habit ULID." },
|
|
21988
|
+
{
|
|
21989
|
+
name: "entry-id",
|
|
21990
|
+
required: true,
|
|
21991
|
+
description: "The check-in's ULID (`do habit check-ins <id>`, or lastCheckIn.id)."
|
|
21992
|
+
},
|
|
21993
|
+
{ name: "note", required: false, description: "The note, at most 280 characters." }
|
|
21994
|
+
],
|
|
21995
|
+
flags: [{ name: "clear", type: "boolean", description: "Drop the check-in's note." }],
|
|
21996
|
+
scopes: ["habits:write"],
|
|
21997
|
+
returns: "HabitEntry",
|
|
21998
|
+
notes: "PATCH /api/v1/habits/{id}/check-ins/{entryId}. Replaces the note; the amount and time stay (undo a wrong check-in instead). A skip's note is its why."
|
|
21999
|
+
},
|
|
22000
|
+
{
|
|
22001
|
+
path: ["habit", "skip"],
|
|
22002
|
+
summary: 'Skip a day: a neutral rest day, never a miss ("skip gym today").',
|
|
22003
|
+
args: [{ name: "id", required: true, description: "Habit ULID." }],
|
|
22004
|
+
flags: [
|
|
22005
|
+
{ name: "date", type: "string", description: "The day (YYYY-MM-DD); defaults to today." },
|
|
22006
|
+
{
|
|
22007
|
+
name: "note",
|
|
22008
|
+
type: "string",
|
|
22009
|
+
description: 'Why, if you like ("Dentist"); shows in the log.'
|
|
22010
|
+
}
|
|
22011
|
+
],
|
|
22012
|
+
scopes: ["habits:write"],
|
|
22013
|
+
returns: "HabitSummary",
|
|
22014
|
+
notes: "POST /api/v1/habits/{id}/skip. The streak treats the period as neutral and spends no grace; the habit leaves Now for the day. Skipping a skipped day changes nothing. Undo: delete the skip entry (`do habit check-ins <id>` lists it with kind `skip`)."
|
|
22015
|
+
},
|
|
22016
|
+
{
|
|
22017
|
+
path: ["routine", "done"],
|
|
22018
|
+
summary: `All taken: check in every open step of today's routine in one go ("took my supplements").`,
|
|
22019
|
+
args: [
|
|
22020
|
+
{
|
|
22021
|
+
name: "id",
|
|
22022
|
+
required: true,
|
|
22023
|
+
description: "Routine ULID (`do habits today` lists today's)."
|
|
22024
|
+
}
|
|
22025
|
+
],
|
|
22026
|
+
flags: [],
|
|
22027
|
+
scopes: ["routines:write"],
|
|
22028
|
+
returns: "RoutineDoneResult",
|
|
22029
|
+
notes: "POST /api/v1/routines/{id}/done. Today's run (your saved time zone's day), started if there's none. Each habit step checks in its habit; a habit already done today isn't counted twice; a step whose habit is skipped today is left alone. Calling it again changes nothing. Returns `run` and `taken` (the steps it resolved). Undo all of it with `do routine undo <run.id> <taken stepRunIds\u2026>`."
|
|
22030
|
+
},
|
|
22031
|
+
{
|
|
22032
|
+
path: ["routine", "undo"],
|
|
22033
|
+
summary: "Take an All taken back in one go: its steps reopen and lose their check-ins.",
|
|
22034
|
+
args: [
|
|
22035
|
+
{
|
|
22036
|
+
name: "runId",
|
|
22037
|
+
required: true,
|
|
22038
|
+
description: "The run's ULID (`run.id` from `do routine done`)."
|
|
22039
|
+
},
|
|
22040
|
+
{
|
|
22041
|
+
name: "stepRunIds",
|
|
22042
|
+
required: true,
|
|
22043
|
+
description: "The `taken` step ids from `do routine done`, space- or comma-separated."
|
|
22044
|
+
}
|
|
22045
|
+
],
|
|
22046
|
+
flags: [],
|
|
22047
|
+
scopes: ["routines:write"],
|
|
22048
|
+
returns: "RoutineRunView",
|
|
22049
|
+
notes: "POST /api/v1/routines/runs/{runId}/undo. Exactly the check-ins those steps wrote are removed; a finished run reopens. Steps no longer done are left alone."
|
|
22050
|
+
},
|
|
22051
|
+
{
|
|
22052
|
+
path: ["habit", "pause"],
|
|
22053
|
+
summary: "Pause a habit until the day it's back: off Now, no push, the plant waits.",
|
|
22054
|
+
args: [{ name: "id", required: true, description: "Habit ULID." }],
|
|
22055
|
+
flags: [
|
|
22056
|
+
{
|
|
22057
|
+
name: "until",
|
|
22058
|
+
type: "string",
|
|
22059
|
+
description: "The day it's back (YYYY-MM-DD), after today. Required."
|
|
22060
|
+
}
|
|
22061
|
+
],
|
|
22062
|
+
scopes: ["habits:write"],
|
|
22063
|
+
returns: "HabitSummary",
|
|
22064
|
+
notes: "POST /api/v1/habits/{id}/pause. Pausing a paused habit moves the day it's back. Paused days are neutral: the streak is frozen, never broken."
|
|
22065
|
+
},
|
|
22066
|
+
{
|
|
22067
|
+
path: ["habit", "remind"],
|
|
22068
|
+
summary: "Turn a habit's daily reminder on or off: one push at its time, never a follow-up.",
|
|
22069
|
+
args: [
|
|
22070
|
+
{ name: "id", required: true, description: "Habit ULID." },
|
|
22071
|
+
{ name: "state", required: true, description: "`on` or `off`." }
|
|
22072
|
+
],
|
|
22073
|
+
flags: [],
|
|
22074
|
+
scopes: ["habits:write"],
|
|
22075
|
+
returns: "HabitSummary",
|
|
22076
|
+
notes: "PATCH /api/v1/habits/{id} {remind}. Off by default. On, the habit sends one Web Push a day at its time of day (a part of day: morning 08:00, midday 12:00, evening 18:00; none: 09:00), only in waking hours (07:00\u201322:00), with Done / +1 / Skip today buttons; not when it's done, skipped, paused or off today."
|
|
22077
|
+
},
|
|
22078
|
+
{
|
|
22079
|
+
path: ["habit", "resume"],
|
|
22080
|
+
summary: "Resume a paused habit: it's back today.",
|
|
22081
|
+
args: [{ name: "id", required: true, description: "Habit ULID." }],
|
|
22082
|
+
flags: [],
|
|
22083
|
+
scopes: ["habits:write"],
|
|
22084
|
+
returns: "HabitSummary",
|
|
22085
|
+
notes: "POST /api/v1/habits/{id}/resume. The rest so far stays neutral."
|
|
22086
|
+
},
|
|
22087
|
+
{
|
|
22088
|
+
path: ["habit", "retire"],
|
|
22089
|
+
summary: `Retire a habit to the Grown shelf ("I'm done with the cold showers habit"): history kept.`,
|
|
22090
|
+
args: [{ name: "id", required: true, description: "Habit ULID." }],
|
|
22091
|
+
flags: [],
|
|
22092
|
+
scopes: ["habits:write"],
|
|
22093
|
+
returns: "HabitSummary",
|
|
22094
|
+
notes: "POST /api/v1/habits/{id}/retire. Not a delete: it keeps every check-in and its plant blooms on the Grown shelf. It leaves Now and Today, sends no push, takes no check-in by title and is never due; Progress keeps its past. `do habits list --retired` lists the shelf. Undo: `do habit unretire <id>`."
|
|
22095
|
+
},
|
|
22096
|
+
{
|
|
22097
|
+
path: ["habit", "unretire"],
|
|
22098
|
+
summary: "Bring a grown (retired) habit back: growing again from today.",
|
|
22099
|
+
args: [{ name: "id", required: true, description: "Habit ULID." }],
|
|
22100
|
+
flags: [],
|
|
22101
|
+
scopes: ["habits:write"],
|
|
22102
|
+
returns: "HabitSummary",
|
|
22103
|
+
notes: "POST /api/v1/habits/{id}/unretire. Its history is intact."
|
|
22104
|
+
},
|
|
22105
|
+
{
|
|
22106
|
+
path: ["away"],
|
|
22107
|
+
summary: 'Away until a day ("away till Monday"): every habit rests. `do away off` comes back.',
|
|
22108
|
+
args: [
|
|
22109
|
+
{
|
|
22110
|
+
name: "off",
|
|
22111
|
+
required: false,
|
|
22112
|
+
description: "`off` comes back now; omit it (and --until) to show the away state."
|
|
22113
|
+
}
|
|
22114
|
+
],
|
|
22115
|
+
flags: [
|
|
22116
|
+
{
|
|
22117
|
+
name: "until",
|
|
22118
|
+
type: "string",
|
|
22119
|
+
description: "The day you're back (YYYY-MM-DD), after today."
|
|
22120
|
+
}
|
|
22121
|
+
],
|
|
22122
|
+
scopes: ["habits:read", "habits:write"],
|
|
22123
|
+
returns: "AwayState",
|
|
22124
|
+
notes: "GET/PUT /api/v1/habits/away. While away, habits leave Now, reminders stop and plants wait; tasks and events carry on. Reading needs habits:read, setting habits:write."
|
|
22125
|
+
},
|
|
21592
22126
|
{
|
|
21593
22127
|
path: ["metrics", "list"],
|
|
21594
22128
|
summary: "Show weight, sleep and mood as daily trend lines (no target, no streak).",
|
|
@@ -22079,6 +22613,66 @@ var COMMAND_SPECS = [
|
|
|
22079
22613
|
returns: "CollectionCoverBackfillResult",
|
|
22080
22614
|
notes: "Returns { checked, found }; run again while checked is 25 to work through more."
|
|
22081
22615
|
},
|
|
22616
|
+
{
|
|
22617
|
+
path: ["areas", "purpose"],
|
|
22618
|
+
summary: "Set an Area's purpose: one line of what it's for.",
|
|
22619
|
+
args: [
|
|
22620
|
+
{ name: "id", required: true, description: "The Area's id." },
|
|
22621
|
+
{ name: "line", required: false, description: "The purpose, in one line (words join)." }
|
|
22622
|
+
],
|
|
22623
|
+
flags: [{ name: "clear", type: "boolean", description: "Remove the purpose." }],
|
|
22624
|
+
scopes: ["areas:write"],
|
|
22625
|
+
returns: "AreaView",
|
|
22626
|
+
notes: "PATCH /api/v1/areas/:id { purpose }. It shows under the Area's name on the hub."
|
|
22627
|
+
},
|
|
22628
|
+
{
|
|
22629
|
+
path: ["areas", "standards", "list"],
|
|
22630
|
+
summary: "List an Area's standards with how each is doing (holding / worth a look).",
|
|
22631
|
+
args: [{ name: "id", required: true, description: "The Area's id." }],
|
|
22632
|
+
flags: [],
|
|
22633
|
+
scopes: ["areas:read"],
|
|
22634
|
+
returns: "AreaStandardView",
|
|
22635
|
+
notes: "Each linked standard says holding or worth a look with the reason in words; an unlinked one has no state (it's checked by hand in review)."
|
|
22636
|
+
},
|
|
22637
|
+
{
|
|
22638
|
+
path: ["areas", "standards", "add"],
|
|
22639
|
+
summary: "Add a standard (what fine looks like) to an Area; up to five.",
|
|
22640
|
+
args: [
|
|
22641
|
+
{ name: "id", required: true, description: "The Area's id." },
|
|
22642
|
+
{ name: "text", required: true, description: "The standard, a plain sentence (words join)." }
|
|
22643
|
+
],
|
|
22644
|
+
flags: STANDARD_LINK_FLAGS,
|
|
22645
|
+
scopes: ["areas:write"],
|
|
22646
|
+
returns: "AreaDetail",
|
|
22647
|
+
notes: "POST /api/v1/areas/:id/standards. Echo adds standards only after the member said yes; the change list keeps Undo."
|
|
22648
|
+
},
|
|
22649
|
+
{
|
|
22650
|
+
path: ["areas", "standards", "link"],
|
|
22651
|
+
summary: "Change what holds a standard: a habit, a recurring task, a Metric, or none.",
|
|
22652
|
+
args: [
|
|
22653
|
+
{ name: "id", required: true, description: "The Area's id." },
|
|
22654
|
+
{ name: "standard", required: true, description: "The standard's id." }
|
|
22655
|
+
],
|
|
22656
|
+
flags: [
|
|
22657
|
+
...STANDARD_LINK_FLAGS,
|
|
22658
|
+
{ name: "none", type: "boolean", description: "Unlink it: checked by hand in review." }
|
|
22659
|
+
],
|
|
22660
|
+
scopes: ["areas:write"],
|
|
22661
|
+
returns: "AreaDetail",
|
|
22662
|
+
notes: "PATCH /api/v1/areas/:id/standards/:standardId { link }."
|
|
22663
|
+
},
|
|
22664
|
+
{
|
|
22665
|
+
path: ["areas", "standards", "rm"],
|
|
22666
|
+
summary: "Remove a standard from an Area.",
|
|
22667
|
+
args: [
|
|
22668
|
+
{ name: "id", required: true, description: "The Area's id." },
|
|
22669
|
+
{ name: "standard", required: true, description: "The standard's id." }
|
|
22670
|
+
],
|
|
22671
|
+
flags: [],
|
|
22672
|
+
scopes: ["areas:write"],
|
|
22673
|
+
returns: "AreaDetail",
|
|
22674
|
+
notes: "DELETE /api/v1/areas/:id/standards/:standardId."
|
|
22675
|
+
},
|
|
22082
22676
|
{
|
|
22083
22677
|
path: ["places", "import"],
|
|
22084
22678
|
summary: "Import the rooms of the house once from Gaard's house.json.",
|
|
@@ -22756,15 +23350,124 @@ function renderTask(data, mode) {
|
|
|
22756
23350
|
}
|
|
22757
23351
|
function renderToday(data, mode) {
|
|
22758
23352
|
const result = data;
|
|
22759
|
-
|
|
22760
|
-
|
|
22761
|
-
|
|
22762
|
-
|
|
22763
|
-
|
|
22764
|
-
|
|
22765
|
-
|
|
22766
|
-
|
|
22767
|
-
|
|
23353
|
+
const tasks = result.count === 0 ? paint(mode, "green", `Nothing scheduled for ${result.date}. Inbox zero. \u2713`) : [
|
|
23354
|
+
paint(mode, "bold", `Today \xB7 ${result.date} \xB7 ${result.count} item(s)`),
|
|
23355
|
+
...result.items.map((item) => {
|
|
23356
|
+
const tag = paint(mode, bucketColor(item.bucket), `[${item.bucket}]`);
|
|
23357
|
+
const star = item.starred ? paint(mode, "yellow", " \u2605") : "";
|
|
23358
|
+
return ` ${tag} ${item.title}${star} ${paint(mode, "dim", item.id)}`;
|
|
23359
|
+
})
|
|
23360
|
+
].join(`
|
|
23361
|
+
`);
|
|
23362
|
+
const habits = result.habits ? habitLines(result.habits, mode) : [];
|
|
23363
|
+
return habits.length > 0 ? `${tasks}
|
|
23364
|
+
|
|
23365
|
+
${habits.join(`
|
|
23366
|
+
`)}` : tasks;
|
|
23367
|
+
}
|
|
23368
|
+
var DAY_MS = 24 * 60 * 60 * 1000;
|
|
23369
|
+
function plannedDay(at, from) {
|
|
23370
|
+
if (!at)
|
|
23371
|
+
return "earlier";
|
|
23372
|
+
const day = new Date(at);
|
|
23373
|
+
const ago = from ? Math.round((Date.parse(from) - day.getTime()) / DAY_MS) : 7;
|
|
23374
|
+
if (ago <= 1)
|
|
23375
|
+
return "yesterday";
|
|
23376
|
+
if (ago < 7)
|
|
23377
|
+
return day.toLocaleDateString("en-GB", { weekday: "long" });
|
|
23378
|
+
return day.toLocaleDateString("en-GB", { day: "numeric", month: "short" });
|
|
23379
|
+
}
|
|
23380
|
+
function renderFromEarlier(data, mode) {
|
|
23381
|
+
const d = data;
|
|
23382
|
+
const tasks = d.tasks ?? [];
|
|
23383
|
+
if (tasks.length === 0)
|
|
23384
|
+
return paint(mode, "dim", "Nothing from earlier.");
|
|
23385
|
+
const later = d.laterThisWeek ? new Date(d.laterThisWeek).toLocaleDateString("en-GB", { weekday: "long" }) : null;
|
|
23386
|
+
return [
|
|
23387
|
+
paint(mode, "bold", "From earlier \xB7 planned, not done. Nothing is late."),
|
|
23388
|
+
...tasks.map((t) => ` \xB7 ${t.title ?? "(untitled)"} ${paint(mode, "dim", `\u2014 planned ${plannedDay(t.scheduledAt, d.from)}`)} ${paint(mode, "dim", t.id)}`),
|
|
23389
|
+
"",
|
|
23390
|
+
paint(mode, "dim", `Answer with \`do today answer <today|later|someday|let-go> <id\u2026>\`${later ? `; later is ${later}` : ""}.`)
|
|
23391
|
+
].join(`
|
|
23392
|
+
`);
|
|
23393
|
+
}
|
|
23394
|
+
function renderFromEarlierAnswer(data, mode) {
|
|
23395
|
+
const d = data;
|
|
23396
|
+
const n = d.tasks ?? 0;
|
|
23397
|
+
const tasks = `${n} task${n === 1 ? "" : "s"}`;
|
|
23398
|
+
if (n === 0)
|
|
23399
|
+
return paint(mode, "dim", "Nothing changed: those tasks are already done, let go or gone.");
|
|
23400
|
+
switch (d.answer) {
|
|
23401
|
+
case "today":
|
|
23402
|
+
return `Planned for today: ${tasks}.`;
|
|
23403
|
+
case "later":
|
|
23404
|
+
return `Planned ${d.to ? new Date(d.to).toLocaleDateString("en-GB", { weekday: "long" }) : "later this week"}: ${tasks}.`;
|
|
23405
|
+
case "someday":
|
|
23406
|
+
return `Moved to Someday: ${tasks}, kept where they were filed.`;
|
|
23407
|
+
default:
|
|
23408
|
+
return `Let go: ${tasks}. ${paint(mode, "dim", "Changed your mind? `do task reopen <id>`.")}`;
|
|
23409
|
+
}
|
|
23410
|
+
}
|
|
23411
|
+
var PART_LABEL = {
|
|
23412
|
+
morning: "Morning",
|
|
23413
|
+
midday: "Midday",
|
|
23414
|
+
evening: "Evening",
|
|
23415
|
+
anytime: "Any time today"
|
|
23416
|
+
};
|
|
23417
|
+
function clock(at, timezone) {
|
|
23418
|
+
return new Intl.DateTimeFormat("en-GB", {
|
|
23419
|
+
timeZone: timezone,
|
|
23420
|
+
hour: "2-digit",
|
|
23421
|
+
minute: "2-digit",
|
|
23422
|
+
hourCycle: "h23"
|
|
23423
|
+
}).format(new Date(at));
|
|
23424
|
+
}
|
|
23425
|
+
function civilDay(at, timezone) {
|
|
23426
|
+
return new Intl.DateTimeFormat("en-CA", {
|
|
23427
|
+
timeZone: timezone,
|
|
23428
|
+
year: "numeric",
|
|
23429
|
+
month: "2-digit",
|
|
23430
|
+
day: "2-digit"
|
|
23431
|
+
}).format(new Date(at));
|
|
23432
|
+
}
|
|
23433
|
+
function habitLines(day, mode) {
|
|
23434
|
+
const lines = [];
|
|
23435
|
+
for (const group of day.groups) {
|
|
23436
|
+
lines.push(paint(mode, "bold", PART_LABEL[group.part]));
|
|
23437
|
+
for (const h of group.habits) {
|
|
23438
|
+
const mark = h.state === "done" ? paint(mode, "green", "\u2713") : h.state === "skipped" ? paint(mode, "dim", "\u2013") : "\u25CB";
|
|
23439
|
+
const meta = [];
|
|
23440
|
+
if (h.timeOfDay)
|
|
23441
|
+
meta.push(h.timeOfDay);
|
|
23442
|
+
if (h.target !== null && h.measurementType !== "binary") {
|
|
23443
|
+
meta.push(`${h.value} of ${h.target}${h.unit ? ` ${h.unit}` : ""}`);
|
|
23444
|
+
}
|
|
23445
|
+
if (h.week)
|
|
23446
|
+
meta.push(`${h.week.done} of ${h.week.target} this week`);
|
|
23447
|
+
if (h.last?.by && civilDay(h.last.at, day.timezone) === day.date) {
|
|
23448
|
+
meta.push(`${h.last.by}, ${clock(h.last.at, day.timezone)}`);
|
|
23449
|
+
}
|
|
23450
|
+
const tail = meta.length > 0 ? paint(mode, "dim", ` \xB7 ${meta.join(" \xB7 ")}`) : "";
|
|
23451
|
+
lines.push(` ${mark} ${h.title}${tail} ${paint(mode, "dim", h.habitId)}`);
|
|
23452
|
+
}
|
|
23453
|
+
}
|
|
23454
|
+
if (day.routines.length > 0) {
|
|
23455
|
+
lines.push(paint(mode, "bold", "Routines"));
|
|
23456
|
+
for (const r of day.routines) {
|
|
23457
|
+
const when = r.timeOfDay ? ` ${r.timeOfDay}` : "";
|
|
23458
|
+
const steps = paint(mode, "dim", ` \xB7 ${r.stepsDone} of ${r.stepsTotal} steps`);
|
|
23459
|
+
lines.push(` ${r.title}${when}${steps} ${paint(mode, "dim", r.routineId)}`);
|
|
23460
|
+
}
|
|
23461
|
+
}
|
|
23462
|
+
return lines;
|
|
23463
|
+
}
|
|
23464
|
+
function renderHabitsToday(data, mode) {
|
|
23465
|
+
const day = data;
|
|
23466
|
+
const lines = habitLines(day, mode);
|
|
23467
|
+
const header = paint(mode, "bold", `Habits \xB7 ${day.date} (${day.timezone})`);
|
|
23468
|
+
if (lines.length === 0)
|
|
23469
|
+
return `${header}
|
|
23470
|
+
Nothing due today.`;
|
|
22768
23471
|
return [header, ...lines].join(`
|
|
22769
23472
|
`);
|
|
22770
23473
|
}
|
|
@@ -22779,13 +23482,45 @@ function bucketColor(bucket) {
|
|
|
22779
23482
|
}
|
|
22780
23483
|
function renderHabit(data, mode) {
|
|
22781
23484
|
const h = data;
|
|
23485
|
+
if (h.retiredAt) {
|
|
23486
|
+
return `${h.title ?? "(habit)"} \u2014 grown ${h.retiredAt.slice(0, 10)}, on the Grown shelf with its history
|
|
23487
|
+
${paint(mode, "dim", h.id)}`;
|
|
23488
|
+
}
|
|
22782
23489
|
const streak = h.streak;
|
|
22783
23490
|
const flame = streak?.satisfiedToday ? paint(mode, "green", "\u2713 today") : "not yet today";
|
|
22784
23491
|
const pct = typeof streak?.completionRate === "number" ? ` \xB7 ${Math.round(streak.completionRate * 100)}% lately` : "";
|
|
22785
23492
|
const recovering = streak?.state === "recovering" ? paint(mode, "yellow", " \xB7 recovering") : "";
|
|
22786
23493
|
const counts = streak ? ` \xB7 streak ${streak.current ?? 0} (best ${streak.longest ?? 0})` : "";
|
|
22787
|
-
|
|
22788
|
-
|
|
23494
|
+
const rest = h.pause ? ` \xB7 ${h.pause.by === "away" ? "away" : "paused"}, back ${h.pause.until}` : streak?.skippedToday ? " \xB7 rest day" : "";
|
|
23495
|
+
const last = h.lastCheckIn?.id ? `
|
|
23496
|
+
${paint(mode, "dim", `last check-in ${h.lastCheckIn.id}`)}${h.lastCheckIn.note ? ` "${h.lastCheckIn.note}"` : ""}` : "";
|
|
23497
|
+
return `${h.title ?? "(habit)"} \u2014 ${flame}${pct}${counts}${recovering}${rest}
|
|
23498
|
+
${paint(mode, "dim", h.id)}${last}`;
|
|
23499
|
+
}
|
|
23500
|
+
function renderHabitEntry(data, mode) {
|
|
23501
|
+
const e = data;
|
|
23502
|
+
const said = e.note ? `Noted: "${e.note}"` : "No note.";
|
|
23503
|
+
return `${said}
|
|
23504
|
+
${paint(mode, "dim", e.id ?? "")}`;
|
|
23505
|
+
}
|
|
23506
|
+
function renderRoutineDone(data, mode) {
|
|
23507
|
+
const d = data;
|
|
23508
|
+
const title = d.run?.routineTitle ?? "(routine)";
|
|
23509
|
+
const taken = d.taken ?? [];
|
|
23510
|
+
if (taken.length === 0)
|
|
23511
|
+
return `${title}: nothing left to check in today.`;
|
|
23512
|
+
const names = taken.map((t) => t.title).join(", ");
|
|
23513
|
+
const undo = `do routine undo ${d.run?.id ?? "<run>"} ${taken.map((t) => t.stepRunId).join(" ")}`;
|
|
23514
|
+
return `${title}: checked in ${names}.
|
|
23515
|
+
${paint(mode, "dim", `undo: ${undo}`)}`;
|
|
23516
|
+
}
|
|
23517
|
+
function renderRoutineUndo(data) {
|
|
23518
|
+
const run = data;
|
|
23519
|
+
return `${run.routineTitle ?? "(routine)"}: undone. Those check-ins are gone.`;
|
|
23520
|
+
}
|
|
23521
|
+
function renderAway(data) {
|
|
23522
|
+
const until = data.until;
|
|
23523
|
+
return until ? `Away until ${until}. Habits are resting; tasks carry on.` : "Here. Habits are on.";
|
|
22789
23524
|
}
|
|
22790
23525
|
function renderWhoami(data, mode) {
|
|
22791
23526
|
const w = data;
|
|
@@ -23011,10 +23746,15 @@ function renderNow(data, mode) {
|
|
|
23011
23746
|
const waiting = now.waitingOnYou ?? [];
|
|
23012
23747
|
const head = paint(mode, "bold", `Waiting on ${actorText(now.for)} \xB7 ${waiting.length}`);
|
|
23013
23748
|
const lines = waiting.length ? waiting.map((t) => taskLine(t, mode)) : [paint(mode, "dim", " nothing is waiting on you")];
|
|
23749
|
+
const ready = now.readyForYou ?? [];
|
|
23750
|
+
const readyLines = ready.length ? [
|
|
23751
|
+
paint(mode, "bold", "Ready for you"),
|
|
23752
|
+
...ready.map((t) => taskLine(t, mode) + (t.readyNote ? paint(mode, "dim", ` \u2014 ${t.readyNote}`) : ""))
|
|
23753
|
+
] : [];
|
|
23014
23754
|
const tl = now.timeline ?? {};
|
|
23015
23755
|
const count = (xs) => xs?.length ?? 0;
|
|
23016
23756
|
const timeline = paint(mode, "dim", `Today: ${count(tl.scheduledTasks)} scheduled \xB7 ${count(tl.dueOccurrences)} due \xB7 ${count(tl.overdueTasks) + count(tl.overdueOccurrences)} overdue`);
|
|
23017
|
-
return [head, ...lines, timeline].join(`
|
|
23757
|
+
return [head, ...lines, ...readyLines, timeline].join(`
|
|
23018
23758
|
`);
|
|
23019
23759
|
}
|
|
23020
23760
|
function renderLanded(data, mode) {
|
|
@@ -23076,6 +23816,44 @@ function renderProgress(data, mode) {
|
|
|
23076
23816
|
return out.join(`
|
|
23077
23817
|
`);
|
|
23078
23818
|
}
|
|
23819
|
+
var CELL = {
|
|
23820
|
+
done: "\u25A0",
|
|
23821
|
+
skipped: "\u2013",
|
|
23822
|
+
empty: "\xB7",
|
|
23823
|
+
ahead: " "
|
|
23824
|
+
};
|
|
23825
|
+
var hh = (h) => `${String(h).padStart(2, "0")}:00`;
|
|
23826
|
+
var usually = (when) => when?.usual ? `usually ${hh(when.usual.from)}\u2013${hh(when.usual.to)}` : null;
|
|
23827
|
+
function renderProgressHabits(data, mode) {
|
|
23828
|
+
const p = data;
|
|
23829
|
+
const out = [
|
|
23830
|
+
paint(mode, "bold", `Habits \xB7 week of ${p.week?.from ?? "?"} \u2192 ${p.week?.to ?? "?"} (${p.timezone ?? "?"})`)
|
|
23831
|
+
];
|
|
23832
|
+
const habits = p.habits ?? [];
|
|
23833
|
+
if (habits.length === 0)
|
|
23834
|
+
out.push(paint(mode, "dim", " (no habits yet)"));
|
|
23835
|
+
const width = Math.max(0, ...habits.map((h) => h.name.length));
|
|
23836
|
+
for (const h of habits) {
|
|
23837
|
+
const cells = h.week.map((d) => CELL[d.state]).join(" ");
|
|
23838
|
+
const count = h.weekOf === null ? `${h.weekDone} done` : `${h.weekDone} of ${h.weekOf}`;
|
|
23839
|
+
const extra = [h.strengthWord.replace("-", " "), usually(h.when)].filter(Boolean).join(" \xB7 ");
|
|
23840
|
+
out.push(` ${h.name.padEnd(width)} ${cells} ${count} \xB7 ${extra}`);
|
|
23841
|
+
}
|
|
23842
|
+
const patterns = p.patterns ?? [];
|
|
23843
|
+
out.push("", paint(mode, "bold", "Patterns"));
|
|
23844
|
+
if (patterns.length === 0) {
|
|
23845
|
+
out.push(paint(mode, "dim", " (none yet: patterns need a few weeks of check-ins)"));
|
|
23846
|
+
}
|
|
23847
|
+
for (const x of patterns) {
|
|
23848
|
+
out.push(` ${x.title}`, ` ${x.body}`, ` ${paint(mode, "dim", x.confidenceLabel)}`);
|
|
23849
|
+
}
|
|
23850
|
+
const when = usually(p.when);
|
|
23851
|
+
if (when && p.when) {
|
|
23852
|
+
out.push("", `When ${when} (${Math.round((p.when.usual?.share ?? 0) * 100)}% of ${p.when.checkins} check-ins)`);
|
|
23853
|
+
}
|
|
23854
|
+
return out.join(`
|
|
23855
|
+
`);
|
|
23856
|
+
}
|
|
23079
23857
|
function renderProgressDay(data, mode) {
|
|
23080
23858
|
const d = data;
|
|
23081
23859
|
const done = d.done ?? [];
|
|
@@ -23113,6 +23891,18 @@ function renderMcpTools(data, mode) {
|
|
|
23113
23891
|
return [paint(mode, "bold", `${tools.length} tools`), ...lines].join(`
|
|
23114
23892
|
`);
|
|
23115
23893
|
}
|
|
23894
|
+
function renderStandards(data, mode) {
|
|
23895
|
+
const list = Array.isArray(data) ? data : [];
|
|
23896
|
+
if (list.length === 0)
|
|
23897
|
+
return paint(mode, "dim", "No standards yet.");
|
|
23898
|
+
return list.map((s) => {
|
|
23899
|
+
const state = s.state === "holding" ? `Holding${s.why ? `: ${s.why}` : ""}` : s.state === "worth_a_look" ? `Worth a look${s.why ? `: ${s.why}` : ""}` : "Checked by hand, in review";
|
|
23900
|
+
const held = s.heldBy ? ` \xB7 ${s.heldBy}` : "";
|
|
23901
|
+
return ` \xB7 ${s.text ?? "(untitled)"}
|
|
23902
|
+
${paint(mode, "dim", `${state}${held} ${s.id ?? ""}`)}`;
|
|
23903
|
+
}).join(`
|
|
23904
|
+
`);
|
|
23905
|
+
}
|
|
23116
23906
|
|
|
23117
23907
|
// src/today.ts
|
|
23118
23908
|
var OPEN_STATUSES = new Set(["todo", "in_progress"]);
|
|
@@ -23229,9 +24019,19 @@ async function dispatchEntity(entity, rest, flags, requireClient) {
|
|
|
23229
24019
|
if (op === "list") {
|
|
23230
24020
|
const query = {};
|
|
23231
24021
|
for (const f of entity.listFlags) {
|
|
23232
|
-
const
|
|
24022
|
+
const key = f.query ?? f.name;
|
|
24023
|
+
if (f.sends !== undefined) {
|
|
24024
|
+
if (flags[f.name] === undefined)
|
|
24025
|
+
continue;
|
|
24026
|
+
const other = entity.listFlags.find((o) => o !== f && o.sends !== undefined && (o.query ?? o.name) === key && (o.name in flags));
|
|
24027
|
+
if (other)
|
|
24028
|
+
throw usageError(`--${other.name} and --${f.name} can't be combined`);
|
|
24029
|
+
query[key] = f.sends;
|
|
24030
|
+
continue;
|
|
24031
|
+
}
|
|
24032
|
+
const value = flags[f.name] === true ? "true" : flagString(flags, f.name);
|
|
23233
24033
|
if (value !== undefined)
|
|
23234
|
-
query[
|
|
24034
|
+
query[key] = value;
|
|
23235
24035
|
else if (f.required)
|
|
23236
24036
|
throw usageError(`\`${entity.name} list\` requires --${f.name}`);
|
|
23237
24037
|
}
|
|
@@ -23347,11 +24147,58 @@ var HANDLERS = {
|
|
|
23347
24147
|
tasks.push(...page.data);
|
|
23348
24148
|
cursor = page.nextCursor ?? undefined;
|
|
23349
24149
|
} while (cursor);
|
|
24150
|
+
const habits = await client.get("/habits/today").catch((error) => {
|
|
24151
|
+
if (error instanceof CliError && (error.code === "auth" || error.exitCode === EXIT.NOT_FOUND))
|
|
24152
|
+
return;
|
|
24153
|
+
throw error;
|
|
24154
|
+
});
|
|
23350
24155
|
return {
|
|
23351
|
-
data:
|
|
24156
|
+
data: {
|
|
24157
|
+
...selectToday(tasks, io.now()),
|
|
24158
|
+
...Array.isArray(habits?.groups) ? { habits } : {}
|
|
24159
|
+
},
|
|
23352
24160
|
render: renderToday
|
|
23353
24161
|
};
|
|
23354
24162
|
},
|
|
24163
|
+
"today earlier": async ({ flags, io, requireClient }) => {
|
|
24164
|
+
const area = flagString(flags, "area");
|
|
24165
|
+
return {
|
|
24166
|
+
data: await requireClient().get("/today/from-earlier", {
|
|
24167
|
+
query: { from: localDayStart(io.now()).toISOString(), areaId: area }
|
|
24168
|
+
}),
|
|
24169
|
+
render: renderFromEarlier
|
|
24170
|
+
};
|
|
24171
|
+
},
|
|
24172
|
+
"today answer": async ({ args, io, requireClient }) => {
|
|
24173
|
+
const answer = requireArg(args, 0, "answer");
|
|
24174
|
+
const taskIds = args.slice(1);
|
|
24175
|
+
if (!FROM_EARLIER_ANSWERS.includes(answer)) {
|
|
24176
|
+
throw usageError(`answer must be one of ${FROM_EARLIER_ANSWERS.join(", ")} (got \`${answer}\`)`);
|
|
24177
|
+
}
|
|
24178
|
+
if (taskIds.length === 0)
|
|
24179
|
+
throw usageError("today answer needs at least one task id");
|
|
24180
|
+
const client = requireClient();
|
|
24181
|
+
const today = localDayStart(io.now());
|
|
24182
|
+
let body;
|
|
24183
|
+
let to;
|
|
24184
|
+
if (answer === "today") {
|
|
24185
|
+
to = today.toISOString();
|
|
24186
|
+
body = { action: "reschedule", to, taskIds };
|
|
24187
|
+
} else if (answer === "later") {
|
|
24188
|
+
const earlier = await client.get("/today/from-earlier", {
|
|
24189
|
+
query: { from: today.toISOString() }
|
|
24190
|
+
});
|
|
24191
|
+
to = earlier.laterThisWeek;
|
|
24192
|
+
body = { action: "reschedule", to, taskIds };
|
|
24193
|
+
} else {
|
|
24194
|
+
body = { action: answer === "someday" ? "someday" : "drop", taskIds };
|
|
24195
|
+
}
|
|
24196
|
+
const result = await client.post("/today/rollover", body);
|
|
24197
|
+
return {
|
|
24198
|
+
data: { answer, ...to ? { to } : {}, ...result },
|
|
24199
|
+
render: renderFromEarlierAnswer
|
|
24200
|
+
};
|
|
24201
|
+
},
|
|
23355
24202
|
export: async ({ flags, requireClient }) => {
|
|
23356
24203
|
const format = flagString(flags, "format") ?? "json";
|
|
23357
24204
|
if (format !== "json" && format !== "ndjson") {
|
|
@@ -23403,6 +24250,10 @@ var HANDLERS = {
|
|
|
23403
24250
|
data: await requireClient().get("/progress", { query: { days: flagString(flags, "days") } }),
|
|
23404
24251
|
render: renderProgress
|
|
23405
24252
|
}),
|
|
24253
|
+
"progress habits": async ({ requireClient }) => ({
|
|
24254
|
+
data: await requireClient().get("/progress/habits"),
|
|
24255
|
+
render: renderProgressHabits
|
|
24256
|
+
}),
|
|
23406
24257
|
"progress day": async ({ args, requireClient }) => {
|
|
23407
24258
|
const date = requireArg(args, 0, "date");
|
|
23408
24259
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
@@ -23574,6 +24425,20 @@ var HANDLERS = {
|
|
|
23574
24425
|
const id = requireArg(args, 0, "task id");
|
|
23575
24426
|
return { data: await requireClient().post(`/tasks/${id}/cancel`, {}), render: renderTask };
|
|
23576
24427
|
},
|
|
24428
|
+
"tasks accept": async ({ args, requireClient }) => {
|
|
24429
|
+
const id = requireArg(args, 0, "task id");
|
|
24430
|
+
return { data: await requireClient().post(`/tasks/${id}/accept`, {}), render: renderTask };
|
|
24431
|
+
},
|
|
24432
|
+
"tasks dismiss": async ({ args, requireClient }) => {
|
|
24433
|
+
const id = requireArg(args, 0, "task id");
|
|
24434
|
+
return { data: await requireClient().post(`/tasks/${id}/not-now`, {}), render: renderTask };
|
|
24435
|
+
},
|
|
24436
|
+
"tasks ready": async ({ args, flags, requireClient }) => {
|
|
24437
|
+
const id = requireArg(args, 0, "task id");
|
|
24438
|
+
const note = flagString(flags, "note");
|
|
24439
|
+
const body = parseInput(markTaskReadyInputSchema, note !== undefined ? { note } : {});
|
|
24440
|
+
return { data: await requireClient().post(`/tasks/${id}/ready`, body), render: renderTask };
|
|
24441
|
+
},
|
|
23577
24442
|
"task reopen": async ({ args, requireClient }) => {
|
|
23578
24443
|
const id = requireArg(args, 0, "task id");
|
|
23579
24444
|
const body = parseInput(updateTaskInputSchema, { status: "todo" });
|
|
@@ -23592,10 +24457,12 @@ var HANDLERS = {
|
|
|
23592
24457
|
if (Number.isNaN(value))
|
|
23593
24458
|
throw usageError("--value must be a number");
|
|
23594
24459
|
const at = flagString(flags, "at");
|
|
24460
|
+
const note = flagString(flags, "note");
|
|
23595
24461
|
const input = parseInput(createHabitEntryInputSchema, {
|
|
23596
24462
|
id: ulid3(),
|
|
23597
24463
|
value,
|
|
23598
|
-
...at ? { occurredAt: at } : {}
|
|
24464
|
+
...at ? { occurredAt: at } : {},
|
|
24465
|
+
...note !== undefined ? { note } : {}
|
|
23599
24466
|
});
|
|
23600
24467
|
return {
|
|
23601
24468
|
data: await requireClient().post(`/habits/${id}/check-ins`, input),
|
|
@@ -23611,13 +24478,44 @@ var HANDLERS = {
|
|
|
23611
24478
|
if (value !== undefined && Number.isNaN(value))
|
|
23612
24479
|
throw usageError("--value must be a number");
|
|
23613
24480
|
const at = flagString(flags, "at");
|
|
24481
|
+
const set = flags.set === true;
|
|
24482
|
+
if (set && value === undefined)
|
|
24483
|
+
throw usageError("--set needs --value, the day's new total");
|
|
24484
|
+
const note = flagString(flags, "note");
|
|
23614
24485
|
const input = parseInput(habitCheckInByTitleInputSchema, {
|
|
23615
24486
|
title,
|
|
23616
24487
|
...value !== undefined ? { value } : {},
|
|
23617
|
-
|
|
24488
|
+
mode: set ? "set" : "add",
|
|
24489
|
+
...at ? { occurredAt: at } : {},
|
|
24490
|
+
...note !== undefined ? { note } : {}
|
|
23618
24491
|
});
|
|
23619
24492
|
return { data: await requireClient().post("/habits/check-in", input), render: renderHabit };
|
|
23620
24493
|
},
|
|
24494
|
+
"habit alias add": async ({ args, requireClient }) => {
|
|
24495
|
+
const id = requireArg(args, 0, "habit id");
|
|
24496
|
+
const alias = args.slice(1).join(" ").trim();
|
|
24497
|
+
if (!alias)
|
|
24498
|
+
throw usageError("habit alias add needs an alias, e.g. `do habit alias add <id> wake`");
|
|
24499
|
+
const input = parseInput(habitAliasInputSchema, { alias });
|
|
24500
|
+
return {
|
|
24501
|
+
data: await requireClient().post(`/habits/${id}/aliases`, input),
|
|
24502
|
+
render: renderHabit
|
|
24503
|
+
};
|
|
24504
|
+
},
|
|
24505
|
+
"habit alias rm": async ({ args, requireClient }) => {
|
|
24506
|
+
const id = requireArg(args, 0, "habit id");
|
|
24507
|
+
const alias = args.slice(1).join(" ").trim();
|
|
24508
|
+
if (!alias)
|
|
24509
|
+
throw usageError("habit alias rm needs the alias to drop");
|
|
24510
|
+
return {
|
|
24511
|
+
data: await requireClient().delete(`/habits/${id}/aliases/${encodeURIComponent(alias)}`),
|
|
24512
|
+
render: renderHabit
|
|
24513
|
+
};
|
|
24514
|
+
},
|
|
24515
|
+
"habits today": async ({ requireClient }) => ({
|
|
24516
|
+
data: await requireClient().get("/habits/today"),
|
|
24517
|
+
render: renderHabitsToday
|
|
24518
|
+
}),
|
|
23621
24519
|
"habit check-ins": async ({ args, flags, requireClient }) => {
|
|
23622
24520
|
const id = requireArg(args, 0, "habit id");
|
|
23623
24521
|
const query = {
|
|
@@ -23629,6 +24527,92 @@ var HANDLERS = {
|
|
|
23629
24527
|
render: renderList
|
|
23630
24528
|
};
|
|
23631
24529
|
},
|
|
24530
|
+
"habit note": async ({ args, flags, requireClient }) => {
|
|
24531
|
+
const id = requireArg(args, 0, "habit id");
|
|
24532
|
+
const entryId = requireArg(args, 1, "check-in id");
|
|
24533
|
+
const text = args.slice(2).join(" ").trim();
|
|
24534
|
+
const clear = flags.clear === true;
|
|
24535
|
+
if (clear && text)
|
|
24536
|
+
throw usageError("habit note takes a note or --clear, not both");
|
|
24537
|
+
if (!clear && !text)
|
|
24538
|
+
throw usageError('habit note needs the note, e.g. `do habit note <id> <check-in id> "felt heavy"`');
|
|
24539
|
+
const input = parseInput(updateHabitEntryInputSchema, { note: clear ? null : text });
|
|
24540
|
+
return {
|
|
24541
|
+
data: await requireClient().patch(`/habits/${id}/check-ins/${entryId}`, input),
|
|
24542
|
+
render: renderHabitEntry
|
|
24543
|
+
};
|
|
24544
|
+
},
|
|
24545
|
+
"habit skip": async ({ args, flags, requireClient }) => {
|
|
24546
|
+
const id = requireArg(args, 0, "habit id");
|
|
24547
|
+
const date = flagString(flags, "date");
|
|
24548
|
+
const note = flagString(flags, "note");
|
|
24549
|
+
const input = parseInput(habitSkipInputSchema, {
|
|
24550
|
+
...date ? { date } : {},
|
|
24551
|
+
...note !== undefined ? { note } : {}
|
|
24552
|
+
});
|
|
24553
|
+
return { data: await requireClient().post(`/habits/${id}/skip`, input), render: renderHabit };
|
|
24554
|
+
},
|
|
24555
|
+
"habit pause": async ({ args, flags, requireClient }) => {
|
|
24556
|
+
const id = requireArg(args, 0, "habit id");
|
|
24557
|
+
const until = flagString(flags, "until");
|
|
24558
|
+
if (!until)
|
|
24559
|
+
throw usageError("habit pause needs --until <YYYY-MM-DD>, the day it's back");
|
|
24560
|
+
const input = parseInput(habitPauseInputSchema, { until });
|
|
24561
|
+
return { data: await requireClient().post(`/habits/${id}/pause`, input), render: renderHabit };
|
|
24562
|
+
},
|
|
24563
|
+
"habit remind": async ({ args, requireClient }) => {
|
|
24564
|
+
const id = requireArg(args, 0, "habit id");
|
|
24565
|
+
const state = requireArg(args, 1, "on|off");
|
|
24566
|
+
if (state !== "on" && state !== "off")
|
|
24567
|
+
throw usageError("habit remind takes `on` or `off`");
|
|
24568
|
+
const input = parseInput(updateHabitInputSchema, { remind: state === "on" });
|
|
24569
|
+
return { data: await requireClient().patch(`/habits/${id}`, input), render: renderHabit };
|
|
24570
|
+
},
|
|
24571
|
+
"habit resume": async ({ args, requireClient }) => {
|
|
24572
|
+
const id = requireArg(args, 0, "habit id");
|
|
24573
|
+
return { data: await requireClient().post(`/habits/${id}/resume`, {}), render: renderHabit };
|
|
24574
|
+
},
|
|
24575
|
+
"habit retire": async ({ args, requireClient }) => {
|
|
24576
|
+
const id = requireArg(args, 0, "habit id");
|
|
24577
|
+
return { data: await requireClient().post(`/habits/${id}/retire`, {}), render: renderHabit };
|
|
24578
|
+
},
|
|
24579
|
+
"habit unretire": async ({ args, requireClient }) => {
|
|
24580
|
+
const id = requireArg(args, 0, "habit id");
|
|
24581
|
+
return { data: await requireClient().post(`/habits/${id}/unretire`, {}), render: renderHabit };
|
|
24582
|
+
},
|
|
24583
|
+
away: async ({ args, flags, requireClient }) => {
|
|
24584
|
+
const until = flagString(flags, "until");
|
|
24585
|
+
const off = args[0] === "off";
|
|
24586
|
+
if (args.length > 0 && !off)
|
|
24587
|
+
throw usageError("`do away` takes `off`, or --until <YYYY-MM-DD>");
|
|
24588
|
+
if (off && until)
|
|
24589
|
+
throw usageError("`do away off` comes back now; it takes no --until");
|
|
24590
|
+
if (!off && !until) {
|
|
24591
|
+
return { data: await requireClient().get("/habits/away"), render: renderAway };
|
|
24592
|
+
}
|
|
24593
|
+
const input = parseInput(awayInputSchema, { until: off ? null : until });
|
|
24594
|
+
return { data: await requireClient().put("/habits/away", input), render: renderAway };
|
|
24595
|
+
},
|
|
24596
|
+
"routine done": async ({ args, requireClient }) => {
|
|
24597
|
+
const id = requireArg(args, 0, "routine id");
|
|
24598
|
+
const input = parseInput(routineDoneInputSchema, {});
|
|
24599
|
+
return {
|
|
24600
|
+
data: await requireClient().post(`/routines/${id}/done`, input),
|
|
24601
|
+
render: renderRoutineDone
|
|
24602
|
+
};
|
|
24603
|
+
},
|
|
24604
|
+
"routine undo": async ({ args, requireClient }) => {
|
|
24605
|
+
const runId = requireArg(args, 0, "run id");
|
|
24606
|
+
const stepRunIds = args.slice(1).flatMap((a) => a.split(",")).map((a) => a.trim()).filter(Boolean);
|
|
24607
|
+
if (stepRunIds.length === 0) {
|
|
24608
|
+
throw usageError("routine undo needs the step ids `do routine done` printed, e.g. `do routine undo <run> <step> <step>`");
|
|
24609
|
+
}
|
|
24610
|
+
const input = parseInput(routineRunUndoInputSchema, { stepRunIds });
|
|
24611
|
+
return {
|
|
24612
|
+
data: await requireClient().post(`/routines/runs/${runId}/undo`, input),
|
|
24613
|
+
render: renderRoutineUndo
|
|
24614
|
+
};
|
|
24615
|
+
},
|
|
23632
24616
|
"metrics list": async ({ flags, requireClient }) => {
|
|
23633
24617
|
const query = { days: flagString(flags, "days") };
|
|
23634
24618
|
return { data: await requireClient().get("/metrics", { query }), render: renderList };
|
|
@@ -23827,6 +24811,51 @@ var HANDLERS = {
|
|
|
23827
24811
|
const result = collectionCoverBackfillResultSchema.parse(await requireClient().post("/collection/covers", undefined));
|
|
23828
24812
|
return { data: result, render: renderRecord };
|
|
23829
24813
|
},
|
|
24814
|
+
"areas purpose": async ({ args, flags, requireClient }) => {
|
|
24815
|
+
const id = requireArg(args, 0, "area id");
|
|
24816
|
+
const line = args.slice(1).join(" ").trim();
|
|
24817
|
+
const clear = flagBool(flags, "clear");
|
|
24818
|
+
if (clear && line)
|
|
24819
|
+
throw usageError("pass a purpose or --clear, not both");
|
|
24820
|
+
if (!clear && !line)
|
|
24821
|
+
throw usageError('areas purpose needs a line, e.g. `do areas purpose <id> "Sleep well, move often"` (or --clear)');
|
|
24822
|
+
const body = parseInput(updateAreaInputSchema, { purpose: clear ? null : line });
|
|
24823
|
+
return { data: await requireClient().patch(`/areas/${id}`, body), render: renderRecord };
|
|
24824
|
+
},
|
|
24825
|
+
"areas standards list": async ({ args, requireClient }) => {
|
|
24826
|
+
const id = requireArg(args, 0, "area id");
|
|
24827
|
+
const area = await requireClient().get(`/areas/${id}`);
|
|
24828
|
+
return { data: area.standards ?? [], render: renderStandards };
|
|
24829
|
+
},
|
|
24830
|
+
"areas standards add": async ({ args, flags, requireClient }) => {
|
|
24831
|
+
const id = requireArg(args, 0, "area id");
|
|
24832
|
+
const text = args.slice(1).join(" ").trim();
|
|
24833
|
+
if (!text)
|
|
24834
|
+
throw usageError('areas standards add needs the standard, e.g. `do areas standards add <id> "Move three times a week" --habit <habitId>`');
|
|
24835
|
+
const link = standardLink(flags);
|
|
24836
|
+
const body = parseInput(addAreaStandardInputSchema, { text, ...link ? { link } : {} });
|
|
24837
|
+
const area = await requireClient().post(`/areas/${id}/standards`, body);
|
|
24838
|
+
return { data: area.standards ?? [], render: renderStandards };
|
|
24839
|
+
},
|
|
24840
|
+
"areas standards link": async ({ args, flags, requireClient }) => {
|
|
24841
|
+
const id = requireArg(args, 0, "area id");
|
|
24842
|
+
const standard = requireArg(args, 1, "standard id");
|
|
24843
|
+
const link = standardLink(flags);
|
|
24844
|
+
const none = flagBool(flags, "none");
|
|
24845
|
+
if (none && link)
|
|
24846
|
+
throw usageError("pass one of --habit, --task, --metric or --none");
|
|
24847
|
+
if (!none && !link)
|
|
24848
|
+
throw usageError("say what holds it: --habit <id>, --task <id>, --metric <key>, or --none");
|
|
24849
|
+
const body = parseInput(updateAreaStandardInputSchema, { link: none ? null : link });
|
|
24850
|
+
const area = await requireClient().patch(`/areas/${id}/standards/${standard}`, body);
|
|
24851
|
+
return { data: area.standards ?? [], render: renderStandards };
|
|
24852
|
+
},
|
|
24853
|
+
"areas standards rm": async ({ args, requireClient }) => {
|
|
24854
|
+
const id = requireArg(args, 0, "area id");
|
|
24855
|
+
const standard = requireArg(args, 1, "standard id");
|
|
24856
|
+
const area = await requireClient().delete(`/areas/${id}/standards/${standard}`);
|
|
24857
|
+
return { data: area.standards ?? [], render: renderStandards };
|
|
24858
|
+
},
|
|
23830
24859
|
"places import": async ({ args, flags, requireClient }) => {
|
|
23831
24860
|
const path = requireArg(args, 0, "house.json path");
|
|
23832
24861
|
let file;
|
|
@@ -24061,6 +25090,21 @@ function isoDay(date) {
|
|
|
24061
25090
|
const day = String(date.getDate()).padStart(2, "0");
|
|
24062
25091
|
return `${date.getFullYear()}-${month}-${day}`;
|
|
24063
25092
|
}
|
|
25093
|
+
function standardLink(flags) {
|
|
25094
|
+
const habit = flagString(flags, "habit");
|
|
25095
|
+
const task = flagString(flags, "task");
|
|
25096
|
+
const metric = flagString(flags, "metric");
|
|
25097
|
+
const given = [habit, task, metric].filter((v) => v !== undefined);
|
|
25098
|
+
if (given.length > 1)
|
|
25099
|
+
throw usageError("pass one of --habit, --task or --metric");
|
|
25100
|
+
if (habit !== undefined)
|
|
25101
|
+
return { kind: "habit", id: habit };
|
|
25102
|
+
if (task !== undefined)
|
|
25103
|
+
return { kind: "task", id: task };
|
|
25104
|
+
if (metric !== undefined)
|
|
25105
|
+
return { kind: "metric", key: metric };
|
|
25106
|
+
return null;
|
|
25107
|
+
}
|
|
24064
25108
|
function requireArg(args, index, name) {
|
|
24065
25109
|
const value = args[index];
|
|
24066
25110
|
if (value === undefined || value.length === 0) {
|
|
@@ -24172,6 +25216,10 @@ function assertDestructiveAllowed(flags, action) {
|
|
|
24172
25216
|
throw new CliError("destructive_blocked", `refusing to ${action} without --allow-destructive (a guardrail for autonomous agents)`, EXIT.USAGE);
|
|
24173
25217
|
}
|
|
24174
25218
|
}
|
|
25219
|
+
var FROM_EARLIER_ANSWERS = ["today", "later", "someday", "let-go"];
|
|
25220
|
+
function localDayStart(now) {
|
|
25221
|
+
return new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
25222
|
+
}
|
|
24175
25223
|
|
|
24176
25224
|
// src/run.ts
|
|
24177
25225
|
async function run(argv, io) {
|