dsh-live-teams 0.1.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 (69) hide show
  1. package/LICENSE +176 -0
  2. package/NOTICE +11 -0
  3. package/README.md +85 -0
  4. package/cordis.patch.yml +25 -0
  5. package/lib/binding.d.ts +18 -0
  6. package/lib/binding.js +42 -0
  7. package/lib/changed-paths.d.ts +26 -0
  8. package/lib/changed-paths.js +69 -0
  9. package/lib/client.js +6753 -0
  10. package/lib/command-queue.d.ts +60 -0
  11. package/lib/command-queue.js +185 -0
  12. package/lib/compatibility.js +109 -0
  13. package/lib/context-provider.d.ts +110 -0
  14. package/lib/context-provider.js +249 -0
  15. package/lib/dispatch.d.ts +174 -0
  16. package/lib/dispatch.js +624 -0
  17. package/lib/errors.d.ts +36 -0
  18. package/lib/errors.js +103 -0
  19. package/lib/git-artifacts.d.ts +50 -0
  20. package/lib/git-artifacts.js +242 -0
  21. package/lib/index.d.ts +14 -0
  22. package/lib/index.js +14 -0
  23. package/lib/mailbox.d.ts +274 -0
  24. package/lib/mailbox.js +721 -0
  25. package/lib/member-tools.d.ts +57 -0
  26. package/lib/member-tools.js +1265 -0
  27. package/lib/migrations.d.ts +17 -0
  28. package/lib/migrations.js +47 -0
  29. package/lib/plugin.d.ts +106 -0
  30. package/lib/plugin.js +1003 -0
  31. package/lib/roles.d.ts +35 -0
  32. package/lib/roles.js +284 -0
  33. package/lib/routes.d.ts +586 -0
  34. package/lib/routes.js +2816 -0
  35. package/lib/scope.d.ts +62 -0
  36. package/lib/scope.js +133 -0
  37. package/lib/session-bridge.d.ts +76 -0
  38. package/lib/session-bridge.js +147 -0
  39. package/lib/session-title.js +35 -0
  40. package/lib/storage.d.ts +9 -0
  41. package/lib/storage.js +65 -0
  42. package/lib/task-store.d.ts +729 -0
  43. package/lib/task-store.js +2205 -0
  44. package/lib/team-store.d.ts +216 -0
  45. package/lib/team-store.js +765 -0
  46. package/lib/tree-snapshot.d.ts +28 -0
  47. package/lib/tree-snapshot.js +80 -0
  48. package/lib/types/client/TeamView.d.ts +26 -0
  49. package/lib/types/client/TeamView.dom.test.d.ts +1 -0
  50. package/lib/types/client/api.d.ts +522 -0
  51. package/lib/types/client/api.test.d.ts +1 -0
  52. package/lib/types/client/attention.d.ts +65 -0
  53. package/lib/types/client/attention.test.d.ts +1 -0
  54. package/lib/types/client/index.d.ts +31 -0
  55. package/lib/types/client/locales.d.ts +577 -0
  56. package/lib/types/client/member-name.d.ts +14 -0
  57. package/lib/types/client/member-name.test.d.ts +1 -0
  58. package/lib/types/client/roster.d.ts +26 -0
  59. package/lib/types/client/roster.test.d.ts +1 -0
  60. package/lib/types/client/styles.d.ts +3 -0
  61. package/package.json +104 -0
  62. package/roles/builder.md +40 -0
  63. package/roles/delegate.md +36 -0
  64. package/roles/lead.md +46 -0
  65. package/roles/oracle.md +36 -0
  66. package/roles/researcher.md +37 -0
  67. package/roles/reviewer.md +45 -0
  68. package/roles/scout.md +36 -0
  69. package/roles/verifier.md +36 -0
@@ -0,0 +1,216 @@
1
+ //#region src/team-store.d.ts
2
+ export type TeamId = string;
3
+ export type MemberId = string;
4
+ export type SessionId = string;
5
+ export type BindingGeneration = number;
6
+ export type ContactTarget = string | 'human' | 'team';
7
+ export interface ContactGrant {
8
+ from: MemberId;
9
+ to: ContactTarget;
10
+ grantedBy: string;
11
+ at: number;
12
+ }
13
+ export interface MemberRecord {
14
+ memberId: MemberId;
15
+ displayName: string;
16
+ role: string;
17
+ roles?: readonly string[];
18
+ /** Short statement of this member's purpose in the team. */
19
+ note?: string;
20
+ availability: string;
21
+ sessionId?: SessionId;
22
+ bindingGeneration: BindingGeneration;
23
+ contractRevision: number;
24
+ [key: string]: unknown;
25
+ }
26
+ /**
27
+ * Whether the dispatcher may start assigned work. `paused` stops starts and
28
+ * nothing else: an attempt already running keeps running, ownership does not
29
+ * move, and a delivery already queued for a member still reaches that member.
30
+ */
31
+ export interface DispatchSwitch {
32
+ mode: 'auto' | 'paused';
33
+ /** Who flipped it: `human:desktop` or a lead member id. */
34
+ by: string;
35
+ reason?: string;
36
+ at: number;
37
+ }
38
+ export interface TeamState {
39
+ schemaVersion: number;
40
+ revision: number;
41
+ teamId: TeamId;
42
+ workspaceId: string;
43
+ workspacePath: string;
44
+ members: MemberRecord[];
45
+ archivedMemberIds: string[];
46
+ createdAt: number;
47
+ updatedAt: number;
48
+ /** Persisted human-readable team name (optional for pre-B10 state). */
49
+ name?: string;
50
+ /** Human-selected lead member; omitted for legacy state until resolved by role. */
51
+ leadMemberId?: MemberId;
52
+ /** Standing contact grants issued by the lead. */
53
+ contactGrants?: ContactGrant[];
54
+ /** Dispatch switch; absent means `auto` (the pre-B29 state). */
55
+ dispatch?: DispatchSwitch;
56
+ [key: string]: unknown;
57
+ }
58
+ type StoreDefaults = {
59
+ workspacePath?: string;
60
+ workspaceId?: string;
61
+ teamId?: string;
62
+ name?: string;
63
+ };
64
+ export type TeamCandidate = {
65
+ readonly teamId: string;
66
+ readonly name?: string;
67
+ readonly memberCount?: number;
68
+ readonly updatedAt?: number;
69
+ readonly usable?: boolean;
70
+ readonly reason?: string;
71
+ };
72
+ export type TeamAdoption = {
73
+ readonly state: TeamState;
74
+ readonly adoptedFrom: string;
75
+ };
76
+ /**
77
+ * Names the transport and the product already use for actors that are not members. A member with one
78
+ * of these ids would send mail *as* that actor — `human` is trusted by the mailbox as a human
79
+ * instruction — so the store refuses to persist such a member at all. The check lives here, not on
80
+ * the HTTP boundary, because a route parser protects one door while the store protects every caller.
81
+ */
82
+ export declare const RESERVED_ACTOR_NAMES: readonly string[];
83
+ export declare function isReservedActorName(memberId: string): boolean;
84
+ /**
85
+ * Who leads this team: the recorded lead when it is still a member, otherwise the single member
86
+ * holding the lead role, otherwise nobody. One definition, because the roster a member is shown and
87
+ * the gate that admits its calls must agree — the expression used to be inlined in a dozen places,
88
+ * and the first change to the rule would have desynchronised them (external review, finding 7).
89
+ */
90
+ export declare function resolveLeadMemberId(team: Pick<TeamState, 'leadMemberId' | 'members'>): string | undefined;
91
+ declare const TEAM_ROOT = ".dsh-live-teams";
92
+ export declare class TeamStore {
93
+ private readonly defaults;
94
+ private readonly locations;
95
+ constructor(defaults?: StoreDefaults);
96
+ open(request?: StoreDefaults): Promise<TeamState>;
97
+ isDisabledSync(teamId: string): boolean;
98
+ readExisting(request?: StoreDefaults): Promise<TeamState | undefined>;
99
+ isDisabled(teamId: string): Promise<boolean>;
100
+ /** Discover old team directories in this workspace without creating state. */
101
+ listAdoptionCandidates(request: {
102
+ workspacePath: string;
103
+ derivedTeamId: string;
104
+ }): Promise<TeamCandidate[]>;
105
+ /** Adopt one old team into the workspace-derived directory. */
106
+ adoptTeam(request: {
107
+ workspacePath: string;
108
+ workspaceId: string;
109
+ derivedTeamId: string;
110
+ candidateTeamId: string;
111
+ replaceEmptyDerived: boolean;
112
+ actor?: string;
113
+ }): Promise<TeamAdoption>;
114
+ /**
115
+ * Adopt the workspace's own team when it sits under another workspace id.
116
+ *
117
+ * The registry mints a new id whenever an entry is re-created, and the team directory is
118
+ * named by id — so after such an event the panel showed an empty team while the real one
119
+ * (members, tasks, journal) sat right next to it, and only a human clicking "adopt" could
120
+ * bring it back. The canonical path is the stable identity here; the id is a registry
121
+ * variable, so it is adopted rather than treated as a reason to refuse.
122
+ *
123
+ * Deliberately conservative: only one usable candidate, only if it has members, only if it
124
+ * declares this path, and never when the current directory already holds a live team. An
125
+ * ambiguous set stays a human decision — the panel already offers the choice.
126
+ */
127
+ adoptByPath(request: {
128
+ workspacePath: string;
129
+ workspaceId: string;
130
+ teamId: string;
131
+ actor?: string;
132
+ }): Promise<{
133
+ adoptedFrom: string;
134
+ memberCount: number;
135
+ } | undefined>;
136
+ setDisabled(teamId: string, disabled: boolean): Promise<void>;
137
+ renameTeam(teamId: string, expectedRevision: number, name: string): Promise<{
138
+ state: TeamState;
139
+ from: string;
140
+ }>;
141
+ /**
142
+ * Flip the dispatch switch. Authority belongs to the callers, exactly as it does
143
+ * for `renameTeam`: the desktop route admits the human, and the lead-only tool
144
+ * admits the lead. A request that changes nothing is refused rather than silently
145
+ * accepted, so a double click cannot look like a state change that never happened.
146
+ */
147
+ setDispatchMode(teamId: string, mode: DispatchSwitch['mode'], request: {
148
+ actor: string;
149
+ reason?: string;
150
+ }, expectedRevision: number): Promise<{
151
+ state: TeamState;
152
+ from: DispatchSwitch['mode'];
153
+ to: DispatchSwitch['mode'];
154
+ }>;
155
+ commit<T>(teamId: string, request: {
156
+ expectedRevision: number;
157
+ mutate: (state: TeamState) => T | Promise<T>;
158
+ }): Promise<{
159
+ state: TeamState;
160
+ value: T;
161
+ }>;
162
+ memberBySession(teamId: string, sessionId: string): Promise<MemberRecord | undefined>;
163
+ bindSession(teamId: string, memberId: string, sessionId: string, expectedRevision: number): Promise<MemberRecord>;
164
+ unbindSession(teamId: string, memberId: string, expectedRevision: number): Promise<MemberRecord>;
165
+ setLead(teamId: string, memberId: string, expectedRevision: number): Promise<TeamState>;
166
+ updateContactGrant(teamId: string, from: MemberId, to: ContactTarget, action: 'add' | 'remove', grantedBy: string): Promise<{
167
+ state: TeamState;
168
+ grants: ContactGrant[];
169
+ changed: boolean;
170
+ }>;
171
+ setMemberNote(teamId: string, memberId: string, note: string, expectedRevision: number): Promise<{
172
+ state: TeamState;
173
+ member: MemberRecord;
174
+ }>;
175
+ removeMember(teamId: string, memberId: string, expectedRevision: number): Promise<{
176
+ state: TeamState;
177
+ removed: MemberRecord;
178
+ }>;
179
+ appendEvent(teamId: string, event: unknown): Promise<void>;
180
+ /**
181
+ * The audit, read from a byte offset when the caller has one.
182
+ *
183
+ * The journal grows forever and the panel re-reads it every few seconds; reading the whole file was
184
+ * the one part of polling that got worse with age (a ten-times-longer journal meant seventeen
185
+ * megabytes a minute). The file is append-only, so an offset is a safe cursor: the caller passes
186
+ * back the offset this returned and pays only for what is new. Without an offset the tail is read —
187
+ * never the whole history, which nobody reads in a panel anyway.
188
+ */
189
+ readEvents(teamId: string, after?: number): Promise<{
190
+ events: unknown[];
191
+ torn: string | null;
192
+ nextOffset: number;
193
+ truncated: boolean;
194
+ }>;
195
+ private location;
196
+ private requireLocation;
197
+ private read;
198
+ memberBySessionSync(teamId: string, sessionId: string): MemberRecord | undefined;
199
+ }
200
+ export declare function createTeamStore(options?: StoreDefaults): TeamStore;
201
+ /**
202
+ * Read the dispatch switch strictly: an absent switch is `auto`, and anything
203
+ * malformed is corrupt state rather than a quiet fallback to automatic dispatch.
204
+ */
205
+ export declare function readDispatchSwitch(state: TeamState): DispatchSwitch;
206
+ export declare function readTeamStateSync(request: {
207
+ workspacePath: string;
208
+ teamId: string;
209
+ }): TeamState | undefined;
210
+ export declare function readMemberBySessionSync(request: {
211
+ workspacePath: string;
212
+ teamId: string;
213
+ sessionId: string;
214
+ }): MemberRecord | undefined;
215
+ //#endregion
216
+ export { TEAM_ROOT };