projectkeeper 0.0.0-stage → 1.0.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/CHANGELOG.md +56 -0
- package/LICENSE +21 -0
- package/README.md +283 -2
- package/README.zh-CN.md +285 -0
- package/THIRD_PARTY_NOTICES.md +53 -0
- package/bin/pk.mjs +6 -0
- package/bin/postinstall.mjs +5 -0
- package/bin/strip-types.mjs +28 -0
- package/package.json +68 -4
- package/patches/README.md +111 -0
- package/patches/pi-ai-0.85.0.ts +122 -0
- package/patches/pi-ai-0.87.1.ts +122 -0
- package/scripts/apply-pi-streaming-patch.ts +86 -0
- package/skills/clerk/coverage/SKILL.md +35 -0
- package/skills/clerk/cross-check/SKILL.md +118 -0
- package/skills/clerk/deepen-dispatch/SKILL.md +69 -0
- package/skills/clerk/lane-follow-up/SKILL.md +94 -0
- package/skills/clerk/lane-plan/SKILL.md +107 -0
- package/skills/clerk/lane-slot/SKILL.md +113 -0
- package/skills/clerk/lane-topic/SKILL.md +116 -0
- package/skills/clerk/orientation/SKILL.md +160 -0
- package/skills/clerk/reconcile/SKILL.md +77 -0
- package/skills/clerk/skeleton-dispatch/SKILL.md +43 -0
- package/skills/clerk/spot-check/SKILL.md +52 -0
- package/skills/clerk/synthesis/SKILL.md +65 -0
- package/skills/table-follow-up/SKILL.md +42 -0
- package/src/cli.ts +319 -0
- package/src/codemap/README.md +13 -0
- package/src/codemap/engines.ts +102 -0
- package/src/codemap/facts.ts +504 -0
- package/src/context/agent-entry.ts +232 -0
- package/src/context/ask.ts +97 -0
- package/src/context/assemble.ts +1058 -0
- package/src/context/code-source.ts +103 -0
- package/src/context/k-briefs.ts +114 -0
- package/src/context/lineage.ts +100 -0
- package/src/context/object-brief.ts +300 -0
- package/src/context/owner-words.ts +191 -0
- package/src/context/pack-fixture.ts +342 -0
- package/src/context/project-rules.ts +160 -0
- package/src/intake/intake.ts +392 -0
- package/src/intake/material-rules.ts +166 -0
- package/src/intake/removal.ts +316 -0
- package/src/intake/skipped.ts +72 -0
- package/src/keeper/adjustment.ts +565 -0
- package/src/keeper/bounds/boundary.ts +509 -0
- package/src/keeper/bounds/command.ts +1665 -0
- package/src/keeper/bounds/paths.ts +164 -0
- package/src/keeper/bounds/reads.ts +718 -0
- package/src/keeper/bounds/shell-write-guard.ts +521 -0
- package/src/keeper/capabilities.ts +136 -0
- package/src/keeper/clerk-steps.ts +151 -0
- package/src/keeper/clerk-tools.ts +1424 -0
- package/src/keeper/conversation.ts +253 -0
- package/src/keeper/evidence.ts +662 -0
- package/src/keeper/fake-provider.ts +132 -0
- package/src/keeper/held.ts +15 -0
- package/src/keeper/history-tools.ts +163 -0
- package/src/keeper/jobs/answering.ts +53 -0
- package/src/keeper/key-check.ts +105 -0
- package/src/keeper/ledger-tools.ts +295 -0
- package/src/keeper/link-check.ts +185 -0
- package/src/keeper/merge.ts +260 -0
- package/src/keeper/note-origin.ts +56 -0
- package/src/keeper/numbers-check.ts +102 -0
- package/src/keeper/open-in-pi.ts +57 -0
- package/src/keeper/organize/absence.ts +266 -0
- package/src/keeper/organize/carried-on.ts +214 -0
- package/src/keeper/organize/clerk-coverage.ts +293 -0
- package/src/keeper/organize/clerk-prompts.ts +132 -0
- package/src/keeper/organize/clerk.ts +1395 -0
- package/src/keeper/organize/coverage-gate.ts +19 -0
- package/src/keeper/organize/coverage-tools.ts +765 -0
- package/src/keeper/organize/entries.ts +153 -0
- package/src/keeper/organize/entry-gate.ts +289 -0
- package/src/keeper/organize/fill-tools.ts +718 -0
- package/src/keeper/organize/follow-up.ts +280 -0
- package/src/keeper/organize/generation-check.ts +504 -0
- package/src/keeper/organize/graph.ts +230 -0
- package/src/keeper/organize/lane-tools.ts +289 -0
- package/src/keeper/organize/looked-tools.ts +54 -0
- package/src/keeper/organize/materials.ts +243 -0
- package/src/keeper/organize/owner-lines.ts +493 -0
- package/src/keeper/organize/place-tools.ts +216 -0
- package/src/keeper/organize/placement-inference.ts +1045 -0
- package/src/keeper/organize/placement-time.ts +320 -0
- package/src/keeper/organize/placing.ts +821 -0
- package/src/keeper/organize/positioning.ts +33 -0
- package/src/keeper/organize/readiness.ts +47 -0
- package/src/keeper/organize/reading.ts +401 -0
- package/src/keeper/organize/round-blocks.ts +65 -0
- package/src/keeper/organize/round-news.ts +164 -0
- package/src/keeper/organize/round-open.ts +586 -0
- package/src/keeper/organize/schedule-state.ts +39 -0
- package/src/keeper/organize/schedule.ts +137 -0
- package/src/keeper/organize/service.ts +409 -0
- package/src/keeper/organize/skills.ts +116 -0
- package/src/keeper/organize/slots.ts +85 -0
- package/src/keeper/organize/stage-gate.ts +175 -0
- package/src/keeper/organize/stage-tools.ts +471 -0
- package/src/keeper/organize/standing-notes.ts +141 -0
- package/src/keeper/organize/table-follow-up.ts +330 -0
- package/src/keeper/organize/takeover-clerk.ts +832 -0
- package/src/keeper/organize/takeover-state.ts +103 -0
- package/src/keeper/organize/takeover.ts +216 -0
- package/src/keeper/organize/update-pending.ts +535 -0
- package/src/keeper/organize/workbench-placement.ts +92 -0
- package/src/keeper/own-keys.ts +114 -0
- package/src/keeper/owner-text.ts +165 -0
- package/src/keeper/project-folder.ts +334 -0
- package/src/keeper/prompts.ts +101 -0
- package/src/keeper/references.ts +177 -0
- package/src/keeper/relook/compose.ts +120 -0
- package/src/keeper/relook/prompts.ts +36 -0
- package/src/keeper/roles.ts +259 -0
- package/src/keeper/round-tools.ts +227 -0
- package/src/keeper/route.ts +148 -0
- package/src/keeper/rules.ts +97 -0
- package/src/keeper/runtime.ts +1858 -0
- package/src/keeper/scope-tools.ts +194 -0
- package/src/keeper/sendback-text.ts +83 -0
- package/src/keeper/step-timing.ts +207 -0
- package/src/keeper/testing/clerk-script.ts +212 -0
- package/src/keeper/testing/streaming-arguments.ts +57 -0
- package/src/keeper/tools.ts +2340 -0
- package/src/keeper/utterance-tools.ts +64 -0
- package/src/keeper/verbatim.ts +397 -0
- package/src/ledger/adapters.ts +186 -0
- package/src/ledger/arrangements.ts +257 -0
- package/src/ledger/blame.ts +58 -0
- package/src/ledger/code-engine-child.ts +69 -0
- package/src/ledger/code-engine.ts +548 -0
- package/src/ledger/code.ts +607 -0
- package/src/ledger/docs.ts +294 -0
- package/src/ledger/git-read.ts +321 -0
- package/src/ledger/index.ts +1850 -0
- package/src/ledger/item-range.ts +16 -0
- package/src/ledger/lines.ts +328 -0
- package/src/ledger/numbering.ts +269 -0
- package/src/ledger/ranges.ts +74 -0
- package/src/ledger/rebuild-worker.ts +15 -0
- package/src/ledger/rebuild.ts +387 -0
- package/src/ledger/repo-scan.ts +181 -0
- package/src/ledger/schema.ts +450 -0
- package/src/ledger/sessions.ts +134 -0
- package/src/ledger/text-scan.ts +466 -0
- package/src/ledger/time.ts +185 -0
- package/src/ledger/ts-symbols.ts +180 -0
- package/src/ledger/views.ts +377 -0
- package/src/mcp/server.ts +127 -0
- package/src/mcp/tools.ts +187 -0
- package/src/model/ids.ts +23 -0
- package/src/model/k-types.ts +912 -0
- package/src/model/time.ts +85 -0
- package/src/model/types.ts +1382 -0
- package/src/model/views-k.ts +707 -0
- package/src/model/vocab.ts +269 -0
- package/src/process/analysis.ts +79 -0
- package/src/process/breakpoint-candidates.ts +383 -0
- package/src/process/breakpoints.ts +746 -0
- package/src/process/claim-check.ts +295 -0
- package/src/process/delivery-links.ts +52 -0
- package/src/process/facts.ts +487 -0
- package/src/process/generations.ts +138 -0
- package/src/process/index.ts +243 -0
- package/src/process/integration.ts +128 -0
- package/src/process/placement.ts +107 -0
- package/src/process/plan.ts +276 -0
- package/src/process/sendbacks.ts +244 -0
- package/src/process/text.ts +185 -0
- package/src/process/units.ts +543 -0
- package/src/process/unnumbered.ts +431 -0
- package/src/process/work.ts +884 -0
- package/src/scope/candidates.ts +86 -0
- package/src/scope/decisions.ts +229 -0
- package/src/scope/discover.ts +741 -0
- package/src/scope/ignore.ts +126 -0
- package/src/scope/ignored-place.ts +93 -0
- package/src/scope/skip.ts +161 -0
- package/src/scope/toolchain.ts +180 -0
- package/src/scope/worktree.ts +187 -0
- package/src/server/api.ts +549 -0
- package/src/server/app.ts +595 -0
- package/src/server/drafts-api.ts +170 -0
- package/src/server/folders-api.ts +243 -0
- package/src/server/graph-view.ts +639 -0
- package/src/server/http.ts +224 -0
- package/src/server/k-agent-api.ts +56 -0
- package/src/server/k-rounds-d99.ts +91 -0
- package/src/server/k-views.ts +405 -0
- package/src/server/keeper-page.ts +446 -0
- package/src/server/keys-api.ts +239 -0
- package/src/server/project-folder-api.ts +104 -0
- package/src/server/vendor.ts +14 -0
- package/src/server/workbench-content.ts +561 -0
- package/src/sources/anchor.ts +129 -0
- package/src/sources/files.ts +267 -0
- package/src/sources/gitobs.ts +41 -0
- package/src/sources/history.ts +231 -0
- package/src/sources/scan-worker.ts +10 -0
- package/src/sources/sessions/locate.ts +292 -0
- package/src/sources/sessions/read.ts +346 -0
- package/src/sources/sessions/scope.ts +42 -0
- package/src/sources/sessions/utterances.ts +223 -0
- package/src/sources/watch.ts +215 -0
- package/src/store/json-file.ts +50 -0
- package/src/store/paths.ts +39 -0
- package/src/store/project-store.ts +295 -0
- package/src/store/versions.ts +172 -0
- package/src/store/workspace.ts +216 -0
- package/src/table/check.ts +333 -0
- package/src/table/follow-up-tools.ts +30 -0
- package/src/table/follow-up.ts +344 -0
- package/src/table/import.ts +610 -0
- package/src/table/project-home.ts +61 -0
- package/src/table/sessions.ts +168 -0
- package/src/table/takeover.ts +483 -0
- package/src/util/git-check.ts +29 -0
- package/src/util/git.ts +411 -0
- package/src/util/own-ts.ts +15 -0
- package/src/util/paths.ts +225 -0
- package/template/FILLING-IN.md +148 -0
- package/template/examples/papertrail.json +747 -0
- package/template/projectkeeper.schema.json +1001 -0
- package/ui/app.js +1135 -0
- package/ui/failures.js +82 -0
- package/ui/flyout.js +120 -0
- package/ui/folder-chooser.js +264 -0
- package/ui/glossary.js +156 -0
- package/ui/graph-fit.js +157 -0
- package/ui/graph-material.js +61 -0
- package/ui/graph-palette.js +109 -0
- package/ui/graph-tools.js +62 -0
- package/ui/graph.js +1712 -0
- package/ui/index.html +31 -0
- package/ui/k/code-view.js +230 -0
- package/ui/k/draft-view.js +93 -0
- package/ui/k/k-views.css +224 -0
- package/ui/k/round-tree.js +450 -0
- package/ui/k/scope-k.js +159 -0
- package/ui/k-data.js +118 -0
- package/ui/k-fold.js +106 -0
- package/ui/k-process.css +302 -0
- package/ui/k-process.js +934 -0
- package/ui/keeper-activity.js +175 -0
- package/ui/keeper-view.js +801 -0
- package/ui/keeper.css +101 -0
- package/ui/key-order.js +62 -0
- package/ui/list-fold.js +67 -0
- package/ui/markdown.d.ts +21 -0
- package/ui/markdown.js +472 -0
- package/ui/placement.d.ts +92 -0
- package/ui/placement.js +445 -0
- package/ui/popover-place.d.ts +16 -0
- package/ui/popover-place.js +89 -0
- package/ui/popover.js +198 -0
- package/ui/project-folder.js +37 -0
- package/ui/shell-state.js +40 -0
- package/ui/strip-rows.js +171 -0
- package/ui/styles.css +492 -0
- package/ui/theme-pick.js +36 -0
- package/ui/theme.js +74 -0
- package/ui/themes/LICENSE.md +13 -0
- package/ui/themes/README.md +44 -0
- package/ui/themes/TOKENS.md +291 -0
- package/ui/themes/a1/board.css +1557 -0
- package/ui/themes/a1/pk.css +392 -0
- package/ui/themes/b1/board.css +1163 -0
- package/ui/themes/b1/pk.css +218 -0
- package/ui/themes/d2/board.css +518 -0
- package/ui/themes/d2/pk.css +243 -0
- package/ui/themes/guard.css +73 -0
- package/ui/themes/i1/board.css +776 -0
- package/ui/themes/i1/pk.css +223 -0
- package/ui/themes/manifest.json +13 -0
- package/ui/views.js +2796 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a Follow up round made new (Spec §3.8, §5.5, §6.2; D79; CKC-07 AC-27, CKC-24 AC-15): Follow up is how the owner
|
|
3
|
+
* sees what is new, so each round with news has one item in `Notes (attention)` listing, each with its position,
|
|
4
|
+
* - the breakpoints it newly lit,
|
|
5
|
+
* - the send-backs that are new or moved to another stage,
|
|
6
|
+
* - what newly became one of the six things the owner judges,
|
|
7
|
+
* - the semantic patches it confirmed,
|
|
8
|
+
* - the notes it wrote or updated;
|
|
9
|
+
* and a round with nothing new says so, for the top bar (QC AY B2: the item used to exist only when objects were left
|
|
10
|
+
* behind, in the old propagation words, and "nothing new" was said nowhere).
|
|
11
|
+
*
|
|
12
|
+
* Counted by the program, never by a model: the candidates are what the round's jobs wrote — its steps, its root job and
|
|
13
|
+
* what they delegated, from the store's trace — and each is compared with where things stood when the round started
|
|
14
|
+
* (`RoundBaseline`, kept on the round from its start to its close). A write by someone else in the meantime — the
|
|
15
|
+
* owner's conversation, an investigation the owner asked for — is not the round's news.
|
|
16
|
+
*/
|
|
17
|
+
import { join } from 'node:path';
|
|
18
|
+
import type { ClerkRound, RoundBaseline, RoundNews, RoundNewsItem, SixThing } from '../../model/k-types.ts';
|
|
19
|
+
import type { Note, TraceEntry } from '../../model/types.ts';
|
|
20
|
+
import type { ProjectStore } from '../../store/project-store.ts';
|
|
21
|
+
import { readJsonLines } from '../../store/json-file.ts';
|
|
22
|
+
|
|
23
|
+
const SIX_NAME: Readonly<Record<SixThing, string>> = { 1: 'stale', 2: 'drift', 3: 'dropped along the way', 4: 'grown by itself', 5: 'let pass', 6: 'looks residual' };
|
|
24
|
+
const clip = (s: string, n = 140): string => { const t = s.replace(/\s+/g, ' ').trim(); return t.length > n ? `${t.slice(0, n)}…` : t; };
|
|
25
|
+
const plural = (n: number, one: string, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;
|
|
26
|
+
|
|
27
|
+
/** A territory anomaly's key: it has no id of its own, and its index moves when the anomalies are written again. */
|
|
28
|
+
const anomalyKey = (territoryId: string, a: { kind: string; text: string }) => `anomaly:${territoryId}:${a.kind}:${a.text.slice(0, 120)}`;
|
|
29
|
+
|
|
30
|
+
/** Where the five kinds of news stand now (the baseline a Follow up round keeps from its start). */
|
|
31
|
+
export function roundBaseline(store: ProjectStore): RoundBaseline {
|
|
32
|
+
return {
|
|
33
|
+
litBreakpoints: store.breakpoints.filter((b) => b.lit).map((b) => b.id),
|
|
34
|
+
sendbackStages: Object.fromEntries(store.sendbacks.all().map((s) => [s.id, s.stage])),
|
|
35
|
+
sixThings: Object.fromEntries(liveSixThings(store).map((x) => [x.key, x.six])),
|
|
36
|
+
confirmedPatches: store.patches.filter((p) => p.status === 'Confirmed').map((p) => p.id),
|
|
37
|
+
noteVersions: Object.fromEntries(store.notes.all().map((n) => [n.id, n.versions.length])),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** What the owner sees an object as: a work item by its number and title, a reference item, a territory, a node. */
|
|
42
|
+
function labelOf(store: ProjectStore, id: string): string {
|
|
43
|
+
const t = store.threads.get(id);
|
|
44
|
+
if (t) return `${t.ids[0] ? `${t.ids[0]} ` : ''}${t.title}`;
|
|
45
|
+
return store.reference.get(id)?.name ?? store.territories.get(id)?.name ?? store.nodes.get(id)?.label ?? id;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function notePosition(store: ProjectStore, n: Note): { position: string; objectId: string | null } {
|
|
49
|
+
const v = n.versions[n.versions.length - 1];
|
|
50
|
+
const asking = (v?.ask === 'For your decision' || v?.ask === 'Worth discussing') && n.status === 'Current';
|
|
51
|
+
const on = n.mount.kind === 'project' ? 'the project' : n.mount.ids.map((id) => labelOf(store, id)).join(', ') || 'the project';
|
|
52
|
+
return { position: `${asking ? 'Notes (attention)' : 'Notes log'} · on ${on}`, objectId: n.mount.kind === 'project' ? null : n.mount.ids[0] ?? null };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Everything that is one of the six things now and still live, keyed as the baseline keeps it. */
|
|
56
|
+
function liveSixThings(store: ProjectStore): { key: string; six: SixThing; id: string; what: string; position: string; objectId: string | null }[] {
|
|
57
|
+
const out: { key: string; six: SixThing; id: string; what: string; position: string; objectId: string | null }[] = [];
|
|
58
|
+
for (const m of store.marks.all()) if (m.sixThing && !m.closed) out.push({ key: `mark:${m.id}`, six: m.sixThing, id: m.id, what: `mark ${m.kind} on ${labelOf(store, m.targetId)}`, position: `Mark on ${labelOf(store, m.targetId)}`, objectId: m.targetId });
|
|
59
|
+
for (const n of store.notes.all()) if (n.sixThing && n.status === 'Current') { const p = notePosition(store, n); out.push({ key: `note:${n.id}`, six: n.sixThing, id: n.id, what: `note “${n.versions[n.versions.length - 1]?.title ?? n.id}”`, position: p.position, objectId: p.objectId }); }
|
|
60
|
+
for (const b of store.breakpoints.all()) if (b.sixThing && b.lit && !b.ownerResponse) out.push({ key: `breakpoint:${b.id}`, six: b.sixThing, id: b.id, what: `breakpoint ${b.kind} on ${labelOf(store, b.targetId)}`, position: `Process view · ${labelOf(store, b.targetId)}`, objectId: b.targetId });
|
|
61
|
+
for (const s of store.sendbacks.all()) if (s.sixThing && s.stage !== 'Closed' && !s.ownerResponse) out.push({ key: `sendback:${s.id}`, six: s.sixThing, id: s.id, what: `send-back to ${s.to} on ${labelOf(store, s.targetId)}`, position: `Process view · ${labelOf(store, s.targetId)} · Reality`, objectId: s.targetId });
|
|
62
|
+
for (const t of store.territories.all()) for (const a of t.anomalies) if (a.sixThing) out.push({ key: anomalyKey(t.id, a), six: a.sixThing, id: t.id, what: `code anomaly ${a.kind} in ${t.name}`, position: `Code view · ${t.name}`, objectId: t.id });
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Every job of a round: its steps, its root, and what they delegated, however deep. */
|
|
67
|
+
export function roundJobIds(store: ProjectStore, round: ClerkRound): Set<string> {
|
|
68
|
+
const ids = new Set<string>([round.rootJobId, ...store.jobs.filter((j) => j.step?.roundId === round.id).map((j) => j.id)]);
|
|
69
|
+
for (let grew = true; grew;) {
|
|
70
|
+
grew = false;
|
|
71
|
+
for (const j of store.jobs.all()) if (j.parentJobId && ids.has(j.parentJobId) && !ids.has(j.id)) { ids.add(j.id); grew = true; }
|
|
72
|
+
}
|
|
73
|
+
return ids;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** The ids each collection's records the round's jobs wrote (one read of the trace). */
|
|
77
|
+
function touchedBy(store: ProjectStore, jobIds: ReadonlySet<string>): Map<string, Set<string>> {
|
|
78
|
+
const out = new Map<string, Set<string>>();
|
|
79
|
+
for (const e of readJsonLines<TraceEntry>(join(store.dir, 'trace.jsonl'))) {
|
|
80
|
+
if (e.op !== 'put' || !e.jobId || !jobIds.has(e.jobId)) continue;
|
|
81
|
+
if (!out.has(e.collection)) out.set(e.collection, new Set());
|
|
82
|
+
out.get(e.collection)!.add(e.id);
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The round's news: what its jobs wrote, against where things stood at its start. Without a baseline (a round begun
|
|
89
|
+
* before rounds kept one), what can be told from the records alone is counted — breakpoints the round lit, send-backs it
|
|
90
|
+
* created, notes it wrote in its window — and the result says it is not complete.
|
|
91
|
+
*/
|
|
92
|
+
export function roundNews(store: ProjectStore, round: ClerkRound, behind = 0, now = new Date().toISOString()): RoundNews {
|
|
93
|
+
const base = round.baseline ?? null;
|
|
94
|
+
const touched = touchedBy(store, roundJobIds(store, round));
|
|
95
|
+
const ids = (collection: string) => [...(touched.get(collection) ?? [])];
|
|
96
|
+
|
|
97
|
+
const breakpoints: RoundNewsItem[] = [];
|
|
98
|
+
for (const id of ids('breakpoints')) {
|
|
99
|
+
const b = store.breakpoints.get(id);
|
|
100
|
+
if (!b || !b.lit || b.ownerResponse) continue;
|
|
101
|
+
if (base ? base.litBreakpoints.includes(id) : b.roundId !== round.id) continue;
|
|
102
|
+
const on = labelOf(store, b.targetId);
|
|
103
|
+
breakpoints.push({ id, label: `${b.kind} on ${on}`, position: `Process view · ${on}`, objectId: b.targetId, detail: clip(b.why) });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const sendbacks: RoundNewsItem[] = [];
|
|
107
|
+
for (const id of ids('sendbacks')) {
|
|
108
|
+
const s = store.sendbacks.get(id);
|
|
109
|
+
if (!s || s.ownerResponse) continue;
|
|
110
|
+
const before = base ? base.sendbackStages[id] : undefined;
|
|
111
|
+
const isNew = base ? before === undefined : s.roundId === round.id;
|
|
112
|
+
const moved = base ? before !== undefined && before !== s.stage : false;
|
|
113
|
+
if (!isNew && !moved) continue;
|
|
114
|
+
const on = labelOf(store, s.targetId);
|
|
115
|
+
sendbacks.push({ id, label: `Send-back to ${s.to} on ${on}: ${clip(s.what, 100)}`, position: `Process view · ${on} · Reality (Copy for agent)`, objectId: s.targetId, detail: isNew ? `new · ${s.stage}` : `${before} → ${s.stage}` });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const sixThings: RoundNewsItem[] = [];
|
|
119
|
+
const touchedSix = new Set([...ids('marks').map((id) => `mark:${id}`), ...ids('notes').map((id) => `note:${id}`), ...ids('breakpoints').map((id) => `breakpoint:${id}`), ...ids('sendbacks').map((id) => `sendback:${id}`)]);
|
|
120
|
+
const touchedTerritories = new Set(ids('territories'));
|
|
121
|
+
for (const x of liveSixThings(store)) {
|
|
122
|
+
const mine = x.key.startsWith('anomaly:') ? touchedTerritories.has(x.id) : touchedSix.has(x.key);
|
|
123
|
+
if (!mine) continue;
|
|
124
|
+
if (base) { if (base.sixThings[x.key] === x.six) continue; }
|
|
125
|
+
else if (!breakpoints.some((b) => `breakpoint:${b.id}` === x.key) && !sendbacks.some((s) => `sendback:${s.id}` === x.key) && !(x.key.startsWith('note:') && store.notes.get(x.id)?.versions[0]?.at && store.notes.get(x.id)!.versions[0]!.at >= round.startedAt)) continue;
|
|
126
|
+
sixThings.push({ id: x.id, label: `${x.six} ${SIX_NAME[x.six]} · ${x.what}`, position: x.position, objectId: x.objectId, detail: `${x.six} ${SIX_NAME[x.six]}` });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const patches: RoundNewsItem[] = [];
|
|
130
|
+
if (base) for (const id of ids('patches')) {
|
|
131
|
+
const p = store.patches.get(id);
|
|
132
|
+
if (!p || p.status !== 'Confirmed' || base.confirmedPatches.includes(id)) continue;
|
|
133
|
+
const on = p.affects.map((a) => labelOf(store, a)).join(', ') || p.oldAnchor.label;
|
|
134
|
+
patches.push({ id, label: `${p.number} ${p.title}`, position: `Struck through on ${on}${p.writtenToFolder ? ' · project folder' : ''}`, objectId: p.affects[0] ?? null, detail: p.partial ? 'part of the old state withdrawn' : null });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const notes: RoundNewsItem[] = [];
|
|
138
|
+
for (const id of ids('notes')) {
|
|
139
|
+
const n = store.notes.get(id);
|
|
140
|
+
if (!n || n.status !== 'Current') continue;
|
|
141
|
+
const had = base ? base.noteVersions[id] : undefined;
|
|
142
|
+
const written = base ? had === undefined || n.versions.length > had : n.versions.some((v) => v.at >= round.startedAt && v.at <= now);
|
|
143
|
+
if (!written) continue;
|
|
144
|
+
const v = n.versions[n.versions.length - 1]!;
|
|
145
|
+
const p = notePosition(store, n);
|
|
146
|
+
notes.push({ id, label: v.title, position: p.position, objectId: p.objectId, detail: n.versions.length === 1 ? 'new' : `v${n.versions.length}` });
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const parts = [
|
|
150
|
+
breakpoints.length ? `${plural(breakpoints.length, 'breakpoint')} newly lit` : '',
|
|
151
|
+
sendbacks.filter((s) => s.detail?.startsWith('new')).length ? plural(sendbacks.filter((s) => s.detail?.startsWith('new')).length, 'new send-back') : '',
|
|
152
|
+
sendbacks.filter((s) => !s.detail?.startsWith('new')).length ? `${plural(sendbacks.filter((s) => !s.detail?.startsWith('new')).length, 'send-back')} moved` : '',
|
|
153
|
+
sixThings.length ? `${sixThings.length} newly among the six things` : '',
|
|
154
|
+
patches.length ? `${plural(patches.length, 'semantic patch', 'semantic patches')} confirmed` : '',
|
|
155
|
+
notes.length ? `${plural(notes.length, 'note')} written or updated` : '',
|
|
156
|
+
behind ? `${plural(behind, 'object')} still on the old understanding` : '',
|
|
157
|
+
].filter(Boolean);
|
|
158
|
+
const nothingNew = parts.length === 0;
|
|
159
|
+
return {
|
|
160
|
+
breakpoints, sendbacks, sixThings, patches, notes, nothingNew,
|
|
161
|
+
statement: nothingNew ? `Follow up round ${round.number} found nothing new` : parts.join(' · '),
|
|
162
|
+
complete: base !== null,
|
|
163
|
+
};
|
|
164
|
+
}
|