jackherd 1.12.2 → 1.12.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +16 -16
  3. package/dist/plan-format.d.ts +23 -11
  4. package/dist/plan-format.js +6 -3
  5. package/herdr-plugin/herdr-plugin.toml +1 -1
  6. package/install.sh +1 -1
  7. package/package.json +1 -1
  8. package/src/context/session-log.ts +4 -6
  9. package/src/plan-format/phases.ts +22 -6
  10. package/src/plan-format/progress.ts +5 -8
  11. package/src/plans/command.ts +10 -3
  12. package/src/plans/current-task.ts +3 -7
  13. package/src/plans/focus-overlay.ts +80 -0
  14. package/src/plans/git.ts +6 -11
  15. package/src/plans/herd-state.ts +201 -0
  16. package/src/plans/lane-reason.ts +1 -1
  17. package/src/plans/lane-summary.ts +6 -2
  18. package/src/plans/layout-phase.ts +1 -3
  19. package/src/plans/layout-summary.ts +1 -1
  20. package/src/plans/layout.ts +32 -31
  21. package/src/plans/link-chips.ts +7 -16
  22. package/src/plans/live.ts +215 -267
  23. package/src/plans/markdown-text.ts +4 -0
  24. package/src/plans/page-sync.ts +39 -0
  25. package/src/plans/phase-source.ts +5 -2
  26. package/src/plans/reader.ts +217 -0
  27. package/src/plans/refresh-schedule.ts +53 -0
  28. package/src/plans/snapshot.ts +32 -31
  29. package/src/plans/status-pace.ts +7 -4
  30. package/src/plans/subagents-read.ts +28 -12
  31. package/src/plans/supervisor.ts +1 -1
  32. package/src/plans/view.ts +9 -101
  33. package/src/plans/waiting-click.ts +27 -17
  34. package/src/plans/worked-phases.ts +1 -1
  35. package/src/plans/worktree-stamp.ts +12 -9
  36. package/src/plans/your-turn-rows.ts +33 -32
  37. package/src/plans/your-turn.ts +6 -4
  38. package/src/shared/bounded-memo.ts +19 -0
  39. package/src/shared/stat-cache.ts +2 -1
  40. package/src/terminal/lifetime.ts +52 -0
  41. package/src/watch/command.ts +6 -0
  42. package/src/watch/herd-publisher.ts +84 -0
  43. package/src/watch/source-entries.ts +7 -0
  44. package/src/watch/source-statuses.ts +2 -2
  45. package/src/watch/sources.ts +5 -2
  46. package/src/plans/next-rows.ts +0 -12
@@ -16,6 +16,12 @@ export const ENTRY_LIMIT = 20
16
16
 
17
17
  const shownAt = ({ changedAt, seenAt }: SourceEntry): number => changedAt ?? seenAt
18
18
 
19
+ /** The source's own time of an entry in epoch milliseconds; null for an unmapped `updatedAt` (`''`) or no date. */
20
+ const sourceTimeOf = (updatedAt: string): number | null => {
21
+ const time = updatedAt === '' ? Number.NaN : Date.parse(updatedAt)
22
+ return Number.isNaN(time) ? null : time
23
+ }
24
+
19
25
  const entryOf = (
20
26
  item: SourceItem,
21
27
  known: SourceEntry | undefined,
@@ -29,6 +35,7 @@ const entryOf = (
29
35
  count: item.count,
30
36
  seenAt: known?.seenAt ?? now,
31
37
  changedAt: seen && reportsItem(seen, item, settings) ? now : (known?.changedAt ?? null),
38
+ updatedAt: sourceTimeOf(item.updatedAt),
32
39
  })
33
40
 
34
41
  /**
@@ -6,7 +6,7 @@ import type { WatchState } from './watch-events'
6
6
  /** The newest entry a source reported, as the herd draws it; `isNew` while it is younger than `NEW_FOR_MS`. */
7
7
  export type LatestStatus = { title: string; url: string | null; isNew: boolean }
8
8
 
9
- /** An entry as the herd lists it under its source: `at` is when it last changed, else when the watcher first saw it; `isNew` only for a reported change younger than `NEW_FOR_MS`. */
9
+ /** An entry as the herd lists it under its source: `at` is the source's own time of it, else when it last changed, else when the watcher first saw it; `isNew` only for a reported change younger than `NEW_FOR_MS`. */
10
10
  export type EntryStatus = {
11
11
  id: string
12
12
  title: string
@@ -30,7 +30,7 @@ const entryStatusOf = (entry: SourceEntry, now: number): EntryStatus => ({
30
30
  title: lineText(entry.title),
31
31
  url: entry.url === null ? null : previewUrlOf(entry.url, undefined),
32
32
  count: entry.count,
33
- at: entry.changedAt ?? entry.seenAt,
33
+ at: entry.updatedAt ?? entry.changedAt ?? entry.seenAt,
34
34
  isNew: entry.changedAt !== null && now - entry.changedAt < NEW_FOR_MS,
35
35
  })
36
36
 
@@ -93,7 +93,8 @@ export type LatestReport = { title: string; url: string | null; at: number }
93
93
 
94
94
  /**
95
95
  * An entry of a source as the herd lists it: its title as one line, its checked URL, its count, when the watcher first
96
- * saw it (`seenAt`) and when it last reported a change of it (`changedAt`, null while only the baseline knows it).
96
+ * saw it (`seenAt`), when it last reported a change of it (`changedAt`, null while only the baseline knows it), and the
97
+ * source's own time of it (`map.updatedAt` read as a date; null when unmapped or no date, absent in older states).
97
98
  */
98
99
  export type SourceEntry = {
99
100
  id: string
@@ -102,6 +103,7 @@ export type SourceEntry = {
102
103
  count: string | null
103
104
  seenAt: number
104
105
  changedAt: number | null
106
+ updatedAt?: number | null
105
107
  }
106
108
 
107
109
  /**
@@ -419,7 +421,8 @@ const isSourceEntry = (value: unknown): boolean =>
419
421
  isTextOrNull(value.url) &&
420
422
  isTextOrNull(value.count) &&
421
423
  typeof value.seenAt === 'number' &&
422
- (value.changedAt === null || typeof value.changedAt === 'number')
424
+ (value.changedAt === null || typeof value.changedAt === 'number') &&
425
+ (value.updatedAt === undefined || value.updatedAt === null || typeof value.updatedAt === 'number')
423
426
 
424
427
  const isSourceRecord = (value: unknown): boolean =>
425
428
  isRecord(value) &&
@@ -1,12 +0,0 @@
1
- import { sectionLines } from '../plan-format/markdown'
2
- import { NEXT_VOCABULARY, type PlanLanguage } from '../vocabulary'
3
-
4
- const MAX_NEXT_LINES = 3
5
-
6
- const LIST_LINE = /^(?:\d+[.)]|[-*])\s+(.+)$/
7
-
8
- /** The board's next section, up to three list lines in the order written; the parser cuts after three, as the board says. */
9
- export const nextLines = (board: string, language: PlanLanguage): string[] =>
10
- sectionLines(board, NEXT_VOCABULARY[language].heading)
11
- .flatMap((line) => LIST_LINE.exec(line.trim())?.[1] ?? [])
12
- .slice(0, MAX_NEXT_LINES)