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.
- package/LICENSE +176 -0
- package/NOTICE +11 -0
- package/README.md +85 -0
- package/cordis.patch.yml +25 -0
- package/lib/binding.d.ts +18 -0
- package/lib/binding.js +42 -0
- package/lib/changed-paths.d.ts +26 -0
- package/lib/changed-paths.js +69 -0
- package/lib/client.js +6753 -0
- package/lib/command-queue.d.ts +60 -0
- package/lib/command-queue.js +185 -0
- package/lib/compatibility.js +109 -0
- package/lib/context-provider.d.ts +110 -0
- package/lib/context-provider.js +249 -0
- package/lib/dispatch.d.ts +174 -0
- package/lib/dispatch.js +624 -0
- package/lib/errors.d.ts +36 -0
- package/lib/errors.js +103 -0
- package/lib/git-artifacts.d.ts +50 -0
- package/lib/git-artifacts.js +242 -0
- package/lib/index.d.ts +14 -0
- package/lib/index.js +14 -0
- package/lib/mailbox.d.ts +274 -0
- package/lib/mailbox.js +721 -0
- package/lib/member-tools.d.ts +57 -0
- package/lib/member-tools.js +1265 -0
- package/lib/migrations.d.ts +17 -0
- package/lib/migrations.js +47 -0
- package/lib/plugin.d.ts +106 -0
- package/lib/plugin.js +1003 -0
- package/lib/roles.d.ts +35 -0
- package/lib/roles.js +284 -0
- package/lib/routes.d.ts +586 -0
- package/lib/routes.js +2816 -0
- package/lib/scope.d.ts +62 -0
- package/lib/scope.js +133 -0
- package/lib/session-bridge.d.ts +76 -0
- package/lib/session-bridge.js +147 -0
- package/lib/session-title.js +35 -0
- package/lib/storage.d.ts +9 -0
- package/lib/storage.js +65 -0
- package/lib/task-store.d.ts +729 -0
- package/lib/task-store.js +2205 -0
- package/lib/team-store.d.ts +216 -0
- package/lib/team-store.js +765 -0
- package/lib/tree-snapshot.d.ts +28 -0
- package/lib/tree-snapshot.js +80 -0
- package/lib/types/client/TeamView.d.ts +26 -0
- package/lib/types/client/TeamView.dom.test.d.ts +1 -0
- package/lib/types/client/api.d.ts +522 -0
- package/lib/types/client/api.test.d.ts +1 -0
- package/lib/types/client/attention.d.ts +65 -0
- package/lib/types/client/attention.test.d.ts +1 -0
- package/lib/types/client/index.d.ts +31 -0
- package/lib/types/client/locales.d.ts +577 -0
- package/lib/types/client/member-name.d.ts +14 -0
- package/lib/types/client/member-name.test.d.ts +1 -0
- package/lib/types/client/roster.d.ts +26 -0
- package/lib/types/client/roster.test.d.ts +1 -0
- package/lib/types/client/styles.d.ts +3 -0
- package/package.json +104 -0
- package/roles/builder.md +40 -0
- package/roles/delegate.md +36 -0
- package/roles/lead.md +46 -0
- package/roles/oracle.md +36 -0
- package/roles/researcher.md +37 -0
- package/roles/reviewer.md +45 -0
- package/roles/scout.md +36 -0
- package/roles/verifier.md +36 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region src/tree-snapshot.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A cheap fingerprint of a workspace tree, for the scope record in `files` mode (B32).
|
|
4
|
+
*
|
|
5
|
+
* Pure filesystem work — no git, no shelling out — so the task store can use it without
|
|
6
|
+
* taking on the git adapter, and so it can be tested against a plain temporary folder.
|
|
7
|
+
* Size and mtime, not content: the question is whether a file moved while an attempt ran,
|
|
8
|
+
* and hashing every file of a workspace on every claim is a cost nobody agreed to. Content
|
|
9
|
+
* digests live in the submission artifact, where they belong.
|
|
10
|
+
*/
|
|
11
|
+
/** Directories that are never a member's work: build output, caches, the team's own state. */
|
|
12
|
+
export declare const SNAPSHOT_EXCLUDED: Set<string>;
|
|
13
|
+
export declare const MAX_SNAPSHOT_FILES = 20000;
|
|
14
|
+
export type TreeSnapshot = Readonly<Record<string, string>>;
|
|
15
|
+
/**
|
|
16
|
+
* A cheap fingerprint of the whole tree: path → `size:mtime`.
|
|
17
|
+
*
|
|
18
|
+
* Size and mtime, not content: the question here is "did this file move while the attempt
|
|
19
|
+
* ran", and hashing every file of a workspace on every claim would be a cost nobody agreed
|
|
20
|
+
* to. Content digests live in the submission artifact, where they belong.
|
|
21
|
+
*
|
|
22
|
+
* `undefined` means the tree was too large to watch, which is reported as `unchecked` with a
|
|
23
|
+
* reason rather than as "nothing changed".
|
|
24
|
+
*/
|
|
25
|
+
export declare function snapshotTree(workspacePath: string): Promise<TreeSnapshot | undefined>;
|
|
26
|
+
/** Paths added, changed or removed between two snapshots, sorted for a stable record. */
|
|
27
|
+
export declare function diffSnapshots(before: TreeSnapshot, after: TreeSnapshot): string[];
|
|
28
|
+
//#endregion
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as path$1 from "node:path";
|
|
2
|
+
import * as fsp from "node:fs/promises";
|
|
3
|
+
//#region src/tree-snapshot.ts
|
|
4
|
+
/**
|
|
5
|
+
* A cheap fingerprint of a workspace tree, for the scope record in `files` mode (B32).
|
|
6
|
+
*
|
|
7
|
+
* Pure filesystem work — no git, no shelling out — so the task store can use it without
|
|
8
|
+
* taking on the git adapter, and so it can be tested against a plain temporary folder.
|
|
9
|
+
* Size and mtime, not content: the question is whether a file moved while an attempt ran,
|
|
10
|
+
* and hashing every file of a workspace on every claim is a cost nobody agreed to. Content
|
|
11
|
+
* digests live in the submission artifact, where they belong.
|
|
12
|
+
*/
|
|
13
|
+
/** Directories that are never a member's work: build output, caches, the team's own state. */
|
|
14
|
+
const SNAPSHOT_EXCLUDED = /* @__PURE__ */ new Set([
|
|
15
|
+
".git",
|
|
16
|
+
".dsh-live-teams",
|
|
17
|
+
"node_modules",
|
|
18
|
+
"dist",
|
|
19
|
+
"build",
|
|
20
|
+
"target",
|
|
21
|
+
".venv",
|
|
22
|
+
"venv",
|
|
23
|
+
"__pycache__",
|
|
24
|
+
".next",
|
|
25
|
+
".cache",
|
|
26
|
+
"coverage",
|
|
27
|
+
".idea",
|
|
28
|
+
".DS_Store"
|
|
29
|
+
]);
|
|
30
|
+
const MAX_SNAPSHOT_FILES = 2e4;
|
|
31
|
+
/**
|
|
32
|
+
* A cheap fingerprint of the whole tree: path → `size:mtime`.
|
|
33
|
+
*
|
|
34
|
+
* Size and mtime, not content: the question here is "did this file move while the attempt
|
|
35
|
+
* ran", and hashing every file of a workspace on every claim would be a cost nobody agreed
|
|
36
|
+
* to. Content digests live in the submission artifact, where they belong.
|
|
37
|
+
*
|
|
38
|
+
* `undefined` means the tree was too large to watch, which is reported as `unchecked` with a
|
|
39
|
+
* reason rather than as "nothing changed".
|
|
40
|
+
*/
|
|
41
|
+
async function snapshotTree(workspacePath) {
|
|
42
|
+
const snapshot = {};
|
|
43
|
+
let count = 0;
|
|
44
|
+
const walk = async (relative) => {
|
|
45
|
+
let entries;
|
|
46
|
+
try {
|
|
47
|
+
entries = await fsp.readdir(path$1.join(workspacePath, relative), { withFileTypes: true });
|
|
48
|
+
} catch {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
const next = relative.length === 0 ? entry.name : `${relative}/${entry.name}`;
|
|
53
|
+
if (entry.isDirectory()) {
|
|
54
|
+
if (SNAPSHOT_EXCLUDED.has(entry.name)) continue;
|
|
55
|
+
if (!await walk(next)) return false;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (!entry.isFile() || SNAPSHOT_EXCLUDED.has(entry.name)) continue;
|
|
59
|
+
count += 1;
|
|
60
|
+
if (count > 2e4) return false;
|
|
61
|
+
try {
|
|
62
|
+
const stat = await fsp.stat(path$1.join(workspacePath, next));
|
|
63
|
+
snapshot[next] = `${stat.size}:${Math.round(stat.mtimeMs)}`;
|
|
64
|
+
} catch {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return true;
|
|
69
|
+
};
|
|
70
|
+
return await walk("") ? snapshot : void 0;
|
|
71
|
+
}
|
|
72
|
+
/** Paths added, changed or removed between two snapshots, sorted for a stable record. */
|
|
73
|
+
function diffSnapshots(before, after) {
|
|
74
|
+
const changed = /* @__PURE__ */ new Set();
|
|
75
|
+
for (const [file, stamp] of Object.entries(before)) if (after[file] !== stamp) changed.add(file);
|
|
76
|
+
for (const file of Object.keys(after)) if (before[file] === void 0) changed.add(file);
|
|
77
|
+
return [...changed].sort();
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
export { MAX_SNAPSHOT_FILES, SNAPSHOT_EXCLUDED, diffSnapshots, snapshotTree };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { MessageKind, TaskStatus, TeamAttemptStatus, TeamSubmissionScope } from './api.js';
|
|
3
|
+
import type { LocaleKey } from './locales.js';
|
|
4
|
+
import './styles.js';
|
|
5
|
+
export type TeamViewContext = {
|
|
6
|
+
readonly sessions: {
|
|
7
|
+
open(sessionId: string): void;
|
|
8
|
+
};
|
|
9
|
+
readonly t: (key: LocaleKey) => string;
|
|
10
|
+
};
|
|
11
|
+
export type TeamViewProps = {
|
|
12
|
+
readonly ctx?: TeamViewContext;
|
|
13
|
+
/** Session the view belongs to; the host serves this Session's workspace team. */
|
|
14
|
+
readonly sessionId?: string;
|
|
15
|
+
/** How often the tab re-reads tasks while visible. Exposed so the test can watch it. */
|
|
16
|
+
readonly pollMs?: number;
|
|
17
|
+
};
|
|
18
|
+
export type TaskFilter = 'active' | 'waiting' | 'archived';
|
|
19
|
+
export declare const attemptStatusKeys: Record<TeamAttemptStatus, LocaleKey>;
|
|
20
|
+
export declare const scopeKeys: Record<TeamSubmissionScope['state'], LocaleKey>;
|
|
21
|
+
export declare const scopeReasonKeys: Record<NonNullable<TeamSubmissionScope['reason']>, LocaleKey>;
|
|
22
|
+
export declare const taskStatusKeys: Record<TaskStatus, LocaleKey>;
|
|
23
|
+
export declare const taskFilterKeys: Record<TaskFilter, LocaleKey>;
|
|
24
|
+
export declare const messageKindKeys: Record<MessageKind, LocaleKey>;
|
|
25
|
+
export declare function TeamView(props: TeamViewProps): React.ReactElement;
|
|
26
|
+
export default TeamView;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
export type TeamMember = {
|
|
2
|
+
memberId: string;
|
|
3
|
+
note?: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
role: string;
|
|
6
|
+
availability: string;
|
|
7
|
+
sessionId: string | null;
|
|
8
|
+
live: boolean;
|
|
9
|
+
status: 'idle' | 'running' | 'unknown';
|
|
10
|
+
bindingGeneration: number;
|
|
11
|
+
contractRevision: number;
|
|
12
|
+
permittedContacts?: string[];
|
|
13
|
+
};
|
|
14
|
+
export type TeamSnapshot = {
|
|
15
|
+
teamName?: string;
|
|
16
|
+
leadMemberId?: string;
|
|
17
|
+
teamId: string;
|
|
18
|
+
workspacePath: string;
|
|
19
|
+
revision: number;
|
|
20
|
+
members: TeamMember[];
|
|
21
|
+
};
|
|
22
|
+
export type MessageKind = 'message' | 'direction' | 'comment';
|
|
23
|
+
export type TeamInboxMessage = {
|
|
24
|
+
id: string;
|
|
25
|
+
from: string;
|
|
26
|
+
fromName: string;
|
|
27
|
+
kind: MessageKind;
|
|
28
|
+
content: string;
|
|
29
|
+
createdAt: number;
|
|
30
|
+
delivery: {
|
|
31
|
+
id: string;
|
|
32
|
+
state: 'stored' | 'acknowledged';
|
|
33
|
+
acknowledgedAt?: number;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
export type TeamInbox = {
|
|
37
|
+
teamId: string;
|
|
38
|
+
messages: TeamInboxMessage[];
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* One member who is waiting for the human. Small on purpose: the chip that shows
|
|
42
|
+
* this lives in the Session header of every Session and must not pull the inbox.
|
|
43
|
+
*/
|
|
44
|
+
export type TeamAttentionEntry = {
|
|
45
|
+
memberId: string;
|
|
46
|
+
name: string;
|
|
47
|
+
sessionId: string | null;
|
|
48
|
+
waiting: number;
|
|
49
|
+
since: number;
|
|
50
|
+
kind: MessageKind;
|
|
51
|
+
};
|
|
52
|
+
export type TeamAttention = {
|
|
53
|
+
teamId: string;
|
|
54
|
+
attention: TeamAttentionEntry[];
|
|
55
|
+
};
|
|
56
|
+
export type JournalCategory = 'message' | 'delivery' | 'task' | 'review' | 'contact' | 'team' | 'member' | 'other';
|
|
57
|
+
export type TeamJournalEntry = {
|
|
58
|
+
id: string;
|
|
59
|
+
kind: string;
|
|
60
|
+
category: JournalCategory;
|
|
61
|
+
at: number;
|
|
62
|
+
actor?: string;
|
|
63
|
+
actorName?: string;
|
|
64
|
+
summary: string;
|
|
65
|
+
refs: {
|
|
66
|
+
taskId?: string;
|
|
67
|
+
taskTitle?: string;
|
|
68
|
+
messageId?: string;
|
|
69
|
+
round?: number; /** Everything the row knows, resolved for a person: who, to whom, which task, which attempt. */
|
|
70
|
+
fields?: {
|
|
71
|
+
label: string;
|
|
72
|
+
value: string;
|
|
73
|
+
}[];
|
|
74
|
+
/** The summary split into plain and emphasised runs: names are names, not words. */
|
|
75
|
+
summaryParts?: {
|
|
76
|
+
text: string;
|
|
77
|
+
strong?: boolean;
|
|
78
|
+
}[];
|
|
79
|
+
};
|
|
80
|
+
detail?: string;
|
|
81
|
+
};
|
|
82
|
+
export type TeamJournal = {
|
|
83
|
+
teamId: string;
|
|
84
|
+
entries: TeamJournalEntry[];
|
|
85
|
+
};
|
|
86
|
+
export type SendMessageResult = {
|
|
87
|
+
messageId: string;
|
|
88
|
+
recipients: string[];
|
|
89
|
+
deliveries: Array<{
|
|
90
|
+
id: string;
|
|
91
|
+
recipient: string;
|
|
92
|
+
state: string;
|
|
93
|
+
failure?: string;
|
|
94
|
+
}>;
|
|
95
|
+
};
|
|
96
|
+
export type TeamCandidate = {
|
|
97
|
+
sessionId: string;
|
|
98
|
+
title: string | null;
|
|
99
|
+
cwd: string;
|
|
100
|
+
live: boolean;
|
|
101
|
+
status: 'idle' | 'running' | 'unknown';
|
|
102
|
+
};
|
|
103
|
+
export type TeamCandidates = {
|
|
104
|
+
teamId: string;
|
|
105
|
+
/** Name the listed Sessions are titled with, so `"<member> - <team>"` can be undone. */
|
|
106
|
+
teamName: string;
|
|
107
|
+
workspacePath: string;
|
|
108
|
+
revision: number;
|
|
109
|
+
candidates: TeamCandidate[];
|
|
110
|
+
};
|
|
111
|
+
export type TeamAdoptionCandidate = {
|
|
112
|
+
teamId: string;
|
|
113
|
+
name?: string;
|
|
114
|
+
memberCount?: number;
|
|
115
|
+
updatedAt?: number;
|
|
116
|
+
usable?: boolean;
|
|
117
|
+
reason?: string;
|
|
118
|
+
};
|
|
119
|
+
export type TeamAdoptionCandidates = {
|
|
120
|
+
teamId: string;
|
|
121
|
+
workspacePath: string;
|
|
122
|
+
candidates: TeamAdoptionCandidate[];
|
|
123
|
+
};
|
|
124
|
+
export type TeamRole = {
|
|
125
|
+
id: string;
|
|
126
|
+
name: string;
|
|
127
|
+
description?: string;
|
|
128
|
+
aliases: string[];
|
|
129
|
+
source: 'global' | 'workspace';
|
|
130
|
+
overridden: boolean;
|
|
131
|
+
};
|
|
132
|
+
export type TeamRoles = {
|
|
133
|
+
roles: TeamRole[];
|
|
134
|
+
globalDirectory: string;
|
|
135
|
+
workspaceDirectory: string;
|
|
136
|
+
workspaceDirectoryExists: boolean;
|
|
137
|
+
openAvailable: boolean;
|
|
138
|
+
globalOpenAvailable: boolean;
|
|
139
|
+
};
|
|
140
|
+
export type TaskStatus = 'draft' | 'ready' | 'claimed' | 'in_progress' | 'waiting' | 'needs_human' | 'completed' | 'failed' | 'cancelled';
|
|
141
|
+
export type TaskRoute = {
|
|
142
|
+
type: 'report';
|
|
143
|
+
to: string | 'human';
|
|
144
|
+
} | {
|
|
145
|
+
type: 'review';
|
|
146
|
+
reviewer: string;
|
|
147
|
+
} | {
|
|
148
|
+
type: 'interactive';
|
|
149
|
+
then: TaskRoute;
|
|
150
|
+
} | {
|
|
151
|
+
type: 'custom';
|
|
152
|
+
description: string;
|
|
153
|
+
};
|
|
154
|
+
export type TaskRouteSummary = {
|
|
155
|
+
type: 'report';
|
|
156
|
+
to: string | 'human';
|
|
157
|
+
toName?: string;
|
|
158
|
+
} | {
|
|
159
|
+
type: 'review';
|
|
160
|
+
reviewer: string;
|
|
161
|
+
reviewerName?: string;
|
|
162
|
+
} | {
|
|
163
|
+
type: 'interactive';
|
|
164
|
+
then: TaskRouteSummary;
|
|
165
|
+
} | {
|
|
166
|
+
type: 'custom';
|
|
167
|
+
description: string;
|
|
168
|
+
};
|
|
169
|
+
export type TeamTask = {
|
|
170
|
+
id: string;
|
|
171
|
+
teamId: string;
|
|
172
|
+
title: string;
|
|
173
|
+
kind: string;
|
|
174
|
+
status: TaskStatus;
|
|
175
|
+
assignee?: string;
|
|
176
|
+
route?: TaskRoute;
|
|
177
|
+
humanContact?: 'none' | 'expected' | 'required';
|
|
178
|
+
activeAttemptId?: string;
|
|
179
|
+
latestSubmissionId?: string;
|
|
180
|
+
acceptedSubmissionId?: string;
|
|
181
|
+
acceptance: string[];
|
|
182
|
+
/** Checks and declared paths are part of the contract the human edits. */
|
|
183
|
+
checks?: string[];
|
|
184
|
+
paths?: string[];
|
|
185
|
+
roundLimit: number;
|
|
186
|
+
createdBy: string;
|
|
187
|
+
createdAt: number;
|
|
188
|
+
updatedAt: number;
|
|
189
|
+
revision: number;
|
|
190
|
+
archivedPath?: string;
|
|
191
|
+
documentMissing?: boolean;
|
|
192
|
+
};
|
|
193
|
+
export type TaskSummary = {
|
|
194
|
+
id: string;
|
|
195
|
+
title: string;
|
|
196
|
+
status: TaskStatus;
|
|
197
|
+
assignee?: string;
|
|
198
|
+
assigneeName?: string;
|
|
199
|
+
route?: TaskRouteSummary;
|
|
200
|
+
round?: number;
|
|
201
|
+
roundLimit?: number;
|
|
202
|
+
updatedAt: number;
|
|
203
|
+
archivedPath?: string;
|
|
204
|
+
documentMissing?: boolean;
|
|
205
|
+
dependsOn?: string[];
|
|
206
|
+
blockedBy?: Array<{
|
|
207
|
+
id: string;
|
|
208
|
+
title: string;
|
|
209
|
+
status: TaskStatus;
|
|
210
|
+
}>;
|
|
211
|
+
/** Declared write paths, so the contract form can be filled without a second read. */
|
|
212
|
+
paths?: string[];
|
|
213
|
+
checks?: string[];
|
|
214
|
+
};
|
|
215
|
+
export type SubmissionArtifact = {
|
|
216
|
+
type: 'report';
|
|
217
|
+
bodyRef: string;
|
|
218
|
+
bodyDigest: string;
|
|
219
|
+
} | {
|
|
220
|
+
type: 'files';
|
|
221
|
+
paths: string[];
|
|
222
|
+
manifestDigest: string;
|
|
223
|
+
};
|
|
224
|
+
export type SubmissionCheck = {
|
|
225
|
+
command: string;
|
|
226
|
+
status: 'passed' | 'failed';
|
|
227
|
+
output?: string;
|
|
228
|
+
};
|
|
229
|
+
export type TeamSubmissionScope = {
|
|
230
|
+
declared?: string[];
|
|
231
|
+
changed?: string[];
|
|
232
|
+
unexpected?: string[];
|
|
233
|
+
sharedTree?: string[];
|
|
234
|
+
state: 'clean' | 'violation' | 'shared-tree' | 'unchecked';
|
|
235
|
+
/** B32: `git` in a work tree, `files` in a folder that is not a repository. */
|
|
236
|
+
mode?: 'git' | 'files';
|
|
237
|
+
reason?: 'no-repository' | 'too-many-files' | 'no-snapshot' | 'unreadable';
|
|
238
|
+
};
|
|
239
|
+
export type Submission = {
|
|
240
|
+
id: string;
|
|
241
|
+
taskId: string;
|
|
242
|
+
attemptId: string;
|
|
243
|
+
attemptGeneration: number;
|
|
244
|
+
artifact: SubmissionArtifact;
|
|
245
|
+
summary: string;
|
|
246
|
+
checks: SubmissionCheck[];
|
|
247
|
+
scope?: TeamSubmissionScope;
|
|
248
|
+
createdAt: number;
|
|
249
|
+
revision: number;
|
|
250
|
+
};
|
|
251
|
+
export type ReviewFinding = {
|
|
252
|
+
severity: 'low' | 'medium' | 'high' | 'blocker';
|
|
253
|
+
problem: string;
|
|
254
|
+
requiredFix: string;
|
|
255
|
+
artifactLocation?: string;
|
|
256
|
+
};
|
|
257
|
+
export type ReviewRound = {
|
|
258
|
+
id: string;
|
|
259
|
+
taskId: string;
|
|
260
|
+
submissionId: string;
|
|
261
|
+
reviewerMemberId: string;
|
|
262
|
+
round: number;
|
|
263
|
+
verdict: 'pass' | 'needs_revision' | 'escalate';
|
|
264
|
+
findings: ReviewFinding[];
|
|
265
|
+
evidence: SubmissionCheck[];
|
|
266
|
+
createdAt: number;
|
|
267
|
+
revision: number;
|
|
268
|
+
};
|
|
269
|
+
export type TeamTasks = {
|
|
270
|
+
teamId: string;
|
|
271
|
+
tasks: TaskSummary[];
|
|
272
|
+
};
|
|
273
|
+
export type TeamAttemptStatus = 'active' | 'revoking' | 'revoked' | 'completed' | 'failed';
|
|
274
|
+
export type TeamTaskAttempt = {
|
|
275
|
+
id: string;
|
|
276
|
+
memberId: string;
|
|
277
|
+
sessionId: string;
|
|
278
|
+
generation: number;
|
|
279
|
+
status: TeamAttemptStatus;
|
|
280
|
+
startedAt: number;
|
|
281
|
+
humanIntervenedAt?: number;
|
|
282
|
+
};
|
|
283
|
+
export type TeamTaskDetail = {
|
|
284
|
+
task: TeamTask;
|
|
285
|
+
document: string;
|
|
286
|
+
documentMissing?: true;
|
|
287
|
+
submissions: Submission[];
|
|
288
|
+
rounds: ReviewRound[];
|
|
289
|
+
attempts: TeamTaskAttempt[];
|
|
290
|
+
};
|
|
291
|
+
export type AcceptTaskResult = {
|
|
292
|
+
task: TeamTask;
|
|
293
|
+
archivedPath: string;
|
|
294
|
+
};
|
|
295
|
+
export type ReviseTaskResult = {
|
|
296
|
+
task: TeamTask;
|
|
297
|
+
};
|
|
298
|
+
/** The workspace folder action only exists after override created its folder. */
|
|
299
|
+
export declare function canOpenWorkspaceRoles(roles: Pick<TeamRoles, 'openAvailable' | 'workspaceDirectoryExists'>): boolean;
|
|
300
|
+
export type CreateSessionSuccess = {
|
|
301
|
+
teamId: string;
|
|
302
|
+
memberId: string;
|
|
303
|
+
sessionId: string;
|
|
304
|
+
revision: number;
|
|
305
|
+
applied: true;
|
|
306
|
+
retried: boolean;
|
|
307
|
+
member: TeamMember;
|
|
308
|
+
};
|
|
309
|
+
export type MutationSuccess = {
|
|
310
|
+
teamId: string;
|
|
311
|
+
memberId: string;
|
|
312
|
+
revision: number;
|
|
313
|
+
applied: true;
|
|
314
|
+
retried: boolean;
|
|
315
|
+
member: TeamMember;
|
|
316
|
+
};
|
|
317
|
+
export type InterruptTurnSuccess = {
|
|
318
|
+
memberId: string;
|
|
319
|
+
interrupted: true;
|
|
320
|
+
status: 'idle' | 'running' | 'unknown';
|
|
321
|
+
};
|
|
322
|
+
export type RemoveMemberSuccess = {
|
|
323
|
+
teamId: string;
|
|
324
|
+
memberId: string;
|
|
325
|
+
revision: number;
|
|
326
|
+
applied: true;
|
|
327
|
+
retried: boolean;
|
|
328
|
+
removed: {
|
|
329
|
+
memberId: string;
|
|
330
|
+
displayName: string;
|
|
331
|
+
role: string;
|
|
332
|
+
sessionId: string | null;
|
|
333
|
+
};
|
|
334
|
+
};
|
|
335
|
+
export type MutationConflict = {
|
|
336
|
+
revision: number;
|
|
337
|
+
members: TeamMember[];
|
|
338
|
+
};
|
|
339
|
+
export declare class LiveTeamsApiError extends Error {
|
|
340
|
+
readonly status: number;
|
|
341
|
+
readonly error: string;
|
|
342
|
+
readonly conflict: MutationConflict | null;
|
|
343
|
+
constructor(status: number, error: string, conflict?: MutationConflict | null);
|
|
344
|
+
}
|
|
345
|
+
export type TeamStateStatus = {
|
|
346
|
+
enabled: boolean;
|
|
347
|
+
briefing?: string;
|
|
348
|
+
openAvailable?: boolean;
|
|
349
|
+
teamId: string;
|
|
350
|
+
teamName: string;
|
|
351
|
+
workspacePath: string;
|
|
352
|
+
revision?: number;
|
|
353
|
+
memberCount?: number;
|
|
354
|
+
compatibility?: {
|
|
355
|
+
verdict: 'compatible' | 'degraded' | 'incompatible';
|
|
356
|
+
hostVersion?: string;
|
|
357
|
+
missing: string[];
|
|
358
|
+
absent: string[];
|
|
359
|
+
detail: string;
|
|
360
|
+
};
|
|
361
|
+
};
|
|
362
|
+
export declare function fetchTeamState(session?: string, signal?: AbortSignal): Promise<TeamStateStatus>;
|
|
363
|
+
export declare function enableTeam(name?: string, session?: string, createNew?: boolean): Promise<TeamStateStatus>;
|
|
364
|
+
export declare function disableTeam(session?: string): Promise<TeamStateStatus>;
|
|
365
|
+
export declare function renameTeam(name: string, expectedRevision: number, session?: string): Promise<TeamStateStatus>;
|
|
366
|
+
export declare function fetchTeamTasks(session?: string, includeArchived?: boolean, signal?: AbortSignal): Promise<TeamTasks>;
|
|
367
|
+
/** One task's dispatch verdict, in the same words the journal uses (B29). */
|
|
368
|
+
export type DispatchTaskVerdict = {
|
|
369
|
+
taskId: string;
|
|
370
|
+
title: string;
|
|
371
|
+
status: string;
|
|
372
|
+
assignee?: string;
|
|
373
|
+
decision: 'assign' | 'active' | 'wait' | 'refused';
|
|
374
|
+
reason: string;
|
|
375
|
+
detail: string;
|
|
376
|
+
warning?: string;
|
|
377
|
+
/** F3: this attempt has been silent long enough to show. Detection only, never an auto-revoke. */
|
|
378
|
+
stalled?: {
|
|
379
|
+
at: number;
|
|
380
|
+
reason: 'unacknowledged' | 'idle';
|
|
381
|
+
detail: string;
|
|
382
|
+
};
|
|
383
|
+
};
|
|
384
|
+
export type TeamDispatch = {
|
|
385
|
+
teamId: string;
|
|
386
|
+
paused: boolean;
|
|
387
|
+
coding: 'manual' | 'automatic';
|
|
388
|
+
pausedBy?: string;
|
|
389
|
+
pausedReason?: string;
|
|
390
|
+
counts: Record<'assign' | 'active' | 'wait' | 'refused', number>;
|
|
391
|
+
tasks: DispatchTaskVerdict[];
|
|
392
|
+
};
|
|
393
|
+
export declare function fetchTeamDispatch(session?: string, signal?: AbortSignal): Promise<TeamDispatch>;
|
|
394
|
+
/** Only the human and the lead may flip this; the server decides which one the caller is. */
|
|
395
|
+
export declare function setTeamDispatch(mode: 'auto' | 'paused', reason?: string, session?: string): Promise<{
|
|
396
|
+
from: string;
|
|
397
|
+
to: string;
|
|
398
|
+
}>;
|
|
399
|
+
export declare function fetchTeamTask(taskId: string, session?: string, signal?: AbortSignal): Promise<TeamTaskDetail>;
|
|
400
|
+
export declare function acceptTeamTask(taskId: string, note?: string, session?: string): Promise<AcceptTaskResult>;
|
|
401
|
+
export declare function reviseTeamTask(taskId: string, instructions: string, session?: string): Promise<ReviseTaskResult>;
|
|
402
|
+
export declare function fetchTeamRoles(session?: string, signal?: AbortSignal): Promise<TeamRoles>;
|
|
403
|
+
export declare function openTeamRoles(kind: 'global' | 'workspace', id?: string, session?: string): Promise<string>;
|
|
404
|
+
export declare function overrideTeamRole(id: string, session?: string): Promise<{
|
|
405
|
+
id: string;
|
|
406
|
+
path: string;
|
|
407
|
+
}>;
|
|
408
|
+
export declare function fetchTeamAdoptionCandidates(session?: string, signal?: AbortSignal): Promise<TeamAdoptionCandidates>;
|
|
409
|
+
export declare function adoptTeam(teamId: string, replaceEmptyDerived: boolean, session?: string): Promise<TeamStateStatus & {
|
|
410
|
+
adoptedFrom: string;
|
|
411
|
+
}>;
|
|
412
|
+
export declare function fetchTeamCandidates(session?: string, signal?: AbortSignal): Promise<TeamCandidates>;
|
|
413
|
+
export declare function fetchTeamInbox(session?: string, limit?: number, signal?: AbortSignal): Promise<TeamInbox>;
|
|
414
|
+
/** Who is waiting for the human, one entry per member. Polled by the header chip. */
|
|
415
|
+
export declare function fetchTeamAttention(session?: string, signal?: AbortSignal): Promise<TeamAttention>;
|
|
416
|
+
/**
|
|
417
|
+
* Clear a whole member's backlog in one request. The chip opens the Session the
|
|
418
|
+
* human was taken to, so acknowledging 22 rows one by one would be busywork.
|
|
419
|
+
*/
|
|
420
|
+
export declare function acknowledgeTeamMessages(messageIds: readonly string[], session?: string): Promise<{
|
|
421
|
+
messageIds: string[];
|
|
422
|
+
}>;
|
|
423
|
+
export declare function fetchTeamJournal(session?: string, limit?: number, signal?: AbortSignal): Promise<TeamJournal>;
|
|
424
|
+
export declare function sendTeamMessage(request: {
|
|
425
|
+
to: string;
|
|
426
|
+
kind: MessageKind;
|
|
427
|
+
content: string;
|
|
428
|
+
threadId?: string;
|
|
429
|
+
}, session?: string): Promise<SendMessageResult>;
|
|
430
|
+
export declare function acknowledgeTeamMessage(messageId: string, session?: string): Promise<{
|
|
431
|
+
messageId: string;
|
|
432
|
+
state: 'acknowledged';
|
|
433
|
+
}>;
|
|
434
|
+
export type TeamLead = {
|
|
435
|
+
leadMemberId?: string;
|
|
436
|
+
resolvedFrom: 'state' | 'role' | 'none';
|
|
437
|
+
};
|
|
438
|
+
export declare function openTeamBriefing(session?: string): Promise<string>;
|
|
439
|
+
export declare function fetchTeamLead(session?: string): Promise<TeamLead>;
|
|
440
|
+
export declare function setTeamLead(memberId: string, session?: string): Promise<{
|
|
441
|
+
leadMemberId: string;
|
|
442
|
+
}>;
|
|
443
|
+
export declare function fetchTeamSnapshot(session?: string, signal?: AbortSignal): Promise<TeamSnapshot>;
|
|
444
|
+
export declare function changeMemberRole(memberId: string, role: string, expectedRevision: number, session?: string): Promise<MutationSuccess>;
|
|
445
|
+
export declare function changeMemberAvailability(memberId: string, availability: 'available' | 'paused', expectedRevision: number, session?: string): Promise<MutationSuccess>;
|
|
446
|
+
export declare function changeMemberDisplayName(memberId: string, displayName: string, expectedRevision: number, session?: string): Promise<MutationSuccess>;
|
|
447
|
+
/**
|
|
448
|
+
* The body's `sessionId` names the Session that JOINS, so the request scope travels
|
|
449
|
+
* in the query instead. Passing it through `withSession` overwrote the joining
|
|
450
|
+
* Session with the caller's, and the server refused it as already a member.
|
|
451
|
+
*/
|
|
452
|
+
/**
|
|
453
|
+
* The human's own control over work (review finding 4): the same operations the lead's tools call.
|
|
454
|
+
* The panel used to read tasks, accept them and send them back — creating one, changing a contract or
|
|
455
|
+
* releasing a held attempt meant asking the lead and waiting a model turn.
|
|
456
|
+
*/
|
|
457
|
+
export type TaskControlDraft = {
|
|
458
|
+
title: string;
|
|
459
|
+
kind: string;
|
|
460
|
+
assignee: string;
|
|
461
|
+
acceptance: string[];
|
|
462
|
+
paths?: string[];
|
|
463
|
+
checks?: string[];
|
|
464
|
+
body?: string;
|
|
465
|
+
why?: string;
|
|
466
|
+
route?: {
|
|
467
|
+
type: string;
|
|
468
|
+
to?: string;
|
|
469
|
+
reviewer?: string;
|
|
470
|
+
};
|
|
471
|
+
roundLimit?: number;
|
|
472
|
+
};
|
|
473
|
+
export declare function createTeamTask(draft: TaskControlDraft, session?: string): Promise<{
|
|
474
|
+
task: {
|
|
475
|
+
id: string;
|
|
476
|
+
title: string;
|
|
477
|
+
status: string;
|
|
478
|
+
};
|
|
479
|
+
}>;
|
|
480
|
+
export declare function updateTeamTask(request: {
|
|
481
|
+
taskId: string;
|
|
482
|
+
acceptance?: string[];
|
|
483
|
+
paths?: string[];
|
|
484
|
+
checks?: string[];
|
|
485
|
+
title?: string;
|
|
486
|
+
assignee?: string;
|
|
487
|
+
body?: string;
|
|
488
|
+
expectedRevision?: number;
|
|
489
|
+
}, session?: string): Promise<MutationSuccess>;
|
|
490
|
+
export declare function revokeTeamTask(request: {
|
|
491
|
+
taskId: string;
|
|
492
|
+
reason: string;
|
|
493
|
+
}, session?: string): Promise<MutationSuccess>;
|
|
494
|
+
export declare function addTeamMember(request: {
|
|
495
|
+
sessionId: string;
|
|
496
|
+
displayName: string;
|
|
497
|
+
role: string;
|
|
498
|
+
memberId?: string;
|
|
499
|
+
expectedRevision: number;
|
|
500
|
+
}, session?: string): Promise<MutationSuccess>;
|
|
501
|
+
export declare function createTeamSessionMember(request: {
|
|
502
|
+
displayName: string;
|
|
503
|
+
role: string;
|
|
504
|
+
expectedRevision: number;
|
|
505
|
+
}, session?: string): Promise<CreateSessionSuccess>;
|
|
506
|
+
export declare function interruptTeamMember(memberId: string, session?: string): Promise<InterruptTurnSuccess>;
|
|
507
|
+
export type ContactGrant = {
|
|
508
|
+
from: string;
|
|
509
|
+
to: string;
|
|
510
|
+
grantedBy: string;
|
|
511
|
+
at: number;
|
|
512
|
+
};
|
|
513
|
+
export type ContactGrantResult = {
|
|
514
|
+
grants: ContactGrant[];
|
|
515
|
+
leadMemberId?: string;
|
|
516
|
+
};
|
|
517
|
+
export declare function grantTeamContact(request: {
|
|
518
|
+
memberId: string;
|
|
519
|
+
allow: string;
|
|
520
|
+
action: 'add' | 'remove';
|
|
521
|
+
}, session?: string): Promise<ContactGrantResult>;
|
|
522
|
+
export declare function removeTeamMember(memberId: string, expectedRevision: number, session?: string): Promise<RemoveMemberSuccess>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|