@clipboard-health/groundcrew 4.20.2 → 4.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +3 -0
  2. package/crew.config.example.ts +10 -9
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +6 -0
  5. package/dist/commands/init.js +5 -3
  6. package/dist/commands/orchestrator.d.ts.map +1 -1
  7. package/dist/commands/orchestrator.js +20 -7
  8. package/dist/commands/status.d.ts.map +1 -1
  9. package/dist/commands/status.js +2 -4
  10. package/dist/commands/task.d.ts +2 -0
  11. package/dist/commands/task.d.ts.map +1 -0
  12. package/dist/commands/task.js +488 -0
  13. package/dist/lib/adapters/linear/factory.d.ts.map +1 -1
  14. package/dist/lib/adapters/linear/factory.js +61 -34
  15. package/dist/lib/adapters/linear/fetch.d.ts +9 -0
  16. package/dist/lib/adapters/linear/fetch.d.ts.map +1 -1
  17. package/dist/lib/adapters/linear/fetch.js +11 -0
  18. package/dist/lib/adapters/shell/factory.d.ts.map +1 -1
  19. package/dist/lib/adapters/shell/factory.js +31 -22
  20. package/dist/lib/adapters/todo-txt/source.d.ts.map +1 -1
  21. package/dist/lib/adapters/todo-txt/source.js +230 -21
  22. package/dist/lib/adapters/todo-txt/writeback.d.ts +1 -0
  23. package/dist/lib/adapters/todo-txt/writeback.d.ts.map +1 -1
  24. package/dist/lib/adapters/todo-txt/writeback.js +1 -1
  25. package/dist/lib/board.d.ts +1 -1
  26. package/dist/lib/board.js +3 -3
  27. package/dist/lib/buildSources.d.ts +7 -18
  28. package/dist/lib/buildSources.d.ts.map +1 -1
  29. package/dist/lib/buildSources.js +9 -48
  30. package/dist/lib/sourceCapabilities.js +1 -1
  31. package/dist/lib/taskSource.d.ts +36 -0
  32. package/dist/lib/taskSource.d.ts.map +1 -1
  33. package/docs/commands.md +30 -0
  34. package/docs/task-sources.md +42 -5
  35. package/package.json +1 -1
@@ -51,6 +51,11 @@ function toCanonicalParentSkip(skip, sourceName) {
51
51
  childCount: skip.childCount,
52
52
  };
53
53
  }
54
+ function isLinearNotFoundError(error, naturalId) {
55
+ return (error instanceof Error &&
56
+ error.message.startsWith(`Task ${naturalId.toUpperCase()} `) &&
57
+ error.message.includes("not found"));
58
+ }
54
59
  export function toCanonicalIssue(linearIssue, sourceName, statusNames = DEFAULT_LINEAR_STATUS_NAMES) {
55
60
  const sourceRef = {
56
61
  uuid: linearIssue.uuid,
@@ -106,51 +111,73 @@ export function createLinearTaskSource(config, context) {
106
111
  return cachedIssueStatusUpdater;
107
112
  }
108
113
  let lastParentSkips = [];
114
+ async function listTasks() {
115
+ const state = await getBoardSource().fetch();
116
+ lastParentSkips = state.parentSkips.map((skip) => toCanonicalParentSkip(skip, sourceName));
117
+ return state.issues.map((linearIssue) => toCanonicalIssue(linearIssue, sourceName, statusNames));
118
+ }
119
+ async function getTask(naturalId) {
120
+ let resolved;
121
+ try {
122
+ resolved = await fetchResolvedIssue({
123
+ client: getClient(),
124
+ config: globalConfig,
125
+ task: naturalId,
126
+ });
127
+ }
128
+ catch (error) {
129
+ if (isLinearNotFoundError(error, naturalId)) {
130
+ return null;
131
+ }
132
+ throw error;
133
+ }
134
+ const sourceRef = {
135
+ uuid: resolved.uuid,
136
+ statusId: resolved.statusId,
137
+ teamId: resolved.teamId,
138
+ stateType: resolved.stateType,
139
+ nativeStatus: resolved.status,
140
+ };
141
+ return {
142
+ id: toCanonicalId(sourceName, naturalId),
143
+ source: sourceName,
144
+ title: resolved.title,
145
+ description: resolved.description,
146
+ status: canonicalStatusFromLinearState({
147
+ nativeStatus: resolved.status,
148
+ stateType: resolved.stateType,
149
+ statusNames,
150
+ }),
151
+ repository: resolved.repository,
152
+ model: resolved.model,
153
+ assignee: resolved.assignee,
154
+ updatedAt: resolved.updatedAt,
155
+ blockers: resolved.blockers.map((b) => toCanonicalBlocker(b, sourceName, statusNames)),
156
+ hasMoreBlockers: resolved.hasMoreBlockers,
157
+ url: resolved.url,
158
+ ...(resolved.priority === 0 ? {} : { priority: resolved.priority }),
159
+ sourceRef,
160
+ };
161
+ }
109
162
  return {
110
163
  name: sourceName,
111
164
  async verify() {
112
165
  await getBoardSource().verify();
113
166
  },
167
+ async listTasks() {
168
+ return await listTasks();
169
+ },
170
+ async getTask(naturalId) {
171
+ return await getTask(naturalId);
172
+ },
114
173
  async fetch() {
115
- const state = await getBoardSource().fetch();
116
- lastParentSkips = state.parentSkips.map((skip) => toCanonicalParentSkip(skip, sourceName));
117
- return state.issues.map((linearIssue) => toCanonicalIssue(linearIssue, sourceName, statusNames));
174
+ return await listTasks();
118
175
  },
119
176
  async fetchParentSkips() {
120
177
  return lastParentSkips;
121
178
  },
122
179
  async resolveOne(naturalId) {
123
- const resolved = await fetchResolvedIssue({
124
- client: getClient(),
125
- config: globalConfig,
126
- task: naturalId,
127
- });
128
- const sourceRef = {
129
- uuid: resolved.uuid,
130
- statusId: resolved.statusId,
131
- teamId: resolved.teamId,
132
- stateType: resolved.stateType,
133
- nativeStatus: resolved.status,
134
- };
135
- return {
136
- id: toCanonicalId(sourceName, naturalId),
137
- source: sourceName,
138
- title: resolved.title,
139
- description: resolved.description,
140
- status: canonicalStatusFromLinearState({
141
- nativeStatus: resolved.status,
142
- stateType: resolved.stateType,
143
- statusNames,
144
- }),
145
- repository: resolved.repository,
146
- model: resolved.model,
147
- assignee: "Unassigned",
148
- updatedAt: new Date().toISOString(),
149
- blockers: [],
150
- hasMoreBlockers: false,
151
- url: resolved.url,
152
- sourceRef,
153
- };
180
+ return (await getTask(naturalId)) ?? undefined;
154
181
  },
155
182
  async markInProgress(issue) {
156
183
  // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- by the Linear adapter's contract, every Issue it produces carries a LinearSourceRef in sourceRef
@@ -116,7 +116,12 @@ interface ResolvedIssue {
116
116
  stateType: string;
117
117
  status: string;
118
118
  statusId: string;
119
+ assignee: string;
120
+ updatedAt: string;
121
+ blockers: Blocker[];
122
+ hasMoreBlockers: boolean;
119
123
  url: string;
124
+ priority: number;
120
125
  }
121
126
  export interface RawLinearIssue {
122
127
  uuid: string;
@@ -130,6 +135,8 @@ export interface RawLinearIssue {
130
135
  stateName: string;
131
136
  stateType: string;
132
137
  stateId: string;
138
+ assignee: string;
139
+ updatedAt: string;
133
140
  blockers: Blocker[];
134
141
  hasMoreBlockers: boolean;
135
142
  /**
@@ -141,6 +148,8 @@ export interface RawLinearIssue {
141
148
  hasChildren: boolean;
142
149
  /** Linear `Issue.url` — direct web link to the task. */
143
150
  url: string;
151
+ /** Linear priority: 1=Urgent, 2=High, 3=Medium, 4=Low, 0=No priority. */
152
+ priority: number;
144
153
  }
145
154
  export declare function fetchBlockersForTask(arguments_: {
146
155
  client: LinearClient;
@@ -1 +1 @@
1
- {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/linear/fetch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/linear/fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGtD,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AAEtB,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAYpC,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B;;;;OAIG;IACH,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,mGAAmG;IACnG,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,4FAA4F;IAC5F,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB,wDAAwD;IACxD,GAAG,EAAE,MAAM,CAAC;IACZ,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,KAAK,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;CAClC;AAED,UAAU,eAAe;IACvB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,WAAW,CAUpE;AAkBD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,OAAO,CAE1E;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,OAAO,CAEpE;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAE1E;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,OAAO,CAEjF;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAEpE;AA0BD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE;QACN,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC;KAChD,GAAG,IAAI,CAAC;CACV;AAqFD,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,OAAO,CAAC,eAAe,EAAE;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,GACzD,MAAM,CAQR;AAyGD,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAKD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3B,yFAAyF;IACzF,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB;;;;;OAKG;IACH,WAAW,EAAE,OAAO,CAAC;IACrB,wDAAwD;IACxD,GAAG,EAAE,MAAM,CAAC;IACZ,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,oBAAoB,CAAC,UAAU,EAAE;IACrD,MAAM,EAAE,YAAY,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,SAAS,OAAO,EAAE,CAAC,CA8C9B;AAED,wBAAsB,mBAAmB,CAAC,UAAU,EAAE;IACpD,MAAM,EAAE,YAAY,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,cAAc,CAAC,CA6E1B;AAUD,wBAAsB,yBAAyB,CAAC,UAAU,EAAE;IAC1D,MAAM,EAAE,YAAY,CAAC;CACtB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2ClB;AAED,wBAAsB,kBAAkB,CAAC,UAAU,EAAE;IACnD,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,aAAa,CAAC,CAuCzB;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,eAAe,EAChC,MAAM,EAAE,cAAc,GACrB,IAAI,CAON;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,iBAAiB,EAAE,GAAG,OAAO,EAAE,CAS/E"}
@@ -260,9 +260,12 @@ export async function fetchRawLinearIssue(arguments_) {
260
260
  id
261
261
  title
262
262
  description
263
+ updatedAt
263
264
  url
265
+ priority
264
266
  team { id }
265
267
  state { id name type }
268
+ assignee { name }
266
269
  children { nodes { id } }
267
270
  labels(first: ${ISSUE_LABEL_PAGE_SIZE}) {
268
271
  nodes { name }
@@ -298,10 +301,13 @@ export async function fetchRawLinearIssue(arguments_) {
298
301
  stateType: issue.state?.type ?? "",
299
302
  /* v8 ignore next @preserve -- ResolveIssue query selects state; null only if Linear genuinely returns a stateless task */
300
303
  stateId: issue.state?.id ?? "",
304
+ assignee: issue.assignee?.name ?? "Unassigned",
305
+ updatedAt: issue.updatedAt,
301
306
  blockers: blockersFromRelations(issue.inverseRelations?.nodes ?? []),
302
307
  hasMoreBlockers: issue.inverseRelations?.pageInfo.hasNextPage ?? false,
303
308
  hasChildren: (issue.children?.nodes.length ?? 0) > 0,
304
309
  url: issue.url,
310
+ priority: issue.priority,
305
311
  };
306
312
  }
307
313
  export async function fetchInProgressIssueCount(arguments_) {
@@ -378,7 +384,12 @@ export async function fetchResolvedIssue(arguments_) {
378
384
  stateType: raw.stateType,
379
385
  status: raw.stateName,
380
386
  statusId: raw.stateId,
387
+ assignee: raw.assignee,
388
+ updatedAt: raw.updatedAt,
389
+ blockers: raw.blockers,
390
+ hasMoreBlockers: raw.hasMoreBlockers,
381
391
  url: raw.url,
392
+ priority: raw.priority,
382
393
  };
383
394
  }
384
395
  export function warnIfNotEnabledFallback(task, modelResolution, config) {
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/shell/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAGL,KAAK,KAAK,IAAI,cAAc,EAG5B,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EACL,KAAK,kBAAkB,EAEvB,KAAK,UAAU,EAEhB,MAAM,aAAa,CAAC;AAkErB,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,CAuB3F;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,kBAAkB,EAC1B,QAAQ,EAAE,cAAc,GACvB,UAAU,CA+GZ"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/shell/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAGL,KAAK,KAAK,IAAI,cAAc,EAG5B,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EACL,KAAK,kBAAkB,EAEvB,KAAK,UAAU,EAEhB,MAAM,aAAa,CAAC;AAkErB,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,CAuB3F;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,kBAAkB,EAC1B,QAAQ,EAAE,cAAc,GACvB,UAAU,CAyHZ"}
@@ -101,6 +101,30 @@ export function createShellTaskSource(config, _context) {
101
101
  const parsed = shellFetchOutputSchema.parse(JSON.parse(stdout));
102
102
  return parsed.map((si) => toCanonicalIssue(si, sourceName));
103
103
  }
104
+ async function getTask(naturalId) {
105
+ const canonicalId = toCanonicalId(sourceName, naturalId);
106
+ if (getTaskCommand === undefined) {
107
+ const all = await runFetch();
108
+ return all.find((i) => i.id === canonicalId) ?? null;
109
+ }
110
+ const result = await invokeShellCommand({
111
+ command: getTaskCommand,
112
+ timeoutMs: timeouts.getTask,
113
+ cwd: config.cwd,
114
+ env: config.env,
115
+ substitutions: {
116
+ id: naturalId,
117
+ canonicalId,
118
+ name: sourceName,
119
+ },
120
+ sourceName,
121
+ });
122
+ if (result.exitCode === 3 || result.stdout.trim().length === 0) {
123
+ return null;
124
+ }
125
+ const parsed = shellIssueSchema.parse(JSON.parse(result.stdout));
126
+ return toCanonicalIssue(parsed, sourceName);
127
+ }
104
128
  // Shared by markInProgress / markInReview: both pipe the canonical issue's
105
129
  // opaque sourceRef to a status-transition script on stdin, with the natural
106
130
  // and canonical ids substituted into the command.
@@ -140,30 +164,15 @@ export function createShellTaskSource(config, _context) {
140
164
  sourceName,
141
165
  });
142
166
  },
167
+ async listTasks() {
168
+ return await runFetch();
169
+ },
170
+ async getTask(naturalId) {
171
+ return await getTask(naturalId);
172
+ },
143
173
  fetch: runFetch,
144
174
  async resolveOne(naturalId) {
145
- const canonicalId = toCanonicalId(sourceName, naturalId);
146
- if (getTaskCommand === undefined) {
147
- const all = await runFetch();
148
- return all.find((i) => i.id === canonicalId);
149
- }
150
- const result = await invokeShellCommand({
151
- command: getTaskCommand,
152
- timeoutMs: timeouts.getTask,
153
- cwd: config.cwd,
154
- env: config.env,
155
- substitutions: {
156
- id: naturalId,
157
- canonicalId,
158
- name: sourceName,
159
- },
160
- sourceName,
161
- });
162
- if (result.exitCode === 3 || result.stdout.trim().length === 0) {
163
- return undefined;
164
- }
165
- const parsed = shellIssueSchema.parse(JSON.parse(result.stdout));
166
- return toCanonicalIssue(parsed, sourceName);
175
+ return (await getTask(naturalId)) ?? undefined;
167
176
  },
168
177
  async markInProgress(issue) {
169
178
  await invokeWriteback(config.commands.markInProgress, timeouts.markInProgress, issue);
@@ -1 +1 @@
1
- {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/todo-txt/source.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAIL,KAAK,UAAU,EAEhB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AA2ExD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,oBAAoB,EAC5B,QAAQ,EAAE,cAAc,GACvB,UAAU,CAkGZ"}
1
+ {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/todo-txt/source.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAKL,KAAK,UAAU,EAEhB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AA+QxD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,oBAAoB,EAC5B,QAAQ,EAAE,cAAc,GACvB,UAAU,CA4IZ"}
@@ -1,8 +1,13 @@
1
- import { readFileSync, statSync } from "node:fs";
1
+ import { spawnSync } from "node:child_process";
2
+ import { appendFileSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
3
+ import path from "node:path";
2
4
  import { toCanonicalId, } from "../../taskSource.js";
5
+ import { readEnvironmentVariable } from "../../util.js";
3
6
  import { isActiveForFetch, normalizeToIssue } from "./normalizer.js";
4
7
  import { getMetadataFirst, parseAllLines } from "./parser.js";
5
- import { copyPromptFile, updateTaskStatus, validateTodoFile } from "./writeback.js";
8
+ import { copyPromptFile, updateTaskStatus, validateTodoFile, withLock } from "./writeback.js";
9
+ const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
10
+ const RECURRENCE_RE = /^\+?\d+[dwmy]$/;
6
11
  function readDescription(promptPath) {
7
12
  try {
8
13
  return readFileSync(promptPath, "utf8");
@@ -29,7 +34,6 @@ function readAndParseTodo(todoPath) {
29
34
  content = "";
30
35
  }
31
36
  return {
32
- rawLines: content.split("\n"),
33
37
  parsedAll: parseAllLines(content),
34
38
  };
35
39
  }
@@ -59,10 +63,183 @@ function buildIssue(options) {
59
63
  updatedAt,
60
64
  });
61
65
  }
66
+ function assertToken(label, value) {
67
+ if (value.length === 0 || /\s/.test(value)) {
68
+ throw new Error(`todo-txt: ${label} must be a non-empty single token`);
69
+ }
70
+ }
71
+ function assertCreateId(id) {
72
+ assertToken("id", id);
73
+ if (id === "." || id === ".." || id.includes("/") || id.includes("\\")) {
74
+ throw new Error("todo-txt: id must be a filename-safe token");
75
+ }
76
+ }
77
+ function normalizeProject(project) {
78
+ return project.startsWith("+") ? project.slice(1) : project;
79
+ }
80
+ function normalizeContext(context) {
81
+ return context.startsWith("@") ? context.slice(1) : context;
82
+ }
83
+ function metadataToken(key, value) {
84
+ assertToken(`${key}: value`, value);
85
+ return `${key}:${value}`;
86
+ }
87
+ function datePartFor(timeZone, now) {
88
+ const parts = new Intl.DateTimeFormat("en-CA", {
89
+ timeZone,
90
+ year: "numeric",
91
+ month: "2-digit",
92
+ day: "2-digit",
93
+ }).formatToParts(now);
94
+ const year = parts.find((part) => part.type === "year")?.value;
95
+ const month = parts.find((part) => part.type === "month")?.value;
96
+ const day = parts.find((part) => part.type === "day")?.value;
97
+ /* v8 ignore next 3 @preserve -- Intl.DateTimeFormat with year/month/day always returns these parts */
98
+ if (year === undefined || month === undefined || day === undefined) {
99
+ throw new Error(`todo-txt: could not format date in timezone "${timeZone}"`);
100
+ }
101
+ return `${year}${month}${day}`;
102
+ }
103
+ /* v8 ignore next @preserve -- Covered in source tests; full-suite V8 coverage remaps this helper inconsistently. */
104
+ function nextGeneratedId(config, parsedAll) {
105
+ const datePart = datePartFor(config.timezone, new Date());
106
+ const prefix = `${config.idPrefix}-${datePart}-`;
107
+ let maximumSequence = 0;
108
+ for (const parsed of parsedAll) {
109
+ if (parsed === null || parsed === undefined) {
110
+ continue;
111
+ }
112
+ const id = getMetadataFirst(parsed, "id");
113
+ if (id === undefined || !id.startsWith(prefix)) {
114
+ continue;
115
+ }
116
+ const sequence = Number.parseInt(id.slice(prefix.length), 10);
117
+ if (Number.isFinite(sequence) && sequence > maximumSequence) {
118
+ maximumSequence = sequence;
119
+ }
120
+ }
121
+ return `${prefix}${String(maximumSequence + 1).padStart(3, "0")}`;
122
+ }
123
+ function assertNewId(id, parsedAll) {
124
+ const existing = parsedAll.some((parsed) => parsed !== null && getMetadataFirst(parsed, "id")?.toLowerCase() === id.toLowerCase());
125
+ if (existing) {
126
+ throw new Error(`todo-txt: task id "${id}" already exists`);
127
+ }
128
+ }
129
+ function buildTodoLine(id, input) {
130
+ const title = input.title.trim();
131
+ if (title.length === 0) {
132
+ throw new Error("todo-txt: title is required");
133
+ }
134
+ if (/[\r\n]/.test(title)) {
135
+ throw new Error("todo-txt: title must be a single line");
136
+ }
137
+ const tokens = [];
138
+ const priority = input.priority ?? "A";
139
+ if (!/^[A-Z]$/.test(priority)) {
140
+ throw new Error("todo-txt: priority must be a single uppercase letter");
141
+ }
142
+ tokens.push(`(${priority})`);
143
+ tokens.push(title);
144
+ for (const rawProject of input.projects) {
145
+ const project = normalizeProject(rawProject);
146
+ assertToken("project", project);
147
+ tokens.push(`+${project}`);
148
+ }
149
+ for (const rawContext of input.contexts) {
150
+ const context = normalizeContext(rawContext);
151
+ assertToken("context", context);
152
+ tokens.push(`@${context}`);
153
+ }
154
+ tokens.push(metadataToken("id", id));
155
+ if (input.repository !== undefined) {
156
+ tokens.push(metadataToken("repo", input.repository));
157
+ }
158
+ tokens.push(metadataToken("agent", input.agent));
159
+ for (const dependency of input.dependencies) {
160
+ tokens.push(metadataToken("dep", dependency));
161
+ }
162
+ if (input.due !== undefined) {
163
+ if (!DATE_RE.test(input.due)) {
164
+ throw new Error("todo-txt: due date must use YYYY-MM-DD");
165
+ }
166
+ tokens.push(metadataToken("due", input.due));
167
+ }
168
+ if (input.recurrence !== undefined) {
169
+ if (!RECURRENCE_RE.test(input.recurrence)) {
170
+ throw new Error("todo-txt: recurrence must look like 1d, 1w, 1m, 1y, or +1m");
171
+ }
172
+ tokens.push(metadataToken("rec", input.recurrence));
173
+ }
174
+ tokens.push("status:todo");
175
+ return tokens.join(" ");
176
+ }
177
+ function promptContentFor(input) {
178
+ if (input.promptFile !== undefined && input.description !== undefined) {
179
+ throw new Error("todo-txt: --prompt-file and --description are mutually exclusive");
180
+ }
181
+ if (input.promptFile !== undefined) {
182
+ return readFileSync(input.promptFile, "utf8");
183
+ }
184
+ if (input.description !== undefined) {
185
+ return input.description;
186
+ }
187
+ return `${input.title.trim()}\n`;
188
+ }
189
+ function appendTodoLine(todoPath, line) {
190
+ mkdirSync(path.dirname(todoPath), { recursive: true });
191
+ let separator = "";
192
+ try {
193
+ const current = readFileSync(todoPath, "utf8");
194
+ separator = current.length === 0 || current.endsWith("\n") ? "" : "\n";
195
+ }
196
+ catch (error) {
197
+ if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) {
198
+ throw error;
199
+ }
200
+ }
201
+ appendFileSync(todoPath, `${separator}${line}\n`, "utf8");
202
+ }
203
+ function writePromptFile(promptPath, content) {
204
+ mkdirSync(path.dirname(promptPath), { recursive: true });
205
+ writeFileSync(promptPath, content.endsWith("\n") ? content : `${content}\n`, "utf8");
206
+ }
207
+ function shellQuote(value) {
208
+ return `'${value.replaceAll("'", String.raw `'\''`)}'`;
209
+ }
210
+ function configuredEditor() {
211
+ const visual = readEnvironmentVariable("VISUAL");
212
+ if (visual !== undefined && visual.trim().length > 0) {
213
+ return visual;
214
+ }
215
+ const editor = readEnvironmentVariable("EDITOR");
216
+ if (editor !== undefined && editor.trim().length > 0) {
217
+ return editor;
218
+ }
219
+ return undefined;
220
+ }
221
+ function openPromptEditor(promptPath) {
222
+ const editor = configuredEditor();
223
+ if (editor === undefined) {
224
+ throw new Error("todo-txt: --edit requires VISUAL or EDITOR to be set");
225
+ }
226
+ const result = spawnSync(`${editor} ${shellQuote(promptPath)}`, {
227
+ shell: true,
228
+ stdio: "inherit",
229
+ });
230
+ /* v8 ignore next 3 @preserve -- with shell:true editor launch failures report a nonzero status */
231
+ if (result.error !== undefined) {
232
+ throw result.error;
233
+ }
234
+ if (result.status !== 0) {
235
+ throw new Error(`todo-txt: editor exited with status ${result.status}`);
236
+ }
237
+ }
62
238
  export function createTodoTxtTaskSource(config, _context) {
63
239
  const sourceName = config.name;
240
+ /* v8 ignore next @preserve -- Covered in source tests; full-suite V8 coverage remaps this line inconsistently. */
64
241
  const { todoPath, tasksDir } = config;
65
- function buildIssueList() {
242
+ function listTasks() {
66
243
  const updatedAt = fileUpdatedAt(todoPath);
67
244
  const { parsedAll } = readAndParseTodo(todoPath);
68
245
  const issues = [];
@@ -90,6 +267,25 @@ export function createTodoTxtTaskSource(config, _context) {
90
267
  }
91
268
  return issues;
92
269
  }
270
+ function getTask(naturalId) {
271
+ const canonicalId = toCanonicalId(sourceName, naturalId);
272
+ const updatedAt = fileUpdatedAt(todoPath);
273
+ const { parsedAll } = readAndParseTodo(todoPath);
274
+ const index = parsedAll.findIndex((parsed) => parsed !== null &&
275
+ toCanonicalId(sourceName, getMetadataFirst(parsed, "id") ?? "") === canonicalId);
276
+ if (index === -1) {
277
+ return null;
278
+ }
279
+ return (buildIssue({
280
+ parsedIndex: index,
281
+ parsedAll,
282
+ sourceName,
283
+ todoPath,
284
+ tasksDir,
285
+ defaultRepository: config.defaultRepository,
286
+ updatedAt,
287
+ }) ?? null);
288
+ }
93
289
  return {
94
290
  name: sourceName,
95
291
  async verify() {
@@ -98,26 +294,39 @@ export function createTodoTxtTaskSource(config, _context) {
98
294
  throw new Error(`todo-txt source "${sourceName}" verification failed:\n${errors.map((e) => ` - ${e}`).join("\n")}`);
99
295
  }
100
296
  },
297
+ async listTasks() {
298
+ return listTasks();
299
+ },
300
+ async getTask(naturalId) {
301
+ return getTask(naturalId);
302
+ },
303
+ async createTask(input) {
304
+ return await withLock(`${todoPath}.lock`, () => {
305
+ const { parsedAll } = readAndParseTodo(todoPath);
306
+ const id = input.id ?? nextGeneratedId(config, parsedAll);
307
+ assertCreateId(id);
308
+ assertNewId(id, parsedAll);
309
+ const promptPath = path.join(tasksDir, `${id}.md`);
310
+ const promptContent = promptContentFor(input);
311
+ const line = buildTodoLine(id, input);
312
+ writePromptFile(promptPath, promptContent);
313
+ appendTodoLine(todoPath, line);
314
+ if (input.edit) {
315
+ openPromptEditor(promptPath);
316
+ }
317
+ const task = getTask(id);
318
+ /* v8 ignore next 3 @preserve -- createTask just appended this id and getTask reads the same file */
319
+ if (task === null) {
320
+ throw new Error(`todo-txt: created task "${id}" could not be read back`);
321
+ }
322
+ return task;
323
+ });
324
+ },
101
325
  async fetch() {
102
- return buildIssueList();
326
+ return listTasks();
103
327
  },
104
328
  async resolveOne(naturalId) {
105
- const canonicalId = toCanonicalId(sourceName, naturalId);
106
- const updatedAt = fileUpdatedAt(todoPath);
107
- const { parsedAll } = readAndParseTodo(todoPath);
108
- const index = parsedAll.findIndex((p) => p !== null && toCanonicalId(sourceName, getMetadataFirst(p, "id") ?? "") === canonicalId);
109
- if (index === -1) {
110
- return undefined;
111
- }
112
- return buildIssue({
113
- parsedIndex: index,
114
- parsedAll,
115
- sourceName,
116
- todoPath,
117
- tasksDir,
118
- defaultRepository: config.defaultRepository,
119
- updatedAt,
120
- });
329
+ return getTask(naturalId) ?? undefined;
121
330
  },
122
331
  async markInProgress(issue) {
123
332
  // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- TodoTxtTaskSource always writes TodoTxtSourceRef
@@ -10,6 +10,7 @@ export interface UpdateOptions {
10
10
  ref: TodoTxtSourceRef;
11
11
  now?: Date;
12
12
  }
13
+ export declare function withLock<T>(lockPath: string, fn: () => T | Promise<T>): Promise<T>;
13
14
  type StatusMutation = "in-progress" | "in-review" | "done";
14
15
  export declare function updateTaskStatus(options: UpdateOptions, newStatus: StatusMutation): Promise<RecurResult | undefined>;
15
16
  export declare function copyPromptFile(oldPath: string, newPath: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"writeback.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/todo-txt/writeback.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB;AAoKD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,gBAAgB,CAAC;IACtB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAYD,KAAK,cAAc,GAAG,aAAa,GAAG,WAAW,GAAG,MAAM,CAAC;AA6E3D,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,cAAc,GACxB,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAsElC;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAQrE;AAwFD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CA0C7E"}
1
+ {"version":3,"file":"writeback.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/todo-txt/writeback.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB;AAoKD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,gBAAgB,CAAC;IACtB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,wBAAsB,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAQxF;AAED,KAAK,cAAc,GAAG,aAAa,GAAG,WAAW,GAAG,MAAM,CAAC;AA6E3D,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,cAAc,GACxB,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAsElC;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAQrE;AAwFD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CA0C7E"}
@@ -133,7 +133,7 @@ function atomicWrite(filePath, content) {
133
133
  writeFileSync(tmpPath, content, "utf8");
134
134
  renameSync(tmpPath, filePath);
135
135
  }
136
- async function withLock(lockPath, fn) {
136
+ export async function withLock(lockPath, fn) {
137
137
  await acquireLock(lockPath);
138
138
  try {
139
139
  // return await is required here so the finally block runs while the lock is held
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Board composer — fans `verify` / `fetch` / `resolveOne` / `markInProgress` /
2
+ * Board composer — fans `verify` / `listTasks` / `getTask` / `markInProgress` /
3
3
  * `markInReview` across N `TaskSource` adapters. Even a single-source config
4
4
  * goes through this; the moment we skip the wrapper we grow Linear assumptions
5
5
  * back into consumers.
package/dist/lib/board.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Board composer — fans `verify` / `fetch` / `resolveOne` / `markInProgress` /
2
+ * Board composer — fans `verify` / `listTasks` / `getTask` / `markInProgress` /
3
3
  * `markInReview` across N `TaskSource` adapters. Even a single-source config
4
4
  * goes through this; the moment we skip the wrapper we grow Linear assumptions
5
5
  * back into consumers.
@@ -9,7 +9,7 @@ async function callVerify(source) {
9
9
  await source.verify();
10
10
  }
11
11
  async function callFetch(source) {
12
- return await source.fetch();
12
+ return await source.listTasks();
13
13
  }
14
14
  async function callFetchParentSkips(source) {
15
15
  if (source.fetchParentSkips !== undefined) {
@@ -18,7 +18,7 @@ async function callFetchParentSkips(source) {
18
18
  return [];
19
19
  }
20
20
  async function callResolveOne(source, naturalId) {
21
- return await source.resolveOne(naturalId);
21
+ return (await source.getTask(naturalId)) ?? undefined;
22
22
  }
23
23
  export function createBoard(sources) {
24
24
  const byName = new Map();