@robbeverhelst/do 1.159.1 → 1.161.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 +857 -45
- 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 })
|
|
@@ -3746,7 +3748,13 @@ var habitMeasurementType = pgEnum("habit_measurement_type", [
|
|
|
3746
3748
|
"negative"
|
|
3747
3749
|
]);
|
|
3748
3750
|
var habitPeriod = pgEnum("habit_period", ["day", "week", "month"]);
|
|
3749
|
-
var habitEntrySource = pgEnum("habit_entry_source", [
|
|
3751
|
+
var habitEntrySource = pgEnum("habit_entry_source", [
|
|
3752
|
+
"manual",
|
|
3753
|
+
"routine",
|
|
3754
|
+
"ingest",
|
|
3755
|
+
"agent"
|
|
3756
|
+
]);
|
|
3757
|
+
var habitEntryKind = pgEnum("habit_entry_kind", ["check_in", "skip"]);
|
|
3750
3758
|
var habitSource = pgEnum("habit_source", ["manual", "google_fit", "strava", "github"]);
|
|
3751
3759
|
var recurrenceMode = pgEnum("recurrence_mode", ["rigid", "flexible"]);
|
|
3752
3760
|
var recurrenceFreq = pgEnum("recurrence_freq", ["daily", "weekly", "monthly", "yearly"]);
|
|
@@ -3816,10 +3824,17 @@ var habits = pgTable("habits", {
|
|
|
3816
3824
|
recurrenceRuleId: text("recurrence_rule_id").references(() => recurrenceRules.id),
|
|
3817
3825
|
areaId: text("area_id").references(() => areas.id),
|
|
3818
3826
|
source: habitSource("source").notNull().default("manual"),
|
|
3819
|
-
sourceMetric: text("source_metric")
|
|
3827
|
+
sourceMetric: text("source_metric"),
|
|
3828
|
+
aliases: text("aliases").array().notNull().default(sql`'{}'::text[]`),
|
|
3829
|
+
timeOfDay: text("time_of_day"),
|
|
3830
|
+
pausedFrom: date("paused_from", { mode: "string" }),
|
|
3831
|
+
pausedUntil: date("paused_until", { mode: "string" }),
|
|
3832
|
+
remind: boolean("remind").notNull().default(false),
|
|
3833
|
+
retiredAt: timestamp("retired_at", { withTimezone: true })
|
|
3820
3834
|
}, (t) => [
|
|
3821
3835
|
index("habits_tenant_idx").on(t.tenantId),
|
|
3822
|
-
index("habits_tenant_area_idx").on(t.tenantId, t.areaId)
|
|
3836
|
+
index("habits_tenant_area_idx").on(t.tenantId, t.areaId),
|
|
3837
|
+
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
3838
|
]);
|
|
3824
3839
|
var habitEntries = pgTable("habit_entries", {
|
|
3825
3840
|
id: text("id").primaryKey(),
|
|
@@ -3827,9 +3842,12 @@ var habitEntries = pgTable("habit_entries", {
|
|
|
3827
3842
|
habitId: text("habit_id").notNull().references(() => habits.id),
|
|
3828
3843
|
value: doublePrecision("value").notNull().default(1),
|
|
3829
3844
|
source: habitEntrySource("source").notNull().default("manual"),
|
|
3845
|
+
kind: habitEntryKind("kind").notNull().default("check_in"),
|
|
3830
3846
|
occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull(),
|
|
3831
3847
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
3832
|
-
externalId: text("external_id")
|
|
3848
|
+
externalId: text("external_id"),
|
|
3849
|
+
agentId: text("agent_id"),
|
|
3850
|
+
note: text("note")
|
|
3833
3851
|
}, (t) => [
|
|
3834
3852
|
index("habit_entries_habit_occurred_idx").on(t.habitId, t.occurredAt),
|
|
3835
3853
|
uniqueIndex("habit_entries_habit_external_uniq").on(t.habitId, t.externalId).where(sql`${t.externalId} IS NOT NULL`)
|
|
@@ -3874,7 +3892,8 @@ var notificationType = pgEnum("notification_type", [
|
|
|
3874
3892
|
"automation",
|
|
3875
3893
|
"streak_at_risk",
|
|
3876
3894
|
"reflection_nudge",
|
|
3877
|
-
"shutdown_nudge"
|
|
3895
|
+
"shutdown_nudge",
|
|
3896
|
+
"habit_reminder"
|
|
3878
3897
|
]);
|
|
3879
3898
|
var notifications = pgTable("notifications", {
|
|
3880
3899
|
id: text("id").primaryKey(),
|
|
@@ -18036,7 +18055,7 @@ var spaceSchema = createSelectSchema(tenants, {
|
|
|
18036
18055
|
createdAt: exports_coerce.date(),
|
|
18037
18056
|
updatedAt: exports_coerce.date(),
|
|
18038
18057
|
deletedAt: exports_coerce.date().nullable()
|
|
18039
|
-
}).omit({ gaardHouseUrl: true });
|
|
18058
|
+
}).omit({ gaardHouseUrl: true, awayFrom: true, awayUntil: true });
|
|
18040
18059
|
var backdropIdSchema = string2().trim().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "a backdrop id is lowercase words joined by dashes").max(40);
|
|
18041
18060
|
var updateSpaceInputSchema = object({
|
|
18042
18061
|
name: string2().trim().min(1).max(120).optional(),
|
|
@@ -18128,6 +18147,7 @@ var routineRunStepStatusSchema = _enum2(routineRunStepStatus.enumValues);
|
|
|
18128
18147
|
var habitMeasurementTypeSchema = _enum2(habitMeasurementType.enumValues);
|
|
18129
18148
|
var habitPeriodSchema = _enum2(habitPeriod.enumValues);
|
|
18130
18149
|
var habitEntrySourceSchema = _enum2(habitEntrySource.enumValues);
|
|
18150
|
+
var habitEntryKindSchema = _enum2(habitEntryKind.enumValues);
|
|
18131
18151
|
var recurrenceModeSchema = _enum2(recurrenceMode.enumValues);
|
|
18132
18152
|
var recurrenceFreqSchema = _enum2(recurrenceFreq.enumValues);
|
|
18133
18153
|
var recurrenceUnitSchema = _enum2(recurrenceUnit.enumValues);
|
|
@@ -18606,13 +18626,31 @@ var habitSourceSchema = _enum2(["manual", "google_fit", "strava", "github"]);
|
|
|
18606
18626
|
// ../../packages/schema/src/contracts/habits.ts
|
|
18607
18627
|
var habitSchema = createSelectSchema(habits, {
|
|
18608
18628
|
source: habitSourceSchema.default("manual"),
|
|
18609
|
-
sourceMetric: string2().nullable().default(null)
|
|
18629
|
+
sourceMetric: string2().nullable().default(null),
|
|
18630
|
+
aliases: array(string2()).default([]),
|
|
18631
|
+
timeOfDay: string2().nullable().default(null),
|
|
18632
|
+
pausedFrom: exports_iso.date().nullable().default(null),
|
|
18633
|
+
pausedUntil: exports_iso.date().nullable().default(null),
|
|
18634
|
+
remind: boolean3().default(false),
|
|
18635
|
+
retiredAt: exports_coerce.date().nullable().default(null)
|
|
18610
18636
|
});
|
|
18611
18637
|
var habitEntrySchema = createSelectSchema(habitEntries, {
|
|
18612
18638
|
occurredAt: exports_coerce.date(),
|
|
18613
18639
|
createdAt: exports_coerce.date(),
|
|
18614
|
-
externalId: string2().nullish()
|
|
18640
|
+
externalId: string2().nullish(),
|
|
18641
|
+
kind: habitEntryKindSchema.default("check_in"),
|
|
18642
|
+
agentId: string2().nullish(),
|
|
18643
|
+
note: string2().nullish()
|
|
18644
|
+
}).extend({
|
|
18645
|
+
by: string2().nullish()
|
|
18615
18646
|
});
|
|
18647
|
+
var HABIT_PARTS_OF_DAY = ["morning", "midday", "evening"];
|
|
18648
|
+
var habitTimeOfDaySchema = union([
|
|
18649
|
+
_enum2(HABIT_PARTS_OF_DAY),
|
|
18650
|
+
string2().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "Use a 24-hour time, like 07:30")
|
|
18651
|
+
]);
|
|
18652
|
+
var habitAliasSchema = string2().trim().min(1).max(60);
|
|
18653
|
+
var habitAliasesSchema = array(habitAliasSchema).max(12).transform((aliases) => aliases.filter((a, i) => aliases.findIndex((b) => b.toLowerCase() === a.toLowerCase()) === i));
|
|
18616
18654
|
var createHabitInputSchema = createInsertSchema(habits, {
|
|
18617
18655
|
id: ulidSchema,
|
|
18618
18656
|
source: habitSourceSchema.optional(),
|
|
@@ -18622,8 +18660,11 @@ var createHabitInputSchema = createInsertSchema(habits, {
|
|
|
18622
18660
|
targetUnit: string2().min(1).nullish(),
|
|
18623
18661
|
period: habitPeriodSchema.default("day"),
|
|
18624
18662
|
frequencyCount: number2().int().positive().default(1),
|
|
18625
|
-
areaId: ulidSchema.nullish()
|
|
18626
|
-
|
|
18663
|
+
areaId: ulidSchema.nullish(),
|
|
18664
|
+
aliases: habitAliasesSchema.optional(),
|
|
18665
|
+
timeOfDay: habitTimeOfDaySchema.nullish(),
|
|
18666
|
+
remind: boolean3().optional()
|
|
18667
|
+
}).omit({ tenantId: true, recurrenceRuleId: true, retiredAt: true }).extend({
|
|
18627
18668
|
title: string2().min(1),
|
|
18628
18669
|
displayKind: string2().min(1).nullish()
|
|
18629
18670
|
});
|
|
@@ -18634,14 +18675,29 @@ var updateHabitInputSchema = createUpdateSchema(habits, {
|
|
|
18634
18675
|
targetUnit: string2().min(1).nullish(),
|
|
18635
18676
|
period: habitPeriodSchema.optional(),
|
|
18636
18677
|
frequencyCount: number2().int().positive().optional(),
|
|
18637
|
-
areaId: ulidSchema.nullish()
|
|
18638
|
-
|
|
18678
|
+
areaId: ulidSchema.nullish(),
|
|
18679
|
+
aliases: habitAliasesSchema.optional(),
|
|
18680
|
+
timeOfDay: habitTimeOfDaySchema.nullish(),
|
|
18681
|
+
remind: boolean3().optional()
|
|
18682
|
+
}).omit({
|
|
18683
|
+
id: true,
|
|
18684
|
+
tenantId: true,
|
|
18685
|
+
measurementType: true,
|
|
18686
|
+
recurrenceRuleId: true,
|
|
18687
|
+
pausedFrom: true,
|
|
18688
|
+
pausedUntil: true,
|
|
18689
|
+
retiredAt: true
|
|
18690
|
+
}).extend({ title: string2().min(1).optional() });
|
|
18691
|
+
var HABIT_ENTRY_NOTE_MAX = 280;
|
|
18692
|
+
var habitEntryNoteSchema = string2().trim().max(HABIT_ENTRY_NOTE_MAX).transform((note) => note === "" ? null : note);
|
|
18639
18693
|
var createHabitEntryInputSchema = createInsertSchema(habitEntries, {
|
|
18640
18694
|
id: ulidSchema,
|
|
18641
18695
|
value: number2().nonnegative().default(1),
|
|
18642
18696
|
source: habitEntrySourceSchema.default("manual"),
|
|
18643
|
-
occurredAt: exports_coerce.date().optional()
|
|
18644
|
-
|
|
18697
|
+
occurredAt: exports_coerce.date().optional(),
|
|
18698
|
+
note: habitEntryNoteSchema.nullish()
|
|
18699
|
+
}).omit({ tenantId: true, habitId: true, createdAt: true, agentId: true, kind: true });
|
|
18700
|
+
var updateHabitEntryInputSchema = object({ note: habitEntryNoteSchema.nullable() }).strict();
|
|
18645
18701
|
var habitStreakStateSchema = _enum2(["active", "recovering", "broken"]);
|
|
18646
18702
|
var habitStreakSchema = object({
|
|
18647
18703
|
current: number2().int().nonnegative(),
|
|
@@ -18652,7 +18708,8 @@ var habitStreakSchema = object({
|
|
|
18652
18708
|
completionRate: number2().min(0).max(1),
|
|
18653
18709
|
state: habitStreakStateSchema,
|
|
18654
18710
|
graceBudget: number2().int().nonnegative(),
|
|
18655
|
-
graceRemaining: number2().int().nonnegative()
|
|
18711
|
+
graceRemaining: number2().int().nonnegative(),
|
|
18712
|
+
skippedToday: boolean3().default(false)
|
|
18656
18713
|
});
|
|
18657
18714
|
var habitRoutineRefSchema = object({
|
|
18658
18715
|
id: ulidSchema,
|
|
@@ -18661,7 +18718,19 @@ var habitRoutineRefSchema = object({
|
|
|
18661
18718
|
var habitLastCheckInSchema = object({
|
|
18662
18719
|
at: exports_coerce.date(),
|
|
18663
18720
|
value: number2(),
|
|
18664
|
-
source: habitEntrySourceSchema
|
|
18721
|
+
source: habitEntrySourceSchema,
|
|
18722
|
+
by: string2().nullish(),
|
|
18723
|
+
id: string2().optional(),
|
|
18724
|
+
note: string2().nullish()
|
|
18725
|
+
});
|
|
18726
|
+
var habitPauseSchema = object({
|
|
18727
|
+
until: exports_iso.date(),
|
|
18728
|
+
by: _enum2(["habit", "away"])
|
|
18729
|
+
});
|
|
18730
|
+
var habitTodaySchema = object({
|
|
18731
|
+
due: boolean3(),
|
|
18732
|
+
done: boolean3(),
|
|
18733
|
+
week: object({ done: number2().int().nonnegative(), target: number2().int().positive() }).optional()
|
|
18665
18734
|
});
|
|
18666
18735
|
var habitSummarySchema = habitSchema.extend({
|
|
18667
18736
|
title: string2(),
|
|
@@ -18669,12 +18738,16 @@ var habitSummarySchema = habitSchema.extend({
|
|
|
18669
18738
|
displayKind: string2().default("default"),
|
|
18670
18739
|
streak: habitStreakSchema,
|
|
18671
18740
|
inRoutines: array(habitRoutineRefSchema).default([]),
|
|
18672
|
-
lastCheckIn: habitLastCheckInSchema.nullable().default(null)
|
|
18741
|
+
lastCheckIn: habitLastCheckInSchema.nullable().default(null),
|
|
18742
|
+
pause: habitPauseSchema.nullable().default(null),
|
|
18743
|
+
today: habitTodaySchema.default({ due: true, done: false })
|
|
18673
18744
|
});
|
|
18674
18745
|
var habitHeatmapCellSchema = object({
|
|
18675
18746
|
date: string2(),
|
|
18676
18747
|
value: number2(),
|
|
18677
|
-
satisfied: boolean3()
|
|
18748
|
+
satisfied: boolean3(),
|
|
18749
|
+
rest: boolean3().default(false),
|
|
18750
|
+
notes: array(string2()).optional()
|
|
18678
18751
|
});
|
|
18679
18752
|
var habitDetailSchema = habitSummarySchema.extend({
|
|
18680
18753
|
heatmap: array(habitHeatmapCellSchema),
|
|
@@ -18686,11 +18759,69 @@ var habitEntriesQuerySchema = object({
|
|
|
18686
18759
|
before: exports_coerce.date().optional(),
|
|
18687
18760
|
limit: exports_coerce.number().int().min(1).max(200).default(50)
|
|
18688
18761
|
});
|
|
18762
|
+
var civilDateSchema = string2().regex(/^\d{4}-\d{2}-\d{2}$/, "expected YYYY-MM-DD");
|
|
18763
|
+
var habitCheckInModeSchema = _enum2(["add", "set"]);
|
|
18689
18764
|
var habitCheckInByTitleInputSchema = object({
|
|
18690
18765
|
title: string2().trim().min(1).max(300),
|
|
18691
18766
|
value: number2().nonnegative().optional(),
|
|
18692
|
-
|
|
18767
|
+
mode: habitCheckInModeSchema.default("add"),
|
|
18768
|
+
occurredAt: union([civilDateSchema, exports_coerce.date()]).optional(),
|
|
18769
|
+
note: habitEntryNoteSchema.nullish()
|
|
18693
18770
|
}).strict();
|
|
18771
|
+
var habitCandidateSchema = object({
|
|
18772
|
+
id: ulidSchema,
|
|
18773
|
+
title: string2(),
|
|
18774
|
+
aliases: array(string2())
|
|
18775
|
+
});
|
|
18776
|
+
var habitCheckInAmbiguousSchema = object({
|
|
18777
|
+
error: object({
|
|
18778
|
+
code: literal("ambiguous_habit"),
|
|
18779
|
+
message: string2(),
|
|
18780
|
+
details: object({ candidates: array(habitCandidateSchema).min(2) })
|
|
18781
|
+
})
|
|
18782
|
+
});
|
|
18783
|
+
var habitAliasInputSchema = object({ alias: habitAliasSchema }).strict();
|
|
18784
|
+
var habitSkipInputSchema = object({
|
|
18785
|
+
date: exports_iso.date().optional(),
|
|
18786
|
+
note: habitEntryNoteSchema.nullish()
|
|
18787
|
+
}).strict();
|
|
18788
|
+
var habitPauseInputSchema = object({ until: exports_iso.date() }).strict();
|
|
18789
|
+
var awayInputSchema = object({ until: exports_iso.date().nullable() }).strict();
|
|
18790
|
+
var awayStateSchema = object({
|
|
18791
|
+
until: exports_iso.date().nullable()
|
|
18792
|
+
});
|
|
18793
|
+
var habitDayPartSchema = _enum2(["morning", "midday", "evening", "anytime"]);
|
|
18794
|
+
var habitTodayStateSchema = _enum2(["done", "open", "skipped"]);
|
|
18795
|
+
var habitTodayItemSchema = object({
|
|
18796
|
+
habitId: ulidSchema,
|
|
18797
|
+
title: string2(),
|
|
18798
|
+
aliases: array(string2()).default([]),
|
|
18799
|
+
measurementType: habitMeasurementTypeSchema,
|
|
18800
|
+
unit: string2().nullable(),
|
|
18801
|
+
target: number2().nullable(),
|
|
18802
|
+
timeOfDay: string2().nullable().default(null),
|
|
18803
|
+
value: number2(),
|
|
18804
|
+
state: habitTodayStateSchema,
|
|
18805
|
+
week: object({ done: number2().int().nonnegative(), target: number2().int().positive() }).optional(),
|
|
18806
|
+
last: object({
|
|
18807
|
+
source: habitEntrySourceSchema,
|
|
18808
|
+
by: string2().optional(),
|
|
18809
|
+
at: exports_coerce.date()
|
|
18810
|
+
}).nullable().default(null)
|
|
18811
|
+
});
|
|
18812
|
+
var habitTodayRoutineSchema = object({
|
|
18813
|
+
routineId: ulidSchema,
|
|
18814
|
+
title: string2(),
|
|
18815
|
+
timeOfDay: string2().nullable(),
|
|
18816
|
+
stepsDone: number2().int().nonnegative(),
|
|
18817
|
+
stepsTotal: number2().int().nonnegative()
|
|
18818
|
+
});
|
|
18819
|
+
var habitsTodayResponseSchema = object({
|
|
18820
|
+
date: string2().regex(/^\d{4}-\d{2}-\d{2}$/),
|
|
18821
|
+
timezone: string2().min(1),
|
|
18822
|
+
groups: array(object({ part: habitDayPartSchema, habits: array(habitTodayItemSchema) })),
|
|
18823
|
+
routines: array(habitTodayRoutineSchema)
|
|
18824
|
+
});
|
|
18694
18825
|
|
|
18695
18826
|
// ../../packages/schema/src/contracts/metrics.ts
|
|
18696
18827
|
var metricKeySchema = _enum2(["weight", "sleep", "mood"]);
|
|
@@ -18880,6 +19011,26 @@ var updateRoutineRunStepInputSchema = object({
|
|
|
18880
19011
|
var updateRoutineRunInputSchema = object({
|
|
18881
19012
|
status: routineRunStatusSchema.optional()
|
|
18882
19013
|
}).strict();
|
|
19014
|
+
var routineRunsQuerySchema = object({
|
|
19015
|
+
limit: exports_coerce.number().int().min(1).max(200).optional()
|
|
19016
|
+
});
|
|
19017
|
+
var routineDoneInputSchema = object({
|
|
19018
|
+
id: ulidSchema.optional(),
|
|
19019
|
+
occurrenceDate: exports_coerce.date().nullish()
|
|
19020
|
+
}).strict();
|
|
19021
|
+
var routineDoneStepSchema = object({
|
|
19022
|
+
stepRunId: string2(),
|
|
19023
|
+
title: string2(),
|
|
19024
|
+
habitId: string2().nullable(),
|
|
19025
|
+
habitEntryId: string2().nullable()
|
|
19026
|
+
});
|
|
19027
|
+
var routineDoneResultSchema = object({
|
|
19028
|
+
run: routineRunViewSchema,
|
|
19029
|
+
taken: array(routineDoneStepSchema)
|
|
19030
|
+
});
|
|
19031
|
+
var routineRunUndoInputSchema = object({
|
|
19032
|
+
stepRunIds: array(string2().min(1)).min(1).max(100)
|
|
19033
|
+
}).strict();
|
|
18883
19034
|
|
|
18884
19035
|
// ../../packages/schema/src/contracts/projects.ts
|
|
18885
19036
|
var projectSchema = createSelectSchema(projects, {
|
|
@@ -19652,9 +19803,16 @@ var agentPageContextSchema = object({
|
|
|
19652
19803
|
}).strict();
|
|
19653
19804
|
var agentChatInputSchema = object({
|
|
19654
19805
|
message: string2().trim().min(1).max(8000),
|
|
19655
|
-
context: agentPageContextSchema
|
|
19806
|
+
context: agentPageContextSchema,
|
|
19807
|
+
threadId: string2().trim().min(1).max(64).optional()
|
|
19656
19808
|
}).strict();
|
|
19657
19809
|
var agentChatEventSchema = discriminatedUnion("type", [
|
|
19810
|
+
object({
|
|
19811
|
+
type: literal("turn"),
|
|
19812
|
+
id: string2(),
|
|
19813
|
+
threadId: string2(),
|
|
19814
|
+
since: string2().nullable()
|
|
19815
|
+
}),
|
|
19658
19816
|
object({ type: literal("delta"), text: string2() }),
|
|
19659
19817
|
object({ type: literal("done") }),
|
|
19660
19818
|
object({ type: literal("error"), message: string2() })
|
|
@@ -19680,7 +19838,12 @@ var agentChangeSchema = object({
|
|
|
19680
19838
|
changedAt: exports_coerce.date(),
|
|
19681
19839
|
title: string2().nullable(),
|
|
19682
19840
|
actor: actorRefSchema,
|
|
19683
|
-
fields: array(agentChangeFieldSchema).optional()
|
|
19841
|
+
fields: array(agentChangeFieldSchema).optional(),
|
|
19842
|
+
checkIn: object({
|
|
19843
|
+
value: number2(),
|
|
19844
|
+
unit: string2().nullable(),
|
|
19845
|
+
measurementType: habitMeasurementTypeSchema
|
|
19846
|
+
}).optional()
|
|
19684
19847
|
});
|
|
19685
19848
|
var agentChangesPageSchema = object({
|
|
19686
19849
|
data: array(agentChangeSchema),
|
|
@@ -20836,7 +20999,7 @@ function parseCapture2(input, now) {
|
|
|
20836
20999
|
|
|
20837
21000
|
// src/meta.ts
|
|
20838
21001
|
var CLI_NAME = "do";
|
|
20839
|
-
var VERSION = "1.
|
|
21002
|
+
var VERSION = "1.161.0";
|
|
20840
21003
|
var API_PREFIX = "/api/v1";
|
|
20841
21004
|
var DEFAULT_API_URL = "http://localhost:3001";
|
|
20842
21005
|
|
|
@@ -21097,7 +21260,14 @@ var ENTITIES = [
|
|
|
21097
21260
|
readScope: "habits:read",
|
|
21098
21261
|
returns: "HabitSummary",
|
|
21099
21262
|
canGet: true,
|
|
21100
|
-
listFlags: [
|
|
21263
|
+
listFlags: [
|
|
21264
|
+
AREA_FLAG,
|
|
21265
|
+
UPDATED_SINCE_FLAG,
|
|
21266
|
+
{
|
|
21267
|
+
name: "retired",
|
|
21268
|
+
description: "list the Grown shelf (retired habits) instead of the growing ones"
|
|
21269
|
+
}
|
|
21270
|
+
],
|
|
21101
21271
|
write: {
|
|
21102
21272
|
scope: "habits:write",
|
|
21103
21273
|
createSchema: createHabitInputSchema,
|
|
@@ -21401,12 +21571,12 @@ var COMMAND_SPECS = [
|
|
|
21401
21571
|
},
|
|
21402
21572
|
{
|
|
21403
21573
|
path: ["today"],
|
|
21404
|
-
summary: "Show today's actionable tasks (scheduled, due, overdue, in-progress).",
|
|
21574
|
+
summary: "Show today's actionable tasks (scheduled, due, overdue, in-progress), then the habits and routines due today.",
|
|
21405
21575
|
args: [],
|
|
21406
21576
|
flags: [],
|
|
21407
21577
|
scopes: ["tasks:read"],
|
|
21408
21578
|
returns: "TodaySummary",
|
|
21409
|
-
notes: "
|
|
21579
|
+
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."
|
|
21410
21580
|
},
|
|
21411
21581
|
{
|
|
21412
21582
|
path: ["now"],
|
|
@@ -21448,6 +21618,34 @@ var COMMAND_SPECS = [
|
|
|
21448
21618
|
scopes: ["tasks:read"],
|
|
21449
21619
|
returns: "ReviewDayStat"
|
|
21450
21620
|
},
|
|
21621
|
+
{
|
|
21622
|
+
path: ["progress"],
|
|
21623
|
+
summary: "How the last 7/30/90 days went: tasks, habits and time blocks done per day.",
|
|
21624
|
+
args: [],
|
|
21625
|
+
flags: [
|
|
21626
|
+
{ name: "days", type: "string", description: "The range: 7 (default), 30 or 90 days." }
|
|
21627
|
+
],
|
|
21628
|
+
scopes: ["tasks:read", "habits:read"],
|
|
21629
|
+
returns: "ProgressResponse",
|
|
21630
|
+
notes: "GET /api/v1/progress \u2014 days are your saved timezone's. Includes the week/month vs the period before, best day, Areas and each habit's rate."
|
|
21631
|
+
},
|
|
21632
|
+
{
|
|
21633
|
+
path: ["progress", "day"],
|
|
21634
|
+
summary: "One day of Progress: what was done (and by whom) and what slipped.",
|
|
21635
|
+
args: [{ name: "date", required: true, description: "The day, YYYY-MM-DD." }],
|
|
21636
|
+
flags: [],
|
|
21637
|
+
scopes: ["tasks:read", "habits:read"],
|
|
21638
|
+
returns: "ProgressDayDetail"
|
|
21639
|
+
},
|
|
21640
|
+
{
|
|
21641
|
+
path: ["progress", "habits"],
|
|
21642
|
+
summary: "Habits this week: a done/skipped grid, each habit's strength word, patterns and when you check in.",
|
|
21643
|
+
args: [],
|
|
21644
|
+
flags: [],
|
|
21645
|
+
scopes: ["habits:read"],
|
|
21646
|
+
returns: "ProgressHabitsResponse",
|
|
21647
|
+
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."
|
|
21648
|
+
},
|
|
21451
21649
|
{
|
|
21452
21650
|
path: ["search"],
|
|
21453
21651
|
summary: "Search node titles and note bodies across the Space.",
|
|
@@ -21535,22 +21733,76 @@ var COMMAND_SPECS = [
|
|
|
21535
21733
|
description: "Amount logged (binary habits use 1).",
|
|
21536
21734
|
default: "1"
|
|
21537
21735
|
},
|
|
21538
|
-
{ name: "at", type: "string", description: "When it occurred (ISO); defaults to now." }
|
|
21736
|
+
{ name: "at", type: "string", description: "When it occurred (ISO); defaults to now." },
|
|
21737
|
+
{
|
|
21738
|
+
name: "note",
|
|
21739
|
+
type: "string",
|
|
21740
|
+
description: 'A short note on the check-in ("felt heavy"), at most 280 characters.'
|
|
21741
|
+
}
|
|
21539
21742
|
],
|
|
21540
21743
|
scopes: ["habits:write"],
|
|
21541
21744
|
returns: "HabitSummary"
|
|
21542
21745
|
},
|
|
21543
21746
|
{
|
|
21544
21747
|
path: ["habit", "check-in"],
|
|
21545
|
-
summary: 'Check a habit in by its title ("did my run").',
|
|
21546
|
-
args: [
|
|
21748
|
+
summary: 'Check a habit in by its title or an alias ("wake", "did my run").',
|
|
21749
|
+
args: [
|
|
21750
|
+
{ name: "title", required: true, description: "The habit's title or one of its aliases." }
|
|
21751
|
+
],
|
|
21547
21752
|
flags: [
|
|
21548
21753
|
{ name: "value", type: "string", description: "Amount logged; defaults to 1." },
|
|
21549
|
-
{
|
|
21754
|
+
{
|
|
21755
|
+
name: "set",
|
|
21756
|
+
type: "boolean",
|
|
21757
|
+
description: "Make --value the day's total instead of adding it (amount habits)."
|
|
21758
|
+
},
|
|
21759
|
+
{
|
|
21760
|
+
name: "at",
|
|
21761
|
+
type: "string",
|
|
21762
|
+
description: "When it occurred: an ISO instant, or a day (YYYY-MM-DD, your time zone); defaults to now."
|
|
21763
|
+
},
|
|
21764
|
+
{
|
|
21765
|
+
name: "note",
|
|
21766
|
+
type: "string",
|
|
21767
|
+
description: 'A short note on the check-in ("felt heavy"), at most 280 characters.'
|
|
21768
|
+
}
|
|
21769
|
+
],
|
|
21770
|
+
scopes: ["habits:write"],
|
|
21771
|
+
returns: "HabitSummary",
|
|
21772
|
+
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.`
|
|
21773
|
+
},
|
|
21774
|
+
{
|
|
21775
|
+
path: ["habit", "alias", "add"],
|
|
21776
|
+
summary: 'Give a habit another name check-ins match ("wake" for "Wake up by 07:00").',
|
|
21777
|
+
args: [
|
|
21778
|
+
{ name: "id", required: true, description: "Habit ULID." },
|
|
21779
|
+
{ name: "alias", required: true, description: "The other name." }
|
|
21780
|
+
],
|
|
21781
|
+
flags: [],
|
|
21782
|
+
scopes: ["habits:write"],
|
|
21783
|
+
returns: "HabitSummary",
|
|
21784
|
+
notes: "POST /api/v1/habits/:id/aliases. One already there (ignoring case) is a no-op; at most 12."
|
|
21785
|
+
},
|
|
21786
|
+
{
|
|
21787
|
+
path: ["habit", "alias", "rm"],
|
|
21788
|
+
summary: "Drop one of a habit's aliases.",
|
|
21789
|
+
args: [
|
|
21790
|
+
{ name: "id", required: true, description: "Habit ULID." },
|
|
21791
|
+
{ name: "alias", required: true, description: "The alias to drop (ignoring case)." }
|
|
21550
21792
|
],
|
|
21793
|
+
flags: [],
|
|
21551
21794
|
scopes: ["habits:write"],
|
|
21552
21795
|
returns: "HabitSummary",
|
|
21553
|
-
notes: "
|
|
21796
|
+
notes: "DELETE /api/v1/habits/:id/aliases/:alias. 404 when the habit doesn't have it."
|
|
21797
|
+
},
|
|
21798
|
+
{
|
|
21799
|
+
path: ["habits", "today"],
|
|
21800
|
+
summary: "What's left today: the habits due by part of day, and today's routines.",
|
|
21801
|
+
args: [],
|
|
21802
|
+
flags: [],
|
|
21803
|
+
scopes: ["habits:read"],
|
|
21804
|
+
returns: "HabitsTodayResponse",
|
|
21805
|
+
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."
|
|
21554
21806
|
},
|
|
21555
21807
|
{
|
|
21556
21808
|
path: ["habit", "check-ins"],
|
|
@@ -21563,6 +21815,149 @@ var COMMAND_SPECS = [
|
|
|
21563
21815
|
scopes: ["habits:read"],
|
|
21564
21816
|
returns: "HabitEntry"
|
|
21565
21817
|
},
|
|
21818
|
+
{
|
|
21819
|
+
path: ["habit", "note"],
|
|
21820
|
+
summary: 'Put a note on a check-in afterwards ("felt heavy"), or clear it.',
|
|
21821
|
+
args: [
|
|
21822
|
+
{ name: "id", required: true, description: "Habit ULID." },
|
|
21823
|
+
{
|
|
21824
|
+
name: "entry-id",
|
|
21825
|
+
required: true,
|
|
21826
|
+
description: "The check-in's ULID (`do habit check-ins <id>`, or lastCheckIn.id)."
|
|
21827
|
+
},
|
|
21828
|
+
{ name: "note", required: false, description: "The note, at most 280 characters." }
|
|
21829
|
+
],
|
|
21830
|
+
flags: [{ name: "clear", type: "boolean", description: "Drop the check-in's note." }],
|
|
21831
|
+
scopes: ["habits:write"],
|
|
21832
|
+
returns: "HabitEntry",
|
|
21833
|
+
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."
|
|
21834
|
+
},
|
|
21835
|
+
{
|
|
21836
|
+
path: ["habit", "skip"],
|
|
21837
|
+
summary: 'Skip a day: a neutral rest day, never a miss ("skip gym today").',
|
|
21838
|
+
args: [{ name: "id", required: true, description: "Habit ULID." }],
|
|
21839
|
+
flags: [
|
|
21840
|
+
{ name: "date", type: "string", description: "The day (YYYY-MM-DD); defaults to today." },
|
|
21841
|
+
{
|
|
21842
|
+
name: "note",
|
|
21843
|
+
type: "string",
|
|
21844
|
+
description: 'Why, if you like ("Dentist"); shows in the log.'
|
|
21845
|
+
}
|
|
21846
|
+
],
|
|
21847
|
+
scopes: ["habits:write"],
|
|
21848
|
+
returns: "HabitSummary",
|
|
21849
|
+
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`)."
|
|
21850
|
+
},
|
|
21851
|
+
{
|
|
21852
|
+
path: ["routine", "done"],
|
|
21853
|
+
summary: `All taken: check in every open step of today's routine in one go ("took my supplements").`,
|
|
21854
|
+
args: [
|
|
21855
|
+
{
|
|
21856
|
+
name: "id",
|
|
21857
|
+
required: true,
|
|
21858
|
+
description: "Routine ULID (`do habits today` lists today's)."
|
|
21859
|
+
}
|
|
21860
|
+
],
|
|
21861
|
+
flags: [],
|
|
21862
|
+
scopes: ["routines:write"],
|
|
21863
|
+
returns: "RoutineDoneResult",
|
|
21864
|
+
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>`."
|
|
21865
|
+
},
|
|
21866
|
+
{
|
|
21867
|
+
path: ["routine", "undo"],
|
|
21868
|
+
summary: "Take an All taken back in one go: its steps reopen and lose their check-ins.",
|
|
21869
|
+
args: [
|
|
21870
|
+
{
|
|
21871
|
+
name: "runId",
|
|
21872
|
+
required: true,
|
|
21873
|
+
description: "The run's ULID (`run.id` from `do routine done`)."
|
|
21874
|
+
},
|
|
21875
|
+
{
|
|
21876
|
+
name: "stepRunIds",
|
|
21877
|
+
required: true,
|
|
21878
|
+
description: "The `taken` step ids from `do routine done`, space- or comma-separated."
|
|
21879
|
+
}
|
|
21880
|
+
],
|
|
21881
|
+
flags: [],
|
|
21882
|
+
scopes: ["routines:write"],
|
|
21883
|
+
returns: "RoutineRunView",
|
|
21884
|
+
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."
|
|
21885
|
+
},
|
|
21886
|
+
{
|
|
21887
|
+
path: ["habit", "pause"],
|
|
21888
|
+
summary: "Pause a habit until the day it's back: off Now, no push, the plant waits.",
|
|
21889
|
+
args: [{ name: "id", required: true, description: "Habit ULID." }],
|
|
21890
|
+
flags: [
|
|
21891
|
+
{
|
|
21892
|
+
name: "until",
|
|
21893
|
+
type: "string",
|
|
21894
|
+
description: "The day it's back (YYYY-MM-DD), after today. Required."
|
|
21895
|
+
}
|
|
21896
|
+
],
|
|
21897
|
+
scopes: ["habits:write"],
|
|
21898
|
+
returns: "HabitSummary",
|
|
21899
|
+
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."
|
|
21900
|
+
},
|
|
21901
|
+
{
|
|
21902
|
+
path: ["habit", "remind"],
|
|
21903
|
+
summary: "Turn a habit's daily reminder on or off: one push at its time, never a follow-up.",
|
|
21904
|
+
args: [
|
|
21905
|
+
{ name: "id", required: true, description: "Habit ULID." },
|
|
21906
|
+
{ name: "state", required: true, description: "`on` or `off`." }
|
|
21907
|
+
],
|
|
21908
|
+
flags: [],
|
|
21909
|
+
scopes: ["habits:write"],
|
|
21910
|
+
returns: "HabitSummary",
|
|
21911
|
+
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."
|
|
21912
|
+
},
|
|
21913
|
+
{
|
|
21914
|
+
path: ["habit", "resume"],
|
|
21915
|
+
summary: "Resume a paused habit: it's back today.",
|
|
21916
|
+
args: [{ name: "id", required: true, description: "Habit ULID." }],
|
|
21917
|
+
flags: [],
|
|
21918
|
+
scopes: ["habits:write"],
|
|
21919
|
+
returns: "HabitSummary",
|
|
21920
|
+
notes: "POST /api/v1/habits/{id}/resume. The rest so far stays neutral."
|
|
21921
|
+
},
|
|
21922
|
+
{
|
|
21923
|
+
path: ["habit", "retire"],
|
|
21924
|
+
summary: `Retire a habit to the Grown shelf ("I'm done with the cold showers habit"): history kept.`,
|
|
21925
|
+
args: [{ name: "id", required: true, description: "Habit ULID." }],
|
|
21926
|
+
flags: [],
|
|
21927
|
+
scopes: ["habits:write"],
|
|
21928
|
+
returns: "HabitSummary",
|
|
21929
|
+
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>`."
|
|
21930
|
+
},
|
|
21931
|
+
{
|
|
21932
|
+
path: ["habit", "unretire"],
|
|
21933
|
+
summary: "Bring a grown (retired) habit back: growing again from today.",
|
|
21934
|
+
args: [{ name: "id", required: true, description: "Habit ULID." }],
|
|
21935
|
+
flags: [],
|
|
21936
|
+
scopes: ["habits:write"],
|
|
21937
|
+
returns: "HabitSummary",
|
|
21938
|
+
notes: "POST /api/v1/habits/{id}/unretire. Its history is intact."
|
|
21939
|
+
},
|
|
21940
|
+
{
|
|
21941
|
+
path: ["away"],
|
|
21942
|
+
summary: 'Away until a day ("away till Monday"): every habit rests. `do away off` comes back.',
|
|
21943
|
+
args: [
|
|
21944
|
+
{
|
|
21945
|
+
name: "off",
|
|
21946
|
+
required: false,
|
|
21947
|
+
description: "`off` comes back now; omit it (and --until) to show the away state."
|
|
21948
|
+
}
|
|
21949
|
+
],
|
|
21950
|
+
flags: [
|
|
21951
|
+
{
|
|
21952
|
+
name: "until",
|
|
21953
|
+
type: "string",
|
|
21954
|
+
description: "The day you're back (YYYY-MM-DD), after today."
|
|
21955
|
+
}
|
|
21956
|
+
],
|
|
21957
|
+
scopes: ["habits:read", "habits:write"],
|
|
21958
|
+
returns: "AwayState",
|
|
21959
|
+
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."
|
|
21960
|
+
},
|
|
21566
21961
|
{
|
|
21567
21962
|
path: ["metrics", "list"],
|
|
21568
21963
|
summary: "Show weight, sleep and mood as daily trend lines (no target, no streak).",
|
|
@@ -21797,6 +22192,42 @@ var COMMAND_SPECS = [
|
|
|
21797
22192
|
returns: "None",
|
|
21798
22193
|
notes: "Owner/admin only. An Agent's key gets a 428 confirmation_required until the member confirms in the Echo panel."
|
|
21799
22194
|
},
|
|
22195
|
+
{
|
|
22196
|
+
path: ["echo", "threads", "list"],
|
|
22197
|
+
summary: "List your recent Echo threads, newest first.",
|
|
22198
|
+
args: [],
|
|
22199
|
+
flags: [{ name: "limit", type: "string", description: "How many, 1\u201350 (default 10)." }],
|
|
22200
|
+
scopes: ["agents:read"],
|
|
22201
|
+
returns: "EchoThreadSummary",
|
|
22202
|
+
notes: "The key's member's own threads; the title is the thread's first question."
|
|
22203
|
+
},
|
|
22204
|
+
{
|
|
22205
|
+
path: ["echo", "threads", "current"],
|
|
22206
|
+
summary: "Show the Echo thread the panel opens on, with its turns.",
|
|
22207
|
+
args: [],
|
|
22208
|
+
flags: [],
|
|
22209
|
+
scopes: ["agents:read"],
|
|
22210
|
+
returns: "{ thread: EchoThread | null }",
|
|
22211
|
+
notes: "The most recently used thread; `thread` is null before the first question."
|
|
22212
|
+
},
|
|
22213
|
+
{
|
|
22214
|
+
path: ["echo", "threads", "show"],
|
|
22215
|
+
summary: "Show one of your Echo threads, with its turns.",
|
|
22216
|
+
args: [{ name: "id", required: true, description: "Thread ULID (see `echo threads list`)." }],
|
|
22217
|
+
flags: [],
|
|
22218
|
+
scopes: ["agents:read"],
|
|
22219
|
+
returns: "EchoThread",
|
|
22220
|
+
notes: "Another member's thread is a 404."
|
|
22221
|
+
},
|
|
22222
|
+
{
|
|
22223
|
+
path: ["echo", "threads", "new"],
|
|
22224
|
+
summary: "Start a new Echo conversation (it becomes the current thread).",
|
|
22225
|
+
args: [],
|
|
22226
|
+
flags: [],
|
|
22227
|
+
scopes: ["agents:write"],
|
|
22228
|
+
returns: "EchoThread",
|
|
22229
|
+
notes: "When the current thread is still empty, that one is returned instead."
|
|
22230
|
+
},
|
|
21800
22231
|
{
|
|
21801
22232
|
path: ["settings", "get"],
|
|
21802
22233
|
summary: "Show the caller's settings for the Space.",
|
|
@@ -22694,15 +23125,81 @@ function renderTask(data, mode) {
|
|
|
22694
23125
|
}
|
|
22695
23126
|
function renderToday(data, mode) {
|
|
22696
23127
|
const result = data;
|
|
22697
|
-
|
|
22698
|
-
|
|
22699
|
-
|
|
22700
|
-
|
|
22701
|
-
|
|
22702
|
-
|
|
22703
|
-
|
|
22704
|
-
|
|
22705
|
-
|
|
23128
|
+
const tasks = result.count === 0 ? paint(mode, "green", `Nothing scheduled for ${result.date}. Inbox zero. \u2713`) : [
|
|
23129
|
+
paint(mode, "bold", `Today \xB7 ${result.date} \xB7 ${result.count} item(s)`),
|
|
23130
|
+
...result.items.map((item) => {
|
|
23131
|
+
const tag = paint(mode, bucketColor(item.bucket), `[${item.bucket}]`);
|
|
23132
|
+
const star = item.starred ? paint(mode, "yellow", " \u2605") : "";
|
|
23133
|
+
return ` ${tag} ${item.title}${star} ${paint(mode, "dim", item.id)}`;
|
|
23134
|
+
})
|
|
23135
|
+
].join(`
|
|
23136
|
+
`);
|
|
23137
|
+
const habits = result.habits ? habitLines(result.habits, mode) : [];
|
|
23138
|
+
return habits.length > 0 ? `${tasks}
|
|
23139
|
+
|
|
23140
|
+
${habits.join(`
|
|
23141
|
+
`)}` : tasks;
|
|
23142
|
+
}
|
|
23143
|
+
var PART_LABEL = {
|
|
23144
|
+
morning: "Morning",
|
|
23145
|
+
midday: "Midday",
|
|
23146
|
+
evening: "Evening",
|
|
23147
|
+
anytime: "Any time today"
|
|
23148
|
+
};
|
|
23149
|
+
function clock(at, timezone) {
|
|
23150
|
+
return new Intl.DateTimeFormat("en-GB", {
|
|
23151
|
+
timeZone: timezone,
|
|
23152
|
+
hour: "2-digit",
|
|
23153
|
+
minute: "2-digit",
|
|
23154
|
+
hourCycle: "h23"
|
|
23155
|
+
}).format(new Date(at));
|
|
23156
|
+
}
|
|
23157
|
+
function civilDay(at, timezone) {
|
|
23158
|
+
return new Intl.DateTimeFormat("en-CA", {
|
|
23159
|
+
timeZone: timezone,
|
|
23160
|
+
year: "numeric",
|
|
23161
|
+
month: "2-digit",
|
|
23162
|
+
day: "2-digit"
|
|
23163
|
+
}).format(new Date(at));
|
|
23164
|
+
}
|
|
23165
|
+
function habitLines(day, mode) {
|
|
23166
|
+
const lines = [];
|
|
23167
|
+
for (const group of day.groups) {
|
|
23168
|
+
lines.push(paint(mode, "bold", PART_LABEL[group.part]));
|
|
23169
|
+
for (const h of group.habits) {
|
|
23170
|
+
const mark = h.state === "done" ? paint(mode, "green", "\u2713") : h.state === "skipped" ? paint(mode, "dim", "\u2013") : "\u25CB";
|
|
23171
|
+
const meta = [];
|
|
23172
|
+
if (h.timeOfDay)
|
|
23173
|
+
meta.push(h.timeOfDay);
|
|
23174
|
+
if (h.target !== null && h.measurementType !== "binary") {
|
|
23175
|
+
meta.push(`${h.value} of ${h.target}${h.unit ? ` ${h.unit}` : ""}`);
|
|
23176
|
+
}
|
|
23177
|
+
if (h.week)
|
|
23178
|
+
meta.push(`${h.week.done} of ${h.week.target} this week`);
|
|
23179
|
+
if (h.last?.by && civilDay(h.last.at, day.timezone) === day.date) {
|
|
23180
|
+
meta.push(`${h.last.by}, ${clock(h.last.at, day.timezone)}`);
|
|
23181
|
+
}
|
|
23182
|
+
const tail = meta.length > 0 ? paint(mode, "dim", ` \xB7 ${meta.join(" \xB7 ")}`) : "";
|
|
23183
|
+
lines.push(` ${mark} ${h.title}${tail} ${paint(mode, "dim", h.habitId)}`);
|
|
23184
|
+
}
|
|
23185
|
+
}
|
|
23186
|
+
if (day.routines.length > 0) {
|
|
23187
|
+
lines.push(paint(mode, "bold", "Routines"));
|
|
23188
|
+
for (const r of day.routines) {
|
|
23189
|
+
const when = r.timeOfDay ? ` ${r.timeOfDay}` : "";
|
|
23190
|
+
const steps = paint(mode, "dim", ` \xB7 ${r.stepsDone} of ${r.stepsTotal} steps`);
|
|
23191
|
+
lines.push(` ${r.title}${when}${steps} ${paint(mode, "dim", r.routineId)}`);
|
|
23192
|
+
}
|
|
23193
|
+
}
|
|
23194
|
+
return lines;
|
|
23195
|
+
}
|
|
23196
|
+
function renderHabitsToday(data, mode) {
|
|
23197
|
+
const day = data;
|
|
23198
|
+
const lines = habitLines(day, mode);
|
|
23199
|
+
const header = paint(mode, "bold", `Habits \xB7 ${day.date} (${day.timezone})`);
|
|
23200
|
+
if (lines.length === 0)
|
|
23201
|
+
return `${header}
|
|
23202
|
+
Nothing due today.`;
|
|
22706
23203
|
return [header, ...lines].join(`
|
|
22707
23204
|
`);
|
|
22708
23205
|
}
|
|
@@ -22717,13 +23214,45 @@ function bucketColor(bucket) {
|
|
|
22717
23214
|
}
|
|
22718
23215
|
function renderHabit(data, mode) {
|
|
22719
23216
|
const h = data;
|
|
23217
|
+
if (h.retiredAt) {
|
|
23218
|
+
return `${h.title ?? "(habit)"} \u2014 grown ${h.retiredAt.slice(0, 10)}, on the Grown shelf with its history
|
|
23219
|
+
${paint(mode, "dim", h.id)}`;
|
|
23220
|
+
}
|
|
22720
23221
|
const streak = h.streak;
|
|
22721
23222
|
const flame = streak?.satisfiedToday ? paint(mode, "green", "\u2713 today") : "not yet today";
|
|
22722
23223
|
const pct = typeof streak?.completionRate === "number" ? ` \xB7 ${Math.round(streak.completionRate * 100)}% lately` : "";
|
|
22723
23224
|
const recovering = streak?.state === "recovering" ? paint(mode, "yellow", " \xB7 recovering") : "";
|
|
22724
23225
|
const counts = streak ? ` \xB7 streak ${streak.current ?? 0} (best ${streak.longest ?? 0})` : "";
|
|
22725
|
-
|
|
22726
|
-
|
|
23226
|
+
const rest = h.pause ? ` \xB7 ${h.pause.by === "away" ? "away" : "paused"}, back ${h.pause.until}` : streak?.skippedToday ? " \xB7 rest day" : "";
|
|
23227
|
+
const last = h.lastCheckIn?.id ? `
|
|
23228
|
+
${paint(mode, "dim", `last check-in ${h.lastCheckIn.id}`)}${h.lastCheckIn.note ? ` "${h.lastCheckIn.note}"` : ""}` : "";
|
|
23229
|
+
return `${h.title ?? "(habit)"} \u2014 ${flame}${pct}${counts}${recovering}${rest}
|
|
23230
|
+
${paint(mode, "dim", h.id)}${last}`;
|
|
23231
|
+
}
|
|
23232
|
+
function renderHabitEntry(data, mode) {
|
|
23233
|
+
const e = data;
|
|
23234
|
+
const said = e.note ? `Noted: "${e.note}"` : "No note.";
|
|
23235
|
+
return `${said}
|
|
23236
|
+
${paint(mode, "dim", e.id ?? "")}`;
|
|
23237
|
+
}
|
|
23238
|
+
function renderRoutineDone(data, mode) {
|
|
23239
|
+
const d = data;
|
|
23240
|
+
const title = d.run?.routineTitle ?? "(routine)";
|
|
23241
|
+
const taken = d.taken ?? [];
|
|
23242
|
+
if (taken.length === 0)
|
|
23243
|
+
return `${title}: nothing left to check in today.`;
|
|
23244
|
+
const names = taken.map((t) => t.title).join(", ");
|
|
23245
|
+
const undo = `do routine undo ${d.run?.id ?? "<run>"} ${taken.map((t) => t.stepRunId).join(" ")}`;
|
|
23246
|
+
return `${title}: checked in ${names}.
|
|
23247
|
+
${paint(mode, "dim", `undo: ${undo}`)}`;
|
|
23248
|
+
}
|
|
23249
|
+
function renderRoutineUndo(data) {
|
|
23250
|
+
const run = data;
|
|
23251
|
+
return `${run.routineTitle ?? "(routine)"}: undone. Those check-ins are gone.`;
|
|
23252
|
+
}
|
|
23253
|
+
function renderAway(data) {
|
|
23254
|
+
const until = data.until;
|
|
23255
|
+
return until ? `Away until ${until}. Habits are resting; tasks carry on.` : "Here. Habits are on.";
|
|
22727
23256
|
}
|
|
22728
23257
|
function renderWhoami(data, mode) {
|
|
22729
23258
|
const w = data;
|
|
@@ -22914,6 +23443,26 @@ function shortDate(iso) {
|
|
|
22914
23443
|
return iso;
|
|
22915
23444
|
return d.toISOString().slice(0, 16).replace("T", " ");
|
|
22916
23445
|
}
|
|
23446
|
+
function renderEchoThread(data, mode) {
|
|
23447
|
+
const wrapped = data;
|
|
23448
|
+
const thread = wrapped && typeof wrapped === "object" && "thread" in wrapped ? wrapped.thread : data;
|
|
23449
|
+
if (!thread)
|
|
23450
|
+
return paint(mode, "dim", "No Echo thread yet.");
|
|
23451
|
+
const head = `${thread.title ?? "New conversation"} ${paint(mode, "dim", thread.id ?? "")}`;
|
|
23452
|
+
const turns = thread.turns ?? [];
|
|
23453
|
+
if (turns.length === 0)
|
|
23454
|
+
return `${head}
|
|
23455
|
+
${paint(mode, "dim", "(nothing asked yet)")}`;
|
|
23456
|
+
const lines = turns.flatMap((t) => {
|
|
23457
|
+
const note = t.status === "error" ? ` (failed: ${t.error ?? "error"})` : t.status === "cancelled" ? " (stopped)" : t.status === "streaming" ? " (still answering)" : "";
|
|
23458
|
+
return [
|
|
23459
|
+
` ${paint(mode, "bold", "You")} ${t.question ?? ""}`,
|
|
23460
|
+
` ${paint(mode, "bold", "Echo")} ${t.reply ?? ""}${paint(mode, "dim", note)}`
|
|
23461
|
+
];
|
|
23462
|
+
});
|
|
23463
|
+
return [head, ...lines].join(`
|
|
23464
|
+
`);
|
|
23465
|
+
}
|
|
22917
23466
|
function actorText(actor) {
|
|
22918
23467
|
if (!actor)
|
|
22919
23468
|
return "system";
|
|
@@ -22950,6 +23499,106 @@ function renderReview(data, mode) {
|
|
|
22950
23499
|
return days.map((d) => `${d.date ?? "?"} ${d.completedTasks ?? 0} task(s) \xB7 ${d.completedOccurrences ?? 0} habit/routine`).join(`
|
|
22951
23500
|
`);
|
|
22952
23501
|
}
|
|
23502
|
+
var percent = (share) => share === null || share === undefined ? "\u2013" : `${Math.round(share * 100)}%`;
|
|
23503
|
+
function delta(now, before) {
|
|
23504
|
+
const d = now - before;
|
|
23505
|
+
return d > 0 ? `+${d}` : d < 0 ? `\u2212${-d}` : "\xB10";
|
|
23506
|
+
}
|
|
23507
|
+
function renderProgress(data, mode) {
|
|
23508
|
+
const p = data;
|
|
23509
|
+
const t = p.today;
|
|
23510
|
+
const out = [
|
|
23511
|
+
paint(mode, "bold", `Progress \xB7 ${p.range?.from ?? "?"} \u2192 ${p.range?.to ?? "?"} (${p.range?.timezone ?? "?"})`)
|
|
23512
|
+
];
|
|
23513
|
+
if (t) {
|
|
23514
|
+
out.push(`Today ${t.tasksDone}/${t.tasksPlanned} tasks \xB7 ${t.habitsDone}/${t.habitsDue} habits \xB7 ${t.blocksDone}/${t.blocksPlanned} blocks \xB7 ${percent(t.completion)} done`);
|
|
23515
|
+
}
|
|
23516
|
+
const days = p.days ?? [];
|
|
23517
|
+
if (days.length > 0) {
|
|
23518
|
+
out.push("");
|
|
23519
|
+
for (const d of days) {
|
|
23520
|
+
const agents = d.tasksDoneAgents ? ` (+${d.tasksDoneAgents} by agents)` : "";
|
|
23521
|
+
out.push(`${d.date} ${d.tasksDoneMine} task(s)${agents} \xB7 ${d.habitsDone}/${d.habitsDue} habits \xB7 ${percent(d.completion)}`);
|
|
23522
|
+
}
|
|
23523
|
+
}
|
|
23524
|
+
const totals = p.totals;
|
|
23525
|
+
if (totals) {
|
|
23526
|
+
const line = (label, x) => `${label} ${x.tasksDone} tasks (${delta(x.tasksDone, x.previous.tasksDone)}) \xB7 ${x.habitsDone} habits (${delta(x.habitsDone, x.previous.habitsDone)}) \xB7 ${percent(x.completion)} done`;
|
|
23527
|
+
out.push("", line("This week ", totals.week), line("This month", totals.month));
|
|
23528
|
+
const best = totals.bestDay ? `${totals.bestDay.date} (${totals.bestDay.tasksDone})` : "\u2013";
|
|
23529
|
+
out.push(`Best day ${best} \xB7 ${totals.averagePerDay.tasksDone} tasks/day \xB7 on time ${totals.onTime}, late ${totals.late}`);
|
|
23530
|
+
}
|
|
23531
|
+
const areas = p.areas ?? [];
|
|
23532
|
+
if (areas.length > 0) {
|
|
23533
|
+
out.push("", paint(mode, "bold", "Areas"));
|
|
23534
|
+
for (const a of areas)
|
|
23535
|
+
out.push(` ${a.name}: ${a.tasksDone}`);
|
|
23536
|
+
}
|
|
23537
|
+
const habits = p.habits ?? [];
|
|
23538
|
+
if (habits.length > 0) {
|
|
23539
|
+
out.push("", paint(mode, "bold", "Habits"));
|
|
23540
|
+
for (const h of habits)
|
|
23541
|
+
out.push(` ${h.name}: ${h.done}/${h.due} (${percent(h.rate)})`);
|
|
23542
|
+
}
|
|
23543
|
+
return out.join(`
|
|
23544
|
+
`);
|
|
23545
|
+
}
|
|
23546
|
+
var CELL = {
|
|
23547
|
+
done: "\u25A0",
|
|
23548
|
+
skipped: "\u2013",
|
|
23549
|
+
empty: "\xB7",
|
|
23550
|
+
ahead: " "
|
|
23551
|
+
};
|
|
23552
|
+
var hh = (h) => `${String(h).padStart(2, "0")}:00`;
|
|
23553
|
+
var usually = (when) => when?.usual ? `usually ${hh(when.usual.from)}\u2013${hh(when.usual.to)}` : null;
|
|
23554
|
+
function renderProgressHabits(data, mode) {
|
|
23555
|
+
const p = data;
|
|
23556
|
+
const out = [
|
|
23557
|
+
paint(mode, "bold", `Habits \xB7 week of ${p.week?.from ?? "?"} \u2192 ${p.week?.to ?? "?"} (${p.timezone ?? "?"})`)
|
|
23558
|
+
];
|
|
23559
|
+
const habits = p.habits ?? [];
|
|
23560
|
+
if (habits.length === 0)
|
|
23561
|
+
out.push(paint(mode, "dim", " (no habits yet)"));
|
|
23562
|
+
const width = Math.max(0, ...habits.map((h) => h.name.length));
|
|
23563
|
+
for (const h of habits) {
|
|
23564
|
+
const cells = h.week.map((d) => CELL[d.state]).join(" ");
|
|
23565
|
+
const count = h.weekOf === null ? `${h.weekDone} done` : `${h.weekDone} of ${h.weekOf}`;
|
|
23566
|
+
const extra = [h.strengthWord.replace("-", " "), usually(h.when)].filter(Boolean).join(" \xB7 ");
|
|
23567
|
+
out.push(` ${h.name.padEnd(width)} ${cells} ${count} \xB7 ${extra}`);
|
|
23568
|
+
}
|
|
23569
|
+
const patterns = p.patterns ?? [];
|
|
23570
|
+
out.push("", paint(mode, "bold", "Patterns"));
|
|
23571
|
+
if (patterns.length === 0) {
|
|
23572
|
+
out.push(paint(mode, "dim", " (none yet: patterns need a few weeks of check-ins)"));
|
|
23573
|
+
}
|
|
23574
|
+
for (const x of patterns) {
|
|
23575
|
+
out.push(` ${x.title}`, ` ${x.body}`, ` ${paint(mode, "dim", x.confidenceLabel)}`);
|
|
23576
|
+
}
|
|
23577
|
+
const when = usually(p.when);
|
|
23578
|
+
if (when && p.when) {
|
|
23579
|
+
out.push("", `When ${when} (${Math.round((p.when.usual?.share ?? 0) * 100)}% of ${p.when.checkins} check-ins)`);
|
|
23580
|
+
}
|
|
23581
|
+
return out.join(`
|
|
23582
|
+
`);
|
|
23583
|
+
}
|
|
23584
|
+
function renderProgressDay(data, mode) {
|
|
23585
|
+
const d = data;
|
|
23586
|
+
const done = d.done ?? [];
|
|
23587
|
+
const slipped = d.slipped ?? [];
|
|
23588
|
+
const out = [
|
|
23589
|
+
paint(mode, "bold", `${d.date ?? "?"} \xB7 ${done.length} done \xB7 ${slipped.length} slipped`)
|
|
23590
|
+
];
|
|
23591
|
+
for (const item of done) {
|
|
23592
|
+
const tags = [item.kind, item.owner === "agent" ? "agent" : null, item.late ? "late" : null].filter(Boolean).join(", ");
|
|
23593
|
+
out.push(` \u2713 ${item.title} ${paint(mode, "dim", `(${tags})`)}`);
|
|
23594
|
+
}
|
|
23595
|
+
for (const item of slipped)
|
|
23596
|
+
out.push(` \xB7 ${item.title} ${paint(mode, "dim", `(${item.kind})`)}`);
|
|
23597
|
+
if (done.length === 0 && slipped.length === 0)
|
|
23598
|
+
out.push(paint(mode, "dim", " (nothing that day)"));
|
|
23599
|
+
return out.join(`
|
|
23600
|
+
`);
|
|
23601
|
+
}
|
|
22953
23602
|
function renderSearch(data, mode) {
|
|
22954
23603
|
const hits = Array.isArray(data) ? data : [];
|
|
22955
23604
|
if (hits.length === 0)
|
|
@@ -23085,7 +23734,7 @@ async function dispatchEntity(entity, rest, flags, requireClient) {
|
|
|
23085
23734
|
if (op === "list") {
|
|
23086
23735
|
const query = {};
|
|
23087
23736
|
for (const f of entity.listFlags) {
|
|
23088
|
-
const value = flagString(flags, f.name);
|
|
23737
|
+
const value = flags[f.name] === true ? "true" : flagString(flags, f.name);
|
|
23089
23738
|
if (value !== undefined)
|
|
23090
23739
|
query[f.query ?? f.name] = value;
|
|
23091
23740
|
else if (f.required)
|
|
@@ -23203,8 +23852,16 @@ var HANDLERS = {
|
|
|
23203
23852
|
tasks.push(...page.data);
|
|
23204
23853
|
cursor = page.nextCursor ?? undefined;
|
|
23205
23854
|
} while (cursor);
|
|
23855
|
+
const habits = await client.get("/habits/today").catch((error) => {
|
|
23856
|
+
if (error instanceof CliError && (error.code === "auth" || error.exitCode === EXIT.NOT_FOUND))
|
|
23857
|
+
return;
|
|
23858
|
+
throw error;
|
|
23859
|
+
});
|
|
23206
23860
|
return {
|
|
23207
|
-
data:
|
|
23861
|
+
data: {
|
|
23862
|
+
...selectToday(tasks, io.now()),
|
|
23863
|
+
...Array.isArray(habits?.groups) ? { habits } : {}
|
|
23864
|
+
},
|
|
23208
23865
|
render: renderToday
|
|
23209
23866
|
};
|
|
23210
23867
|
},
|
|
@@ -23255,6 +23912,24 @@ var HANDLERS = {
|
|
|
23255
23912
|
}),
|
|
23256
23913
|
render: renderReview
|
|
23257
23914
|
}),
|
|
23915
|
+
progress: async ({ flags, requireClient }) => ({
|
|
23916
|
+
data: await requireClient().get("/progress", { query: { days: flagString(flags, "days") } }),
|
|
23917
|
+
render: renderProgress
|
|
23918
|
+
}),
|
|
23919
|
+
"progress habits": async ({ requireClient }) => ({
|
|
23920
|
+
data: await requireClient().get("/progress/habits"),
|
|
23921
|
+
render: renderProgressHabits
|
|
23922
|
+
}),
|
|
23923
|
+
"progress day": async ({ args, requireClient }) => {
|
|
23924
|
+
const date = requireArg(args, 0, "date");
|
|
23925
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
23926
|
+
throw usageError("progress day needs a date as YYYY-MM-DD, e.g. `do progress day 2026-10-15`");
|
|
23927
|
+
}
|
|
23928
|
+
return {
|
|
23929
|
+
data: await requireClient().get(`/progress/days/${date}`),
|
|
23930
|
+
render: renderProgressDay
|
|
23931
|
+
};
|
|
23932
|
+
},
|
|
23258
23933
|
search: async ({ args, flags, requireClient }) => {
|
|
23259
23934
|
const q = args.join(" ").trim();
|
|
23260
23935
|
if (q.length === 0)
|
|
@@ -23434,10 +24109,12 @@ var HANDLERS = {
|
|
|
23434
24109
|
if (Number.isNaN(value))
|
|
23435
24110
|
throw usageError("--value must be a number");
|
|
23436
24111
|
const at = flagString(flags, "at");
|
|
24112
|
+
const note = flagString(flags, "note");
|
|
23437
24113
|
const input = parseInput(createHabitEntryInputSchema, {
|
|
23438
24114
|
id: ulid3(),
|
|
23439
24115
|
value,
|
|
23440
|
-
...at ? { occurredAt: at } : {}
|
|
24116
|
+
...at ? { occurredAt: at } : {},
|
|
24117
|
+
...note !== undefined ? { note } : {}
|
|
23441
24118
|
});
|
|
23442
24119
|
return {
|
|
23443
24120
|
data: await requireClient().post(`/habits/${id}/check-ins`, input),
|
|
@@ -23453,13 +24130,44 @@ var HANDLERS = {
|
|
|
23453
24130
|
if (value !== undefined && Number.isNaN(value))
|
|
23454
24131
|
throw usageError("--value must be a number");
|
|
23455
24132
|
const at = flagString(flags, "at");
|
|
24133
|
+
const set = flags.set === true;
|
|
24134
|
+
if (set && value === undefined)
|
|
24135
|
+
throw usageError("--set needs --value, the day's new total");
|
|
24136
|
+
const note = flagString(flags, "note");
|
|
23456
24137
|
const input = parseInput(habitCheckInByTitleInputSchema, {
|
|
23457
24138
|
title,
|
|
23458
24139
|
...value !== undefined ? { value } : {},
|
|
23459
|
-
|
|
24140
|
+
mode: set ? "set" : "add",
|
|
24141
|
+
...at ? { occurredAt: at } : {},
|
|
24142
|
+
...note !== undefined ? { note } : {}
|
|
23460
24143
|
});
|
|
23461
24144
|
return { data: await requireClient().post("/habits/check-in", input), render: renderHabit };
|
|
23462
24145
|
},
|
|
24146
|
+
"habit alias add": async ({ args, requireClient }) => {
|
|
24147
|
+
const id = requireArg(args, 0, "habit id");
|
|
24148
|
+
const alias = args.slice(1).join(" ").trim();
|
|
24149
|
+
if (!alias)
|
|
24150
|
+
throw usageError("habit alias add needs an alias, e.g. `do habit alias add <id> wake`");
|
|
24151
|
+
const input = parseInput(habitAliasInputSchema, { alias });
|
|
24152
|
+
return {
|
|
24153
|
+
data: await requireClient().post(`/habits/${id}/aliases`, input),
|
|
24154
|
+
render: renderHabit
|
|
24155
|
+
};
|
|
24156
|
+
},
|
|
24157
|
+
"habit alias rm": async ({ args, requireClient }) => {
|
|
24158
|
+
const id = requireArg(args, 0, "habit id");
|
|
24159
|
+
const alias = args.slice(1).join(" ").trim();
|
|
24160
|
+
if (!alias)
|
|
24161
|
+
throw usageError("habit alias rm needs the alias to drop");
|
|
24162
|
+
return {
|
|
24163
|
+
data: await requireClient().delete(`/habits/${id}/aliases/${encodeURIComponent(alias)}`),
|
|
24164
|
+
render: renderHabit
|
|
24165
|
+
};
|
|
24166
|
+
},
|
|
24167
|
+
"habits today": async ({ requireClient }) => ({
|
|
24168
|
+
data: await requireClient().get("/habits/today"),
|
|
24169
|
+
render: renderHabitsToday
|
|
24170
|
+
}),
|
|
23463
24171
|
"habit check-ins": async ({ args, flags, requireClient }) => {
|
|
23464
24172
|
const id = requireArg(args, 0, "habit id");
|
|
23465
24173
|
const query = {
|
|
@@ -23471,6 +24179,92 @@ var HANDLERS = {
|
|
|
23471
24179
|
render: renderList
|
|
23472
24180
|
};
|
|
23473
24181
|
},
|
|
24182
|
+
"habit note": async ({ args, flags, requireClient }) => {
|
|
24183
|
+
const id = requireArg(args, 0, "habit id");
|
|
24184
|
+
const entryId = requireArg(args, 1, "check-in id");
|
|
24185
|
+
const text = args.slice(2).join(" ").trim();
|
|
24186
|
+
const clear = flags.clear === true;
|
|
24187
|
+
if (clear && text)
|
|
24188
|
+
throw usageError("habit note takes a note or --clear, not both");
|
|
24189
|
+
if (!clear && !text)
|
|
24190
|
+
throw usageError('habit note needs the note, e.g. `do habit note <id> <check-in id> "felt heavy"`');
|
|
24191
|
+
const input = parseInput(updateHabitEntryInputSchema, { note: clear ? null : text });
|
|
24192
|
+
return {
|
|
24193
|
+
data: await requireClient().patch(`/habits/${id}/check-ins/${entryId}`, input),
|
|
24194
|
+
render: renderHabitEntry
|
|
24195
|
+
};
|
|
24196
|
+
},
|
|
24197
|
+
"habit skip": async ({ args, flags, requireClient }) => {
|
|
24198
|
+
const id = requireArg(args, 0, "habit id");
|
|
24199
|
+
const date = flagString(flags, "date");
|
|
24200
|
+
const note = flagString(flags, "note");
|
|
24201
|
+
const input = parseInput(habitSkipInputSchema, {
|
|
24202
|
+
...date ? { date } : {},
|
|
24203
|
+
...note !== undefined ? { note } : {}
|
|
24204
|
+
});
|
|
24205
|
+
return { data: await requireClient().post(`/habits/${id}/skip`, input), render: renderHabit };
|
|
24206
|
+
},
|
|
24207
|
+
"habit pause": async ({ args, flags, requireClient }) => {
|
|
24208
|
+
const id = requireArg(args, 0, "habit id");
|
|
24209
|
+
const until = flagString(flags, "until");
|
|
24210
|
+
if (!until)
|
|
24211
|
+
throw usageError("habit pause needs --until <YYYY-MM-DD>, the day it's back");
|
|
24212
|
+
const input = parseInput(habitPauseInputSchema, { until });
|
|
24213
|
+
return { data: await requireClient().post(`/habits/${id}/pause`, input), render: renderHabit };
|
|
24214
|
+
},
|
|
24215
|
+
"habit remind": async ({ args, requireClient }) => {
|
|
24216
|
+
const id = requireArg(args, 0, "habit id");
|
|
24217
|
+
const state = requireArg(args, 1, "on|off");
|
|
24218
|
+
if (state !== "on" && state !== "off")
|
|
24219
|
+
throw usageError("habit remind takes `on` or `off`");
|
|
24220
|
+
const input = parseInput(updateHabitInputSchema, { remind: state === "on" });
|
|
24221
|
+
return { data: await requireClient().patch(`/habits/${id}`, input), render: renderHabit };
|
|
24222
|
+
},
|
|
24223
|
+
"habit resume": async ({ args, requireClient }) => {
|
|
24224
|
+
const id = requireArg(args, 0, "habit id");
|
|
24225
|
+
return { data: await requireClient().post(`/habits/${id}/resume`, {}), render: renderHabit };
|
|
24226
|
+
},
|
|
24227
|
+
"habit retire": async ({ args, requireClient }) => {
|
|
24228
|
+
const id = requireArg(args, 0, "habit id");
|
|
24229
|
+
return { data: await requireClient().post(`/habits/${id}/retire`, {}), render: renderHabit };
|
|
24230
|
+
},
|
|
24231
|
+
"habit unretire": async ({ args, requireClient }) => {
|
|
24232
|
+
const id = requireArg(args, 0, "habit id");
|
|
24233
|
+
return { data: await requireClient().post(`/habits/${id}/unretire`, {}), render: renderHabit };
|
|
24234
|
+
},
|
|
24235
|
+
away: async ({ args, flags, requireClient }) => {
|
|
24236
|
+
const until = flagString(flags, "until");
|
|
24237
|
+
const off = args[0] === "off";
|
|
24238
|
+
if (args.length > 0 && !off)
|
|
24239
|
+
throw usageError("`do away` takes `off`, or --until <YYYY-MM-DD>");
|
|
24240
|
+
if (off && until)
|
|
24241
|
+
throw usageError("`do away off` comes back now; it takes no --until");
|
|
24242
|
+
if (!off && !until) {
|
|
24243
|
+
return { data: await requireClient().get("/habits/away"), render: renderAway };
|
|
24244
|
+
}
|
|
24245
|
+
const input = parseInput(awayInputSchema, { until: off ? null : until });
|
|
24246
|
+
return { data: await requireClient().put("/habits/away", input), render: renderAway };
|
|
24247
|
+
},
|
|
24248
|
+
"routine done": async ({ args, requireClient }) => {
|
|
24249
|
+
const id = requireArg(args, 0, "routine id");
|
|
24250
|
+
const input = parseInput(routineDoneInputSchema, {});
|
|
24251
|
+
return {
|
|
24252
|
+
data: await requireClient().post(`/routines/${id}/done`, input),
|
|
24253
|
+
render: renderRoutineDone
|
|
24254
|
+
};
|
|
24255
|
+
},
|
|
24256
|
+
"routine undo": async ({ args, requireClient }) => {
|
|
24257
|
+
const runId = requireArg(args, 0, "run id");
|
|
24258
|
+
const stepRunIds = args.slice(1).flatMap((a) => a.split(",")).map((a) => a.trim()).filter(Boolean);
|
|
24259
|
+
if (stepRunIds.length === 0) {
|
|
24260
|
+
throw usageError("routine undo needs the step ids `do routine done` printed, e.g. `do routine undo <run> <step> <step>`");
|
|
24261
|
+
}
|
|
24262
|
+
const input = parseInput(routineRunUndoInputSchema, { stepRunIds });
|
|
24263
|
+
return {
|
|
24264
|
+
data: await requireClient().post(`/routines/runs/${runId}/undo`, input),
|
|
24265
|
+
render: renderRoutineUndo
|
|
24266
|
+
};
|
|
24267
|
+
},
|
|
23474
24268
|
"metrics list": async ({ flags, requireClient }) => {
|
|
23475
24269
|
const query = { days: flagString(flags, "days") };
|
|
23476
24270
|
return { data: await requireClient().get("/metrics", { query }), render: renderList };
|
|
@@ -23513,6 +24307,24 @@ var HANDLERS = {
|
|
|
23513
24307
|
await requireClient().delete("/agent/connection");
|
|
23514
24308
|
return { data: { ok: true, removed: "agent connection" }, render: renderRecord };
|
|
23515
24309
|
},
|
|
24310
|
+
"echo threads list": async ({ flags, requireClient }) => ({
|
|
24311
|
+
data: await requireClient().getPage("/echo/threads", {
|
|
24312
|
+
query: { limit: flagString(flags, "limit") }
|
|
24313
|
+
}),
|
|
24314
|
+
render: renderList
|
|
24315
|
+
}),
|
|
24316
|
+
"echo threads current": async ({ requireClient }) => ({
|
|
24317
|
+
data: await requireClient().get("/echo/threads/current"),
|
|
24318
|
+
render: renderEchoThread
|
|
24319
|
+
}),
|
|
24320
|
+
"echo threads show": async ({ args, requireClient }) => ({
|
|
24321
|
+
data: await requireClient().get(`/echo/threads/${requireArg(args, 0, "thread id")}`),
|
|
24322
|
+
render: renderEchoThread
|
|
24323
|
+
}),
|
|
24324
|
+
"echo threads new": async ({ requireClient }) => ({
|
|
24325
|
+
data: await requireClient().post("/echo/threads", {}),
|
|
24326
|
+
render: renderEchoThread
|
|
24327
|
+
}),
|
|
23516
24328
|
"settings get": async ({ requireClient }) => ({
|
|
23517
24329
|
data: await requireClient().get("/settings"),
|
|
23518
24330
|
render: renderRecord
|
package/package.json
CHANGED