@tashks/core 0.1.4 → 0.2.3
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/src/id.d.ts.map +1 -1
- package/dist/src/id.js +3 -1
- package/dist/src/proseql-repository.d.ts.map +1 -1
- package/dist/src/proseql-repository.js +100 -4
- package/dist/src/query.d.ts +59 -11
- package/dist/src/query.d.ts.map +1 -1
- package/dist/src/query.js +97 -9
- package/dist/src/recurrence.d.ts.map +1 -1
- package/dist/src/recurrence.js +3 -0
- package/dist/src/repository.d.ts +38 -1
- package/dist/src/repository.d.ts.map +1 -1
- package/dist/src/repository.js +312 -6
- package/dist/src/schema.d.ts +108 -34
- package/dist/src/schema.d.ts.map +1 -1
- package/dist/src/schema.js +54 -10
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/src/query.test.d.ts +0 -2
- package/dist/src/query.test.d.ts.map +0 -1
- package/dist/src/query.test.js +0 -673
- package/dist/src/repository.test.d.ts +0 -2
- package/dist/src/repository.test.d.ts.map +0 -1
- package/dist/src/repository.test.js +0 -1443
- package/dist/src/schema.test.d.ts +0 -2
- package/dist/src/schema.test.d.ts.map +0 -1
- package/dist/src/schema.test.js +0 -123
package/dist/src/id.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../../src/id.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../../src/id.ts"],"names":[],"mappings":"AA2BA,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,KAAG,MACF,CAAC"}
|
package/dist/src/id.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
const idSuffixAlphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
3
3
|
const idSuffixLength = 6;
|
|
4
|
+
const maxSlugLength = 30;
|
|
4
5
|
const slugifyTitle = (title) => {
|
|
5
6
|
const slug = title
|
|
6
7
|
.toLowerCase()
|
|
@@ -8,7 +9,8 @@ const slugifyTitle = (title) => {
|
|
|
8
9
|
.replace(/[\u0300-\u036f]/g, "")
|
|
9
10
|
.replace(/[^a-z0-9]+/g, "-")
|
|
10
11
|
.replace(/^-+|-+$/g, "");
|
|
11
|
-
|
|
12
|
+
const base = slug.length > 0 ? slug : "task";
|
|
13
|
+
return base.slice(0, maxSlugLength).replace(/-+$/, "");
|
|
12
14
|
};
|
|
13
15
|
const randomIdSuffix = () => {
|
|
14
16
|
const random = randomBytes(idSuffixLength);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proseql-repository.d.ts","sourceRoot":"","sources":["../../src/proseql-repository.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"proseql-repository.d.ts","sourceRoot":"","sources":["../../src/proseql-repository.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAmCtC,OAAO,EACN,cAAc,EAUd,MAAM,iBAAiB,CAAC;AA8CzB,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACrC;AAsgBD,eAAO,MAAM,qBAAqB,GACjC,SAAS,wBAAwB,KAC/B,KAAK,CAAC,KAAK,CAAC,cAAc,EAAE,MAAM,CACwB,CAAC"}
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { dirname, join } from "node:path";
|
|
2
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import * as Effect from "effect/Effect";
|
|
4
4
|
import * as Layer from "effect/Layer";
|
|
5
5
|
import * as Schema from "effect/Schema";
|
|
6
6
|
import { createNodeDatabase } from "@proseql/node";
|
|
7
7
|
import YAML from "yaml";
|
|
8
|
-
import { Task as TaskSchema, WorkLogCreateInput as WorkLogCreateInputSchema, WorkLogEntry as WorkLogEntrySchema, } from "./schema.js";
|
|
9
|
-
import { byUpdatedDescThenTitle, isStalerThan, } from "./query.js";
|
|
8
|
+
import { Task as TaskSchema, WorkLogCreateInput as WorkLogCreateInputSchema, WorkLogEntry as WorkLogEntrySchema, Project as ProjectSchema, ProjectCreateInput as ProjectCreateInputSchema, ProjectPatch as ProjectPatchSchema, } from "./schema.js";
|
|
9
|
+
import { byUpdatedDescThenTitle, isStalerThan, listContexts as listContextsFromTasks, } from "./query.js";
|
|
10
10
|
import { runCreateHooks, runModifyHooks, runNonMutatingHooks, } from "./hooks.js";
|
|
11
11
|
import { buildCompletionRecurrenceTask, buildNextClockRecurrenceTask, isClockRecurrenceDue, } from "./recurrence.js";
|
|
12
|
-
import { TaskRepository, applyListTaskFilters, todayIso, applyTaskPatch, applyWorkLogPatch, createTaskFromInput, } from "./repository.js";
|
|
12
|
+
import { TaskRepository, applyListTaskFilters, applyListProjectFilters, todayIso, applyTaskPatch, applyWorkLogPatch, applyProjectPatch, buildInstanceFromTemplate, createTaskFromInput, createProjectFromInput, } from "./repository.js";
|
|
13
13
|
const decodeTask = Schema.decodeUnknownSync(TaskSchema);
|
|
14
14
|
const decodeWorkLogCreateInput = Schema.decodeUnknownSync(WorkLogCreateInputSchema);
|
|
15
15
|
const decodeWorkLogEntry = Schema.decodeUnknownSync(WorkLogEntrySchema);
|
|
16
|
+
const decodeProject = Schema.decodeUnknownSync(ProjectSchema);
|
|
17
|
+
const decodeProjectCreateInput = Schema.decodeUnknownSync(ProjectCreateInputSchema);
|
|
18
|
+
const decodeProjectPatch = Schema.decodeUnknownSync(ProjectPatchSchema);
|
|
16
19
|
const toErrorMessage = (error) => {
|
|
17
20
|
if (error !== null && typeof error === "object" && "_tag" in error) {
|
|
18
21
|
const tagged = error;
|
|
@@ -58,6 +61,11 @@ const makeDbConfig = (options) => ({
|
|
|
58
61
|
: {}),
|
|
59
62
|
relationships: {},
|
|
60
63
|
},
|
|
64
|
+
projects: {
|
|
65
|
+
schema: ProjectSchema,
|
|
66
|
+
file: join(dirname(options.tasksFile), "projects.yaml"),
|
|
67
|
+
relationships: {},
|
|
68
|
+
},
|
|
61
69
|
});
|
|
62
70
|
const makeProseqlRepository = (options) => Effect.gen(function* () {
|
|
63
71
|
const config = makeDbConfig(options);
|
|
@@ -112,6 +120,28 @@ const makeProseqlRepository = (options) => Effect.gen(function* () {
|
|
|
112
120
|
try: () => db.workLog.delete(id).runPromise,
|
|
113
121
|
catch: (error) => `ProseqlRepository failed to delete work log entry ${id}: ${toErrorMessage(error)}`,
|
|
114
122
|
});
|
|
123
|
+
const collectProjects = () => Effect.tryPromise({
|
|
124
|
+
try: () => db.projects.query().runPromise.then((results) => results),
|
|
125
|
+
catch: (error) => `ProseqlRepository.listProjects failed: ${toErrorMessage(error)}`,
|
|
126
|
+
});
|
|
127
|
+
const findProject = (id) => Effect.tryPromise({
|
|
128
|
+
try: () => db.projects.findById(id).runPromise,
|
|
129
|
+
catch: (error) => `ProseqlRepository failed to read project ${id}: ${toErrorMessage(error)}`,
|
|
130
|
+
});
|
|
131
|
+
const saveProject = (project) => Effect.tryPromise({
|
|
132
|
+
try: () => db.projects
|
|
133
|
+
.upsert({
|
|
134
|
+
where: { id: project.id },
|
|
135
|
+
create: project,
|
|
136
|
+
update: project,
|
|
137
|
+
})
|
|
138
|
+
.runPromise.then((r) => r),
|
|
139
|
+
catch: (error) => `ProseqlRepository failed to write project ${project.id}: ${toErrorMessage(error)}`,
|
|
140
|
+
});
|
|
141
|
+
const removeProject = (id) => Effect.tryPromise({
|
|
142
|
+
try: () => db.projects.delete(id).runPromise,
|
|
143
|
+
catch: (error) => `ProseqlRepository failed to delete project ${id}: ${toErrorMessage(error)}`,
|
|
144
|
+
});
|
|
115
145
|
const writeDailyHighlight = (id) => Effect.tryPromise({
|
|
116
146
|
try: async () => {
|
|
117
147
|
const highlightPath = join(dataDir, "daily-highlight.yaml");
|
|
@@ -127,6 +157,32 @@ const makeProseqlRepository = (options) => Effect.gen(function* () {
|
|
|
127
157
|
}
|
|
128
158
|
return a.id.localeCompare(b.id);
|
|
129
159
|
};
|
|
160
|
+
const readDailyHighlight = () => Effect.gen(function* () {
|
|
161
|
+
const highlightPath = join(dataDir, "daily-highlight.yaml");
|
|
162
|
+
const source = yield* Effect.tryPromise({
|
|
163
|
+
try: () => readFile(highlightPath, "utf8").catch((error) => {
|
|
164
|
+
if (error !== null &&
|
|
165
|
+
typeof error === "object" &&
|
|
166
|
+
"code" in error &&
|
|
167
|
+
error.code === "ENOENT") {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
throw error;
|
|
171
|
+
}),
|
|
172
|
+
catch: (error) => `ProseqlRepository failed to read daily highlight: ${toErrorMessage(error)}`,
|
|
173
|
+
});
|
|
174
|
+
if (source === null || source.trim().length === 0) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
const parsed = YAML.parse(source);
|
|
178
|
+
if (parsed === null ||
|
|
179
|
+
typeof parsed !== "object" ||
|
|
180
|
+
typeof parsed.id !== "string") {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
const result = yield* Effect.catchAll(Effect.map(findTask(parsed.id), (t) => t), () => Effect.succeed(null));
|
|
184
|
+
return result;
|
|
185
|
+
});
|
|
130
186
|
const service = {
|
|
131
187
|
listTasks: (filters) => Effect.map(collectTasks(), (tasks) => applyListTaskFilters(tasks, filters)),
|
|
132
188
|
getTask: (id) => findTask(id),
|
|
@@ -206,6 +262,7 @@ const makeProseqlRepository = (options) => Effect.gen(function* () {
|
|
|
206
262
|
yield* writeDailyHighlight(id);
|
|
207
263
|
return existing;
|
|
208
264
|
}),
|
|
265
|
+
getDailyHighlight: () => readDailyHighlight(),
|
|
209
266
|
listStale: (days) => Effect.map(collectTasks(), (tasks) => {
|
|
210
267
|
const stalePredicate = isStalerThan(days, todayIso());
|
|
211
268
|
return tasks
|
|
@@ -249,6 +306,45 @@ const makeProseqlRepository = (options) => Effect.gen(function* () {
|
|
|
249
306
|
yield* saveWorkLogEntry(entry);
|
|
250
307
|
return entry;
|
|
251
308
|
}),
|
|
309
|
+
listProjects: (filters) => Effect.map(collectProjects(), (projects) => applyListProjectFilters(projects, filters)),
|
|
310
|
+
getProject: (id) => findProject(id),
|
|
311
|
+
createProject: (input) => Effect.gen(function* () {
|
|
312
|
+
const created = createProjectFromInput(input);
|
|
313
|
+
yield* saveProject(created);
|
|
314
|
+
return created;
|
|
315
|
+
}),
|
|
316
|
+
updateProject: (id, patch) => Effect.gen(function* () {
|
|
317
|
+
const existing = yield* findProject(id);
|
|
318
|
+
const updated = applyProjectPatch(existing, patch);
|
|
319
|
+
yield* saveProject(updated);
|
|
320
|
+
return updated;
|
|
321
|
+
}),
|
|
322
|
+
deleteProject: (id) => Effect.gen(function* () {
|
|
323
|
+
yield* removeProject(id);
|
|
324
|
+
return { deleted: true };
|
|
325
|
+
}),
|
|
326
|
+
importProject: (project) => Effect.gen(function* () {
|
|
327
|
+
yield* saveProject(project);
|
|
328
|
+
return project;
|
|
329
|
+
}),
|
|
330
|
+
listContexts: () => Effect.map(collectTasks(), (tasks) => listContextsFromTasks(tasks)),
|
|
331
|
+
getRelated: (id) => Effect.gen(function* () {
|
|
332
|
+
const target = yield* findTask(id);
|
|
333
|
+
const allTasks = yield* collectTasks();
|
|
334
|
+
const targetRelated = new Set(target.related);
|
|
335
|
+
return allTasks.filter((t) => t.id !== id &&
|
|
336
|
+
(targetRelated.has(t.id) || t.related.includes(id)));
|
|
337
|
+
}),
|
|
338
|
+
instantiateTemplate: (templateId, overrides) => Effect.gen(function* () {
|
|
339
|
+
const template = yield* findTask(templateId);
|
|
340
|
+
if (!template.is_template) {
|
|
341
|
+
return yield* Effect.fail(`Task ${templateId} is not a template`);
|
|
342
|
+
}
|
|
343
|
+
const instance = buildInstanceFromTemplate(template, overrides);
|
|
344
|
+
const taskFromHooks = yield* runCreateHooks(instance, hookRuntimeOptions);
|
|
345
|
+
yield* saveTask(taskFromHooks);
|
|
346
|
+
return taskFromHooks;
|
|
347
|
+
}),
|
|
252
348
|
};
|
|
253
349
|
return service;
|
|
254
350
|
});
|
package/dist/src/query.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
2
|
import * as Schema from "effect/Schema";
|
|
3
|
-
import { type Task, type
|
|
3
|
+
import { type Task, type Project } from "./schema.js";
|
|
4
4
|
export declare const isBlocked: (task: Task, allTasks: Task[]) => boolean;
|
|
5
5
|
export declare const isUnblocked: (task: Task, allTasks: Task[]) => boolean;
|
|
6
6
|
export declare const isDueBefore: (date: string) => (task: Task) => boolean;
|
|
7
7
|
export declare const isDueThisWeek: (today: string) => (task: Task) => boolean;
|
|
8
8
|
export declare const isDeferred: (today: string) => (task: Task) => boolean;
|
|
9
|
-
export declare const hasEnergy: (level:
|
|
9
|
+
export declare const hasEnergy: (level: string) => (task: Task) => boolean;
|
|
10
10
|
export declare const hasTag: (tag: string) => (task: Task) => boolean;
|
|
11
11
|
export declare const hasProject: (project: string) => (task: Task) => boolean;
|
|
12
|
+
export declare const hasDurationMin: (min: number) => (task: Task) => boolean;
|
|
13
|
+
export declare const hasDurationMax: (max: number) => (task: Task) => boolean;
|
|
14
|
+
export declare const hasContext: (context: string) => (task: Task) => boolean;
|
|
12
15
|
export declare const isStalerThan: (days: number, today: string) => (task: Task) => boolean;
|
|
13
16
|
export declare const wasCompletedOn: (date: string) => (task: Task) => boolean;
|
|
14
17
|
export declare const wasCompletedBetween: (start: string, end: string) => (task: Task) => boolean;
|
|
@@ -18,10 +21,10 @@ export declare const byCreatedAsc: (a: Task, b: Task) => number;
|
|
|
18
21
|
export declare const byUpdatedDescThenTitle: (a: Task, b: Task) => number;
|
|
19
22
|
export declare const resolveRelativeDate: (value: string, today: string) => string | null;
|
|
20
23
|
export declare const PerspectiveFilters: Schema.Struct<{
|
|
21
|
-
status: Schema.optionalWith<Schema.
|
|
24
|
+
status: Schema.optionalWith<typeof Schema.String, {
|
|
22
25
|
exact: true;
|
|
23
26
|
}>;
|
|
24
|
-
area: Schema.optionalWith<Schema.
|
|
27
|
+
area: Schema.optionalWith<typeof Schema.String, {
|
|
25
28
|
exact: true;
|
|
26
29
|
}>;
|
|
27
30
|
project: Schema.optionalWith<typeof Schema.String, {
|
|
@@ -39,7 +42,7 @@ export declare const PerspectiveFilters: Schema.Struct<{
|
|
|
39
42
|
unblocked_only: Schema.optionalWith<typeof Schema.Boolean, {
|
|
40
43
|
exact: true;
|
|
41
44
|
}>;
|
|
42
|
-
energy: Schema.optionalWith<Schema.
|
|
45
|
+
energy: Schema.optionalWith<typeof Schema.String, {
|
|
43
46
|
exact: true;
|
|
44
47
|
}>;
|
|
45
48
|
stale_days: Schema.optionalWith<typeof Schema.Number, {
|
|
@@ -48,16 +51,28 @@ export declare const PerspectiveFilters: Schema.Struct<{
|
|
|
48
51
|
completed_on: Schema.optionalWith<typeof Schema.String, {
|
|
49
52
|
exact: true;
|
|
50
53
|
}>;
|
|
54
|
+
duration_min: Schema.optionalWith<typeof Schema.Number, {
|
|
55
|
+
exact: true;
|
|
56
|
+
}>;
|
|
57
|
+
duration_max: Schema.optionalWith<typeof Schema.Number, {
|
|
58
|
+
exact: true;
|
|
59
|
+
}>;
|
|
60
|
+
context: Schema.optionalWith<typeof Schema.String, {
|
|
61
|
+
exact: true;
|
|
62
|
+
}>;
|
|
63
|
+
include_templates: Schema.optionalWith<typeof Schema.Boolean, {
|
|
64
|
+
exact: true;
|
|
65
|
+
}>;
|
|
51
66
|
}>;
|
|
52
67
|
export type PerspectiveFilters = Schema.Schema.Type<typeof PerspectiveFilters>;
|
|
53
68
|
export declare const PerspectiveSort: typeof Schema.String;
|
|
54
69
|
export type PerspectiveSort = Schema.Schema.Type<typeof PerspectiveSort>;
|
|
55
70
|
export declare const Perspective: Schema.Struct<{
|
|
56
71
|
filters: Schema.Struct<{
|
|
57
|
-
status: Schema.optionalWith<Schema.
|
|
72
|
+
status: Schema.optionalWith<typeof Schema.String, {
|
|
58
73
|
exact: true;
|
|
59
74
|
}>;
|
|
60
|
-
area: Schema.optionalWith<Schema.
|
|
75
|
+
area: Schema.optionalWith<typeof Schema.String, {
|
|
61
76
|
exact: true;
|
|
62
77
|
}>;
|
|
63
78
|
project: Schema.optionalWith<typeof Schema.String, {
|
|
@@ -75,7 +90,7 @@ export declare const Perspective: Schema.Struct<{
|
|
|
75
90
|
unblocked_only: Schema.optionalWith<typeof Schema.Boolean, {
|
|
76
91
|
exact: true;
|
|
77
92
|
}>;
|
|
78
|
-
energy: Schema.optionalWith<Schema.
|
|
93
|
+
energy: Schema.optionalWith<typeof Schema.String, {
|
|
79
94
|
exact: true;
|
|
80
95
|
}>;
|
|
81
96
|
stale_days: Schema.optionalWith<typeof Schema.Number, {
|
|
@@ -84,6 +99,18 @@ export declare const Perspective: Schema.Struct<{
|
|
|
84
99
|
completed_on: Schema.optionalWith<typeof Schema.String, {
|
|
85
100
|
exact: true;
|
|
86
101
|
}>;
|
|
102
|
+
duration_min: Schema.optionalWith<typeof Schema.Number, {
|
|
103
|
+
exact: true;
|
|
104
|
+
}>;
|
|
105
|
+
duration_max: Schema.optionalWith<typeof Schema.Number, {
|
|
106
|
+
exact: true;
|
|
107
|
+
}>;
|
|
108
|
+
context: Schema.optionalWith<typeof Schema.String, {
|
|
109
|
+
exact: true;
|
|
110
|
+
}>;
|
|
111
|
+
include_templates: Schema.optionalWith<typeof Schema.Boolean, {
|
|
112
|
+
exact: true;
|
|
113
|
+
}>;
|
|
87
114
|
}>;
|
|
88
115
|
sort: Schema.optionalWith<typeof Schema.String, {
|
|
89
116
|
exact: true;
|
|
@@ -92,10 +119,10 @@ export declare const Perspective: Schema.Struct<{
|
|
|
92
119
|
export type Perspective = Schema.Schema.Type<typeof Perspective>;
|
|
93
120
|
export declare const PerspectiveConfig: Schema.Record$<typeof Schema.String, Schema.Struct<{
|
|
94
121
|
filters: Schema.Struct<{
|
|
95
|
-
status: Schema.optionalWith<Schema.
|
|
122
|
+
status: Schema.optionalWith<typeof Schema.String, {
|
|
96
123
|
exact: true;
|
|
97
124
|
}>;
|
|
98
|
-
area: Schema.optionalWith<Schema.
|
|
125
|
+
area: Schema.optionalWith<typeof Schema.String, {
|
|
99
126
|
exact: true;
|
|
100
127
|
}>;
|
|
101
128
|
project: Schema.optionalWith<typeof Schema.String, {
|
|
@@ -113,7 +140,7 @@ export declare const PerspectiveConfig: Schema.Record$<typeof Schema.String, Sch
|
|
|
113
140
|
unblocked_only: Schema.optionalWith<typeof Schema.Boolean, {
|
|
114
141
|
exact: true;
|
|
115
142
|
}>;
|
|
116
|
-
energy: Schema.optionalWith<Schema.
|
|
143
|
+
energy: Schema.optionalWith<typeof Schema.String, {
|
|
117
144
|
exact: true;
|
|
118
145
|
}>;
|
|
119
146
|
stale_days: Schema.optionalWith<typeof Schema.Number, {
|
|
@@ -122,6 +149,18 @@ export declare const PerspectiveConfig: Schema.Record$<typeof Schema.String, Sch
|
|
|
122
149
|
completed_on: Schema.optionalWith<typeof Schema.String, {
|
|
123
150
|
exact: true;
|
|
124
151
|
}>;
|
|
152
|
+
duration_min: Schema.optionalWith<typeof Schema.Number, {
|
|
153
|
+
exact: true;
|
|
154
|
+
}>;
|
|
155
|
+
duration_max: Schema.optionalWith<typeof Schema.Number, {
|
|
156
|
+
exact: true;
|
|
157
|
+
}>;
|
|
158
|
+
context: Schema.optionalWith<typeof Schema.String, {
|
|
159
|
+
exact: true;
|
|
160
|
+
}>;
|
|
161
|
+
include_templates: Schema.optionalWith<typeof Schema.Boolean, {
|
|
162
|
+
exact: true;
|
|
163
|
+
}>;
|
|
125
164
|
}>;
|
|
126
165
|
sort: Schema.optionalWith<typeof Schema.String, {
|
|
127
166
|
exact: true;
|
|
@@ -132,4 +171,13 @@ export declare const parsePerspectiveConfig: (record: unknown) => PerspectiveCon
|
|
|
132
171
|
export declare const resolvePerspectiveConfigRelativeDates: (config: PerspectiveConfig, today: string) => PerspectiveConfig | null;
|
|
133
172
|
export declare const applyPerspectiveToTasks: (tasks: ReadonlyArray<Task>, perspective: Perspective, today?: string) => Array<Task>;
|
|
134
173
|
export declare const loadPerspectiveConfig: (dataDir: string, today?: string) => Effect.Effect<PerspectiveConfig, string>;
|
|
174
|
+
export declare const listAreas: (tasks: ReadonlyArray<Task>, projects: ReadonlyArray<Project>) => Array<string>;
|
|
175
|
+
export declare const byUrgencyDesc: (a: Task, b: Task) => number;
|
|
176
|
+
export interface DependencyChain {
|
|
177
|
+
readonly ancestors: Task[];
|
|
178
|
+
readonly target: Task | null;
|
|
179
|
+
readonly descendants: Task[];
|
|
180
|
+
}
|
|
181
|
+
export declare const buildDependencyChain: (targetId: string, allTasks: ReadonlyArray<Task>) => DependencyChain;
|
|
182
|
+
export declare const listContexts: (tasks: ReadonlyArray<Task>) => Array<string>;
|
|
135
183
|
//# sourceMappingURL=query.d.ts.map
|
package/dist/src/query.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/query.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/query.ts"],"names":[],"mappings":"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"}
|
package/dist/src/query.js
CHANGED
|
@@ -4,7 +4,7 @@ import * as Effect from "effect/Effect";
|
|
|
4
4
|
import * as Either from "effect/Either";
|
|
5
5
|
import * as Schema from "effect/Schema";
|
|
6
6
|
import YAML from "yaml";
|
|
7
|
-
import {
|
|
7
|
+
import { TaskEnergy as TaskEnergySchema, TaskStatus as TaskStatusSchema, } from "./schema.js";
|
|
8
8
|
const addDays = (date, days) => {
|
|
9
9
|
const next = new Date(`${date}T00:00:00.000Z`);
|
|
10
10
|
next.setUTCDate(next.getUTCDate() + days);
|
|
@@ -58,7 +58,10 @@ export const isDueThisWeek = (today) => {
|
|
|
58
58
|
export const isDeferred = (today) => (task) => task.defer_until !== null && task.defer_until > today;
|
|
59
59
|
export const hasEnergy = (level) => (task) => task.energy === level;
|
|
60
60
|
export const hasTag = (tag) => (task) => task.tags.includes(tag);
|
|
61
|
-
export const hasProject = (project) => (task) => task.project
|
|
61
|
+
export const hasProject = (project) => (task) => task.projects.includes(project);
|
|
62
|
+
export const hasDurationMin = (min) => (task) => task.estimated_minutes !== null && task.estimated_minutes >= min;
|
|
63
|
+
export const hasDurationMax = (max) => (task) => task.estimated_minutes !== null && task.estimated_minutes <= max;
|
|
64
|
+
export const hasContext = (context) => (task) => task.context === context;
|
|
62
65
|
export const isStalerThan = (days, today) => (task) => {
|
|
63
66
|
const updated = dateToUtcMidnight(task.updated);
|
|
64
67
|
const now = dateToUtcMidnight(today);
|
|
@@ -76,10 +79,9 @@ export const wasCompletedBetween = (start, end) => (task) => {
|
|
|
76
79
|
}
|
|
77
80
|
return completed >= start && completed <= end;
|
|
78
81
|
};
|
|
79
|
-
const energyRank = {
|
|
80
|
-
low: 0,
|
|
81
|
-
|
|
82
|
-
high: 2,
|
|
82
|
+
const energyRank = (e) => {
|
|
83
|
+
const ranks = { low: 0, medium: 1, high: 2 };
|
|
84
|
+
return ranks[e] ?? -1;
|
|
83
85
|
};
|
|
84
86
|
export const byDueAsc = (a, b) => {
|
|
85
87
|
if (a.due === null && b.due === null) {
|
|
@@ -93,7 +95,7 @@ export const byDueAsc = (a, b) => {
|
|
|
93
95
|
}
|
|
94
96
|
return a.due.localeCompare(b.due);
|
|
95
97
|
};
|
|
96
|
-
export const byEnergyAsc = (a, b) => energyRank
|
|
98
|
+
export const byEnergyAsc = (a, b) => energyRank(a.energy) - energyRank(b.energy);
|
|
97
99
|
export const byCreatedAsc = (a, b) => a.created.localeCompare(b.created);
|
|
98
100
|
export const byUpdatedDescThenTitle = (a, b) => {
|
|
99
101
|
const byUpdatedDesc = b.updated.localeCompare(a.updated);
|
|
@@ -145,7 +147,7 @@ export const resolveRelativeDate = (value, today) => {
|
|
|
145
147
|
};
|
|
146
148
|
export const PerspectiveFilters = Schema.Struct({
|
|
147
149
|
status: Schema.optionalWith(TaskStatusSchema, { exact: true }),
|
|
148
|
-
area: Schema.optionalWith(
|
|
150
|
+
area: Schema.optionalWith(Schema.String, { exact: true }),
|
|
149
151
|
project: Schema.optionalWith(Schema.String, { exact: true }),
|
|
150
152
|
tags: Schema.optionalWith(Schema.Array(Schema.String), { exact: true }),
|
|
151
153
|
due_before: Schema.optionalWith(Schema.String, { exact: true }),
|
|
@@ -154,6 +156,10 @@ export const PerspectiveFilters = Schema.Struct({
|
|
|
154
156
|
energy: Schema.optionalWith(TaskEnergySchema, { exact: true }),
|
|
155
157
|
stale_days: Schema.optionalWith(Schema.Number, { exact: true }),
|
|
156
158
|
completed_on: Schema.optionalWith(Schema.String, { exact: true }),
|
|
159
|
+
duration_min: Schema.optionalWith(Schema.Number, { exact: true }),
|
|
160
|
+
duration_max: Schema.optionalWith(Schema.Number, { exact: true }),
|
|
161
|
+
context: Schema.optionalWith(Schema.String, { exact: true }),
|
|
162
|
+
include_templates: Schema.optionalWith(Schema.Boolean, { exact: true }),
|
|
157
163
|
});
|
|
158
164
|
export const PerspectiveSort = Schema.String;
|
|
159
165
|
export const Perspective = Schema.Struct({
|
|
@@ -207,7 +213,20 @@ export const applyPerspectiveToTasks = (tasks, perspective, today = currentIsoDa
|
|
|
207
213
|
const completedOnPredicate = perspective.filters.completed_on !== undefined
|
|
208
214
|
? wasCompletedOn(perspective.filters.completed_on)
|
|
209
215
|
: null;
|
|
216
|
+
const durationMinPredicate = perspective.filters.duration_min !== undefined
|
|
217
|
+
? hasDurationMin(perspective.filters.duration_min)
|
|
218
|
+
: null;
|
|
219
|
+
const durationMaxPredicate = perspective.filters.duration_max !== undefined
|
|
220
|
+
? hasDurationMax(perspective.filters.duration_max)
|
|
221
|
+
: null;
|
|
222
|
+
const contextPredicate = perspective.filters.context !== undefined
|
|
223
|
+
? hasContext(perspective.filters.context)
|
|
224
|
+
: null;
|
|
210
225
|
const filtered = taskList.filter((task) => {
|
|
226
|
+
if (perspective.filters.include_templates !== true &&
|
|
227
|
+
task.is_template === true) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
211
230
|
if (perspective.filters.status !== undefined &&
|
|
212
231
|
task.status !== perspective.filters.status) {
|
|
213
232
|
return false;
|
|
@@ -217,7 +236,7 @@ export const applyPerspectiveToTasks = (tasks, perspective, today = currentIsoDa
|
|
|
217
236
|
return false;
|
|
218
237
|
}
|
|
219
238
|
if (perspective.filters.project !== undefined &&
|
|
220
|
-
task.
|
|
239
|
+
!task.projects.includes(perspective.filters.project)) {
|
|
221
240
|
return false;
|
|
222
241
|
}
|
|
223
242
|
if (perspective.filters.tags !== undefined &&
|
|
@@ -246,6 +265,15 @@ export const applyPerspectiveToTasks = (tasks, perspective, today = currentIsoDa
|
|
|
246
265
|
if (completedOnPredicate !== null && !completedOnPredicate(task)) {
|
|
247
266
|
return false;
|
|
248
267
|
}
|
|
268
|
+
if (durationMinPredicate !== null && !durationMinPredicate(task)) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
if (durationMaxPredicate !== null && !durationMaxPredicate(task)) {
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
if (contextPredicate !== null && !contextPredicate(task)) {
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
249
277
|
return true;
|
|
250
278
|
});
|
|
251
279
|
switch (perspective.sort) {
|
|
@@ -301,3 +329,63 @@ export const loadPerspectiveConfig = (dataDir, today = currentIsoDate()) => Effe
|
|
|
301
329
|
},
|
|
302
330
|
catch: (error) => `Perspective config loader failed: ${toErrorMessage(error)}`,
|
|
303
331
|
});
|
|
332
|
+
export const listAreas = (tasks, projects) => {
|
|
333
|
+
const areas = new Set();
|
|
334
|
+
for (const task of tasks) {
|
|
335
|
+
areas.add(task.area);
|
|
336
|
+
}
|
|
337
|
+
for (const project of projects) {
|
|
338
|
+
areas.add(project.area);
|
|
339
|
+
}
|
|
340
|
+
return Array.from(areas).sort();
|
|
341
|
+
};
|
|
342
|
+
export const byUrgencyDesc = (a, b) => {
|
|
343
|
+
const urgencyRanks = { low: 0, medium: 1, high: 2 };
|
|
344
|
+
const aRank = urgencyRanks[a.urgency] ?? -1;
|
|
345
|
+
const bRank = urgencyRanks[b.urgency] ?? -1;
|
|
346
|
+
return bRank - aRank;
|
|
347
|
+
};
|
|
348
|
+
export const buildDependencyChain = (targetId, allTasks) => {
|
|
349
|
+
const taskById = new Map(allTasks.map((t) => [t.id, t]));
|
|
350
|
+
const target = taskById.get(targetId) ?? null;
|
|
351
|
+
const ancestors = [];
|
|
352
|
+
const visitedUp = new Set();
|
|
353
|
+
const walkUp = (id) => {
|
|
354
|
+
const task = taskById.get(id);
|
|
355
|
+
if (task === undefined)
|
|
356
|
+
return;
|
|
357
|
+
for (const blockerId of task.blocked_by) {
|
|
358
|
+
if (visitedUp.has(blockerId))
|
|
359
|
+
continue;
|
|
360
|
+
visitedUp.add(blockerId);
|
|
361
|
+
const blocker = taskById.get(blockerId);
|
|
362
|
+
if (blocker !== undefined) {
|
|
363
|
+
walkUp(blockerId);
|
|
364
|
+
ancestors.push(blocker);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
walkUp(targetId);
|
|
369
|
+
const descendants = [];
|
|
370
|
+
const visitedDown = new Set();
|
|
371
|
+
const walkDown = (id) => {
|
|
372
|
+
for (const task of allTasks) {
|
|
373
|
+
if (task.blocked_by.includes(id) && !visitedDown.has(task.id)) {
|
|
374
|
+
visitedDown.add(task.id);
|
|
375
|
+
descendants.push(task);
|
|
376
|
+
walkDown(task.id);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
walkDown(targetId);
|
|
381
|
+
return { ancestors, target, descendants };
|
|
382
|
+
};
|
|
383
|
+
export const listContexts = (tasks) => {
|
|
384
|
+
const contexts = new Set();
|
|
385
|
+
for (const task of tasks) {
|
|
386
|
+
if (task.context.length > 0) {
|
|
387
|
+
contexts.add(task.context);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return Array.from(contexts).sort();
|
|
391
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recurrence.d.ts","sourceRoot":"","sources":["../../src/recurrence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAIxC,OAAO,EAAsB,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAQ5D,MAAM,WAAW,4BAA4B;IAC5C,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC9D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;AAYD,eAAO,MAAM,iCAAiC,GAC7C,YAAY,MAAM,KAChB,MAAM,CAAC,MAAM,CAAC,4BAA4B,EAAE,MAAM,CA8BlD,CAAC;AAEJ,eAAO,MAAM,qBAAqB,GACjC,MAAM,IAAI,EACV,oBAAoB,4BAA4B,KAC9C,IAmBF,CAAC;AAEF,eAAO,MAAM,gCAAgC,GAC5C,MAAM,MAAM,EACZ,oBAAoB,4BAA4B,KAC9C,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAc5B,CAAC;AAEJ,eAAO,MAAM,0CAA0C,GACtD,UAAU,MAAM,EAChB,oBAAoB,4BAA4B,KAC9C,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAc5B,CAAC;AAEJ,eAAO,MAAM,aAAa,GACzB,OAAO,IAAI,EACX,OAAO,MAAM,KACX,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAW5B,CAAC;AAEJ,eAAO,MAAM,sBAAsB,GAClC,OAAO,MAAM,EACb,OAAO,MAAM,KACX,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAW1B,CAAC;AAEJ,eAAO,MAAM,gBAAgB,GAC5B,OAAO,MAAM,EACb,OAAO,MAAM,KACX,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAW1B,CAAC;AAEJ,eAAO,MAAM,6BAA6B,GACzC,eAAe,IAAI,EACnB,aAAa,MAAM,KACjB,MAAM,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,EAAE,MAAM,CAwCnC,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAChC,MAAM,IAAI,EACV,KAAK,IAAI,KACP,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CA8B7B,CAAC;AAEJ,eAAO,MAAM,4BAA4B,GACxC,cAAc,IAAI,EAClB,aAAa,IAAI,KACf,MAAM,CAAC,MAAM,CACf;IACC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,IAAI,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC;CACvC,EACD,MAAM,
|
|
1
|
+
{"version":3,"file":"recurrence.d.ts","sourceRoot":"","sources":["../../src/recurrence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAIxC,OAAO,EAAsB,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAQ5D,MAAM,WAAW,4BAA4B;IAC5C,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC9D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;AAYD,eAAO,MAAM,iCAAiC,GAC7C,YAAY,MAAM,KAChB,MAAM,CAAC,MAAM,CAAC,4BAA4B,EAAE,MAAM,CA8BlD,CAAC;AAEJ,eAAO,MAAM,qBAAqB,GACjC,MAAM,IAAI,EACV,oBAAoB,4BAA4B,KAC9C,IAmBF,CAAC;AAEF,eAAO,MAAM,gCAAgC,GAC5C,MAAM,MAAM,EACZ,oBAAoB,4BAA4B,KAC9C,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAc5B,CAAC;AAEJ,eAAO,MAAM,0CAA0C,GACtD,UAAU,MAAM,EAChB,oBAAoB,4BAA4B,KAC9C,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAc5B,CAAC;AAEJ,eAAO,MAAM,aAAa,GACzB,OAAO,IAAI,EACX,OAAO,MAAM,KACX,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAW5B,CAAC;AAEJ,eAAO,MAAM,sBAAsB,GAClC,OAAO,MAAM,EACb,OAAO,MAAM,KACX,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAW1B,CAAC;AAEJ,eAAO,MAAM,gBAAgB,GAC5B,OAAO,MAAM,EACb,OAAO,MAAM,KACX,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAW1B,CAAC;AAEJ,eAAO,MAAM,6BAA6B,GACzC,eAAe,IAAI,EACnB,aAAa,MAAM,KACjB,MAAM,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,EAAE,MAAM,CAwCnC,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAChC,MAAM,IAAI,EACV,KAAK,IAAI,KACP,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CA8B7B,CAAC;AAEJ,eAAO,MAAM,4BAA4B,GACxC,cAAc,IAAI,EAClB,aAAa,IAAI,KACf,MAAM,CAAC,MAAM,CACf;IACC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,IAAI,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC;CACvC,EACD,MAAM,CA6DJ,CAAC"}
|
package/dist/src/recurrence.js
CHANGED
|
@@ -151,6 +151,9 @@ export const isClockRecurrenceDue = (task, now) => Effect.gen(function* () {
|
|
|
151
151
|
return (nextOccurrence !== null && nextOccurrence.getTime() <= nowDate.getTime());
|
|
152
152
|
});
|
|
153
153
|
export const buildNextClockRecurrenceTask = (existingTask, generatedAt) => Effect.gen(function* () {
|
|
154
|
+
if (existingTask.is_template) {
|
|
155
|
+
return yield* Effect.fail(`TaskRepository failed to generate next recurrence for ${existingTask.id}: task is a template (use instantiation instead)`);
|
|
156
|
+
}
|
|
154
157
|
const recurrence = existingTask.recurrence;
|
|
155
158
|
if (recurrence === null) {
|
|
156
159
|
return yield* Effect.fail(`TaskRepository failed to generate next recurrence for ${existingTask.id}: task is not recurring`);
|
package/dist/src/repository.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as Context from "effect/Context";
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
3
|
import * as Layer from "effect/Layer";
|
|
4
|
-
import { type Task, type TaskCreateInput, type TaskPatch, type WorkLogCreateInput, type WorkLogEntry, type WorkLogPatch } from "./schema.js";
|
|
4
|
+
import { type Task, type TaskCreateInput, type TaskPatch, type WorkLogCreateInput, type WorkLogEntry, type WorkLogPatch, type Project, type ProjectCreateInput, type ProjectPatch } from "./schema.js";
|
|
5
5
|
export { discoverHooksForEvent } from "./hooks.js";
|
|
6
6
|
export type { HookEvent, HookDiscoveryOptions } from "./hooks.js";
|
|
7
7
|
export { generateTaskId } from "./id.js";
|
|
@@ -15,7 +15,17 @@ export interface ListTasksFilters {
|
|
|
15
15
|
readonly due_after?: string;
|
|
16
16
|
readonly unblocked_only?: boolean;
|
|
17
17
|
readonly date?: string;
|
|
18
|
+
readonly duration_min?: number;
|
|
19
|
+
readonly duration_max?: number;
|
|
20
|
+
readonly context?: string;
|
|
21
|
+
readonly include_templates?: boolean;
|
|
22
|
+
readonly stale_days?: number;
|
|
18
23
|
}
|
|
24
|
+
export interface ListProjectsFilters {
|
|
25
|
+
readonly status?: string;
|
|
26
|
+
readonly area?: string;
|
|
27
|
+
}
|
|
28
|
+
export declare const applyListProjectFilters: (projects: Array<Project>, filters?: ListProjectsFilters) => Array<Project>;
|
|
19
29
|
export interface ListWorkLogFilters {
|
|
20
30
|
readonly date?: string;
|
|
21
31
|
}
|
|
@@ -42,6 +52,22 @@ export interface TaskRepositoryService {
|
|
|
42
52
|
readonly deleteWorkLogEntry: (id: string) => Effect.Effect<DeleteResult, string>;
|
|
43
53
|
readonly importTask: (task: Task) => Effect.Effect<Task, string>;
|
|
44
54
|
readonly importWorkLogEntry: (entry: WorkLogEntry) => Effect.Effect<WorkLogEntry, string>;
|
|
55
|
+
readonly listProjects: (filters?: ListProjectsFilters) => Effect.Effect<Array<Project>, string>;
|
|
56
|
+
readonly getProject: (id: string) => Effect.Effect<Project, string>;
|
|
57
|
+
readonly createProject: (input: ProjectCreateInput) => Effect.Effect<Project, string>;
|
|
58
|
+
readonly updateProject: (id: string, patch: ProjectPatch) => Effect.Effect<Project, string>;
|
|
59
|
+
readonly deleteProject: (id: string) => Effect.Effect<DeleteResult, string>;
|
|
60
|
+
readonly importProject: (project: Project) => Effect.Effect<Project, string>;
|
|
61
|
+
readonly getDailyHighlight: () => Effect.Effect<Task | null, string>;
|
|
62
|
+
readonly listContexts: () => Effect.Effect<Array<string>, string>;
|
|
63
|
+
readonly getRelated: (id: string) => Effect.Effect<Array<Task>, string>;
|
|
64
|
+
readonly instantiateTemplate: (templateId: string, overrides?: {
|
|
65
|
+
readonly title?: string;
|
|
66
|
+
readonly due?: string;
|
|
67
|
+
readonly defer_until?: string;
|
|
68
|
+
readonly status?: string;
|
|
69
|
+
readonly projects?: ReadonlyArray<string>;
|
|
70
|
+
}) => Effect.Effect<Task, string>;
|
|
45
71
|
}
|
|
46
72
|
declare const TaskRepository_base: Context.TagClass<TaskRepository, "TaskRepository", TaskRepositoryService>;
|
|
47
73
|
export declare class TaskRepository extends TaskRepository_base {
|
|
@@ -51,6 +77,13 @@ export interface TaskRepositoryLiveOptions {
|
|
|
51
77
|
readonly hooksDir?: string;
|
|
52
78
|
readonly hookEnv?: NodeJS.ProcessEnv;
|
|
53
79
|
}
|
|
80
|
+
export declare const buildInstanceFromTemplate: (template: Task, overrides?: {
|
|
81
|
+
readonly title?: string;
|
|
82
|
+
readonly due?: string;
|
|
83
|
+
readonly defer_until?: string;
|
|
84
|
+
readonly status?: string;
|
|
85
|
+
readonly projects?: ReadonlyArray<string>;
|
|
86
|
+
}) => Task;
|
|
54
87
|
export declare const TaskRepositoryLive: (options?: TaskRepositoryLiveOptions) => Layer.Layer<TaskRepository>;
|
|
55
88
|
export declare const todayIso: () => string;
|
|
56
89
|
export declare const parseTaskRecord: (record: unknown) => Task | null;
|
|
@@ -58,4 +91,8 @@ export declare const parseWorkLogRecord: (record: unknown) => WorkLogEntry | nul
|
|
|
58
91
|
export declare const createTaskFromInput: (input: TaskCreateInput) => Task;
|
|
59
92
|
export declare const applyTaskPatch: (task: Task, patch: TaskPatch) => Task;
|
|
60
93
|
export declare const applyWorkLogPatch: (entry: WorkLogEntry, patch: WorkLogPatch) => WorkLogEntry;
|
|
94
|
+
export declare const parseProjectRecord: (record: unknown) => Project | null;
|
|
95
|
+
export declare const createProjectFromInput: (input: ProjectCreateInput) => Project;
|
|
96
|
+
export declare const promoteSubtask: (repository: TaskRepositoryService, taskId: string, subtaskIndex: number) => Effect.Effect<Task, string>;
|
|
97
|
+
export declare const applyProjectPatch: (project: Project, patch: ProjectPatch) => Project;
|
|
61
98
|
//# sourceMappingURL=repository.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/repository.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAE1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAGtC,OAAO,
|
|
1
|
+
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/repository.ts"],"names":[],"mappings":"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"}
|